5.5.2 Allocating and Initializing the OLECLIENT and OLESTREAM Structures

The OLECLIENT data structure is allocated and initialized by the client application, and then passed to the client DLL.

Before calling any function in the client DLL, the client application needs to allocate and initialize the OLECLIENTVTBL and OLESTREAMVTBL structures with the MakeProcInstance call, setting each field in these structures. Memory must be allocated for these structures since the OLECLIENT and OLESTREAM structures only contain pointers to the VTBLs.

If a MakeProcInstance call fails, then the application should fail initialization and terminate—a client application cannot function without the ability for the client DLL to call these callback functions.

To illustrate, consider the following code examples from CLIDEMO.EXE, which are used to allocate and initialize the OLECLIENT and OLESTREAM wrapper structures:

/*

* InitAsOleClient()

*

* Initiates the creation of stream and client vtbls. These vtbls

* are very important for the proper operation of this application.

* The stream vtbl lets the OLE libraries know where the location of

* the stream I/O routines reside. The stream routines are used by

* OleLoadFromStream and the like. The client vtbl is used to hold

* the pointer to the CallBack function.

*

* IMPORTANT: both the client and the stream structures have pointers

* to vtbls which have the pointers to the functions. Therefore, it

* is necessary to allocate space for the vtbl and the client

* structure that has the pointer to the vtbl.

*/

static BOOL InitAsOleClient( // ENTRY:

HANDLE hInstance, // application instance handle

HWND hwnd, // main window handle

PSTR pFileName, // document file name

LHCLIENTDOC *lhcDoc, // pointer to document Handle

LPOLECLIENT *lpClient, // pointer to client pointer

LPAPPSTREAM *lpStream) // pointer to APPSTREAM pointer

{

// initiate client vtbl creation

if (!(*lpClient = InitClient(hInstance)))

{

SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);

return FALSE; // ERROR return

}

// initiate stream vtbl creation

if (!(*lpStream = InitStream(hInstance)))

{

SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);

return FALSE; // ERROR return

}

if (*pFileName && RegDoc(pFileName,lhcDoc)

&& LoadFile(pFileName,*lhcDoc,*lpClient,*lpStream))

{

SetTitle(pFileName);

return TRUE; // SUCCESS return

}

NewFile(pFileName, lhcDoc, *lpStream);

return TRUE; // SUCCESS return

} // SUCCESS return

/*

* InitClient()

* Initialize the OLE client structure, create and fill the

* OLECLIENTVTBL structure.

*

* Returns LPOLECLIENT - if successful a pointer to a client

* structure otherwise NULL.

*/

static LPOLECLIENT InitClient // ENTRY:

(HANDLE hInstance) // application instance handle

{ // LOCAL:

LPOLECLIENT lpClient=NULL; // pointer to client struct

// Allocate vtbls

if (!(lpClient = (LPOLECLIENT)GlobalLock(

GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLECLIENT)))))

goto Error; // ERROR jump

if (!(lpClient->lpvtbl = (LPOLECLIENTVTBL)GlobalLock(

GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,sizeof(OLECLIENTVTBL)))))

goto Error; // ERROR jump

// set the CALLBACK function

// pointer

lpClient->lpvtbl->CallBack = MakeProcInstance(CallBack, hInst);

return lpClient; // SUCCESS return

Error: // ERROR Tag

ErrorMessage(E_FAILED_TO_ALLOC);

EndClient(lpClient); // free any allocated space

return NULL; // ERROR return

}

/*

* InitStream()

*

* Create and fill the STREAMVTBL. Create a stream structure and

* initialize pointer to stream vtbl.

*

* Returns LPAPPSTREAM - if successful a pointer to a stream

* structure otherwise NULL .

.*/

static LPAPPSTREAM InitStream // ENTRY:

(HANDLE hInstance) // handle to application instance

{ // LOCAL:

LPAPPSTREAM lpStream = NULL; // pointer to stream structure

if (!(lpStream = (LPAPPSTREAM)GlobalLock(

GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(APPSTREAM)))))

goto Error; // ERROR jump

if (!(lpStream->olestream.lpstbl = (LPOLESTREAMVTBL)GlobalLock(

GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,sizeof(OLESTREAMVTBL)))))

goto Error; // ERROR jump

// set stream func. pointers

lpStream->olestream.lpstbl->Get = (DWORD (FAR PASCAL *)(LPOLESTREAM,

LPSTR, DWORD)) MakeProcInstance((FARPROC)ReadStream, hInst);

lpStream->olestream.lpstbl->Put = (DWORD (FAR PASCAL *)(LPOLESTREAM,

LPSTR, DWORD)) MakeProcInstance((FARPROC)WriteStream, hInst);

return lpStream; // SUCCESS return

Error: // ERROR Tag

ErrorMessage(E_FAILED_TO_ALLOC);

EndStream(lpStream);

return NULL; // ERROR return

}