5.7.1 Creating Objects

A client application can put linked and embedded objects in a document by pasting them from the clipboard, creating them from a file, copying them from other objects, or by starting a server application to create them from a file, copying them from other objects, or by starting a server application to create them directly.

5.7.1.1 Object-Creation Functions

Each of the following functions creates an embedded or linked object in a specified document:

Function Description

OleClone Creates an exact copy of an object.
OleCopyFromLink Creates an embedded object that is a copy of a linked object.
OleCreate Creates an embedded object of a specified class.
OleCreateFromClip Creates an object from the clipboard. This function typically creates an embedded object.
OleCreateFromFile Creates an object by using the contents of a file. This function typically creates an embedded object.
OleCreateFromTemplate Creates an embedded object by using another object as a template.
OleCreateInvisible Creates an object without displaying the server application to the user.
OleCreateLinkFromClip Creates an object by using information on the clipboard. This function typically creates a linked object.
OleCreateLinkFromFile Creates an object by using the contents of a file. This function typically creates a linked object.
OleObjectConvert Creates an object that supports a specified protocol by converting an existing object.

Each of these functions takes a parameter that points to an LPOLEOBJECT structure when the function returns.

Before the client DLL gives the client application a pointer to this structure, the DLL includes with the structure some internal information corresponding to the OwnerLink or ObjectLink data. This internal information allows the client DLL to identify the correct server when an OLE function such as OleActivate passes it a pointer to an OLEOBJECT structure.

Note Each object must have a name that is unique to the client document. Although meaningful object names can be helpful, some applications assign unique object names simply by incrementing a counter for each new object. Remember too, that OLE object names are persistent; that is, when a document is saved, closed, and then reopened, the objects are loaded with the same names they had when they were saved.

If a client application implements the Insert Object menu command, it should use the system registration database to find out which OLE server applications are available and then list those applications for the user. When the user selects one of the server applications and chooses the OK button, the client application can use the OleCreate function to create an object at the current position.

The OleCopyFromLink, OleCreate, and OleCreateFromTemplate functions always create an embedded object. The other object-creation functions can create either an embedded object or a linked object, depending on the order and type of available data.

If a client application's CallBack function receives the OLE_RELEASE notification after the client calls the OleCreate or OleCreateFromFile function, the client application should respond by calling the OleQueryReleaseError function. If OleQueryReleaseError shows that there was an error when the object was created, the client application should delete the object.

Whenever an object-creation function returns OLE_WAIT_FOR_RELEASE, the calling application should either wait for the OLE_RELEASE notification, or notify the user that the object cannot be created. For more information, see "Handling Asynchronous Operations," earlier in this chapter.

If a client application accepts files dropped from File Manager for Microsoft Windows, version 3.1, it should respond to the WM_DROPFILES message by calling the OleCreateFromFile function and specifying Packager for the lpszClass parameter.

5.7.1.2 Paste and Paste Link Commands

A client application should do the following to create an embedded or linked object by pasting from the clipboard:

Call the OleQueryCreateFromClip function to determine whether to enable the Paste command. If this function fails when StdFileEditing is specified for the lpszProtocol parameter, call it again, specifying Static.

Call the OleQueryLinkFromClip function to determine whether to enable the Paste Link command.

If the user chooses the Paste command, open the clipboard and call the OleCreateFromClip function.

If the user chooses Paste Link, open the clipboard and call the OleCreateLinkFromClip function.

Close the clipboard.

Call the OleQueryType function to determine the kind of object created by the creation function. (Depending on the order of clipboard data, OleCreateFromClip can sometimes create a linked object and OleCreateLinkFromClip can sometimes create an embedded object.)

The client application should put the pasted data or object into the document at the current position. The client should select the object so that the user can work with it immediately. If both the OleQueryCreateFromClip and OleQueryLinkFromClip functions fail but there is data on the clipboard that the client can interpret, the client should enable the Paste command.

If the information on the clipboard is incomplete—for example, if Native data is not accompanied by OwnerLink format—the Paste command should insert a static object into the document.

Note Static objects consist of only the presentation data for an object. Attempts to open static objects fail.

If the client application implements the Paste Special command, it should use the EnumClipboardFormats function to produce a list of data formats on the clipboard. The client application should also check the system registration database to find the full name of the server application. The Paste Link button in the Paste Special dialog box works in exactly the same way as the Paste Link command on the Edit menu.

If the DDE Link format is available on the clipboard instead of ObjectLink format, the client application should perform the same link operation as it supported prior to the implementation of OLE.

The following code example demonstrates pasting an object from within CLIDEMO.EXE:

From CLIDEMO.C:

.

.

case IDM_PASTE

case IDM_PASTELINK:

ANY_OBJECT_BUSY;

ObjPaste(wParam == IDM_PASTE, lhcDoc, lpClient);

break;

From Object.C:

.

.

/*

* ObjPaste()

*

* This function obtains an object from the clipboard.

* Handles both embedded and linked objects. An item window is

* created for each new object.

*

* Returns BOOL - TRUE if object was pasted successfully.

*/

void FAR ObjPaste // ENTRY:

(BOOL fPaste, // Paste/PasteLink flag

LHCLIENTDOC lhcDoc, // client document handle

LPOLECLIENT lpClient) // pointer to client

