5.6.1 Opening a Compound Document

To open a compound document, a client application should:

Register the client application document with the client DLL using the OleRegisterClientDoc function.

Load the application-specific document data from a file.

Load each object in the document.

Automatically update any automatic links. List any objects with manual links so that the user can update them.

5.6.1.1 Registering an OLE Document

Each time a client application creates or opens a document, it should register the document with the client DLL. A client application should register all documents it opens or creates, including untitled documents. Untitled documents can be registered initially using a default name, and then renamed when the document is saved under a new name by the user.

The OleRegisterClientDoc function is used to register a document with the client DLL. (This registration does not involve the system registration database.) OleRegisterClientDoc returns a handle to the document, which is then used to notify the client DLL of changes to the document such as renaming, saving, and closing.

When a document is saved under a new name, the client application should call the OleRenameClientDoc and OleSavedClientDoc functions, specifying the handle obtained from OleRegisterClientDoc.

5.6.1.2 Loading Objects

A client application calls the OleLoadFromStream function for each object in the document that will be shown on the screen or otherwise activated. It is not necessary to load every object in a document immediately when the document is opened; often only the objects that must be drawn or activated are loaded when the document is opened. Parameters for OleLoadFromStream include a pointer to the OLECLIENT structure, which is used to locate the client's CallBack function, and a pointer to the OLESTREAM structure, which is used to locate the Get function (pointed to in OLESTREAMVTBL) to load the object.

As the following code examples show, CLIDEMO.EXE initiates the loading of a document by calling ReadFromFile. ReadFromFile in turn calls ObjRead to read the individual objects. ObjRead then calls OleLoadFromStream to locate and call the Get callback function.

As part of loading the document, ReadFromFile calls the UpdateLinks function, which prompts the user to update any links to the objects in the document.

/*

* ReadFromFile()

*

* This function reads OLE objects from a file. If the document

* contains manual links, the user will be prompted to update those

* links.

*

* Returns BOOL - TRUE if the read(s) were successful

*/

BOOL FAR ReadFromFile // ENTRY:

(LPAPPSTREAM lpStream, // application stream pointer

LHCLIENTDOC lhcDoc, // document handle

LPOLECLIENT lpClient) // pointer to OLE client

// structure

{ // LOCAL:

BOOL bReturn = FALSE; // return value

unsigned int cFileObjects; // number of file objects

Hourglass(TRUE);

fLoadFile = TRUE;

_llseek(lpStream->fh, 0L, 0); // Read the number of objects

// in the file

if (_lread(lpStream->fh, (LPSTR)&cFileObjects,

sizeof(int)) < sizeof(int))

goto Error;

for (; cFileObjects; --cFileObjects)

{

if (!ObjRead(lpStream,lhcDoc,lpClient))

{

ErrorMessage(E_FAILED_TO_READ_OBJECT);

goto Error;

}

}

ShowDoc(lhcDoc,1);

UpdateLinks(lhcDoc);

bReturn = TRUE; // SUCCESS

Error: // ERROR Tag

Hourglass(FALSE);

fLoadFile = FALSE;

return bReturn; // return

}

/*

* ObjRead()

*

* Read an object from the specified file. The file pointer will

* be advanced past the object.

*

* HANDLE fh - DOS file handle of file to be read from

*

* returns HWND - window handle to item window containing the OLE

* object

*/

BOOL FAR ObjRead // ENTRY:

(LPAPPSTREAM lpStream, // application stream pointer

LHCLIENTDOC lhcDoc, // document handle

LPOLECLIENT lpClient) // pointer to OLE client

// structure

{ // LOCAL:

APPITEMPTR pItem; // application item pointer

LPOLEOBJECT lpObject; // pointer OLE object

long otObject; // type of object

RECT rcObject; // object rect

char szTmp[CBOBJNAMEMAX]; // temporary string buffer

// protocol string

char szProto[PROTOCOL_STRLEN+1];

int i; // index

if (_lread(lpStream->fh, szTmp, CBOBJNAMEMAX) < CBOBJNAMEMAX )

return FALSE;

if (_lread(lpStream->fh, szProto,PROTOCOL_STRLEN) < PROTOCOL_STRLEN)

return FALSE;

for (i=0; szProto[i] != ' '; i++);

szProto[i] = NULL;

ValidateName( szTmp );

if (!(pItem = PreItemCreate(lpClient, TRUE, lhcDoc)))

return FALSE;

if (Error(OleLoadFromStream((LPOLESTREAM)&(lpStream->olestream),

szProto,(LPOLECLIENT)&(pItem->oleclient), lhcDoc, szTmp,

&lpObject)))

goto Error;

if (_lread(lpStream->fh, (LPSTR)&rcObject,

sizeof(RECT)) < sizeof(RECT))

goto Error;

if (_lread(lpStream->fh, (LPSTR)&otObject,

sizeof(long)) < sizeof(long))

goto Error;

if (PostItemCreate(lpObject, otObject, &rcObject, pItem))

{

pItem->fNew = TRUE;

ObjSetBounds(pItem);

return TRUE; // SUCCESS return

}

else

return FALSE;

Error: // ERROR Tag

FreeAppItem(pItem);

return FALSE;

}

/*

* UpdateLinks()

*

* Get the most up to date rendering information and show it.

*/

static void UpdateLinks // ENTRY

(LHCLIENTDOC lhcDoc) // client document handle

{ // LOCAL:

int i=0; // index

APPITEMPTR pItem; // temporary item pointer

char szUpdate[CBMESSAGEMAX];// update message?

for (pItem = GetTopItem(); pItem; pItem = GetNextItem(pItem))

{

if (pItem->lhcDoc == lhcDoc && pItem->otObject == OT_LINK)

{

if (!i)

{

LoadString(hInst, IDS_UPDATELINKS, szUpdate, CBMESSAGEMAX);

if (MessageBox(hwndFrame, szUpdate, szAppName, MB_YESNO |

MB_ICONEXCLAMATION) != IDYES)

break;

i++;

}

Error(OleUpdate(pItem->lpObject));

}

}

WaitForAllObjects();

}