windows-nt/Source/XPSP1/NT/com/winole/client/le.c

2350 lines
64 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/****************************** 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);
#ifdef WIN16
#pragma alloc_text(_RARETEXT, LeObjectLong, LeQueryProtocol, LeEqual, AreTopicsEqual, LeObjectConvert, wAtomCat)
#pragma alloc_text(_DDETEXT, LeRequestData, RequestData, LeChangeData, ContextCallBack, DeleteExtraData, NextAsyncCmd, InitAsyncCmd, FarInitAsyncCmd, EndAsyncCmd, ProcessErr, ScheduleAsyncCmd, LeQueryReleaseStatus, EmbLnkDelete, LeRelease, DeleteObjectAto
ms, QueryClose, SendStdClose, TermDocConv, DeleteDocEdit, QueryUnlaunch, SendStdExit, QueryOpen, GetPictType, RequestOn, DocShow, EmbLnkClose, LnkSetUpdateOptions, LnkChangeLnk, TermSrvrConv, DeleteSrvrEdit, LeCopyFromLink)
#endif
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;
#if FIREWALLS
if (lpobj->pDocEdit)
ASSERT (!lpobj->pDocEdit->hClient, "unexpected client conv exists");
#endif
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");
GlobalGetAtomName (lpdoc->aDoc, lpstr, sizeof(buf));
// strip the path
lpstr += (len = lstrlen(lpstr));
while (--lpstr != (LPSTR) buf) {
if ((*lpstr == '\\') || (*lpstr == ':')) {
lpstr++;
break;
}
}
GlobalGetAtomName (lpdoc->aClass, lptmp, sizeof(buf1));
lstrcat (lptmp, "%");
lstrcat (lptmp, lpstr);
lstrcat (lptmp, "%");
lpstr = lptmp;
lptmp += lstrlen (lptmp);
if (lpobj->head.aObjName) {
GlobalGetAtomName (lpobj->head.aObjName, lptmp, sizeof(buf)-(len+1));
}
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';
}
}
lstrcat (lptmp, embStr);
lpobj->topic = GlobalAddAtom (lpstr);
// Topic, item have changed, lpobj->hLink is out of date.
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;
}
#ifdef WIN16
void FARINTERNAL FarInitAsyncCmd (
LPOBJECT_LE lpobj,
UINT cmd,
UINT mainRtn
){
return (InitAsyncCmd(lpobj, cmd, mainRtn));
}
#endif
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.
#ifdef FIREWALLS
ASSERT (lpobj->bAsync, "Not an asynchronous command");
#endif
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);
}