A server installing an object handler registers the handler with the registration database, using the keyword handler. Whenever a client application calls one of the object-creation functions, the client library uses the class name specified for the object and the handler keyword to search the registration database. If the library finds an object handler, the client library loads the handler and calls it to create the object. The handler can create an object for which all of the creation functions and methods are defined by the handler, or it can call default object-creation functions in the client library.
The client library exports the object-creation OLE functions with new names; in each case, the prefix “Ole” is changed to “Def” (for “default”). Object handlers can import any of these functions and use them when creating objects.
Object handlers must import the following functions:
OLE function | Name exported by client library |
OleCreate | DefCreate |
OleCreateFromClip | DefCreateFromClip |
OleCreateFromFile | DefCreateFromFile |
OleCreateFromTemplate | DefCreateFromTemplate |
OleCreateLinkFromClip | DefCreateLinkFromClip |
OleCreateLinkFromFile | DefCreateLinkFromFile |
OleLoadFromStream | DefLoadFromStream |
When an object handler defines a function that is to be called by the client application, it should use the same name as the corresponding OLE function the client calls, with the prefix “Ole” replaced by “Dll”. For example, when an object handler uses the DefCreate function exported by the client library, the handler should use it inside a function named DllCreate. When the client library finds an object handler for a class of object, it calls handler-specific object-creation functions by specifying this “Dll” prefix.
When the handler calls one of the default object-creation functions, it receives a handle of an OLEOBJECT structure, which in turn points to the OLEOBJECTVTBL structure containing the current object-management functions. The object handler should copy this OLEOBJECTVTBL structure and customize the structure by replacing any function pointers in the structure with pointers to functions of its own. (If the object handler saves the pointers to the default functions, any of the replacement functions can also call the default functions in the table of function pointers.) When the object handler has finished customizing the structure, it should replace the pointer to the old OLEOBJECTVTBL structure with a pointer to the modified OLEOBJECTVTBL structure.
When the client makes a call to a function in the client library, the call is dispatched through the object handler's OLEOBJECTVTBL structure. If the object handler has replaced the function pointer, the call is routed to the function supplied by the handler. Otherwise, the call is routed to the client library.
Each OLECLIENT, OLEOBJECT, OLESERVER, OLESERVERDOC, or OLESTREAM structure contains a pointer to a structure that contains a table of function pointers. (Structures containing tables of function pointers are identified with the “VTBL” suffix.) Each of the structures containing a pointer to a “VTBL”structure can also contain extra instance-specific information. This information is meaningful only to the application that supplies it and should not be used by other applications; for example, an object handler should not attempt to use any instance-specific information in an OLECLIENT structure.
The object handler should use the “Def” and “Dll” renaming conventions when it defines specialized functions. For example, if an object handler modifies the Draw function from an object's OLEOBJECTVTBL structure, it should copy that Draw function to a function named DefDraw and replace the Draw function with a specialized function named DllDraw. Inside the DllDraw function, the object handler can call DefDraw if the default drawing operation is appropriate in a particular case.
The following example demonstrates this process of copying and replacing pointers to functions. Functions with the “Dll” prefix should be exported in the module-definition file.
/* Declare the DllDraw and DefDraw functions. */
OLESTATUS FAR PASCAL DllDraw(LPOLEOBJECT, HDC, LPRECT, LPRECT, HDC);
OLESTATUS (FAR PASCAL *DefDraw)(LPOLEOBJECT, HDC, LPRECT, LPRECT, HDC);
/* Copy the Draw function from OLEOBJECTVTBL to DefDraw. */
DefDraw = lpobj->lpvtbl->Draw;
/* Copy DllDraw to OLEOBJECTVTBL. */
*lpobj->lpvtbl->Draw = DllDraw;
OLESTATUS FAR PASCAL DllDraw(lpObject, hdc, lpBounds, lpWBounds,
hdcFormat)
LPOLEOBJECT lpObject;
HDC hdc;
LPRECT lpBounds;
LPRECT lpWBounds;
HDC hdcFormat;
{
/* Return DefDraw if Native data is not available. */
if ((*lpobj->lpvtbl->GetData) (lpobj, cfNative, &hData) != OLE_OK)
return (*DefDraw) (lpobj, hdc, lpBounds, lpWBounds, hdcFormat);
.
.
.
}