II. Header file describing Office 97 Binder file format

/*************************************************************************
**
**    Office 97 Binder
**
**    datadef.h
**
**    (c) Copyright Microsoft Corp. 1996 All Rights Reserved
**
*************************************************************************/
// Number of elements in an array
#define ARRAYSIZE(a)   (sizeof(a)/sizeof((a)[0]))

// Maximum size of a string within Binder. Nominally used for LoadString calls.
#define MAX_STR_SIZE              256

#define MAX_SHELL_FILENAME_LEN 250

#define MAX_FILENAME_LEN   256         // Including NULL

#define MAX_PATH_LEN    MAX_PATH       // Including NULL, drive, colon, leading seperator.
#define MAX_FILE_LEN    MAX_PATH_LEN

#define MAX_MENUNAME_LEN           64  // Including NULL

#define MAX_EXT_SIZE             4

#define MAX_STATUS_SIZE      MAX_STR_SIZE

// {59850400-6664-101B-B21C-00AA004BA90B} + NULL.
// The number of TEXT characters that a CLSID will be represented by.
#define MAX_CLSID_STR_LEN                39

// CWSTORAGENAME is the maximum amount allowed for a sub-storage. It is currently
// defined as 32 characters INCLUDING the NULL.
#define MAX_SECTION_STG_NAME       CWCSTORAGENAME
#define MAX_SECTION_STG_CHARS     (MAX_SECTION_STG_NAME - 1)

#define MAX_SECTION_DISPLAY_NAME          MAX_FILENAME_LEN
#define MAX_SECTION_DISPLAY_CHARS        (MAX_SECTION_DISPLAY_NAME - 1)


#define APPMAJORVERSIONNO  8  // major no. incremented for major releases
                              //  (eg. when an incompatible change is made
                              //  to the storage format)
#define APPMINORVERSIONNO   0 // minor no. incremented for minor releases

#define APPMINIMUMVERSIONNO   5 // minimum version # that this version of app can read
#define BDRTYPELIBMAJORVERNO  8 // major ver. # for Binder Typelib
#define BDRTYPELIBMINORVERNO  0 // minor ver. # for Binder Typelib





typedef struct{
             int                        SectionIndex;
             char                       SectionName[MAX_SECTION_DISPLAY_NAME];
} SECTIONDATA, *PSECTIONDATA;

typedef enum tagSAVE_TYPE{
             SAVE_SAME                    =   0,
             SAVE_AS                          =   1,
             SAVE_COPY_AS             =   2
}SAVE_TYPE;

#define  LOAD_NEW_FILE_FROM_TEMPLATE                  0x0001
#define  LOAD_READONLY                                0x0002
#define  LOAD_APPLY_FRAME_POS                         0x0004
#define  LOAD_DISPLAY_ERRORS                          0x0008

// struct definition for persistent data storage of Binder data

// Format of Binder stream.
//
//             1)DOCHEADER 
//             2)SECTION_RECORD
//             3)History list for that section (used by Reconciler) 
//             .
//             .
//             ... for as many sections as are present, repeat 2 and 3 for all sections
//   and all deleted sections.

// Stored in Binder stream. Opened and read by CDocument::FLoadFromStg.
typedef struct tagDOCHEADER {
              DWORD              m_dwLength;                 // Length (in bytes) of the structure
              LONG               m_narrAppVersionNo[2];
              LONG               m_narrMinAppVersionNo[2];
              GUID               m_guidBinderId;             // The unique ID of the binder
              DWORD              m_cSections;
              DWORD              m_cDeletedSections;
              LONG               m_nActiveSection;
              LONG               m_nFirstVisibleTab;         // in the left pane
              FILETIME           m_TotalEditTime; // amount of time file is open for edit
              FILETIME           m_CreateTime;    // Time Created
              FILETIME           m_LastPrint;     // When last printed
              FILETIME           m_LastSave;      // When last saved
              DWORD              m_dwState;       // remember state info like left pane visibility
              DWORD              m_reserved[3];             // space reserved for future use
} DOCHEADER, * PDOCHEADER;