{ // LOCAL:

LPOLEOBJECT lpObject; // object pointer

long otObject; // object type

APPITEMPTR pItem; // application item pointer

char szTmp[CBOBJNAMEMAX]; // temporary object name string

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

return; // ERROR return

if (!OpenClipboard(hwndFrame))

goto Error; // ERROR jump

if (fPaste) // PASTE the object.

{ // Try "StdFileEditing" protocol

if (Error(OleCreateFromClip(STDFILEEDITING,(LPOLECLIENT)&

(pItem->oleclient),lhcDoc, CreateNewUniqueName(szTmp),&lpObject,

olerender_draw,0)))

{

// next try "Static" protocol

if (Error(OleCreateFromClip(STATICP, (LPOLECLIENT)&

(pItem->oleclient), lhcDoc, CreateNewUniqueName(szTmp),

&lpObject, olerender_draw, 0)))

goto Error; // ERROR jump

}

}

else

{ // LINK therefore must be

// "STdFileEditing" protocol

if (Error(OleCreateLinkFromClip(STDFILEEDITING,(LPOLECLIENT)&

(pItem->oleclient), lhcDoc, CreateNewUniqueName(szTmp),

&lpObject, olerender_draw, 0)))

goto Error; // ERROR jump

}

OleQueryType(lpObject, &otObject);

CloseClipboard();

if (!PostItemCreate(lpObject, otObject, NULL, pItem))

return; // ERROR return

ShowNewWindow(pItem);

return; // SUCCESS return

Error: // TAG Error

ErrorMessage(E_GET_FROM_CLIPBOARD_FAILED);

CloseClipboard();

FreeAppItem(pItem);

return; // ERROR return

}

/*

* PostItemCreate()

*

* This function creates a child window which will contain the newly

* created OLE object. A pointer to our item information is stored in

* the extra bytes of this window. This is where we internally keep

* track of information related to the object as well as the

* pointer to the object for subsequent OLE API calls. This routine is

* called after an OLE object has been created by the client library.

*

* Returns BOOL - TRUE if application item has been created.

*

*/

BOOL FAR PostItemCreate // ENTRY:

(LPOLEOBJECT lpObject, // OLE object pointer

long otObject, // OLE object type

LPRECT lprcObject, // object bounding rect

APPITEMPTR pItem) // application item pointer

{ // LOCAL:

int i; // index

RECT rc; // bounding rectangle

char pData[OBJECT_LINK_MAX];// copy of link data

if (lprcObject) // if the size of the objects

rc = *lprcObject; // bounding rectangle is not

else if (OleQueryBounds(lpObject, &rc) == OLE_OK)

ConvertToClient(&rc);

else

SetRect(&rc, 0, 0, 0, 0);

// Create the child window

if (!(pItem->hwnd = CreateWindow( szItemClass, "",

WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_THICKFRAME,

rc.left,rc.top, rc.right - rc.left + 2 *

GetSystemMetrics(SM_CXFRAME), rc.bottom - rc.top + 2 *

GetSystemMetrics(SM_CYFRAME), hwndFrame, NULL, hInst, NULL)))

goto Error;

// in windows extra bytes

SetWindowWord(pItem->hwnd, 0, (WORD)pItem);

pItem->otObject = otObject;

pItem->lpObject = lpObject;

pItem->fRetry = TRUE;

if( pItem->otObject == OT_EMBEDDED ) // if object is embedded tell

// library the container name

{ // and object name.

int cb = CBOBJNAMEMAX; // Name will be server window title

char sz[CBOBJNAMEMAX]; // when the object is edited.

OleQueryName(lpObject, (LPSTR)sz, &cb );

WaitForObject(pItem);

Error(OleSetHostNames(lpObject, (LPSTR)szAppName, (LPSTR)sz ));

WaitForObject(pItem);

}

else if (pItem->otObject == OT_LINK) // if the object is linked

{ // retrieve update options

WaitForObject(pItem);

if(Error(OleGetLinkUpdateOptions(pItem->lpObject,

&pItem->uoObject)))

goto Error;

if (ObjGetData(pItem,pData))

{

for (i=0; pData[i];i++); // Skip past the server name

pItem->aLinkName = AddAtom(&pData[++i]);

}

else

pItem->aLinkName = AddAtom("");

}

iObjects++;

Dirty(DOC_DIRTY);

// a user interface recommendations.

return TRUE; // SUCCESS return

Error: // ERROR Tag

ErrorMessage(E_FAILED_TO_CREATE_CHILD_WINDOW);

FreeAppItem(pItem);

return FALSE; // ERROR return

}

/*

* ConvertToClient()

*

* This function will convert to client from himetric.

*/

void FAR ConvertToClient // ENTRY:

(LPRECT lprc) // pointer to bounding

// rectangle

{ // LOCAL

// If we have an empty rectangle then set the default size

if (!(lprc->left || lprc->top || lprc->right || lprc->bottom))

SetRect(lprc, 0, 0, CXDEFAULT, CYDEFAULT);

else

{

// We got the himetric units, converts them to pixels now.

lprc->right = MulDiv (giXppli, (lprc->right - lprc->left),

HIMETRIC_PER_INCH);

lprc->bottom = MulDiv (giYppli, (lprc->top - lprc->bottom),

HIMETRIC_PER_INCH);

lprc->left = 0;

lprc->top = 0;

}

}