INF: OLE Data Structures and Structure Allocation

ID Number: Q83457

3.10

WINDOWS

Summary:

In general, object linking and embedding (OLE) client and server

applications deal with the data structures defined in the OLE.H header

file. However, these data structures contain only a single pointer to

a table of function pointers (a VTBL structure).

To associate additional data with the item represented by the VTBL

data structure, an application must create a superset of the

appropriate structures in OLE.H. The new structure must contain all

fields of the original structure and any additional application-

specific data desired.

This article describes the OLE data structures and provides examples

of application-specific structures. This article also discusses how

the OLE libraries use pointers to structures and details the most

efficient way to allocate memory for OLE data structures.

More Information:

OLE Data Structures and Parameter Types

---------------------------------------

The OLE.H header file defines five main data structures and a VTBL

structure for each. The following table lists these structures and

their contents:

Data Structure Contents

-------------- --------

OLECLIENT One LPOLECLIENTVTBL

OLECLIENTVTBL One far pointer to the client application's

notification procedure: CallBack.

OLESTREAM One LPOLESTREAMVTBL

OLESTREAMVTBL Far pointers to the stream methods, Get and Put.

OLEOBJECT One LPOLEOBJECTVTBL

OLEOBJECTVTBL Far pointers to object methods. For example:

DoVerb, GetData, Release, and Show.

OLESERVER One LPOLESERVERVTBL

OLESERVERVTBL Far pointers to server methods. For example:

Create, Edit, and Release.

OLESERVERDOC One LPOLESERVERDOCVTBL

OLESERVERDOCVTBL Far pointers to document methods. For example:

GetObject, Release, and SetHostNames.

OLE client applications use only the OLECLIENT and OLESTREAM data

structures and their associated VTBL structures. OLE server

applications use all the structures above except for the OLESTREAM

data structure.

Each of the five data structures above contains only a single pointer

to its associated VTBL data type. An application can achieve the

greatest use of these structures by defining its own data types. Make

sure that the VTBL pointer is the first member of each application-

specific data structure.

For example, the following code defines MYOLESERVER as a replacement

for the OLESERVER data structure:

typedef struct

{

LPOLESERVERVTBL pvtbl; // Standard

LHSERVER lh; // Required by OleRegisterServer

BOOL fRelease; // TRUE if waiting required

BOOL fEmbed; // TRUE if only embedding

BOOL fLink; // TRUE if only linking

WORD wCmdShow; // OLE-specific window show command

HWND hWnd; // Main application window

HANDLE hMem; // Memory handle to this structure

LPDOCUMENT pDoc; // Last document allocated

} MYOLESERVER;

An LPOLESERVERVTBL must be the first member of the MYOLESERVER data

structure. The MYOLESERVER structure also contains other information

that is useful in OLESERVTBL methods, such as a pointer to the default

document.

An application can pass a pointer to a variable of the MYOLESERVER

data type to any OLE function that requires a pointer to an OLESERVER.

OLE will typecast the pointer to an LPOLESERVER to access the VTBL

member, leaving the remainder of the structure untouched.

Any time that an OLE library calls any callback function (method) in

the application, it uses the pointer the application passed in, which

continues to point to the application-specific data.

This technique applies to both client and server applications for all

five data structures. Specifically,

- A pointer to an OLECLIENT structure is provided by the client

application's CallBack function.

- Pointers to OLESTREAM structures are provided by the client

application's Get and Put methods (in OLESTREAMVTBL).

- Pointers to OLEOBJECT, OLESERVER and OLESERVERDOC structures are

provided by the methods defined and referenced in the appropriate

VTBL structures.

During the process of creating an application's methods and callback

functions (to fill in VTBL structures), the application can replace

any standard OLE structure pointer with a pointer to an application-

defined data type. For example, all OLESERVERVTBL methods are defined

to accept an LPOLESERVER type. However, the OLESERVTBL method accepts

the same pointer that the application passed to a function such as

OleRegisterServer, the application can replace the LPOLESERVER type in

the function with an application-defined far pointer data type.

Replacing standard OLE data types with application-defined data types

eliminates local variables in which the application stores a typecast

copy of a parameter with a standard data type. This technique applies

to all five OLE data structures; the client application's CallBack can

change the LPOLECLIENT data type, and other methods can perform

similar changes.

How OLE Uses Pointers, Allocating Structures

--------------------------------------------

OLE uses pointers to structures to allow an application to define its

own data structures as outlined above. However, doing so precludes the

application from running in real mode Windows 3.0. An OLE application

will run only in protected mode.

After an application allocates a data structure, it must lock the

allocated memory to obtain a pointer to the memory. It is important to

plan how the application will use memory to ensure that leaving the

block of memory locked is of little consequence.

If the application allocates local memory with the LocalAlloc

function, specify LMEM_FIXED as the value for the wFlags parameter. Do

not use the alternative method to allocate fixed local memory (calling

LocalAlloc with wFlags set to LMEM_MOVEABLE, followed by a call to

LocalLock) because this creates a "sand bar" in the local heap.

LMEM_FIXED local memory is the better choice for local memory that

will remain locked.

If the application allocates global memory with the GlobalAlloc

function, specify GMEM_MOVEABLE as the wFlags parameter. Then call

GlobalLock to lock the memory. If GMEM_FIXED is specified in the

GlobalAlloc call, the data structure is allocated from the scarce

memory with an address below 1 megabyte (MB). Allocating the object as

GMEM_MOVEABLE and keeping the memory locked enables the application to

retain a pointer to the memory block without creating any "sand bars"

that interfere with memory management.