The OLE UI Library and the Busy Dialog Box

I begged and pleaded and it finally happened. When I first worked with OLE version 1, I figured that the hardest part about implementing a compound document container (the only kind of client then) was providing all of the user interface, namely a bunch of dialog boxes. When I began working with OLE 2, I tried hard to convince others that Microsoft should implement common dialog boxes. Although I initially met stiff resistance ("not enough resources"), eventually it made sense to everyone: I was going to have to implement these dialog boxes anyway, the OLE 2 team would have to provide them in their own samples, and various Microsoft product groups—including product support—were going to have to implement them for their customers. So a number of us got together to divide up the work. From that effort came the OLE UI Library, or just OLEUI, which will save you a tremendous amount of time in providing the proper OLE user interface elements in various types of applications, notably those involved with OLE Documents.

The OLE UI Library was shipped originally as a bunch of sample code containing not only the dialog boxes but a host of other helper functions that usually began with the prefix OleStd. Many of these functions—some renamed and others modified—have ended up in the utility library for this book's samples, found in the INOLE directory. Since that time, a reduced version of this code, containing little more than the dialogs themselves, has become part of the operating system (Microsoft Windows 95, Microsoft Windows NT 3.51, and later). It is now called OLEDLG.DLL. This book's samples attempt to link to this library. Documentation is generally found in the file OLE2UI.HLP, but check the header file for the most accurate information.

We'll see quite a lot of OLEUI as we go through additional chapters in this book. What is of interest here is the standard busy dialog box that we saw in Figure 6-4 on page 307. To invoke this dialog box, you must fill a structure named OLEUIBUSY and pass it to the function OleUIBusy. The structure and the function are defined in OLE2UI.H as follows:


typedef struct tagOLEUIBUSY
{
//These IN fields are standard across all OLEUI dialog functions.
DWORD cbStruct; //Structure size
DWORD dwFlags; //IN-OUT: flags
HWND hWndOwner; //Owning window
LPCTSTR lpszCaption; //Dialog caption bar contents
LPFNOLEUIHOOK lpfnHook; //Hook callback
LPARAM lCustData; //Custom data to pass to hook
HINSTANCE hInstance; //Instance for customized template
LPCTSTR lpszTemplate; //Customized template name
HRSRC hResource; //Customized template handle

//Specifics for OLEUIBUSY
HTASK hTask; //IN: hTask that is blocking
HWND FAR * lphWndDialog; //IN: dialog's HWND placed here.
} OLEUIBUSY, *POLEUIBUSY, FAR *LPOLEUIBUSY;

//API prototype
STDAPI_(UINT) OleUIBusy(LPOLEUIBUSY);

The first set of fields in the structure is common across all the OLEUI dialogs by design. These fields allow you to control various standard aspects of the dialog boxes, such as the caption, the layout template, and the dialog box's parent window. You can also hook the dialog box to preprocess Windows messages coming into it, with the exception of WM_INITDIALOG, for which you can perform post-processing.

Each dialog box–specific structure also includes a few extra fields as needed for that dialog box. In the case of the busy dialog box, there are only two: hTask is where a client stores a busy server's task handle, the exact one it receives in IMessageFilter members (intelligent, no?); lphWndDialog is a pointer to an HWND variable in which the calling client can obtain the (modal) dialog box's handle while that dialog box is visible if the client needs to cancel it for any reason.

There are four flags that you can combine and store in the dwFlags field of the structure. The first three, BZ_DISABLECANCELBUTTON, BZ_DISABLESWITCHTOBUTTON, and BZ_DISABLERETRYBUTTON, selectively disable the dialog box's buttons, whereas the fourth, BZ_NOTRESPONDINGDIALOG, changes the wording slightly, from a "server is busy" description to "server is not responding," and disables the Cancel button. Usually you use this flag when invoking the dialog from IMessageFilter::MessagePending rather than from IMessageFilter::RetryRejectedCall.

Let's see how we use this dialog in ObjectUser2.