// Stored in Binder stream. 1 per Section. Read by CSection::Load
typedef struct tagSECTIONRECORD
{
              DWORD              m_dwLength;      // Length (in bytes) of all the
                                                  // data that make up a section.
                                                  // It includes the size of the
                                                  // SECTIONNAMERECORD and of the
                                                  // history list.
              GUID               m_guidSectionId; // The unique ID of the section
              DWORD              m_dwState;       // state of this section
              DWORD              m_dwStgNumber;
                                                  // Unique stg number for this section
              DWORD              m_reserved1;     // space reserved for future use
              DWORD              m_reserved2;     // space reserved for future use
              DWORD              m_reserved3;     // space reserved for future use
              DWORD              m_reserved4;     // space reserved for future use
              DWORD              m_dwDisplayNameOffset;
                                                  // Offset to the SECTIONNAMERECORD
                                                  // from the beggining of this struct.
              DWORD              m_dwHistoryListOffset;
                                                  // Offset to the history list
                                                  // from the beggining of this struct.
                                                  // Display name
                                                  // History list
} SECTIONRECORD, * PSECTIONRECORD;


typedef struct tagSECTIONNAMERECORD
{
              DWORD              m_dwNameSize;   // Size of variable length
                                                 // Display name
                                                 // Display name of size m_dwNameSize
} SECTIONNAMERECORD, * PSECTIONNAMERECORD;


// Stored in binder stream. 1 per deleted section (used for Reconciler)
typedef struct tagDELETEDSECTIONRECORD
{
              DWORD              m_dwLength;
                                                 // Length in bytes of all the
                                                 // data that make up a section
                                                 // It includes the size of the
                                                 // SECTIONNAMERECORD and of the
                                                 // history list.
              GUID               m_guidSectionId;// The unique ID of the section
              DWORD              m_reserved1;    // space reserved for future use
              DWORD              m_reserved2;    // space reserved for future use
              DWORD              m_reserved3;    // space reserved for future use
              DWORD              m_reserved4;    // space reserved for future use
              DWORD              m_dwDisplayNameOffset; // Offset to the SECTIONNAMERECORD
                                                 // from the beggining of this struct.
              DWORD              m_dwHistoryListOffset; // Offset to the history list
                                                 // from the beggining of this struct.
                                                 // Display name
                                                 // History list
} DELETEDSECTIONRECORD, * PDELETEDSECTIONRECORD;


struct CGenericMetaSection
{
public:
              CGenericMetaSection(LPSTREAM pStm, LONG *narrAppVersionNo)
              {
                                m_pStm = pStm;
                                m_narrAppVersionNo[0] = narrAppVersionNo[0];
                                m_narrAppVersionNo[1] = narrAppVersionNo[1];
              }

              virtual ~CGenericMetaSection() {};

              /*
               * Read the current record.  The stream must be positioned at the
               * beginning of the record to be read.
               */
              HRESULT ReadRecord()
              {
                             HRESULT hrErr;
                             LARGE_INTEGER libZero = {0,0};
                             if (SUCCEEDED(hrErr = m_pStm->Seek(libZero, STREAM_SEEK_CUR,
              &m_libStart)))
                           {
                                           hrErr = m_pStm->Read(GetRecordAddress(), GetRecordSize(), NULL);
                           }
                           return hrErr;
                           }

              /*
               * Seek to the beginning of the display name structure
               */
              HRESULT SeekDisplayName()
              {
                             return SeekOffset(GetDisplayNameOffset());
              }

              /*
               * Seek to the beginning of the history list structure
               */
              HRESULT SeekHistoryList()
              {
                             return SeekOffset(GetHistoryListOffset());
              }

