New OLE Interfaces for the Office 97 Binder

by Vinod Anantharaman

August 26, 1996

Abstract

This article describes two interesting new container interfaces supported by the Office 97 Binder. The first set of interfaces is used to support common headers and footers across Binder sections, while the second is used to print preview sections contained in a Binder. Third party applications can implement the corresponding server side interfaces to take advantage of these features when they are contained as sections within an Office 97 Binder.

1. Binder Headers and Footers

The Office 97 Binder allows common headers and footers across multiple heterogeneous sections contained in the Binder. The user interface for the Binder header/footer feature is accessed from the Binder Page Setup dialog on the File menu. Users can apply the Binder header/footer to sections created with Word 97, Excel 97 and Powerpoint 97. The shared header/footer can also be applied to third party applications that implement the necessary server interfaces described in this section.

Binder and server applications will communicate through two new interfaces: IMsoHdrFtrProvider, implemented by Binder, and IMsoHdrFtrClient, implemented by the server application. (In order to minimize the number of interfaces to be implemented by the server application, we decided against using IDataObject and IAdviceSink for the necessary data transfer.)

The header/footer interfaces and data structures are as follows:

/* Header footer item types */
typedef enum {
   MSOHFIT_TEXT,
   MSOHFIT_FACE,
   MSOHFIT_SIZE,
   MSOHFIT_EFFECTS,
   MSOHFIT_PAGENUM,
   MSOHFIT_TOTALPAGES,
   MSOHFIT_SECTIONNUM,
   MSOHFIT_SECTIONNAME,
   MSOHFIT_BINDERNAME,
   MSOHFIT_DATE,
   MSOHFIT_TIME
   MSOHFIT_BITMAP,      // Not currently used
} MSOHFIT;

/* Supported style flags */
typedef enum 
{
   MSOEFFECT_BOLD            = 0x00000001,
   MSOEFFECT_ITALIC            = 0x00000002,
   MSOEFFECT_UNDERLINE         = 0x00000004,
   MSOEFFECT_STRIKEOUT         = 0x00000008
} MSOEFFECT;

/* Used in IMsoHdrFtrProvider::GetFieldValues() */
typedef struct tagHDRFTRFIELD
{
/* msohfit can be one of {MSOHFIT_PAGENUM, MSOHFIT_TOTALPAGES, MSOHFIT_SECTIONNUM, MSOHFIT_SECTIONNAME, MSOHFIT_BINDERNAME, MSOHFIT_DATE, MSOHFIT_TIME} */
   MSOHFIT msohfit;

   ULONG cwActual;
   ULONG cwBuf;   /* size in wide chars of the buffer for text */
   wchar_t *wz;   /* Ptr to buffer into which callee writes the text */
} HDRFTRFIELD;

/* This structure represents one ‘item’ of hdr/ftr data.  It can hold a piece of text, a style definition, a font name, a font size, or a binder field. */
typedef struct  tagHDRFTRITEM
{
DWORD msohfit;
union 
{
/* Applies if msohfit is MSOHFIT_SIZE or MSOHFIT_EFFECTS.
If msohfit is MSOHFIT_SIZE, dwParam holds the font size in twips.
If msohfit is MSOHFIT_ EFFECTS, dwParam is a set of MSOEFFECT flags */
DWORD dwParam;

/* Applies if msohfit is MSOHFIT_TEXT or MSOHFIT_FACE. pvParam is a pointer to the text or the font name. dwParamLen holds the number of bytes pointed to by pvParam, including the string terminator. */
struct  
{
   DWORD dwParamLen;
   byte *pvParam;
};

/* for other values of msohfit, there are no parameters */
};
} HDRFTRITEM;

/* A hdr/ftr section is a block of hdr/ftr data.  It can hold the left hdr, center hdr, right hdr, left ftr, center ftr or right ftr.  It is made up of an array of hdr/ftr items. */
typedef struct tagHDRFTRSECTION
{
   DWORD dwCount;   // number of items pointed to by pItems.
   HDRFTRITEM *pItems;
} HDRFTRSECTION;

