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
}