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.
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();
}