              /*
               * Should only be called after ReadRecord has been called.  This function
               * will position the stream at the end of the current record, no matter
               * what its current position is.  ReadRecord can be called again after
               * SkipCurrentRecord is called in order to get the next record.
               */
              HRESULT SkipCurrentRecord()
              {
                             return SeekOffset(GetTotalSectionSize());
              }

              virtual PVOID GetRecordAddress() = 0;
              virtual DWORD GetRecordSize() = 0;

protected:
              
              /*
               * Seek to a given offset from the beginning of the section record
               */
              HRESULT SeekOffset(DWORD dwOffset)
              {
                             LARGE_INTEGER libTemp = {0,0};
                             libTemp.LowPart = m_libStart.LowPart + dwOffset;
                             return m_pStm->Seek(libTemp, STREAM_SEEK_SET, NULL);
              }

              virtual DWORD GetTotalSectionSize() = 0;
              virtual DWORD GetDisplayNameOffset() = 0;
              virtual DWORD GetHistoryListOffset() = 0;

              ULARGE_INTEGER        m_libStart;
              LPSTREAM                      m_pStm;
              LONG                                m_narrAppVersionNo[2];
};


struct CMetaSectionRecord: public CGenericMetaSection, public tagSECTIONRECORD
{
public:
              CMetaSectionRecord(LPSTREAM pStm, LONG *narrAppVersionNo)
                           : CGenericMetaSection(pStm, narrAppVersionNo) {};

              virtual PVOID GetRecordAddress()
                             { return (tagSECTIONRECORD*)this; }
              virtual DWORD GetRecordSize()
                             { return sizeof SECTIONRECORD; }

protected:
              virtual DWORD GetTotalSectionSize() { return m_dwLength; }
              virtual DWORD GetDisplayNameOffset() { return m_dwDisplayNameOffset; }
              virtual DWORD GetHistoryListOffset() { return m_dwHistoryListOffset; }
};


struct CMetaDeletedSectionRecord: public CGenericMetaSection,
public tagDELETEDSECTIONRECORD
{
public:
              CMetaDeletedSectionRecord(LPSTREAM pStm, LONG *narrAppVersionNo)
                          : CGenericMetaSection(pStm, narrAppVersionNo) {};

              virtual PVOID GetRecordAddress()
                             { return (tagDELETEDSECTIONRECORD*)this; }
              virtual DWORD GetRecordSize()
                             { return sizeof DELETEDSECTIONRECORD; }

protected:
              virtual DWORD GetTotalSectionSize() { return m_dwLength; }
              virtual DWORD GetDisplayNameOffset() { return m_dwDisplayNameOffset; }
              virtual DWORD GetHistoryListOffset() { return m_dwHistoryListOffset; }
};


// Persistent section flags: DO NOT MODIFY THE VALUES
typedef enum {
              SECTIONSTATE_VISIBLE                        = 0x00000001L,
              SECTIONSTATE_SELECTED                       = 0x00000002L,
              SECTIONSTATE_ACTIVE                         = 0x00000004L,
              SECTIONSTATE_USEGLOBALHDRFTR                = 0x00000008L,
// Does the section use the global Header/Footer (only valid if FSupportHdrFtr() is TRUE).
              SECTIONSTATE_CREATEFROMOLE                  = 0x01000000L
// When section is Run, re-create from file.
} SECTIONSTATE;


/////////////////////////////////////////////////////////////////////////////
// OLE 2.0 COM (Component Object Model) implementation infrastructure.
// Taken from MFC (afxdisp.h) and extended.

#define _AFX_NO_NESTED_DERIVATION