/* Implemented by Binder. */
interface IMsoHdrFtrProvider : IUnknown
{
   typedef IMsoHdrFtrProvider *LPMSOHDRFTRPROVIDER;

/* Called by the server to get the string value of some fields.  cFields specifies the number of fields. hffFields is an array of cField HDRFTRFIELD structs. */
   HRESULT GetFieldValues(
      ULONG cFields,
      HDRFTRFIELD hffFields[]);

/* Called by the server to tell binder whether this section is to use the global header/footer. Binder will change the state of ‘Apply binder header/footer to’ box appropriately. UseGlobalHeaderFooter(FALSE) is called by the server when the user decides to use custom headers/footers through the server’s UI. UseGlobalHeaderFooter(TRUE) will normally not be called. */
   HRESULT UseGlobalHeaderFooter(
      BOOL fUseGlobal);
}

/* Implemented by the server application */
interface IMsoHdrFtrClient : IUnknown
{
   typedef IMsoHdrFtrClient *LPMSOHDRFTRCLIENT;

/* Called initially by binder to give its IMsoHeaderFooterProvider pointer to the server */
   HRESULT SetProvider(
      IMsoHdrFtrProvider *pmsohfp);

/* Called by binder to tell the server whether it should use the global headers/footers as   opposed to custom ones. Binder will call this when the user changes the state of the section in the ‘Apply binder header/footer to’ box. */
   HRESULT UseGlobalHeaderFooter(
      BOOL fUseGlobal);

/* Called by binder to to give the hdr/ftr data to the server.  The entries are in the order {left hdr,center hdr, right hdr, left ftr, center ftr, right ftr} */
   HRESULT SetData(
      HDRFTRSECTION rghfs[6]);
}

How does it work?

The general communication path between Binder and a server application for Binder header and footer is described below:

When a section object is run, Binder queries the server for IMsoHdrFtrClient.  If it cannot get this interface pointer, then the section will not use the header/footer feature.

If Binder successfully obtains an IMsoHdrFtrClient pointer, it calls the IMsoHdrFtrClient::SetProvider method, passing a pointer to its implementation of IMsoHdrFtrProvider.

The server saves the interface pointer it got from SetProvider.

Whenever the header/footer information changes in Binder (as a result of the user bringing up the ‘Binder Page Setup’ dialog), Binder calls IMsoHdrFtrClient::SetData, and passes all the data to the server.

If the user changes the ‘Apply binder header/footer to’ settings through the ‘Binder Page Setup’ dialog, Binder will call IMsoHeaderFooterClient::UseGlobalHeaderFooter to tell the server whether it should be using the global headers and footers, or its own custom version.

Similarly, when the user tells the server (through whatever UI the server provides) whether it should use the global headers and footers, the server calls IMsoHeaderFooterProvider::UseGlobalHeaderFooter.  Binder needs this information to properly display the state of the sections in the ‘Apply binder header/footer to’ box.

2. Binder Print Preview

The Office 97 Binder allows in-place print preview across multiple heterogeneous sections contained in the Binder. The print preview command is accessed from the Binder File menu. Sections created using Word 97 and Excel 97 support print previews inside Office 97 Binder. Third party applications that implement the necessary server interfaces described in this section can also make use of this feature.

In order to support print preview, server applications need to implement the IInplacePrintPreview interface, which has 3 methods: StartPrintPreview, EndPrintPreview, and QueryStatus, all of which are input-sync. The container (Binder) implements the IPreviewCallback interface.

The print preview interfaces and data structures are shown below:

interface IInplacePrintPreview : IUnknown
{
   typedef [unique] IInplacePrintPreview *LPPRINTPREVIEW;

   typedef enum
   {
      PREVIEWFLAG_MAYBOTHERUSER    = 1,
      PREVIEWFLAG_PROMPTUSER      = 2,
      PREVIEWFLAG_USERMAYCHANGEPRINTER  = 4,
      PREVIEWFLAG_RECOMPOSETODEVICE   = 8,
   } PREVIEWFLAG;

