You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2339 lines
65 KiB
2339 lines
65 KiB
|
|
/****************************** Module Header ******************************\
|
|
* Module Name: le.c
|
|
*
|
|
* Purpose: Handles all API routines for the dde L&E sub-dll of the ole dll.
|
|
*
|
|
* Created: 1990
|
|
*
|
|
* Copyright (c) 1990, 1991 Microsoft Corporation
|
|
*
|
|
* History:
|
|
* Raor, srinik (../../1990,91) Designed and coded
|
|
* curts created portable version for win16/32
|
|
*
|
|
\***************************************************************************/
|
|
|
|
#include <windows.h>
|
|
#include "dll.h"
|
|
|
|
#define EMB_ID_INDEX 3 // index of ones digit in #000
|
|
char embStr[] = "#000";
|
|
|
|
extern HANDLE hInfo;
|
|
extern OLECLIPFORMAT cfNetworkName;
|
|
|
|
HANDLE GetNetNameHandle (LPOBJECT_LE);
|
|
BOOL AreTopicsEqual (LPOBJECT_LE, LPOBJECT_LE);
|
|
|
|
ATOM FARINTERNAL wAtomCat (ATOM, ATOM);
|
|
|
|
|
|
OLEOBJECTVTBL vtblLE = {
|
|
|
|
LeQueryProtocol, // check whether the speced protocol is supported
|
|
|
|
LeRelease, // release
|
|
LeShow, // Show
|
|
LeDoVerb, // run
|
|
LeGetData,
|
|
LeSetData,
|
|
LeSetTargetDevice, //
|
|
|
|
LeSetBounds, // set viewport bounds
|
|
LeEnumFormat, // returns format
|
|
LeSetColorScheme, // set color scheme
|
|
LeRelease, // delete
|
|
LeSetHostNames, //
|
|
LeSaveToStream, // write to file
|
|
LeClone, // clone object
|
|
LeCopyFromLink, // Create embedded from Link
|
|
|
|
LeEqual, // test whether the object data is similar
|
|
|
|
LeCopy, // copy to clip
|
|
|
|
LeDraw, // draw the object
|
|
|
|
LeActivate, // activate
|
|
LeExecute, // excute the given commands
|
|
LeClose, // stop
|
|
LeUpdate, // Update
|
|
LeReconnect, // Reconnect
|
|
|
|
LeObjectConvert, // convert object to specified type
|
|
|
|
LeGetUpdateOptions, // Get Link Update options
|
|
LeSetUpdateOptions, // Set Link Update options
|
|
|
|
ObjRename, // Change Object name
|
|
ObjQueryName, // Get current object name
|
|
|
|
LeQueryType, // object Type
|
|
LeQueryBounds, // QueryBounds
|
|
ObjQuerySize, // Find the size of the object
|
|
LeQueryOpen, // Query open
|
|
LeQueryOutOfDate, // query whether object is current
|
|
|
|
LeQueryReleaseStatus, // returns release status
|
|
LeQueryReleaseError, // assynchronusrelease error
|
|
LeQueryReleaseMethod, // the method/proc which is in assynchronus
|
|
// operation.
|
|
LeRequestData, // requestdata
|
|
LeObjectLong, // objectLong
|
|
LeChangeData // change native data of existing object
|
|
};
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS FAR PASCAL LeObjectLong (lpoleobj, wFlags, lpData)
|
|
//
|
|
//
|
|
// Returns whether a given object is still processing a previous
|
|
// asynchronous command. returns OLE_BUSY if the object is still
|
|
// processing the previous command
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobj - ole object pointer
|
|
// wFlags - get, set flags
|
|
// lpData - long pointer to data
|
|
//
|
|
// Returns:
|
|
//
|
|
// OLE_OK
|
|
// OLE_ERROR_OBJECT
|
|
//
|
|
// Effects:
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
OLESTATUS FARINTERNAL LeObjectLong (
|
|
LPOLEOBJECT lpoleobj,
|
|
UINT wFlags,
|
|
LPLONG lpData
|
|
){
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
LONG lData;
|
|
|
|
Puts("LeObjectLong");
|
|
|
|
if (!FarCheckObject((LPOLEOBJECT) lpobj))
|
|
return OLE_ERROR_OBJECT;
|
|
|
|
if ((lpobj->head.ctype != CT_EMBEDDED) && (lpobj->head.ctype != CT_LINK))
|
|
return OLE_ERROR_OBJECT;
|
|
|
|
if (wFlags & OF_HANDLER) {
|
|
lData = lpobj->lHandlerData;
|
|
if (wFlags & OF_SET)
|
|
lpobj->lHandlerData = *lpData;
|
|
|
|
if (wFlags & OF_GET)
|
|
*lpData = lData;
|
|
}
|
|
else {
|
|
lData = lpobj->lAppData;
|
|
if (wFlags & OF_SET)
|
|
lpobj->lAppData = *lpData;
|
|
|
|
if (wFlags & OF_GET)
|
|
*lpData = lData;
|
|
}
|
|
|
|
return OLE_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS FAR PASCAL LeQueryReleaseStatus (lpoleobj)
|
|
//
|
|
//
|
|
// Returns whether a given object is still processing a previous
|
|
// asynchronous command. returns OLE_BUSY if the object is still
|
|
// processing the previous command
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobj - ole object pointer
|
|
//
|
|
// Returns:
|
|
//
|
|
// OLE_BUSY - object is busy
|
|
// OLE_OK - not busy
|
|
//
|
|
// Effects:
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
OLESTATUS FAR PASCAL LeQueryReleaseStatus (LPOLEOBJECT lpoleobj)
|
|
{
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
|
|
// probe async will clean up the channels
|
|
// if the server died.
|
|
|
|
|
|
PROBE_ASYNC (lpobj);
|
|
return OLE_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS FAR PASCAL LeQueryReleaseError (lpoleobj)
|
|
//
|
|
// returns the errors of an asynchronous command.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobj - ole object pointer
|
|
//
|
|
// Returns:
|
|
//
|
|
// OLE_ERROR_.. - if there is any error
|
|
// OLE_OK - no error
|
|
//
|
|
// Note: This api is typically valid only during the callback of
|
|
// OLE_RELEASE.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
OLESTATUS FAR PASCAL LeQueryReleaseError (LPOLEOBJECT lpoleobj)
|
|
{
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
|
|
return lpobj->mainErr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLE_RELEASE_METHOD FAR PASCAL LeQueryReleaseMethod (lpoleobj)
|
|
//
|
|
// returns the method/command of the asynchronous command which
|
|
// resulted in the OLE_RELEASE call back.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobj - ole object pointer
|
|
//
|
|
// Returns:
|
|
// OLE_RELEASE_METHOD
|
|
//
|
|
// Note: This api is typically valid only during the callback of
|
|
// OLE_RELEASE. Using this api, clients can decide which previous
|
|
// asynchronous command resulted in OLE_RELEASE.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
OLE_RELEASE_METHOD FAR PASCAL LeQueryReleaseMethod (LPOLEOBJECT lpoleobj)
|
|
{
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
|
|
return lpobj->oldasyncCmd;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LPVOID FARINTERNAL LeQueryProtocol (lpoleobj, lpprotocol)
|
|
//
|
|
// Given an oject, returns the new object handle for the new protocol.
|
|
// Does the conversion of objects from one protocol to another one.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobj - ole object pointer
|
|
// lpprotocol - ptr to new protocol string
|
|
//
|
|
// Returns:
|
|
// lpobj - New object handle
|
|
// null - if the protocol is not supported.
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
LPVOID FARINTERNAL LeQueryProtocol (
|
|
LPOLEOBJECT lpoleobj,
|
|
OLE_LPCSTR lpprotocol
|
|
){
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
|
|
if (lpobj->bOldLink)
|
|
return NULL;
|
|
|
|
if (!lstrcmp (lpprotocol, PROTOCOL_EDIT))
|
|
return lpobj;
|
|
|
|
if (!lstrcmp (lpprotocol, PROTOCOL_EXECUTE)) {
|
|
if (UtilQueryProtocol (lpobj, lpprotocol))
|
|
return lpobj;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS EmbLnkDelete (lpoleobj)
|
|
//
|
|
// Routine for the object termination/deletion. Schedules differnt
|
|
// asynchronous commands depending on different conditions.
|
|
// Arguments:
|
|
//
|
|
// Sends "StdClose" only if it is Ok to close the document. Sends
|
|
// "StdExit" only if the server has to be unlaunched. Deletes the object
|
|
// only if the original command is OLE_DELETE. No need to call back the
|
|
// client if the deletion is internal.
|
|
//
|
|
// While delete, this routine is entered several times. EAIT_FOR_ASYNC_MSG
|
|
// results in going back to from where it is called and the next DDE message
|
|
// brings back the control to this routine.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpobj - object pointer
|
|
//
|
|
// Returns:
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
OLESTATUS FARINTERNAL EmbLnkDelete (LPOBJECT_LE lpobj)
|
|
{
|
|
HOBJECT hobj;
|
|
|
|
switch (lpobj->subRtn) {
|
|
|
|
case 0:
|
|
|
|
SKIP_TO (!QueryClose (lpobj), step1);
|
|
// Send "StdCloseDocument"
|
|
SendStdClose (lpobj);
|
|
WAIT_FOR_ASYNC_MSG (lpobj);
|
|
|
|
case 1:
|
|
|
|
step1:
|
|
SETSTEP (lpobj, 1);
|
|
|
|
// End the doc conversation
|
|
TermDocConv (lpobj);
|
|
WAIT_FOR_ASYNC_MSG (lpobj);
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
// delete the doc edit block. It is Ok even if the object
|
|
// is not actually getting deleted.
|
|
DeleteDocEdit (lpobj);
|
|
|
|
// if need to unluanch the app, send stdexit.
|
|
SKIP_TO (!QueryUnlaunch (lpobj), step3);
|
|
SendStdExit (lpobj);
|
|
WAIT_FOR_ASYNC_MSG (lpobj);
|
|
|
|
case 3:
|
|
|
|
step3:
|
|
SETSTEP (lpobj, 3);
|
|
|
|
// Do not set any errors.
|
|
// Terminate the server conversation.
|
|
TermSrvrConv (lpobj);
|
|
WAIT_FOR_ASYNC_MSG (lpobj);
|
|
|
|
case 4:
|
|
|
|
// delete the server edit block
|
|
DeleteSrvrEdit (lpobj);
|
|
if (lpobj->asyncCmd != OLE_DELETE) {
|
|
|
|
// if this delete is called because of unlauncinh of
|
|
// object because of some error, no need to
|
|
// call end asynchronous. It should have been already
|
|
// called from somewhere else.
|
|
|
|
if (lpobj->asyncCmd == OLE_SERVERUNLAUNCH){
|
|
// send the async cmd;
|
|
CLEARASYNCCMD (lpobj);
|
|
} else
|
|
EndAsyncCmd (lpobj);
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
|
|
// for real delete delete the atoms and space.
|
|
DeleteObjectAtoms (lpobj);
|
|
|
|
if (lpobj->lpobjPict)
|
|
(*lpobj->lpobjPict->lpvtbl->Delete) (lpobj->lpobjPict);
|
|
|
|
if (lpobj->hnative)
|
|
GlobalFree (lpobj->hnative);
|
|
|
|
if (lpobj->hLink)
|
|
GlobalFree (lpobj->hLink);
|
|
|
|
if (lpobj->hhostNames)
|
|
GlobalFree (lpobj->hhostNames);
|
|
|
|
if (lpobj->htargetDevice)
|
|
GlobalFree (lpobj->htargetDevice);
|
|
|
|
if (lpobj->hdocDimensions)
|
|
GlobalFree (lpobj->hdocDimensions);
|
|
|
|
DeleteExtraData (lpobj);
|
|
|
|
DocDeleteObject ((LPOLEOBJECT) lpobj);
|
|
// send the async cmd;
|
|
EndAsyncCmd (lpobj);
|
|
|
|
if (lpobj->head.iTable != INVALID_INDEX)
|
|
DecreaseHandlerObjCount (lpobj->head.iTable);
|
|
|
|
hobj = lpobj->head.hobj;
|
|
ASSERT (hobj, "Object handle NULL in delete")
|
|
|
|
GlobalUnlock (hobj);
|
|
GlobalFree (hobj);
|
|
|
|
return OLE_OK;
|
|
}
|
|
|
|
return OLE_ERROR_GENERIC;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS FARINTERNAL LeRelease (lpoleobj)
|
|
//
|
|
// Deletes the given object. This is can be asynchronous operation.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobj - ole object pointer
|
|
//
|
|
// Returns:
|
|
//
|
|
// OLE_WAIT_FOR_RELASE: If any DDE_TRANSACTIONS have been queued
|
|
// OLE_OK : If deletion successfully
|
|
// OLE_ERROR_... : If any error
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
OLESTATUS FARINTERNAL LeRelease (LPOLEOBJECT lpoleobj)
|
|
{
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE) lpoleobj;
|
|
|
|
|
|
// For delete allow if the object has been aborted.
|
|
|
|
PROBE_ASYNC (lpobj);
|
|
|
|
// reset the flags so that we do not delete the object based on the old
|
|
// flags
|
|
lpobj->fCmd = 0;
|
|
InitAsyncCmd (lpobj, OLE_DELETE, EMBLNKDELETE);
|
|
return EmbLnkDelete (lpobj);
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS FARINTERNAL LeClone (lpoleobjsrc, lpclient, lhclientdoc, lpobjname, lplpobj)
|
|
//
|
|
// Clones a given object.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobjsrc: ptr to the src object.
|
|
// lpclient: client callback handle
|
|
// lhclientdoc: doc handle
|
|
// lpobjname: object name
|
|
// lplpobj: holder for returning object.
|
|
//
|
|
// Returns:
|
|
// OLE_OK : successful
|
|
// OLE_ERROR_... : error
|
|
//
|
|
// Note: If the object being cloned is connected to the server, then
|
|
// the cloned object is not connected to the server. For linked
|
|
// objects, OleConnect has to be called.
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
OLESTATUS FARINTERNAL LeClone (
|
|
LPOLEOBJECT lpoleobjsrc,
|
|
LPOLECLIENT lpclient,
|
|
LHCLIENTDOC lhclientdoc,
|
|
OLE_LPCSTR lpobjname,
|
|
LPOLEOBJECT FAR * lplpoleobj
|
|
){
|
|
LPOBJECT_LE lpobjsrc = (LPOBJECT_LE) lpoleobjsrc;
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE) NULL;
|
|
int retval = OLE_ERROR_MEMORY;
|
|
|
|
// Assumes all the creates are in order
|
|
// PROBE_OBJECT_BLANK(lpobjsrc);
|
|
|
|
PROBE_CREATE_ASYNC(lpobjsrc);
|
|
|
|
if (!(lpobj = LeCreateBlank(lhclientdoc, (LPSTR)lpobjname,
|
|
lpobjsrc->head.ctype)))
|
|
goto errRtn;
|
|
|
|
lpobj->head.lpclient = lpclient;
|
|
lpobj->head.iTable = lpobjsrc->head.iTable; //!!! dll loading
|
|
lpobj->head.lpvtbl = lpobjsrc->head.lpvtbl;
|
|
|
|
// set the atoms.
|
|
lpobj->app = DuplicateAtom (lpobjsrc->app);
|
|
lpobj->topic = DuplicateAtom (lpobjsrc->topic);
|
|
lpobj->item = DuplicateAtom (lpobjsrc->item);
|
|
lpobj->aServer = DuplicateAtom (lpobjsrc->aServer);
|
|
|
|
lpobj->bOleServer = lpobjsrc->bOleServer;
|
|
lpobj->verb = lpobjsrc->verb;
|
|
lpobj->fCmd = lpobjsrc->fCmd;
|
|
|
|
lpobj->aNetName = DuplicateAtom (lpobjsrc->aNetName);
|
|
lpobj->cDrive = lpobjsrc->cDrive;
|
|
lpobj->dwNetInfo = lpobjsrc->dwNetInfo;
|
|
|
|
if (lpobjsrc->htargetDevice)
|
|
lpobj->htargetDevice = DuplicateGlobal (lpobjsrc->htargetDevice,
|
|
GMEM_MOVEABLE);
|
|
|
|
if (lpobjsrc->head.ctype == CT_EMBEDDED) {
|
|
if (lpobjsrc->hnative) {
|
|
if (!(lpobj->hnative = DuplicateGlobal (lpobjsrc->hnative,
|
|
GMEM_MOVEABLE)))
|
|
goto errRtn;
|
|
}
|
|
|
|
if (lpobjsrc->hdocDimensions)
|
|
lpobj->hdocDimensions = DuplicateGlobal (lpobjsrc->hdocDimensions,
|
|
GMEM_MOVEABLE);
|
|
if (lpobjsrc->hlogpal)
|
|
lpobj->hlogpal = DuplicateGlobal (lpobjsrc->hlogpal,
|
|
GMEM_MOVEABLE);
|
|
SetEmbeddedTopic (lpobj);
|
|
}
|
|
else {
|
|
lpobj->bOldLink = lpobjsrc->bOldLink;
|
|
lpobj->optUpdate = lpobjsrc->optUpdate;
|
|
}
|
|
|
|
retval = OLE_OK;
|
|
// if picture is needed clone the picture object.
|
|
if ((!lpobjsrc->lpobjPict) ||
|
|
((retval = (*lpobjsrc->lpobjPict->lpvtbl->Clone)(lpobjsrc->lpobjPict,
|
|
lpclient, lhclientdoc, lpobjname,
|
|
(LPOLEOBJECT FAR *)&lpobj->lpobjPict))
|
|
== OLE_OK)) {
|
|
SetExtents (lpobj);
|
|
*lplpoleobj = (LPOLEOBJECT)lpobj;
|
|
if (lpobj->lpobjPict)
|
|
lpobj->lpobjPict->lpParent = (LPOLEOBJECT) lpobj;
|
|
}
|
|
|
|
return retval;
|
|
|
|
errRtn:
|
|
|
|
// This oledelete should not result in any async communication.
|
|
if (lpobj)
|
|
OleDelete ((LPOLEOBJECT)lpobj);
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS FARINTERNAL LeCopyFromLink (lpoleobjsrc, lpclient, lhclientdoc, lpobjname, lplpobj)
|
|
//
|
|
// Creates an embedded object from a lonked object. If the linked object
|
|
// is not activated, then launches the server, gets the native data and
|
|
// unlaunches the server. All these operations are done silently.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobjsrc: ptr to the src object.
|
|
// lpclient: client callback handle
|
|
// lhclientdoc: doc handle
|
|
// lpobjname: object name
|
|
// lplpobj: holder for returning object.
|
|
//
|
|
// Returns:
|
|
// OLE_OK : successful
|
|
// OLE_ERROR_... : error
|
|
// OLE_WAITF_FOR_RELEASE : if DDE transcation is queued
|
|
//
|
|
// Note: Could result in asynchronous operation if there is any
|
|
// DDE operaion involved in getting any data from the server.
|
|
//
|
|
// Also, If there is any error in getting the native data, the
|
|
// client is expected delete the object after the OLE_RELEASE
|
|
// call back
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
OLESTATUS FARINTERNAL LeCopyFromLink (
|
|
LPOLEOBJECT lpoleobjsrc,
|
|
LPOLECLIENT lpclient,
|
|
LHCLIENTDOC lhclientdoc,
|
|
OLE_LPCSTR lpobjname,
|
|
LPOLEOBJECT FAR * lplpoleobj
|
|
){
|
|
|
|
LPOBJECT_LE lpobjsrc = (LPOBJECT_LE)lpoleobjsrc;
|
|
LPOBJECT_LE lpobj;
|
|
int retval;
|
|
|
|
|
|
*lplpoleobj = (LPOLEOBJECT)NULL;
|
|
PROBE_OLDLINK (lpobjsrc);
|
|
if (lpobjsrc->head.ctype != CT_LINK)
|
|
return OLE_ERROR_NOT_LINK;
|
|
|
|
PROBE_ASYNC (lpobjsrc);
|
|
PROBE_SVRCLOSING(lpobjsrc);
|
|
|
|
if ((retval = LeClone ((LPOLEOBJECT)lpobjsrc, lpclient, lhclientdoc, lpobjname,
|
|
(LPOLEOBJECT FAR *)&lpobj)) != OLE_OK)
|
|
return retval;
|
|
|
|
|
|
// we successfully cloned the object. if picture object has native data
|
|
// then grab it and put it in LE object. otherwise activate and get native
|
|
// data also.
|
|
|
|
if (lpobj->lpobjPict
|
|
&& (*lpobj->lpobjPict->lpvtbl->EnumFormats)
|
|
(lpobj->lpobjPict, 0) == cfNative){
|
|
// Now we know that the picture object is of native format, and it
|
|
// means that it is a generic object. So grab the handle to native
|
|
// data and put it in LE object.
|
|
|
|
lpobj->hnative = ((LPOBJECT_GEN) (lpobj->lpobjPict))->hData;
|
|
((LPOBJECT_GEN) (lpobj->lpobjPict))->hData = (HANDLE)NULL;
|
|
(*lpobj->lpobjPict->lpvtbl->Delete) (lpobj->lpobjPict);
|
|
lpobj->lpobjPict = (LPOLEOBJECT)NULL;
|
|
SetEmbeddedTopic (lpobj);
|
|
*lplpoleobj = (LPOLEOBJECT)lpobj;
|
|
return OLE_OK;
|
|
} else {
|
|
|
|
// if necessary launch, get native data and unlaunch the app.
|
|
lpobj->fCmd = LN_LNKACT | ACT_REQUEST | ACT_NATIVE | (QueryOpen(lpobjsrc) ? ACT_TERMDOC : ACT_UNLAUNCH);
|
|
InitAsyncCmd (lpobj, OLE_COPYFROMLNK, LNKOPENUPDATE);
|
|
if ((retval = LnkOpenUpdate (lpobj)) > OLE_WAIT_FOR_RELEASE)
|
|
LeRelease ((LPOLEOBJECT)lpobj);
|
|
else
|
|
*lplpoleobj = (LPOLEOBJECT)lpobj;
|
|
|
|
return retval;
|
|
|
|
// we will be changing the topic in end conversation.
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS FARINTERNAL LeEqual (lpoleobj1, lpoleobj2)
|
|
//
|
|
// Checks whethere two objects are equal. Checks for equality
|
|
// of links, native data and picture data.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobj1: first object
|
|
// lpoleobj2: second object
|
|
//
|
|
// Returns:
|
|
// OLE_OK : equal
|
|
// OLE_ERROR_NOT_EQUAL : if not equal
|
|
// OLE_ERROR_..... : any errors
|
|
//
|
|
// Note: If any of the objects are connectd to the servers, leequal operaion
|
|
// may not make much sense because the data might be changing from the
|
|
// the server
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
OLESTATUS FARINTERNAL LeEqual (
|
|
LPOLEOBJECT lpoleobj1,
|
|
LPOLEOBJECT lpoleobj2
|
|
){
|
|
LPOBJECT_LE lpobj1 = (LPOBJECT_LE)lpoleobj1;
|
|
LPOBJECT_LE lpobj2 = (LPOBJECT_LE)lpoleobj2;
|
|
|
|
if (lpobj1->app != lpobj2->app)
|
|
return OLE_ERROR_NOT_EQUAL;
|
|
|
|
// type of the objects is same. Otherwise this routine won't be called
|
|
if (lpobj1->head.ctype == CT_LINK) {
|
|
if (AreTopicsEqual (lpobj1, lpobj2) && (lpobj1->item == lpobj2->item))
|
|
return OLE_OK;
|
|
|
|
return OLE_ERROR_NOT_EQUAL;
|
|
}
|
|
else {
|
|
ASSERT (lpobj1->head.ctype == CT_EMBEDDED, "Invalid ctype in LeEqual")
|
|
|
|
if (lpobj1->item != lpobj2->item)
|
|
return OLE_ERROR_NOT_EQUAL;
|
|
|
|
if (CmpGlobals (lpobj1->hnative, lpobj2->hnative))
|
|
return OLE_OK;
|
|
else
|
|
return OLE_ERROR_NOT_EQUAL;
|
|
}
|
|
|
|
//### we may have to compare the picture data also
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS FARINTERNAL LeCopy (lpoleobj)
|
|
//
|
|
// Copies the object to the clipboard. Even for linked objects
|
|
// we do not render the objectlink. It is up to the client app
|
|
// to render object link
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobj: object handle
|
|
//
|
|
// Returns:
|
|
// OLE_OK : successful
|
|
// OLE_ERROR_..... : any errors
|
|
//
|
|
// Note: Library does not open the clipboard. Client is supposed to
|
|
// open the librray before this call is made
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
OLESTATUS FARINTERNAL LeCopy (LPOLEOBJECT lpoleobj)
|
|
{
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
HANDLE hlink = (HANDLE)NULL;
|
|
HANDLE hnative = (HANDLE)NULL;
|
|
|
|
PROBE_OLDLINK (lpobj);
|
|
// Assumes all the creates are in order
|
|
// PROBE_OBJECT_BLANK(lpobj);
|
|
|
|
PROBE_CREATE_ASYNC(lpobj);
|
|
|
|
if (lpobj->head.ctype == CT_EMBEDDED){
|
|
if (!(hnative = DuplicateGlobal (lpobj->hnative, GMEM_MOVEABLE)))
|
|
return OLE_ERROR_MEMORY;
|
|
SetClipboardData (cfNative, hnative);
|
|
}
|
|
|
|
hlink = GetLink (lpobj);
|
|
if (!(hlink = DuplicateGlobal (hlink, GMEM_MOVEABLE)))
|
|
return OLE_ERROR_MEMORY;
|
|
SetClipboardData (cfOwnerLink, hlink);
|
|
|
|
// copy network name if it exists
|
|
if (lpobj->head.ctype == CT_LINK && lpobj->aNetName) {
|
|
HANDLE hNetName;
|
|
|
|
if (hNetName = GetNetNameHandle (lpobj))
|
|
SetClipboardData (cfNetworkName, hNetName);
|
|
}
|
|
|
|
if (lpobj->lpobjPict)
|
|
return (*lpobj->lpobjPict->lpvtbl->CopyToClipboard)(lpobj->lpobjPict);
|
|
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS FARINTERNAL LeQueryBounds (lpoleobj, lpRc)
|
|
//
|
|
// Returns the bounding rectangle of the object. Returns topleft
|
|
// as zero always and the units are himetric units.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobj: object handle
|
|
//
|
|
// Returns:
|
|
// OLE_OK : successful
|
|
// OLE_ERROR_..... : any errors
|
|
//
|
|
// Note: Library does not open the clipboard. Client is supposed to
|
|
// open the librray before this call is made
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
OLESTATUS FARINTERNAL LeQueryBounds (
|
|
LPOLEOBJECT lpoleobj,
|
|
LPRECT lpRc
|
|
){
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
Puts("LeQueryBounds");
|
|
|
|
// MM_HIMETRIC units
|
|
|
|
lpRc->left = 0;
|
|
lpRc->top = 0;
|
|
lpRc->right = (int) lpobj->head.cx;
|
|
lpRc->bottom = (int) lpobj->head.cy;
|
|
|
|
if (lpRc->right || lpRc->bottom)
|
|
return OLE_OK;
|
|
|
|
if (!lpobj->lpobjPict)
|
|
return OLE_ERROR_BLANK;
|
|
|
|
return (*lpobj->lpobjPict->lpvtbl->QueryBounds) (lpobj->lpobjPict, lpRc);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS FARINTERNAL LeDraw (lpoleobj, hdc, lprc, lpWrc, hdcTarget)
|
|
//
|
|
// Draws the object. Calls the picture object for drawing the object
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobj: source object
|
|
// hdc: handle to dest dc. Could be metafile dc
|
|
// lprc: rectangle into which the object should be drawn
|
|
// should be in himetric units and topleft
|
|
// could be nonzero.
|
|
// hdctarget: Target dc for which the object should be drawn
|
|
// (Ex: Draw metafile on the dest dc using the attributes
|
|
// of traget dc).
|
|
//
|
|
// Returns:
|
|
// OLE_OK : successful
|
|
// OLE_ERROR_BLANK : no picture
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
OLESTATUS FARINTERNAL LeDraw (
|
|
LPOLEOBJECT lpoleobj,
|
|
HDC hdc,
|
|
OLE_CONST RECT FAR* lprc,
|
|
OLE_CONST RECT FAR* lpWrc,
|
|
HDC hdcTarget
|
|
){
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
|
|
if (lpobj->lpobjPict)
|
|
return (*lpobj->lpobjPict->lpvtbl->Draw) (lpobj->lpobjPict,
|
|
hdc, lprc, lpWrc, hdcTarget);
|
|
return OLE_ERROR_BLANK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLECLIPFORMAT FARINTERNAL LeEnumFormat (lpoleobj, cfFormat)
|
|
//
|
|
// Enumerates the object formats.
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobj : source object
|
|
// cfFormat : ref fprmat
|
|
//
|
|
// Returns:
|
|
// NULL : no more formats or if we do not understand the
|
|
// given format.
|
|
//
|
|
// Note: Even if the object is connected, we do not enumerate all the formats
|
|
// the server can render. Server protocol can render the format list
|
|
// only on system channel. Object can be connected only on the doc
|
|
// channel
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
OLECLIPFORMAT FARINTERNAL LeEnumFormat (
|
|
LPOLEOBJECT lpoleobj,
|
|
OLECLIPFORMAT cfFormat
|
|
){
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
|
|
Puts("LeEnumFormat");
|
|
|
|
ASSERT((lpobj->head.ctype == CT_LINK)||(lpobj->head.ctype == CT_EMBEDDED),
|
|
"Invalid Object Type");
|
|
|
|
// switch is not used because case won't take variable argument
|
|
if (cfFormat == (OLECLIPFORMAT)NULL) {
|
|
if (lpobj->head.ctype == CT_EMBEDDED)
|
|
return cfNative;
|
|
else
|
|
return (lpobj->bOldLink ? cfLink : cfObjectLink);
|
|
}
|
|
|
|
if (cfFormat == cfNative) {
|
|
if (lpobj->head.ctype == CT_EMBEDDED)
|
|
return cfOwnerLink;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
if (cfFormat == cfObjectLink) {
|
|
if (lpobj->aNetName)
|
|
return cfNetworkName;
|
|
else
|
|
cfFormat = (OLECLIPFORMAT)NULL;
|
|
}
|
|
else if (cfFormat == cfOwnerLink || cfFormat == cfLink
|
|
|| cfFormat == cfNetworkName)
|
|
cfFormat = (OLECLIPFORMAT)NULL;
|
|
|
|
if (lpobj->lpobjPict)
|
|
return (*lpobj->lpobjPict->lpvtbl->EnumFormats) (lpobj->lpobjPict, cfFormat);
|
|
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
// OLESTATUS FARINTERNAL LeRequestData (lpoleobj, cfFormat)
|
|
//
|
|
// Requests data from the server for a given format, if the server
|
|
// is connected. If the server is not connected returns error.
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobj: source object
|
|
// cfFormat: ref fprmat
|
|
//
|
|
// Returns:
|
|
// OLE_WAIT_FOR_RELEASE : If the data request data is sent to
|
|
// the server.
|
|
// OLE_ERROR_NOT_OPEN : Server is not open for data
|
|
//
|
|
// Note: If the server is ready, sends request to the server. When the
|
|
// the data comes back from the server OLE_DATA_READY is sent in
|
|
// the callback and the client can use Getdata to get the data.
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
OLESTATUS FARINTERNAL LeRequestData (
|
|
LPOLEOBJECT lpoleobj,
|
|
OLECLIPFORMAT cfFormat
|
|
){
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
|
|
// Assumes all the creates are in order
|
|
PROBE_ASYNC(lpobj);
|
|
PROBE_SVRCLOSING(lpobj);
|
|
|
|
if (!QueryOpen (lpobj))
|
|
return OLE_ERROR_NOT_OPEN;
|
|
|
|
if (cfFormat == cfOwnerLink || cfFormat == cfObjectLink)
|
|
return OLE_ERROR_FORMAT;
|
|
|
|
if (!(cfFormat == cfNative && lpobj->head.ctype == CT_EMBEDDED)
|
|
&& (cfFormat != (OLECLIPFORMAT) GetPictType (lpobj))) {
|
|
DeleteExtraData (lpobj);
|
|
lpobj->cfExtra = cfFormat;
|
|
}
|
|
|
|
InitAsyncCmd (lpobj, OLE_REQUESTDATA, REQUESTDATA);
|
|
lpobj->pDocEdit->bCallLater = FALSE;
|
|
return RequestData(lpobj, cfFormat);
|
|
}
|
|
|
|
|
|
OLESTATUS RequestData (
|
|
LPOBJECT_LE lpobj,
|
|
OLECLIPFORMAT cfFormat
|
|
){
|
|
switch (lpobj->subRtn) {
|
|
|
|
case 0:
|
|
RequestOn (lpobj, cfFormat);
|
|
WAIT_FOR_ASYNC_MSG (lpobj);
|
|
|
|
case 1:
|
|
ProcessErr (lpobj);
|
|
return EndAsyncCmd (lpobj);
|
|
|
|
default:
|
|
ASSERT (TRUE, "unexpected step in Requestdata");
|
|
return OLE_ERROR_GENERIC;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
// OLESTATUS FARINTERNAL LeGetData (lpoleobj, cfFormat, lphandle)
|
|
//
|
|
// Returns the data handle for a given format
|
|
//
|
|
// Arguments:
|
|
//
|
|
// lpoleobj: source object
|
|
// cfFormat: ref fprmat
|
|
// lphandle: handle return
|
|
//
|
|
// Returns:
|
|
// NULL : no more formats or if we do not understand the
|
|
// given format.
|
|
//
|
|
// Note: Even if the object is connected, we do not get the data from the
|
|
// server. Getdata can not be used for getting data in any other
|
|
// format other than the formats available with the object on
|
|
// the client side.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
OLESTATUS FARINTERNAL LeGetData (
|
|
LPOLEOBJECT lpoleobj,
|
|
OLECLIPFORMAT cfFormat,
|
|
LPHANDLE lphandle
|
|
){
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
|
|
// Assumes all the creates are in order
|
|
// PROBE_OBJECT_BLANK(lpobj);
|
|
|
|
PROBE_CREATE_ASYNC(lpobj);
|
|
|
|
*lphandle = (HANDLE)NULL;
|
|
|
|
// The assumption made here is that the native data can be in either
|
|
// LE object or picture object.
|
|
if ((cfFormat == cfNative) && (lpobj->hnative)) {
|
|
ASSERT ((lpobj->head.ctype == CT_EMBEDDED) || (!lpobj->lpobjPict) ||
|
|
((*lpobj->lpobjPict->lpvtbl->EnumFormats) (lpobj->lpobjPict, NULL)
|
|
!= cfNative), "Native data at wrong Place");
|
|
*lphandle = lpobj->hnative;
|
|
return OLE_OK;
|
|
}
|
|
|
|
if (cfFormat == cfOwnerLink && lpobj->head.ctype == CT_EMBEDDED) {
|
|
if (*lphandle = GetLink (lpobj))
|
|
return OLE_OK;
|
|
|
|
return OLE_ERROR_BLANK;
|
|
}
|
|
|
|
if ((cfFormat == cfObjectLink || cfFormat == cfLink) &&
|
|
lpobj->head.ctype == CT_LINK) {
|
|
if (*lphandle = GetLink (lpobj))
|
|
return OLE_OK;
|
|
|
|
return OLE_ERROR_BLANK;
|
|
}
|
|
|
|
if (cfFormat == cfNetworkName) {
|
|
if (lpobj->aNetName && (*lphandle = GetNetNameHandle (lpobj)))
|
|
return OLE_WARN_DELETE_DATA;
|
|
|
|
return OLE_ERROR_BLANK;
|
|
}
|
|
|
|
if (cfFormat == (OLECLIPFORMAT)lpobj->cfExtra) {
|
|
if (*lphandle = lpobj->hextraData)
|
|
return OLE_OK;
|
|
|
|
return OLE_ERROR_BLANK;
|
|
}
|
|
|
|
if (!lpobj->lpobjPict && cfFormat)
|
|
return OLE_ERROR_FORMAT;
|
|
|
|
return (*lpobj->lpobjPict->lpvtbl->GetData) (lpobj->lpobjPict, cfFormat, lphandle);
|
|
}
|
|
|
|
|
|
|
|
|
|
OLESTATUS FARINTERNAL LeQueryOutOfDate (LPOLEOBJECT lpoleobj)
|
|
{
|
|
UNREFERENCED_PARAMETER(lpoleobj);
|
|
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS FARINTERNAL LeObjectConvert (lpoleobj, lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj)
|
|
//
|
|
// Converts a given linked/embedded object to static object.
|
|
//
|
|
// Arguments:
|
|
// lpoleobj : source object
|
|
// lpprotocol : protocol
|
|
// lpclient : client callback for the new object
|
|
// lhclientdoc: client doc
|
|
// lpobjname : object name
|
|
// lplpoleobj : object return
|
|
//
|
|
//
|
|
// Returns:
|
|
// OLE_OK : successful
|
|
// OLE_ERROR_.... : any errors
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
OLESTATUS FARINTERNAL LeObjectConvert (
|
|
LPOLEOBJECT lpoleobj,
|
|
LPCSTR lpprotocol,
|
|
LPOLECLIENT lpclient,
|
|
LHCLIENTDOC lhclientdoc,
|
|
LPCSTR lpobjname,
|
|
LPOLEOBJECT FAR * lplpoleobj
|
|
){
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
OLESTATUS retVal;
|
|
|
|
PROBE_ASYNC (lpobj);
|
|
|
|
*lplpoleobj = (LPOLEOBJECT)NULL;
|
|
|
|
if (lstrcmp (lpprotocol, PROTOCOL_STATIC))
|
|
return OLE_ERROR_PROTOCOL;
|
|
|
|
if (!lpobj->lpobjPict ||
|
|
((*lpobj->lpobjPict->lpvtbl->QueryType) (lpobj->lpobjPict, NULL)
|
|
== OLE_ERROR_GENERIC)) {
|
|
// Either no picture object or non-standard picture object.
|
|
// Create a metafile Object.
|
|
|
|
HDC hMetaDC;
|
|
RECT rc;
|
|
HANDLE hMF = (HANDLE)NULL, hmfp = (HANDLE)NULL;
|
|
LPMETAFILEPICT lpmfp;
|
|
|
|
OleQueryBounds ((LPOLEOBJECT) lpobj, &rc);
|
|
if (!(hMetaDC = CreateMetaFile (NULL)))
|
|
goto Cleanup;
|
|
|
|
MSetWindowOrg (hMetaDC, rc.left, rc.top);
|
|
MSetWindowExt (hMetaDC, rc.right - rc.left, rc.bottom - rc.top);
|
|
retVal = OleDraw ((LPOLEOBJECT) lpobj, hMetaDC, &rc, &rc, NULL);
|
|
hMF = CloseMetaFile (hMetaDC);
|
|
if ((retVal != OLE_OK) || !hMF)
|
|
goto Cleanup;
|
|
|
|
if (!(hmfp = GlobalAlloc (GMEM_MOVEABLE, sizeof (METAFILEPICT))))
|
|
goto Cleanup;
|
|
|
|
if (!(lpmfp = (LPMETAFILEPICT) GlobalLock (hmfp)))
|
|
goto Cleanup;
|
|
|
|
lpmfp->hMF = hMF;
|
|
lpmfp->mm = MM_ANISOTROPIC;
|
|
lpmfp->xExt = rc.right - rc.left;
|
|
lpmfp->yExt = rc.top - rc.bottom;
|
|
GlobalUnlock (hmfp);
|
|
|
|
if (*lplpoleobj = (LPOLEOBJECT) MfCreateObject (hmfp, lpclient, TRUE,
|
|
lhclientdoc, lpobjname, CT_STATIC))
|
|
return OLE_OK;
|
|
|
|
Cleanup:
|
|
if (hMF)
|
|
DeleteMetaFile (hMF);
|
|
|
|
if (hmfp)
|
|
GlobalFree (hmfp);
|
|
|
|
return OLE_ERROR_MEMORY;
|
|
}
|
|
|
|
|
|
// Picture object is one of the standard objects
|
|
if ((retVal = (*lpobj->lpobjPict->lpvtbl->Clone) (lpobj->lpobjPict,
|
|
lpclient, lhclientdoc,
|
|
lpobjname, lplpoleobj)) == OLE_OK) {
|
|
(*lplpoleobj)->ctype = CT_STATIC;
|
|
DocAddObject ((LPCLIENTDOC) lhclientdoc, *lplpoleobj, lpobjname);
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
|
|
// internal method used for changing picture/native data
|
|
OLESTATUS FARINTERNAL LeChangeData (
|
|
LPOLEOBJECT lpoleobj,
|
|
HANDLE hnative,
|
|
LPOLECLIENT lpoleclient,
|
|
BOOL fDelete
|
|
){
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
|
|
UNREFERENCED_PARAMETER(lpoleclient);
|
|
|
|
if (!fDelete) {
|
|
if (!(hnative = DuplicateGlobal (hnative, GMEM_MOVEABLE)))
|
|
return OLE_ERROR_MEMORY;
|
|
}
|
|
|
|
// In case of a CopyFromLink, eventhough the object type is CT_LINK, the
|
|
// native data should go to LE object rather than the picture object, as
|
|
// we are going to change the object type to embedded after the required
|
|
// data is recieved.
|
|
|
|
if ((lpobj->head.ctype == CT_LINK)
|
|
&& (lpobj->asyncCmd != OLE_COPYFROMLNK)
|
|
&& (lpobj->asyncCmd != OLE_CREATEFROMFILE)) {
|
|
if (lpobj->lpobjPict)
|
|
return (*lpobj->lpobjPict->lpvtbl->SetData)
|
|
(lpobj->lpobjPict, cfNative, hnative);
|
|
}
|
|
else { // It must be embedded.
|
|
if (lpobj->hnative)
|
|
GlobalFree (lpobj->hnative);
|
|
lpobj->hnative = hnative;
|
|
return OLE_OK;
|
|
}
|
|
|
|
GlobalFree(hnative);
|
|
return OLE_ERROR_BLANK;
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LPOBJECT_LE FARINTERNAL LeCreateBlank (lhclientdoc, lpobjname, ctype)
|
|
//
|
|
// Create a blank object. Global block is used for the object and it is
|
|
// locked once sucessful. Unlocking is done only while deletion. Object
|
|
// is added to the corresponding doc.
|
|
//
|
|
// 'LE' signature is used for object validation.
|
|
//
|
|
// Arguments:
|
|
// lhclientdoc : client doc handle
|
|
// lpobjname : object name
|
|
// ctype : type of object to be created
|
|
//
|
|
// Returns:
|
|
// LPOBJECT : successful
|
|
// NULL : any errors
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
LPOBJECT_LE FARINTERNAL LeCreateBlank (
|
|
LHCLIENTDOC lhclientdoc,
|
|
LPSTR lpobjname,
|
|
LONG ctype
|
|
){
|
|
HOBJECT hobj;
|
|
LPOBJECT_LE lpobj;
|
|
|
|
if (!(ctype == CT_LINK || ctype == CT_EMBEDDED || ctype == CT_OLDLINK))
|
|
return NULL;
|
|
|
|
if (!(hobj = GlobalAlloc (GMEM_MOVEABLE|GMEM_ZEROINIT,
|
|
sizeof (OBJECT_LE))))
|
|
return NULL;
|
|
|
|
if (!(lpobj = (LPOBJECT_LE) GlobalLock (hobj))) {
|
|
GlobalFree (hobj);
|
|
return NULL;
|
|
}
|
|
|
|
if (ctype == CT_OLDLINK) {
|
|
ctype = CT_LINK;
|
|
lpobj->bOldLink = TRUE;
|
|
}
|
|
|
|
lpobj->head.objId[0] = 'L';
|
|
lpobj->head.objId[1] = 'E';
|
|
lpobj->head.ctype = ctype;
|
|
lpobj->head.iTable = INVALID_INDEX;
|
|
|
|
lpobj->head.lpvtbl = (LPOLEOBJECTVTBL)&vtblLE;
|
|
|
|
if (ctype == CT_LINK){
|
|
lpobj->optUpdate = oleupdate_always;
|
|
|
|
}else {
|
|
lpobj->optUpdate = oleupdate_onclose;
|
|
}
|
|
lpobj->head.hobj = hobj;
|
|
DocAddObject ((LPCLIENTDOC) lhclientdoc, (LPOLEOBJECT) lpobj, lpobjname);
|
|
return lpobj;
|
|
}
|
|
|
|
|
|
void FARINTERNAL SetExtents (LPOBJECT_LE lpobj)
|
|
{
|
|
RECT rc = {0, 0, 0, 0};
|
|
|
|
if (lpobj->lpobjPict) {
|
|
if ((*lpobj->lpobjPict->lpvtbl->QueryBounds) (lpobj->lpobjPict,
|
|
(LPRECT)&rc) == OLE_OK) {
|
|
// Bounds are in MM_HIMETRIC units
|
|
lpobj->head.cx = (LONG) (rc.right - rc.left);
|
|
lpobj->head.cy = (LONG) (rc.bottom - rc.top);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS FARINTERNAL LeSaveToStream (lpoleobj, lpstream)
|
|
//
|
|
// Save the object to the stream. Uses the stream functions provided
|
|
// in the lpclient.
|
|
//
|
|
// Format: (!!! Document the fomrat here).
|
|
//
|
|
//
|
|
//
|
|
// Arguments:
|
|
// lpoleobj - pointer to ole object
|
|
// lpstream - pointer to stream
|
|
//
|
|
// Returns:
|
|
// LPOBJECT : successful
|
|
// NULL : any errors
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
OLESTATUS FARINTERNAL LeSaveToStream (
|
|
LPOLEOBJECT lpoleobj,
|
|
LPOLESTREAM lpstream
|
|
){
|
|
DWORD dwFileVer = GetFileVersion(lpoleobj);
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
// PROBE_OBJECT_BLANK(lpobj);
|
|
|
|
PROBE_CREATE_ASYNC(lpobj);
|
|
|
|
if (lpobj->head.ctype == CT_LINK && lpobj->bOldLink)
|
|
lpobj->head.ctype = CT_OLDLINK;
|
|
|
|
if (PutBytes (lpstream, (LPSTR) &dwFileVer, sizeof(LONG)))
|
|
return OLE_ERROR_STREAM;
|
|
|
|
if (PutBytes (lpstream, (LPSTR) &lpobj->head.ctype, sizeof(LONG)))
|
|
return OLE_ERROR_STREAM;
|
|
|
|
if (lpobj->bOldLink)
|
|
lpobj->head.ctype = CT_OLDLINK;
|
|
|
|
return LeStreamWrite (lpstream, lpobj);
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OLESTATUS FARINTERNAL LeLoadFromStream (lpstream, lpclient, lhclientdoc, lpobjname, lplpoleobject, ctype, aClass, cfFormat)
|
|
//
|
|
// Create an object, loading the object from the stream.
|
|
//
|
|
// Arguments:
|
|
// lpstream : stream table
|
|
// lpclient : client callback table
|
|
// lhclientdoc : Doc handle foe which the object should be created
|
|
// lpobjname : Object name
|
|
// lplpoleobject : object return
|
|
// ctype : Type of object
|
|
// aClass : class atom
|
|
// cfFormat : render format
|
|
//
|
|
// Returns:
|
|
// LPOBJECT : successful
|
|
// NULL : any errors
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
OLESTATUS FARINTERNAL LeLoadFromStream (
|
|
LPOLESTREAM lpstream,
|
|
LPOLECLIENT lpclient,
|
|
LHCLIENTDOC lhclientdoc,
|
|
LPSTR lpobjname,
|
|
LPOLEOBJECT FAR * lplpoleobject,
|
|
LONG ctype,
|
|
ATOM aClass,
|
|
OLECLIPFORMAT cfFormat
|
|
){
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)NULL;
|
|
OLESTATUS retval = OLE_ERROR_STREAM;
|
|
LONG type; // this not same as ctype
|
|
char chVerb [80];
|
|
|
|
*lplpoleobject = (LPOLEOBJECT)NULL;
|
|
|
|
if (!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, ctype)))
|
|
return OLE_ERROR_MEMORY;
|
|
|
|
lpobj->head.lpclient = lpclient;
|
|
lpobj->app = aClass;
|
|
// if the entry is present, then it is
|
|
lpobj->bOleServer = QueryVerb (lpobj, 0, (LPSTR)&chVerb, 80);
|
|
|
|
if (LeStreamRead (lpstream, lpobj) == OLE_OK) {
|
|
|
|
// Get exe name from aClass and set it as aServer
|
|
SetExeAtom (lpobj);
|
|
if (!GetBytes (lpstream, (LPSTR) &dwVerFromFile, sizeof(LONG))) {
|
|
if (!GetBytes (lpstream, (LPSTR) &type, sizeof(LONG))) {
|
|
if (type == CT_NULL)
|
|
retval = OLE_OK;
|
|
else if (aClass = GetAtomFromStream (lpstream)) {
|
|
retval = DefLoadFromStream (lpstream, NULL, lpclient,
|
|
lhclientdoc, lpobjname,
|
|
(LPOLEOBJECT FAR *)&lpobj->lpobjPict,
|
|
CT_PICTURE, aClass, cfFormat);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (retval == OLE_OK) {
|
|
SetExtents (lpobj);
|
|
*lplpoleobject = (LPOLEOBJECT) lpobj;
|
|
if (lpobj->lpobjPict)
|
|
lpobj->lpobjPict->lpParent = (LPOLEOBJECT) lpobj;
|
|
|
|
if ((lpobj->head.ctype != CT_LINK)
|
|
|| (!InitDocConv (lpobj, !POPUP_NETDLG))
|
|
|| (lpobj->optUpdate >= oleupdate_oncall))
|
|
return OLE_OK;
|
|
|
|
lpobj->fCmd = ACT_ADVISE;
|
|
|
|
// If it's auto update, then get the latest data.
|
|
if (lpobj->optUpdate == oleupdate_always)
|
|
lpobj->fCmd |= ACT_REQUEST;
|
|
|
|
FarInitAsyncCmd (lpobj, OLE_LOADFROMSTREAM, LNKOPENUPDATE);
|
|
return LnkOpenUpdate (lpobj);
|
|
}
|
|
}
|
|
|
|
// This delete will not run into async command. We did not even
|
|
// even connect.
|
|
OleDelete ((LPOLEOBJECT) lpobj);
|
|
return OLE_ERROR_STREAM;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
OLESTATUS INTERNAL LeStreamRead (
|
|
LPOLESTREAM lpstream,
|
|
LPOBJECT_LE lpobj
|
|
){
|
|
DWORD dwBytes;
|
|
LPSTR lpstr;
|
|
OLESTATUS retval = OLE_OK;
|
|
|
|
if (!(lpobj->topic = GetAtomFromStream(lpstream))
|
|
&& (lpobj->head.ctype != CT_EMBEDDED))
|
|
return OLE_ERROR_STREAM;
|
|
|
|
// !!! This atom could be NULL. How do we distinguish the
|
|
// error case
|
|
|
|
lpobj->item = GetAtomFromStream(lpstream);
|
|
|
|
if (lpobj->head.ctype == CT_EMBEDDED) {
|
|
if (GetBytes (lpstream, (LPSTR) &dwBytes, sizeof(LONG)))
|
|
return OLE_ERROR_STREAM;
|
|
|
|
if (!(lpobj->hnative = GlobalAlloc (GMEM_MOVEABLE, dwBytes)))
|
|
return OLE_ERROR_MEMORY;
|
|
else if (!(lpstr = GlobalLock (lpobj->hnative))) {
|
|
GlobalFree (lpobj->hnative);
|
|
return OLE_ERROR_MEMORY;
|
|
}
|
|
else {
|
|
if (GetBytes(lpstream, lpstr, dwBytes))
|
|
retval = OLE_ERROR_STREAM;
|
|
GlobalUnlock (lpobj->hnative);
|
|
}
|
|
|
|
if (retval == OLE_OK)
|
|
SetEmbeddedTopic (lpobj);
|
|
}
|
|
else {
|
|
if (lpobj->aNetName = GetAtomFromStream (lpstream)) {
|
|
if (HIWORD(dwVerFromFile) == OS_MAC) {
|
|
// if it is a mac file this field will have "ZONE:MACHINE:"
|
|
// string. Lets prepend this to the topic, so that server
|
|
// app or user can fix the string
|
|
|
|
ATOM aTemp;
|
|
|
|
aTemp = wAtomCat (lpobj->aNetName, lpobj->topic);
|
|
GlobalDeleteAtom (lpobj->aNetName);
|
|
lpobj->aNetName = (ATOM)0;
|
|
GlobalDeleteAtom (lpobj->topic);
|
|
lpobj->topic = aTemp;
|
|
}
|
|
else
|
|
SetNetDrive (lpobj);
|
|
}
|
|
|
|
if (HIWORD(dwVerFromFile) != OS_MAC) {
|
|
if (GetBytes (lpstream, (LPSTR) &lpobj->dwNetInfo, sizeof(LONG)))
|
|
return OLE_ERROR_STREAM;
|
|
}
|
|
|
|
if (GetBytes (lpstream, (LPSTR) &lpobj->optUpdate, sizeof(LONG)))
|
|
return OLE_ERROR_STREAM;
|
|
}
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
OLESTATUS INTERNAL LeStreamWrite (
|
|
LPOLESTREAM lpstream,
|
|
LPOBJECT_LE lpobj
|
|
){
|
|
DWORD dwFileVer = GetFileVersion((LPOLEOBJECT)lpobj);
|
|
LPSTR lpstr;
|
|
DWORD dwBytes = 0L;
|
|
LONG nullType = CT_NULL;
|
|
int error;
|
|
|
|
if (PutAtomIntoStream(lpstream, lpobj->app))
|
|
return OLE_ERROR_STREAM;
|
|
|
|
if (lpobj->head.ctype == CT_EMBEDDED) {
|
|
// we set the topic at load time, no point in saving it
|
|
if (PutBytes (lpstream, (LPSTR) &dwBytes, sizeof(LONG)))
|
|
return OLE_ERROR_STREAM;
|
|
}
|
|
else {
|
|
if (PutAtomIntoStream(lpstream, lpobj->topic))
|
|
return OLE_ERROR_STREAM;
|
|
}
|
|
|
|
#ifdef OLD
|
|
if (PutAtomIntoStream(lpstream, lpobj->topic))
|
|
return OLE_ERROR_STREAM;
|
|
#endif
|
|
|
|
if (PutAtomIntoStream(lpstream, lpobj->item))
|
|
return OLE_ERROR_STREAM;
|
|
|
|
// !!! deal with objects > 64k
|
|
|
|
if (lpobj->head.ctype == CT_EMBEDDED) {
|
|
|
|
if (!lpobj->hnative)
|
|
return OLE_ERROR_BLANK;
|
|
|
|
// assumption low bytes are first
|
|
dwBytes = (DWORD)GlobalSize (lpobj->hnative);
|
|
|
|
if (PutBytes (lpstream, (LPSTR)&dwBytes, sizeof(LONG)))
|
|
return OLE_ERROR_STREAM;
|
|
|
|
if (!(lpstr = GlobalLock (lpobj->hnative)))
|
|
return OLE_ERROR_MEMORY;
|
|
|
|
error = PutBytes (lpstream, lpstr, dwBytes);
|
|
GlobalUnlock (lpobj->hnative);
|
|
|
|
if (error)
|
|
return OLE_ERROR_STREAM;
|
|
}
|
|
else {
|
|
if (PutAtomIntoStream(lpstream, lpobj->aNetName))
|
|
return OLE_ERROR_STREAM;
|
|
|
|
if (PutBytes (lpstream, (LPSTR) &lpobj->dwNetInfo, sizeof(LONG)))
|
|
return OLE_ERROR_STREAM;
|
|
|
|
if (PutBytes (lpstream, (LPSTR) &lpobj->optUpdate, sizeof(LONG)))
|
|
return OLE_ERROR_STREAM;
|
|
}
|
|
|
|
if (lpobj->lpobjPict)
|
|
return (*lpobj->lpobjPict->lpvtbl->SaveToStream) (lpobj->lpobjPict,
|
|
lpstream);
|
|
|
|
if (PutBytes (lpstream, (LPSTR) &dwFileVer, sizeof(LONG)))
|
|
return OLE_ERROR_STREAM;
|
|
|
|
if (PutBytes (lpstream, (LPSTR) &nullType, sizeof(LONG)))
|
|
return OLE_ERROR_STREAM;
|
|
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
/***************************** Public Function ****************************\
|
|
* OLESTATUS FARINTERNAL LeQueryType (lpobj, lptype)
|
|
*
|
|
* Effects:
|
|
*
|
|
* History:
|
|
* Wrote it.
|
|
\***************************************************************************/
|
|
|
|
OLESTATUS FARINTERNAL LeQueryType (
|
|
LPOLEOBJECT lpoleobj,
|
|
LPLONG lptype
|
|
){
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
|
|
Puts("LeQueryType");
|
|
|
|
if ((lpobj->head.ctype == CT_EMBEDDED)
|
|
|| (lpobj->asyncCmd == OLE_COPYFROMLNK)
|
|
|| (lpobj->asyncCmd == OLE_CREATEFROMFILE))
|
|
*lptype = CT_EMBEDDED;
|
|
else if ((lpobj->head.ctype == CT_LINK)
|
|
|| (lpobj->head.ctype == CT_OLDLINK))
|
|
*lptype = CT_LINK;
|
|
else
|
|
return OLE_ERROR_OBJECT;
|
|
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
|
|
// ContextCallBack: internal function. Calls callback function of <hobj>
|
|
// with flags.
|
|
|
|
int FARINTERNAL ContextCallBack (
|
|
LPOLEOBJECT lpobj,
|
|
OLE_NOTIFICATION flags
|
|
){
|
|
LPOLECLIENT lpclient;
|
|
|
|
Puts("ContextCallBack");
|
|
|
|
if (!FarCheckObject(lpobj))
|
|
return FALSE;
|
|
|
|
if (!(lpclient = lpobj->lpclient))
|
|
return FALSE;
|
|
|
|
ASSERT (lpclient->lpvtbl->CallBack, "Client Callback ptr is NULL");
|
|
|
|
return ((*lpclient->lpvtbl->CallBack) (lpclient, flags, lpobj));
|
|
}
|
|
|
|
|
|
void FARINTERNAL DeleteExtraData (LPOBJECT_LE lpobj)
|
|
{
|
|
if (lpobj->hextraData == (HANDLE)NULL)
|
|
return;
|
|
|
|
switch (lpobj->cfExtra) {
|
|
case CF_BITMAP:
|
|
DeleteObject (lpobj->hextraData);
|
|
break;
|
|
|
|
case CF_METAFILEPICT:
|
|
{
|
|
LPMETAFILEPICT lpmfp;
|
|
|
|
if (!(lpmfp = (LPMETAFILEPICT) GlobalLock (lpobj->hextraData)))
|
|
break;
|
|
|
|
DeleteMetaFile (lpmfp->hMF);
|
|
GlobalUnlock (lpobj->hextraData);
|
|
GlobalFree (lpobj->hextraData);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
GlobalFree (lpobj->hextraData);
|
|
}
|
|
|
|
lpobj->hextraData = (HANDLE)NULL;
|
|
}
|
|
|
|
|
|
void INTERNAL DeleteObjectAtoms(LPOBJECT_LE lpobj)
|
|
{
|
|
if (lpobj->app) {
|
|
GlobalDeleteAtom (lpobj->app);
|
|
lpobj->app = (ATOM)0;
|
|
}
|
|
|
|
if (lpobj->topic) {
|
|
GlobalDeleteAtom (lpobj->topic);
|
|
lpobj->topic = (ATOM)0;
|
|
}
|
|
|
|
if (lpobj->item) {
|
|
GlobalDeleteAtom (lpobj->item);
|
|
lpobj->item = (ATOM)0;
|
|
}
|
|
|
|
if (lpobj->aServer) {
|
|
GlobalDeleteAtom (lpobj->aServer);
|
|
lpobj->aServer = (ATOM)0;
|
|
}
|
|
|
|
if (lpobj->aNetName) {
|
|
GlobalDeleteAtom (lpobj->aNetName);
|
|
lpobj->aNetName = (ATOM)0;
|
|
}
|
|
}
|
|
|
|
|
|
// LeGetUpdateOptions: Gets the update options.
|
|
|
|
OLESTATUS FARINTERNAL LeGetUpdateOptions (
|
|
LPOLEOBJECT lpoleobj,
|
|
OLEOPT_UPDATE FAR *lpOptions
|
|
){
|
|
LPOBJECT_LE lpobj = (LPOBJECT_LE)lpoleobj;
|
|
|
|
if (lpobj->head.ctype != CT_LINK)
|
|
return OLE_ERROR_OBJECT;
|
|
|
|
*lpOptions = lpobj->optUpdate;
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
OLESTATUS FARINTERNAL LnkPaste (
|
|
LPOLECLIENT lpclient,
|
|
LHCLIENTDOC lhclientdoc,
|
|
LPSTR lpobjname,
|
|
LPOLEOBJECT FAR * lplpoleobject,
|
|
OLEOPT_RENDER optRender,
|
|
OLECLIPFORMAT cfFormat,
|
|
OLECLIPFORMAT sfFormat
|
|
){
|
|
LPOBJECT_LE lpobj = NULL;
|
|
OLESTATUS retval = OLE_ERROR_MEMORY;
|
|
LPSTR lpClass = NULL;
|
|
|
|
if (!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, CT_LINK)))
|
|
goto errRtn;
|
|
|
|
lpobj->head.lpclient = lpclient;
|
|
|
|
#ifdef OLD
|
|
if (!bWLO) {
|
|
// we are not running under WLO
|
|
if (!(hInfo = GetClipboardData (sfFormat))) {
|
|
if (hInfo = GetClipboardData (cfLink))
|
|
lpobj->bOldLink = TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!hInfo)
|
|
goto errRtn;
|
|
|
|
if (!IsClipboardFormatAvailable (sfFormat))
|
|
lpobj->bOldLink = TRUE;
|
|
|
|
if (!SetLink (lpobj, hInfo, &lpClass))
|
|
goto errRtn;
|
|
|
|
if ((retval = SetNetName(lpobj)) != OLE_OK) {
|
|
// see whether network name is on the clipboard and try to use it
|
|
HANDLE hNetName;
|
|
LPSTR lpNetName;
|
|
|
|
if (!IsClipboardFormatAvailable (cfNetworkName))
|
|
goto errRtn;
|
|
|
|
if (!(hNetName = GetClipboardData (cfNetworkName)))
|
|
goto errRtn;
|
|
|
|
if (!(lpNetName = GlobalLock (hNetName)))
|
|
goto errRtn;
|
|
|
|
GlobalUnlock (hNetName);
|
|
if (!(lpobj->aNetName = GlobalAddAtom (lpNetName)))
|
|
goto errRtn;
|
|
|
|
SetNetDrive (lpobj);
|
|
}
|
|
|
|
retval = CreatePictFromClip (lpclient, lhclientdoc, lpobjname,
|
|
(LPOLEOBJECT FAR *)&lpobj->lpobjPict, optRender,
|
|
cfFormat, lpClass, CT_PICTURE);
|
|
|
|
if (retval == OLE_OK) {
|
|
SetExtents (lpobj);
|
|
// why do we have to update the link, do we show it?
|
|
|
|
// Reconnect if we could and advise for updates
|
|
*lplpoleobject = (LPOLEOBJECT)lpobj;
|
|
if (lpobj->lpobjPict)
|
|
lpobj->lpobjPict->lpParent = (LPOLEOBJECT) lpobj;
|
|
|
|
if (!InitDocConv (lpobj, !POPUP_NETDLG))
|
|
return OLE_OK; // document is not loaded , it is OK.
|
|
|
|
lpobj->fCmd = ACT_ADVISE | ACT_REQUEST;
|
|
FarInitAsyncCmd (lpobj, OLE_LNKPASTE, LNKOPENUPDATE);
|
|
return LnkOpenUpdate (lpobj);
|
|
|
|
}
|
|
else {
|
|
errRtn:
|
|
if (lpobj)
|
|
OleDelete ((LPOLEOBJECT)lpobj);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
|
|
// !!! EmbPaste and LnkPaste Can be combined
|
|
OLESTATUS FARINTERNAL EmbPaste (
|
|
LPOLECLIENT lpclient,
|
|
LHCLIENTDOC lhclientdoc,
|
|
LPSTR lpobjname,
|
|
LPOLEOBJECT FAR * lplpoleobject,
|
|
OLEOPT_RENDER optRender,
|
|
OLECLIPFORMAT cfFormat
|
|
){
|
|
LPOBJECT_LE lpobj = NULL;
|
|
HANDLE hnative;
|
|
OLESTATUS retval = OLE_ERROR_MEMORY;
|
|
LPSTR lpClass = NULL;
|
|
|
|
if (!IsClipboardFormatAvailable (cfOwnerLink))
|
|
return OLE_ERROR_CLIPBOARD;
|
|
|
|
if (!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, CT_EMBEDDED)))
|
|
goto errRtn;
|
|
|
|
lpobj->head.lpclient = lpclient;
|
|
|
|
#ifdef OLD
|
|
if (!bWLO) {
|
|
// we are not running under WLO
|
|
hInfo = GetClipboardData (cfOwnerLink);
|
|
}
|
|
#endif
|
|
|
|
if (!hInfo)
|
|
goto errRtn;
|
|
|
|
if (!SetLink (lpobj, hInfo, &lpClass))
|
|
goto errRtn;
|
|
|
|
SetEmbeddedTopic (lpobj);
|
|
|
|
hnative = GetClipboardData (cfNative);
|
|
if (!(lpobj->hnative = DuplicateGlobal (hnative, GMEM_MOVEABLE)))
|
|
goto errRtn;
|
|
|
|
retval = CreatePictFromClip (lpclient, lhclientdoc, lpobjname,
|
|
(LPOLEOBJECT FAR *)&lpobj->lpobjPict, optRender,
|
|
cfFormat, lpClass, CT_PICTURE);
|
|
|
|
if (retval == OLE_OK) {
|
|
SetExtents (lpobj);
|
|
*lplpoleobject = (LPOLEOBJECT) lpobj;
|
|
if (lpobj->lpobjPict)
|
|
lpobj->lpobjPict->lpParent = (LPOLEOBJECT) lpobj;
|
|
}
|
|
else {
|
|
errRtn:
|
|
// Note: This oledelete should not result in any async commands.
|
|
if (lpobj)
|
|
OleDelete ((LPOLEOBJECT)lpobj);
|
|
}
|
|
|
|
#ifdef EXCEL_BUG
|
|
// Some server apps (ex: Excel) copy picture (to clipboard) which is
|
|
// formatted for printer DC. So, we want to update the picture if the
|
|
// server app is running, and the it's a old server
|
|
|
|
if ((retval == OLE_OK) && (!lpobj->bOleServer)) {
|
|
lpobj->fCmd = LN_EMBACT | ACT_NOLAUNCH | ACT_REQUEST | ACT_UNLAUNCH;
|
|
FarInitAsyncCmd (lpobj, OLE_EMBPASTE, EMBOPENUPDATE);
|
|
if ((retval = EmbOpenUpdate (lpobj)) > OLE_WAIT_FOR_RELEASE)
|
|
return OLE_OK;
|
|
}
|
|
#endif
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
|
|
BOOL INTERNAL SetLink (
|
|
LPOBJECT_LE lpobj,
|
|
HANDLE hinfo,
|
|
LPSTR FAR * lpLpClass
|
|
){
|
|
LPSTR lpinfo;
|
|
char chVerb[80];
|
|
// If there exits a conversation, then terminate it.
|
|
|
|
if (!(lpinfo = GlobalLock (hinfo)))
|
|
return FALSE;
|
|
|
|
*lpLpClass = lpinfo;
|
|
|
|
lpobj->app = GlobalAddAtom (lpinfo);
|
|
SetExeAtom (lpobj);
|
|
lpobj->bOleServer = QueryVerb (lpobj, 0, (LPSTR)&chVerb, 80);
|
|
|
|
// lpobj->aServer = GetAppAtom (lpinfo);
|
|
|
|
lpinfo += lstrlen (lpinfo) + 1;
|
|
lpobj->topic = GlobalAddAtom (lpinfo);
|
|
lpinfo += lstrlen (lpinfo) + 1;
|
|
if (*lpinfo)
|
|
lpobj->item = GlobalAddAtom (lpinfo);
|
|
else
|
|
lpobj->item = (ATOM)0;
|
|
|
|
if (lpobj->hLink) { // As the atoms have already changed,
|
|
GlobalFree (lpobj->hLink); // lpobj->hLink becomes irrelevant.
|
|
lpobj->hLink = NULL;
|
|
}
|
|
|
|
if (lpinfo)
|
|
GlobalUnlock(hinfo);
|
|
|
|
if (!lpobj->app)
|
|
return FALSE;
|
|
|
|
if (!lpobj->topic && (lpobj->head.ctype == CT_LINK))
|
|
return FALSE;
|
|
|
|
lpobj->hLink = DuplicateGlobal (hinfo, GMEM_MOVEABLE);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
HANDLE INTERNAL GetLink (LPOBJECT_LE lpobj)
|
|
{
|
|
HANDLE hLink = NULL;
|
|
LPSTR lpLink;
|
|
int len;
|
|
WORD size;
|
|
|
|
if (lpobj->hLink)
|
|
return lpobj->hLink;
|
|
|
|
size = 4; // three nulls and one null at the end
|
|
size += (WORD)GlobalGetAtomLen (lpobj->app);
|
|
size += (WORD)GlobalGetAtomLen (lpobj->topic);
|
|
size += (WORD)GlobalGetAtomLen (lpobj->item);
|
|
|
|
if (!(hLink = GlobalAlloc (GMEM_MOVEABLE, (DWORD) size)))
|
|
return NULL;
|
|
|
|
if (!(lpLink = GlobalLock (hLink))) {
|
|
GlobalFree (hLink);
|
|
return NULL;
|
|
}
|
|
|
|
len = (int) GlobalGetAtomName (lpobj->app, lpLink, size);
|
|
lpLink += ++len;
|
|
|
|
len = (int) GlobalGetAtomName (lpobj->topic, lpLink, (size -= (WORD)len));
|
|
lpLink += ++len;
|
|
|
|
if (!lpobj->item)
|
|
*lpLink = '\0';
|
|
else {
|
|
len = (int) GlobalGetAtomName (lpobj->item, lpLink, size - len);
|
|
lpLink += len;
|
|
}
|
|
|
|
*++lpLink = '\0'; // put another null the end
|
|
GlobalUnlock (hLink);
|
|
return (lpobj->hLink = hLink);
|
|
|
|
}
|
|
|
|
|
|
void FARINTERNAL SetEmbeddedTopic (LPOBJECT_LE lpobj)
|
|
{
|
|
LPCLIENTDOC lpdoc;
|
|
char buf[MAX_STR];
|
|
char buf1[MAX_STR];
|
|
LPSTR lpstr, lptmp;
|
|
int len;
|
|
|
|
if (lpobj->topic)
|
|
GlobalDeleteAtom (lpobj->topic);
|
|
|
|
if (lpobj->aNetName) {
|
|
GlobalDeleteAtom (lpobj->aNetName);
|
|
lpobj->aNetName = (ATOM)0;
|
|
}
|
|
|
|
lpobj->cDrive = '\0';
|
|
lpobj->dwNetInfo = 0;
|
|
lpobj->head.ctype = CT_EMBEDDED;
|
|
|
|
lpdoc = (LPCLIENTDOC) lpobj->head.lhclientdoc;
|
|
lpstr = (LPSTR) buf;
|
|
lptmp = (LPSTR) buf1;
|
|
ASSERT(lpdoc->aDoc, "lpdoc->aDoc is null");
|
|
if (!GlobalGetAtomName (lpdoc->aDoc, lpstr, sizeof(buf)))
|
|
goto fail;
|
|
|
|
// strip the path
|
|
lpstr += (len = lstrlen(lpstr));
|
|
while (--lpstr != (LPSTR) buf) {
|
|
if ((*lpstr == '\\') || (*lpstr == ':')) {
|
|
lpstr++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!(len = GlobalGetAtomName (lpdoc->aClass, lptmp, sizeof(buf1))))
|
|
goto fail;
|
|
if (lstrlen(lpstr) + 2 + len < MAX_STR - 1)
|
|
{
|
|
lstrcat (lptmp, "%");
|
|
lstrcat (lptmp, lpstr);
|
|
lstrcat (lptmp, "%");
|
|
}
|
|
lpstr = lptmp;
|
|
lptmp += lstrlen (lptmp);
|
|
|
|
if (lpobj->head.aObjName) {
|
|
if (!GlobalGetAtomName (lpobj->head.aObjName, lptmp, sizeof(buf1)-lstrlen(lpstr)-1))
|
|
goto fail;
|
|
}
|
|
|
|
if ((embStr[EMB_ID_INDEX] += 1) > '9') {
|
|
embStr[EMB_ID_INDEX] = '0';
|
|
if ((embStr[EMB_ID_INDEX - 1] += 1) > '9') {
|
|
embStr[EMB_ID_INDEX - 1] = '0';
|
|
if ((embStr[EMB_ID_INDEX - 2] += 1) > '9')
|
|
embStr[EMB_ID_INDEX - 2] = '0';
|
|
}
|
|
}
|
|
|
|
if (lstrlen(lpstr) - lstrlen(embStr) < MAX_STR - 1)
|
|
lstrcat (lptmp, embStr);
|
|
else
|
|
goto fail;
|
|
|
|
lpobj->topic = GlobalAddAtom (lpstr);
|
|
goto end;
|
|
|
|
fail:
|
|
lpobj->topic = (ATOM)0;
|
|
// Topic, item have changed, lpobj->hLink is out of date.
|
|
|
|
end:
|
|
if (lpobj->hLink) {
|
|
GlobalFree (lpobj->hLink);
|
|
lpobj->hLink = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Routines related to the asynchronous processing. //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
void NextAsyncCmd (
|
|
LPOBJECT_LE lpobj,
|
|
UINT mainRtn
|
|
){
|
|
lpobj->mainRtn = mainRtn;
|
|
lpobj->subRtn = 0;
|
|
|
|
}
|
|
|
|
void InitAsyncCmd (
|
|
LPOBJECT_LE lpobj,
|
|
UINT cmd,
|
|
UINT mainRtn
|
|
){
|
|
|
|
lpobj->asyncCmd = cmd;
|
|
lpobj->mainErr = OLE_OK;
|
|
lpobj->mainRtn = mainRtn;
|
|
lpobj->subRtn = 0;
|
|
lpobj->subErr = 0;
|
|
lpobj->bAsync = 0;
|
|
lpobj->endAsync = 0;
|
|
lpobj->errHint = 0;
|
|
|
|
}
|
|
|
|
OLESTATUS EndAsyncCmd (LPOBJECT_LE lpobj)
|
|
{
|
|
OLESTATUS olderr;
|
|
|
|
|
|
if (!lpobj->endAsync) {
|
|
lpobj->asyncCmd = OLE_NONE;
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
// this is an asynchronous operation. Send callback with or without
|
|
// error.
|
|
|
|
switch (lpobj->asyncCmd) {
|
|
|
|
case OLE_DELETE:
|
|
break;
|
|
|
|
case OLE_COPYFROMLNK:
|
|
case OLE_CREATEFROMFILE:
|
|
// change the topic name to embedded.
|
|
SetEmbeddedTopic (lpobj);
|
|
break;
|
|
|
|
case OLE_LOADFROMSTREAM:
|
|
case OLE_LNKPASTE:
|
|
case OLE_RUN:
|
|
case OLE_SHOW:
|
|
case OLE_ACTIVATE:
|
|
case OLE_UPDATE:
|
|
case OLE_CLOSE:
|
|
case OLE_RECONNECT:
|
|
case OLE_CREATELINKFROMFILE:
|
|
case OLE_CREATEINVISIBLE:
|
|
case OLE_CREATE:
|
|
case OLE_CREATEFROMTEMPLATE:
|
|
case OLE_SETUPDATEOPTIONS:
|
|
case OLE_SERVERUNLAUNCH:
|
|
case OLE_SETDATA:
|
|
case OLE_REQUESTDATA:
|
|
case OLE_OTHER:
|
|
break;
|
|
|
|
case OLE_EMBPASTE:
|
|
lpobj->mainErr = OLE_OK;
|
|
break;
|
|
|
|
default:
|
|
DEBUG_OUT ("unexpected maincmd", 0);
|
|
break;
|
|
|
|
}
|
|
|
|
lpobj->bAsync = FALSE;
|
|
lpobj->endAsync = FALSE;
|
|
lpobj->oldasyncCmd = lpobj->asyncCmd;
|
|
olderr = lpobj->mainErr;
|
|
lpobj->asyncCmd = OLE_NONE; // no async command in progress.
|
|
|
|
if (lpobj->head.lpclient)
|
|
ContextCallBack ((LPOLEOBJECT)lpobj, OLE_RELEASE);
|
|
|
|
lpobj->mainErr = OLE_OK;
|
|
return olderr;
|
|
}
|
|
|
|
|
|
BOOL ProcessErr (LPOBJECT_LE lpobj)
|
|
{
|
|
|
|
if (lpobj->subErr == OLE_OK)
|
|
return FALSE;
|
|
|
|
if (lpobj->mainErr == OLE_OK)
|
|
lpobj->mainErr = lpobj->subErr;
|
|
|
|
lpobj->subErr = OLE_OK;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void ScheduleAsyncCmd (LPOBJECT_LE lpobj)
|
|
{
|
|
|
|
// replacs this with direct proc jump later on.
|
|
lpobj->bAsync = FALSE;
|
|
|
|
// if the object is active and we do pokes we go thru this path
|
|
// !!! We may have to go thru the endasynccmd.
|
|
|
|
if ((lpobj->asyncCmd == OLE_OTHER)
|
|
|| ((lpobj->asyncCmd == OLE_SETDATA) && !lpobj->mainRtn)) {
|
|
lpobj->endAsync = TRUE;
|
|
lpobj->mainErr = lpobj->subErr;
|
|
EndAsyncCmd (lpobj);
|
|
if (lpobj->bUnlaunchLater) {
|
|
lpobj->bUnlaunchLater = FALSE;
|
|
CallEmbLnkDelete(lpobj);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
switch (lpobj->mainRtn) {
|
|
|
|
case EMBLNKDELETE:
|
|
EmbLnkDelete (lpobj);
|
|
break;
|
|
|
|
case LNKOPENUPDATE:
|
|
LnkOpenUpdate (lpobj);
|
|
break;
|
|
|
|
case DOCSHOW:
|
|
DocShow (lpobj);
|
|
break;
|
|
|
|
|
|
case EMBOPENUPDATE:
|
|
EmbOpenUpdate (lpobj);
|
|
break;
|
|
|
|
|
|
case EMBLNKCLOSE:
|
|
EmbLnkClose (lpobj);
|
|
break;
|
|
|
|
case LNKSETUPDATEOPTIONS:
|
|
LnkSetUpdateOptions (lpobj);
|
|
break;
|
|
|
|
case LNKCHANGELNK:
|
|
LnkChangeLnk (lpobj);
|
|
break;
|
|
|
|
case REQUESTDATA:
|
|
RequestData (lpobj, 0);
|
|
break;
|
|
|
|
default:
|
|
DEBUG_OUT ("Unexpected asyn command", 0);
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void SetNetDrive (LPOBJECT_LE lpobj)
|
|
{
|
|
char buf[MAX_STR];
|
|
|
|
if (GlobalGetAtomName (lpobj->topic, buf, sizeof(buf))
|
|
&& (buf[1] == ':')) {
|
|
AnsiUpperBuff ((LPSTR) buf, 1);
|
|
lpobj->cDrive = buf[0];
|
|
}
|
|
}
|
|
|
|
HANDLE GetNetNameHandle (LPOBJECT_LE lpobj)
|
|
{
|
|
HANDLE hNetName;
|
|
LPSTR lpNetName;
|
|
int size;
|
|
|
|
if (!(size = GlobalGetAtomLen (lpobj->aNetName)))
|
|
return NULL;
|
|
|
|
size++;
|
|
if (!(hNetName = GlobalAlloc (GMEM_MOVEABLE, (DWORD) size)))
|
|
return NULL;
|
|
|
|
if (lpNetName = GlobalLock (hNetName)) {
|
|
GlobalUnlock (hNetName);
|
|
if (GlobalGetAtomName(lpobj->aNetName, lpNetName, size))
|
|
return hNetName;
|
|
}
|
|
|
|
// error case
|
|
GlobalFree (hNetName);
|
|
return NULL;
|
|
}
|
|
|
|
BOOL AreTopicsEqual (
|
|
LPOBJECT_LE lpobj1,
|
|
LPOBJECT_LE lpobj2
|
|
){
|
|
char buf1[MAX_STR];
|
|
char buf2[MAX_STR];
|
|
|
|
if (lpobj1->aNetName != lpobj2->aNetName)
|
|
return FALSE;
|
|
|
|
if (!lpobj1->aNetName) {
|
|
if (lpobj1->topic == lpobj2->topic)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GlobalGetAtomName (lpobj1->topic, buf1, MAX_STR))
|
|
return FALSE;
|
|
|
|
if (!GlobalGetAtomName (lpobj2->topic, buf2, MAX_STR))
|
|
return FALSE;
|
|
|
|
if (!lstrcmpi (&buf1[1], &buf2[1]))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
ATOM FARINTERNAL wAtomCat (
|
|
ATOM a1,
|
|
ATOM a2
|
|
){
|
|
char buf[MAX_STR+MAX_STR];
|
|
LPSTR lpBuf = (LPSTR)buf;
|
|
|
|
if (!GlobalGetAtomName (a1, lpBuf, MAX_STR+MAX_STR))
|
|
return (ATOM)0;
|
|
|
|
lpBuf += lstrlen(lpBuf);
|
|
|
|
if (!GlobalGetAtomName(a2, lpBuf, MAX_STR))
|
|
return (ATOM)0;
|
|
|
|
return GlobalAddAtom ((LPSTR) buf);
|
|
}
|
|
|