#define METHOD_PROLOGUE(theClass, localClass) \
              theClass* pThis = \
                             ((theClass*)((BYTE*)this - offsetof(theClass, m_x##localClass)));

#ifndef _AFX_NO_NESTED_DERIVATION
#define METHOD_PROLOGUE_EX(theClass, localClass) \
              theClass* pThis = ((theClass*)((BYTE*)this - m_nOffset));

#else
#define METHOD_PROLOGUE_EX(theClass, localClass) \
              METHOD_PROLOGUE(theClass, localClass)

#endif

#define BEGIN_INTERFACE_PART(localClass, baseClass) \
              class X##localClass : public baseClass \
              { \
              public: \
                             STDMETHOD_(ULONG, AddRef)(); \
                             STDMETHOD_(ULONG, Release)(); \
                             STDMETHOD(QueryInterface)(REFIID iid, PVOID* ppvObj);

#ifdef _DEBUG

#define IMPLEMENT_DEBUG_ADDREF \
                             m_cRef++;

#define IMPLEMENT_DEBUG_RELEASE \
              Assert(m_cRef > 0); \
              m_cRef--;

#else
#define IMPLEMENT_DEBUG_ADDREF
#define IMPLEMENT_DEBUG_RELEASE
#endif /* !_DEBUG */

#define IMPLEMENT_INTERFACE_PART_EX(theClass, localClass, addref, release, qi) \
              ULONG theClass::X##localClass::AddRef() { \
                             METHOD_PROLOGUE_EX(theClass, localClass) \
                             IMPLEMENT_DEBUG_ADDREF \
                             return pThis->addref(); \
              } \
              ULONG theClass::X##localClass::Release() { \
                             METHOD_PROLOGUE_EX(theClass, localClass) \
                             IMPLEMENT_DEBUG_RELEASE \
                             return pThis->release(); \
              } \
              STDMETHODIMP theClass::X##localClass::QueryInterface(REFIID iid, void **ppvObj) { \
                             METHOD_PROLOGUE_EX(theClass, localClass) \
                             return pThis->qi(iid, ppvObj); \
              }

#define IMPLEMENT_INTERFACE_PART(theClass, localClass) \
              IMPLEMENT_INTERFACE_PART_EX(theClass, localClass, AddRef, \
                             Release, QueryInterface)


// Section uses these macros
#define IMPLEMENT_SECTION_INTERFACE_PART_EX(theClass, localClass, addref, release, qi) \
              ULONG theClass::X##localClass::AddRef() { \
                             hrIllegalSectionCallChk(); \
                             METHOD_PROLOGUE_EX(theClass, localClass) \
                             IMPLEMENT_DEBUG_ADDREF \
                             return pThis->addref(); \
              } \
              ULONG theClass::X##localClass::Release() { \
                             dwIllegalSectionCallChk(); \
                             METHOD_PROLOGUE_EX(theClass, localClass) \
                             IMPLEMENT_DEBUG_RELEASE \
                             return pThis->release(); \
              } \
              STDMETHODIMP theClass::X##localClass::QueryInterface(REFIID iid, void **ppvObj) { \
                             dwIllegalSectionCallChk(); \
                             METHOD_PROLOGUE_EX(theClass, localClass) \
                             return pThis->qi(iid, ppvObj); \
              }

#define IMPLEMENT_SECTION_INTERFACE_PART(theClass, localClass) \
              IMPLEMENT_SECTION_INTERFACE_PART_EX(theClass, localClass, AddRef, \
                             Release, QueryInterface)


//

#ifdef _DEBUG

#define DEFINE_REFCOUNT \
              ULONG m_cRef;

#else
#define DEFINE_REFCOUNT
#endif

#ifndef _AFX_NO_NESTED_DERIVATION
#define INIT_INTERFACE_PART(theClass, localClass) \
                             DEFINE_REFCOUNT \
                             size_t m_nOffset; \
                             X##localClass() \
                                           { m_nOffset = offsetof(theClass, m_x##localClass); }

#else
#define INIT_INTERFACE_PART(theClass, localClass) \
                             DEFINE_REFCOUNT

#endif

// Note: Inserts the rest of OLE functionality between these two macros,
//  depending upon the interface that is being implemented.  It is not
//  necessary to include AddRef, Release, and QueryInterface since those
//  member functions are declared by the macro.

#define END_INTERFACE_PART(localClass) \
              } m_x##localClass; \
              friend class X##localClass;


*************