   HRESULT __stdcall StartPrintPreview(
      [in] DWORD grfFlags,
      [in] DVTARGETDEVICE *pptd,
         [in] IPreviewCallback *ppCallback,
      [in]  LONG nFirstPage);

   [input_sync] 
   HRESULT __stdcall EndPrintPreview([in] BOOL fForceClose);
    
   [input_sync] 
   HRESULT QueryStatus();
}
   
interface IPreviewCallback : IUnknown
{
   typedef [unique] IPreviewCallback *LPPREVIEWCALLBACK;

   typedef enum
   {
    NOTIFY_FINISHED = 1,
    NOTIFY_BUSY = 2,
    NOTIFY_IDLE = 4,
    NOTIFY_DISABLERESIZE = 8,
    NOTIFY_QUERYCLOSEPREVIEW = 16,
    NOTIFY_FORCECLOSEPREVIEW  = 32,
    NOTIFY_UIACTIVE     = 64,
    NOTIFY_UNABLETOPREVIEW     = 128
   } NOTIFICATIONFLAG;

   [input_sync] 
   HRESULT Notify(
        [in] DWORD wStatus, 
        [in] LONG nLastPage, 
        [in, unique] wchar_t * pwszPreviewStatus);
}

Print preview interface description

The grfFlags in the call to StartPrintPreview  maybe a combination of the following  -PREVIEWFLAG_RECOMPOSETODEVICE, PREVIEWFLAG_PROMPTUSER, PREVIEWFLAG_MAYBOTHERUSER, PREVIEWFLAG_USERMAYCHANGEPRINTER. Binder uses the first 2 flags mentioned above.

The caller creates a target device and passes a pointer to the target device to the  StartPrintPreview method. A pointer to IPreviewCallback implemented by the caller is also passed in through StartPrintPreview so the callee can callback into the caller with notifications on preview status. The callee must AddRef the latter. The last parameter is the starting page number.

IPreviewCallback is implemented by the caller.  This interface has one method – Notify. The first parameter to the Notify function  is the status – which is any one of the enumerated types in  NOTIFICATIONFLAG. The most commonly used one is when the callee has exited  from print preview – NOTIFY_FINISHED.  Binder will pull down its preview toolbar, re-enable its menu items, and show its left pane when it receives this notification from the section that is in preview mode. Binder is in a fairly modal state during print preview. Other notifications are - NOTIFY_UNABLETOPREVIEW -  when the section normally supports the IInplacePrintPreview interface but is unable at that time to go into preview (for instance Excel will fail print preview when it has nothing to print, in which case it notifies Binder via this callback. Binder displays that section as a thumbnail instead of exiting print preview).

Binder calls EndPrintPreview when the user hits the ‘Exit’ button on the preview toolbar.  The section is then expected to  take itself out of print preview and then notify Binder via the IPreviewCallback::Notify function with NOTIFY_FINISHED

Binder calls the QueryStatus method to find out if the section is able to support PrintPreview at a given time. This is useful for sections that normally support IInplacePrintPreview, but may be unable to when they are in specific states.

Based on the result from QueryStatus Binder will decide to enable or disable the Print Preview command on the Binder Section menu.  Given that a section supports IInplacePrintPreview, Binder will first call QueryStatus, if that succeeds Binder will call StartPrintPreview with the appropriate parameters. Finally to end the preview, Binder will call EndPrintPreview.

If the section does not support the IInplacePrintPreview interface, Binder unloads the section to the loaded state and shows it in thumbnail mode.  The user can still use the Previous, Next and Exit buttons on Binder’s preview toolbar. 

Print preview  is similarly implemented at the section level, except only the active section will be put in preview mode. Binder’s preview toolbar will not be shown in this case and the user cannot navigate across sections in this mode.  The server’s preview toolbar button is implemented via the IMsoCommandTarget interface.  The inplace section has to call Binder’s IMsoCommandTarget::Exec with MSOCMDID_PRINTPREVIEW.   Binder will put only the active section into preview without showing Binder’s preview toolbar.