|
|
/****************************** 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); }
|