windows-nt/Source/XPSP1/NT/base/mvdm/wow16/ole/client/ledde.c

2595 lines
65 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/****************************** Module Header ******************************\
* Module Name: LEDDE.C
*
* Purpose: ?????
*
* Created: 1990
*
* Copyright (c) 1990, 1991 Microsoft Corporation
*
* History:
* Raor, Srinik (../../1990,91) Designed and coded
*
\***************************************************************************/
#include <windows.h>
#include "dde.h"
#include "dll.h"
#define LN_FUDGE 16 // [],(), 3 * 3 (2 double quotes and comma)
#define RUNITEM
#define OLEVERB_CONNECT 0xFFFF
// Definitions for sending the server sys command.
char *srvrSysCmd[] = {"StdNewFromTemplate",
"StdNewDocument",
"StdEditDocument",
"StdOpenDocument"
};
#define EMB_ID_INDEX 11 // index of ones digit in #00
extern char embStr[];
extern BOOL gbCreateInvisible;
extern BOOL gbLaunchServer;
extern ATOM aMSDraw;
extern BOOL (FAR PASCAL *lpfnIsTask) (HANDLE);
// !!! set error hints
OLESTATUS FARINTERNAL LeDoVerb (lpobj, verb, fShow, fActivate)
LPOBJECT_LE lpobj;
WORD verb;
BOOL fShow;
BOOL fActivate;
{
PROBE_ASYNC (lpobj);
PROBE_SVRCLOSING(lpobj);
if (!QueryOpen(lpobj))
return OLE_OK;
lpobj->verb = verb;
lpobj->fCmd = ACT_DOVERB;
if (fActivate)
lpobj->fCmd |= ACT_ACTIVATE;
if (fShow)
lpobj->fCmd |= ACT_SHOW;
InitAsyncCmd (lpobj, OLE_RUN, DOCSHOW);
return DocShow (lpobj);
}
OLESTATUS FARINTERNAL LeShow (lpobj, fActivate)
LPOBJECT_LE lpobj;
BOOL fActivate;
{
PROBE_ASYNC (lpobj);
PROBE_SVRCLOSING(lpobj);
if (!QueryOpen(lpobj))
return OLE_OK;
lpobj->fCmd = ACT_SHOW;
InitAsyncCmd (lpobj, OLE_SHOW, DOCSHOW);
return DocShow (lpobj);
}
// DocShow : If the server is connected, show the item
// for editing. For embedded objects us NULL Item.
OLESTATUS DocShow (lpobj)
LPOBJECT_LE lpobj;
{
switch (lpobj->subRtn) {
case 0:
SendStdShow (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 1:
ProcessErr (lpobj);
return EndAsyncCmd (lpobj);
default:
DEBUG_OUT ("Unexpected subroutine", 0);
return OLE_ERROR_GENERIC;
}
}
void SendStdShow (lpobj)
LPOBJECT_LE lpobj;
{
WORD len;
WORD size;
LPSTR lpdata = NULL;
HANDLE hdata = NULL;
BOOL bShow;
lpobj->subErr = OLE_OK;
if (lpobj->verb == OLEVERB_CONNECT) {
lpobj->verb = NULL;
return;
}
if (!(lpobj->fCmd & (ACT_SHOW | ACT_DOVERB)))
return;
if (bShow = (!lpobj->bOleServer || !(lpobj->fCmd & ACT_DOVERB))) {
// show is off, do not show the server.
if (!(lpobj->fCmd & ACT_SHOW))
return;
SETERRHINT(lpobj, OLE_ERROR_SHOW);
// and 18 "[StdShowItem(\"")for 5 extra for ",FALSE
len = 18 + 7;
} else {
// 19 for the string [StdDoVerbItem(\"") and
// 18 extra is for ",000,FALSE,FALSE
SETERRHINT(lpobj, OLE_ERROR_DOVERB);
len = 19 + 18;
}
len += GlobalGetAtomLen (lpobj->item);
len += 4; // ")]" + NULL
hdata = GlobalAlloc (GMEM_DDESHARE, size = len);
if (hdata == NULL || (lpdata = (LPSTR)GlobalLock (hdata)) == NULL)
goto errRtn;
if (bShow)
lstrcpy (lpdata, "[StdShowItem(\"");
else
lstrcpy (lpdata, "[StdDoVerbItem(\"");
len = lstrlen (lpdata);
if (lpobj->item)
GlobalGetAtomName (lpobj->item , lpdata + len, size - len);
if (!bShow) {
lstrcat (lpdata, (LPSTR)"\",");
// assume that the number of verbs are < 10
len = lstrlen (lpdata);
#ifdef FIREWALLS
ASSERT ( (lpobj->verb & 0x000f) < 9 , "Verb value more than 9");
#endif
lpdata += len;
*lpdata++ = (char)((lpobj->verb & 0x000f) + '0');
*lpdata = 0;
if (lpobj->fCmd & ACT_SHOW)
lstrcat (lpdata, (LPSTR) ",TRUE");
else
lstrcat (lpdata, (LPSTR) ",FALSE");
// StdVerbItem (item, verb, TRUE
// add TRUE/FALSE constant for the activate
if (!(lpobj->fCmd & ACT_ACTIVATE))
lstrcat (lpdata, (LPSTR) ",TRUE)]");
else
lstrcat (lpdata, (LPSTR) ",FALSE)]");
// [StdDoVerb ("item", verb, FALSE, FALSE)]
} else
lstrcat (lpdata, (LPSTR)"\")]");
// apps like excel and wingraph do not suuport activate at
// item level.
GlobalUnlock (hdata);
DocExecute (lpobj, hdata);
return;
errRtn:
if (lpdata)
GlobalUnlock (hdata);
if (hdata)
GlobalFree (hdata);
lpobj->subErr = OLE_ERROR_MEMORY;
return;
}
OLESTATUS FARINTERNAL LeQueryOpen (LPOBJECT_LE lpobj)
{
if (QueryOpen(lpobj))
return OLE_OK;
else
return OLE_ERROR_NOT_OPEN;
}
BOOL INTERNAL QueryOpen (LPOBJECT_LE lpobj)
{
if (lpobj->pDocEdit && lpobj->pDocEdit->hClient) {
if (IsServerValid (lpobj))
return TRUE;
// destroy the windows and pretend as if the server was never
// connected.
DestroyWindow (lpobj->pDocEdit->hClient);
if (lpobj->pSysEdit && lpobj->pSysEdit->hClient)
DestroyWindow (lpobj->pSysEdit->hClient);
}
return FALSE;
}
OLESTATUS FARINTERNAL LeActivate (lpobj, verb, fShow, fActivate, hWnd, lprc)
LPOBJECT_LE lpobj;
WORD verb;
BOOL fShow;
BOOL fActivate;
HWND hWnd;
LPRECT lprc;
{
lpobj->verb = verb;
if (lpobj->head.ctype == CT_EMBEDDED)
return EmbOpen (lpobj, fShow, fActivate, hWnd, lprc);
#ifdef FIREWALLS
ASSERT (lpobj->head.ctype == CT_LINK, "unknown object");
#endif
return LnkOpen (lpobj, fShow, fActivate, hWnd, lprc);
}
OLESTATUS FARINTERNAL LeUpdate (lpobj)
LPOBJECT_LE lpobj;
{
if (lpobj->head.ctype == CT_EMBEDDED)
return EmbUpdate (lpobj);
#ifdef FIREWALLS
ASSERT (lpobj->head.ctype == CT_LINK, "unknown object");
#endif
return LnkUpdate (lpobj);
}
OLESTATUS FARINTERNAL EmbOpen (lpobj, fShow, fActivate, hWnd, lprc)
LPOBJECT_LE lpobj;
BOOL fShow;
BOOL fActivate;
HWND hWnd;
LPRECT lprc;
{
PROBE_ASYNC (lpobj);
PROBE_SVRCLOSING(lpobj);
if(QueryOpen (lpobj))
return LeDoVerb (lpobj, lpobj->verb, fShow, fActivate);
// show the window
// advise for data only on close
// and shut down the conv after the advises.
lpobj->fCmd = LN_EMBACT | ACT_DOVERB | ACT_ADVISE | ACT_CLOSE;
if (fActivate)
lpobj->fCmd |= ACT_ACTIVATE;
if (fShow)
lpobj->fCmd |= ACT_SHOW;
InitAsyncCmd (lpobj, OLE_ACTIVATE, EMBOPENUPDATE);
return EmbOpenUpdate (lpobj);
}
/***************************** Public Function ****************************\
* OLESTATUS FARINTERNAL EmbUpdate (lpobj)
*
* This function updates an EMB object. If the server is connected
* simply send a request for the native as well as the display formats.
* If the server is connected, then tries to start the conversationa and
* get the data. If the conversation fails, then load the server and
* start the conversation. The embeded objects may have links in it.
*
* Effects:
*
* History:
* Wrote it.
\***************************************************************************/
OLESTATUS FARINTERNAL EmbUpdate (lpobj)
LPOBJECT_LE lpobj;
{
// if we are loading the server, then definitly unload.
// if the connection is established, then unload if it is
// to be unloaded, when all the previous requests are satisfied.
PROBE_ASYNC (lpobj);
PROBE_SVRCLOSING(lpobj);
lpobj->fCmd = LN_EMBACT | ACT_REQUEST | (QueryOpen(lpobj) ? 0 : ACT_UNLAUNCH);
InitAsyncCmd (lpobj, OLE_UPDATE, EMBOPENUPDATE);
return EmbOpenUpdate (lpobj);
}
OLESTATUS FARINTERNAL EmbOpenUpdate (lpobj)
LPOBJECT_LE lpobj;
{
switch (lpobj->subRtn) {
case 0:
SKIP_TO (QueryOpen(lpobj), step6);
SendSrvrMainCmd (lpobj, lpobj->lptemplate);
lpobj->lptemplate = NULL;
WAIT_FOR_ASYNC_MSG (lpobj);
case 1:
if (ProcessErr (lpobj))
goto errRtn;
// Init doc conversation should set the failure error
if (!InitDocConv (lpobj, !POPUP_NETDLG))
goto errRtn;
// If there is no native data, do not do any poke.
// creates will not have any poke data to start with
SKIP_TO (!(lpobj->hnative), step6);
PokeNativeData (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 2:
if (ProcessErr (lpobj))
goto errRtn;
// Now poke the hostnames etc stuff.
PokeHostNames (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 3:
// do not worry about the poke hostname errors
PokeTargetDeviceInfo (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 4:
PokeDocDimensions (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 5:
PokeColorScheme (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 6:
step6:
// wingraph does not accept the doc dimensions
// after sttedit.
CLEAR_STEP_ERROR (lpobj);
SETSTEP (lpobj, 6);
STEP_NOP (lpobj);
// step_nop simply increments the step numebr
// merge the steps later on
case 7:
if (ProcessErr (lpobj))
goto errRtn;
SKIP_TO (!(lpobj->fCmd & ACT_ADVISE), step11);
lpobj->optUpdate = oleupdate_onsave;
lpobj->pDocEdit->nAdviseSave = 0;
AdviseOn (lpobj, cfNative, aSave);
WAIT_FOR_ASYNC_MSG (lpobj);
case 8:
// do not go for errors on /save. Some servers may not support
// this.
CLEAR_STEP_ERROR (lpobj);
AdvisePict (lpobj, aSave);
WAIT_FOR_ASYNC_MSG (lpobj);
case 9:
// do not worry about the error case for save. Ignore them
CLEAR_STEP_ERROR (lpobj);
lpobj->optUpdate = oleupdate_onclose;
lpobj->pDocEdit->nAdviseClose = 0;
AdviseOn (lpobj, cfNative, aClose);
WAIT_FOR_ASYNC_MSG (lpobj);
case 10:
if (ProcessErr(lpobj))
goto errRtn;
AdvisePict (lpobj, aClose);
WAIT_FOR_ASYNC_MSG (lpobj);
case 11:
step11:
SETSTEP (lpobj, 11);
if (ProcessErr(lpobj))
goto errRtn;
SKIP_TO (!(lpobj->fCmd & ACT_REQUEST), step13);
// we don't want to send OLE_CHANGED when we get this data, if we
// are going to request for picture data also.
lpobj->pDocEdit->bCallLater = ((lpobj->lpobjPict) ? TRUE: FALSE);
RequestOn (lpobj, cfNative);
WAIT_FOR_ASYNC_MSG (lpobj);
// If request pict fails, then native and pict are
// not in sync.
case 12:
if (ProcessErr(lpobj))
goto errRtn;
lpobj->pDocEdit->bCallLater = FALSE;
RequestPict (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 13:
step13:
SETSTEP(lpobj, 13);
if (ProcessErr(lpobj))
goto errRtn;
SendStdShow (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 14:
if (ProcessErr(lpobj))
goto errRtn;
SKIP_TO ((lpobj->fCmd & ACT_UNLAUNCH), step15);
return EndAsyncCmd (lpobj);
case 15:
errRtn:
step15:
ProcessErr (lpobj);
if ((lpobj->asyncCmd == OLE_UPDATE)
&& (!(lpobj->fCmd & ACT_UNLAUNCH)))
return EndAsyncCmd (lpobj);
// if we launched and error, unlaunch (send stdexit)
NextAsyncCmd (lpobj, EMBLNKDELETE);
lpobj->fCmd |= ACT_UNLAUNCH;
EmbLnkDelete (lpobj);
return lpobj->mainErr;
default:
DEBUG_OUT ("Unexpected subroutine", 0);
return OLE_ERROR_GENERIC;
}
}
OLESTATUS FARINTERNAL LnkOpen (lpobj, fShow, fActivate, hWnd, lprc)
LPOBJECT_LE lpobj;
BOOL fShow;
BOOL fActivate;
HWND hWnd;
LPRECT lprc;
{
PROBE_ASYNC (lpobj);
PROBE_SVRCLOSING(lpobj);
if(QueryOpen (lpobj))
return LeDoVerb (lpobj, lpobj->verb, fShow, fActivate);
// Just end the system conversation. we are not unloading
// this instance at all.
lpobj->fCmd = LN_LNKACT | ACT_DOVERB;
if (lpobj->optUpdate == oleupdate_always)
lpobj->fCmd |= ACT_ADVISE | ACT_REQUEST;
else if (lpobj->optUpdate == oleupdate_onsave)
lpobj->fCmd |= ACT_ADVISE;
if (fActivate)
lpobj->fCmd |= ACT_ACTIVATE;
if (fShow)
lpobj->fCmd |= ACT_SHOW;
InitAsyncCmd (lpobj, OLE_ACTIVATE, LNKOPENUPDATE);
return LnkOpenUpdate (lpobj);
}
OLESTATUS FARINTERNAL LnkUpdate (lpobj)
LPOBJECT_LE lpobj;
{
// if we are loading the server, then definitly unload.
// if the connection is established, then unload if it is
// to be unloaded, when all the previous requests are satisfied.
PROBE_ASYNC (lpobj);
PROBE_SVRCLOSING(lpobj);
lpobj->fCmd = LN_LNKACT | ACT_REQUEST | (QueryOpen (lpobj) ? 0 : ACT_UNLAUNCH);
InitAsyncCmd (lpobj, OLE_UPDATE, LNKOPENUPDATE);
return LnkOpenUpdate (lpobj);
}
OLESTATUS FARINTERNAL LnkOpenUpdate (lpobj)
LPOBJECT_LE lpobj;
{
switch (lpobj->subRtn) {
case 0:
SKIP_TO (QueryOpen(lpobj), step2);
InitDocConv (lpobj, !POPUP_NETDLG);
if (QueryOpen(lpobj)) {
if (lpobj->app == aPackage)
RemoveLinkStringFromTopic (lpobj);
goto step2;
}
SendSrvrMainCmd (lpobj, NULL);
WAIT_FOR_ASYNC_MSG (lpobj);
case 1:
if (ProcessErr (lpobj))
goto errRtn;
if (lpobj->app == aPackage)
RemoveLinkStringFromTopic (lpobj);
if (!InitDocConv (lpobj, POPUP_NETDLG)) {
lpobj->subErr = OLE_ERROR_OPEN;
goto errRtn;
}
case 2:
step2:
SETSTEP (lpobj, 2);
PokeTargetDeviceInfo (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 3:
if (ProcessErr (lpobj))
goto errRtn;
SKIP_TO (!(lpobj->fCmd & ACT_ADVISE), step6);
SKIP_TO (!(lpobj->fCmd & ACT_NATIVE), step4);
AdviseOn (lpobj, cfNative, NULL);
WAIT_FOR_ASYNC_MSG (lpobj);
case 4:
step4:
SETSTEP (lpobj, 4);
if (ProcessErr (lpobj))
goto errRtn;
AdvisePict (lpobj, NULL);
WAIT_FOR_ASYNC_MSG (lpobj);
case 5:
if (ProcessErr (lpobj))
goto errRtn;
// Now send advise for renaming the documnet.
AdviseOn (lpobj, cfBinary, aStdDocName);
WAIT_FOR_ASYNC_MSG (lpobj);
case 6:
step6:
// if name advise fails ignore it
SETSTEP (lpobj, 6);
CLEAR_STEP_ERROR (lpobj);
SKIP_TO (!(lpobj->fCmd & ACT_REQUEST), step8);
SKIP_TO (!(lpobj->fCmd & ACT_NATIVE), step7);
// we don't want to send OLE_CHANGED when we get this data, if we
// are going to request for picture data also.
lpobj->pDocEdit->bCallLater = ((lpobj->lpobjPict) ? TRUE: FALSE);
RequestOn (lpobj, cfNative);
WAIT_FOR_ASYNC_MSG (lpobj);
case 7:
step7:
SETSTEP (lpobj, 7);
if (ProcessErr (lpobj))
goto errRtn;
lpobj->pDocEdit->bCallLater = FALSE;
RequestPict (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 8:
step8:
SETSTEP (lpobj, 8);
if (ProcessErr (lpobj))
goto errRtn;
SKIP_TO (!(lpobj->fCmd & ACT_TERMDOC), step10);
// terminate the document conversataion.
TermDocConv (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 9:
if (ProcessErr (lpobj))
goto errRtn;
// delete the server edit block
DeleteDocEdit (lpobj);
SKIP_TO ((lpobj->fCmd & ACT_UNLAUNCH), step14);
return EndAsyncCmd (lpobj);
case 10:
step10:
SETSTEP (lpobj, 10);
if (ProcessErr (lpobj))
goto errRtn;
SKIP_TO (!(lpobj->fCmd & ACT_TERMSRVR), step12);
// terminate the server conversataion.
TermSrvrConv (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 11:
if (ProcessErr (lpobj))
goto errRtn;
// delete the server edit block
DeleteSrvrEdit (lpobj);
return EndAsyncCmd (lpobj);
case 12:
step12:
SETSTEP (lpobj, 12);
if (ProcessErr (lpobj))
goto errRtn;
SendStdShow (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 13:
if (ProcessErr (lpobj))
goto errRtn;
SKIP_TO ((lpobj->fCmd & ACT_UNLAUNCH), step14);
return EndAsyncCmd (lpobj);
case 14:
errRtn:
step14:
ProcessErr (lpobj);
if ((lpobj->asyncCmd == OLE_UPDATE)
&& (!(lpobj->fCmd & ACT_UNLAUNCH)))
return EndAsyncCmd (lpobj);
// if we launched and error, unlaunch (send stdexit)
NextAsyncCmd (lpobj, EMBLNKDELETE);
lpobj->fCmd |= ACT_UNLAUNCH;
EmbLnkDelete (lpobj);
return lpobj->mainErr;
default:
DEBUG_OUT ("Unexpected subroutine", 0);
return OLE_ERROR_GENERIC;
}
}
OLESTATUS EmbLnkClose (lpobj)
LPOBJECT_LE lpobj;
{
switch (lpobj->subRtn) {
case 0:
TermDocConv (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 1:
// delete the edit block
DeleteDocEdit (lpobj);
TermSrvrConv (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 2:
// Do not set any errors, just delete the object.
// delete the server edit block
DeleteSrvrEdit (lpobj);
return EndAsyncCmd (lpobj);
default:
DEBUG_OUT ("Unexpected subroutine", 0);
return OLE_ERROR_GENERIC;
}
}
OLESTATUS FARINTERNAL LeClose (lpobj)
LPOBJECT_LE lpobj;
{
PROBE_ASYNC (lpobj);
if (IS_SVRCLOSING(lpobj))
return OLE_OK;
lpobj->fCmd = 0;
if (lpobj->head.ctype == CT_EMBEDDED) {
InitAsyncCmd (lpobj, OLE_CLOSE, EMBLNKDELETE);
return EmbLnkDelete (lpobj);
}
else {
InitAsyncCmd (lpobj, OLE_CLOSE, EMBLNKCLOSE);
return EmbLnkClose (lpobj);
}
}
OLESTATUS FARINTERNAL LeReconnect (lpobj)
LPOBJECT_LE lpobj;
{
// check for the existing conversation.
// if the client window is non-null, then
// connection exits.
if (lpobj->head.ctype != CT_LINK)
return OLE_ERROR_NOT_LINK; // allow only for linked
PROBE_ASYNC (lpobj);
PROBE_SVRCLOSING(lpobj);
if (QueryOpen (lpobj))
return OLE_OK;
// start just the conversation. Do not load
// the app.
if (!InitDocConv (lpobj, !POPUP_NETDLG))
return OLE_OK; // document is not loaded , it is OK.
lpobj->fCmd = LN_LNKACT;
if (lpobj->optUpdate == oleupdate_always)
lpobj->fCmd |= ACT_ADVISE | ACT_REQUEST;
InitAsyncCmd (lpobj, OLE_RECONNECT, LNKOPENUPDATE);
return LnkOpenUpdate (lpobj);
}
OLESTATUS INTERNAL PokeNativeData (lpobj)
LPOBJECT_LE lpobj;
{
SETERRHINT(lpobj, OLE_ERROR_POKE_NATIVE);
return SendPokeData (lpobj,
lpobj->item,
lpobj->hnative,
cfNative);
}
BOOL INTERNAL PostMessageToServer (pedit, msg, lparam)
PEDIT_DDE pedit;
WORD msg;
LONG lparam;
{
#ifdef FIREWALLS
ASSERT (pedit, "Dde edit block is NULL");
#endif
// save the lparam and msg fpr possible reposting incase of error.
// we are in abort state. no messages except for terminate.
if (pedit->bAbort && msg != WM_DDE_TERMINATE)
return FALSE;
pedit->lParam = lparam;
pedit->msg = msg;
if (pedit->hClient && pedit->hServer) {
while (TRUE){
if (!IsWindowValid (pedit->hServer))
return FALSE;
if (PostMessage (pedit->hServer, msg, pedit->hClient, lparam) == FALSE)
Yield ();
else
return TRUE;
}
}
return FALSE;
}
OLESTATUS FARINTERNAL LeCreateFromTemplate (lpclient, lptemplate, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat)
LPOLECLIENT lpclient;
LPSTR lptemplate;
LHCLIENTDOC lhclientdoc;
LPSTR lpobjname;
LPOLEOBJECT FAR * lplpoleobject;
OLEOPT_RENDER optRender;
OLECLIPFORMAT cfFormat;
{
char buf[MAX_STR];
if (!MapExtToClass (lptemplate, (LPSTR)buf, MAX_STR))
return OLE_ERROR_CLASS;
return CreateFromClassOrTemplate (lpclient, (LPSTR) buf, lplpoleobject,
optRender, cfFormat, LN_TEMPLATE, lptemplate,
lhclientdoc, lpobjname);
}
OLESTATUS FARINTERNAL LeCreate (lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat)
LPSTR lpclass;
LPOLECLIENT lpclient;
LHCLIENTDOC lhclientdoc;
LPSTR lpobjname;
LPOLEOBJECT FAR * lplpoleobject;
OLEOPT_RENDER optRender;
OLECLIPFORMAT cfFormat;
{
if (gbCreateInvisible) {
// this is in fact a call for invisible create
return LeCreateInvisible (lpclient, lpclass, lhclientdoc, lpobjname,
lplpoleobject, optRender, cfFormat, gbLaunchServer);
}
return CreateFromClassOrTemplate (lpclient, lpclass, lplpoleobject,
optRender, cfFormat, LN_NEW, NULL,
lhclientdoc, lpobjname);
}
OLESTATUS FARINTERNAL CreateFromClassOrTemplate (lpclient, lpclass, lplpoleobject, optRender, cfFormat, lnType, lptemplate, lhclientdoc, lpobjname)
LPOLECLIENT lpclient;
LPSTR lpclass;
LPOLEOBJECT FAR * lplpoleobject;
OLEOPT_RENDER optRender;
OLECLIPFORMAT cfFormat;
WORD lnType;
LPSTR lptemplate;
LHCLIENTDOC lhclientdoc;
LPSTR lpobjname;
{
OLESTATUS retval = OLE_ERROR_MEMORY;
LPOBJECT_LE lpobj = NULL;
ATOM aServer;
char chVerb [2];
if (!(aServer = GetAppAtom (lpclass)))
return OLE_ERROR_CLASS;
if(!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, CT_EMBEDDED))) {
GlobalDeleteAtom (aServer);
goto errRtn;
}
// Now set the server.
lpobj->head.lpclient = lpclient;
lpobj->app = GlobalAddAtom (lpclass);
SetEmbeddedTopic (lpobj);
lpobj->item = NULL;
lpobj->bOleServer = QueryVerb (lpobj, 0, (LPSTR)&chVerb, 2);
lpobj->aServer = aServer;
// launch the app and start the system conversation.
if (!CreatePictObject (lhclientdoc, lpobjname, lpobj,
optRender, cfFormat, lpclass))
goto errRtn;
// show the window. Advise for data and close on receiving data
lpobj->fCmd = lnType | ACT_SHOW | ACT_ADVISE | ACT_CLOSE;
InitAsyncCmd (lpobj, lptemplate? OLE_CREATEFROMTEMPLATE : OLE_CREATE, EMBOPENUPDATE);
*lplpoleobject = (LPOLEOBJECT)lpobj;
lpobj->lptemplate = lptemplate;
if ((retval = EmbOpenUpdate (lpobj)) <= OLE_WAIT_FOR_RELEASE)
return retval;
// If there is error afterwards, then the client app should call
// to delete the object.
errRtn:
// for error termination OleDelete will terminate any conversation
// in action.
if (lpobj) {
// This oledelete will not result in asynchronous command.
OleDelete ((LPOLEOBJECT)lpobj);
*lplpoleobject = NULL;
}
return retval;
}
OLESTATUS FARINTERNAL CreateEmbLnkFromFile (lpclient, lpclass, lpfile, lpitem, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, objType)
LPOLECLIENT lpclient;
LPSTR lpclass;
LPSTR lpfile;
LPSTR lpitem;
LHCLIENTDOC lhclientdoc;
LPSTR lpobjname;
LPOLEOBJECT FAR * lplpoleobject;
OLEOPT_RENDER optRender;
OLECLIPFORMAT cfFormat;
LONG objType;
{
OLESTATUS retval = OLE_ERROR_MEMORY;
LPOBJECT_LE lpobj = NULL;
ATOM aServer;
char buf[MAX_STR];
OLE_RELEASE_METHOD releaseMethod;
WORD wFlags = NULL;
char chVerb[2];
if (!lpclass && (lpclass = (LPSTR) buf)
&& !MapExtToClass (lpfile, (LPSTR)buf, MAX_STR))
return OLE_ERROR_CLASS;
if (!(aServer = GetAppAtom (lpclass)))
return OLE_ERROR_CLASS;
if (!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, CT_LINK))) {
GlobalDeleteAtom (aServer);
goto errFileCreate;
}
lpobj->head.lpclient = lpclient;
lpobj->app = GlobalAddAtom (lpclass);
lpobj->topic = GlobalAddAtom (lpfile);
lpobj->aServer = aServer;
lpobj->bOleServer = QueryVerb (lpobj, 0, (LPSTR)&chVerb, 2);
if ((retval = SetNetName (lpobj)) != OLE_OK)
goto errFileCreate;
if (lpitem)
lpobj->item = GlobalAddAtom (lpitem);
if (!CreatePictObject (lhclientdoc, lpobjname, lpobj,
optRender, cfFormat, lpclass)) {
retval = OLE_ERROR_MEMORY;
goto errFileCreate;
}
*lplpoleobject = (LPOLEOBJECT) lpobj;
if (objType == CT_EMBEDDED) {
releaseMethod = OLE_CREATEFROMFILE;
if ((optRender == olerender_format) && (cfFormat == cfNative))
wFlags = 0;
else
wFlags = ACT_NATIVE;
}
else {
// caller wants linked object to be created
// if no presentation data is requested and the link is to the whole
// file, then there is no need to launch the server.
if ((optRender == olerender_none) && !lpobj->item)
return FileExists (lpobj);
// we want to establish hot link
wFlags = ACT_ADVISE;
releaseMethod = OLE_CREATELINKFROMFILE;
}
lpobj->fCmd = LN_LNKACT | ACT_REQUEST | ACT_UNLAUNCH | wFlags;
InitAsyncCmd (lpobj, releaseMethod , LNKOPENUPDATE);
if ((retval = LnkOpenUpdate (lpobj)) <= OLE_WAIT_FOR_RELEASE)
return retval;
// If there is error afterwards, then the client app should call
// to delete the object.
errFileCreate:
if (lpobj) {
// This oledelete will not result in asynchronous command.
OleDelete ((LPOLEOBJECT)lpobj);
*lplpoleobject = NULL;
}
return retval;
}
//////////////////////////////////////////////////////////////////////////////
//
// OLESTATUS FARINTERNAL LeCreateInvisible (lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, bActivate)
//
// Arguments:
//
// lpclient -
// lpclass -
// lhclientdoc -
// lpobjname -
// lplpoleobject -
// optRender -
// cfFormat -
// fActivate -
//
// Returns:
//
// OLE_ERROR_CLASS -
// OLE_OK -
// EmbOpenUpdate (lpobj) -
// retval -
//
// Effects:
//
//////////////////////////////////////////////////////////////////////////////
OLESTATUS FARINTERNAL LeCreateInvisible (lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, fActivate)
LPSTR lpclass;
LPOLECLIENT lpclient;
LHCLIENTDOC lhclientdoc;
LPSTR lpobjname;
LPOLEOBJECT FAR * lplpoleobject;
OLEOPT_RENDER optRender;
OLECLIPFORMAT cfFormat;
BOOL fActivate;
{
OLESTATUS retval = OLE_ERROR_MEMORY;
LPOBJECT_LE lpobj = NULL;
ATOM aServer;
char chVerb [2];
if (!(aServer = GetAppAtom (lpclass)))
return OLE_ERROR_CLASS;
if(!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, CT_EMBEDDED))) {
GlobalDeleteAtom (aServer);
goto errRtn;
}
// Now set the server.
lpobj->head.lpclient = lpclient;
lpobj->app = GlobalAddAtom (lpclass);
lpobj->item = NULL;
lpobj->bOleServer = QueryVerb (lpobj, 0, (LPSTR)&chVerb, 2);
lpobj->aServer = aServer;
lpobj->lptemplate = NULL;
SetEmbeddedTopic (lpobj);
if (!CreatePictObject (lhclientdoc, lpobjname, lpobj,
optRender, cfFormat, lpclass))
goto errRtn;
*lplpoleobject = (LPOLEOBJECT)lpobj;
if (!fActivate)
return OLE_OK;
// show the window. Advise for data and close on receiving data
lpobj->fCmd = LN_NEW | ACT_ADVISE | ACT_CLOSE;
InitAsyncCmd (lpobj, OLE_CREATEINVISIBLE, EMBOPENUPDATE);
// launch the app and start the system conversation.
if ((retval = EmbOpenUpdate (lpobj)) <= OLE_WAIT_FOR_RELEASE)
return retval;
// If there is error afterwards, then the client app should call
// to delete the object.
errRtn:
// for error termination OleDelete will terminate any conversation
// in action.
if (lpobj) {
// This oledelete will not result in asynchronous command.
OleDelete ((LPOLEOBJECT)lpobj);
*lplpoleobject = NULL;
}
return retval;
}
// LeSetUpdateOptions: sets the update options. If the server
// is connectd then it unadvises for the current options and
// advises for the new options.
OLESTATUS FARINTERNAL LeSetUpdateOptions (lpobj, options)
LPOBJECT_LE lpobj;
OLEOPT_UPDATE options;
{
PROBE_OLDLINK (lpobj);
PROBE_ASYNC (lpobj);
//!!! make sure the options are within range.
if (lpobj->head.ctype != CT_LINK)
return (OLE_ERROR_OBJECT);
if (options > oleupdate_oncall)
return OLE_ERROR_OPTION;
if (lpobj->optUpdate == options)
return OLE_OK;
if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj)) {
lpobj->optUpdate = options;
return OLE_OK;
}
lpobj->optNew = options;
lpobj->fCmd = 0;
InitAsyncCmd (lpobj, OLE_SETUPDATEOPTIONS, LNKSETUPDATEOPTIONS);
return LnkSetUpdateOptions (lpobj);
}
OLESTATUS LnkSetUpdateOptions (lpobj)
LPOBJECT_LE lpobj;
{
switch (lpobj->subRtn) {
case 0:
if (lpobj->optUpdate == oleupdate_oncall)
goto step1;
// If the server is active then unadvise for old
// options.
UnAdvisePict (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 1:
step1:
SETSTEP (lpobj, 1);
ProcessErr (lpobj);
lpobj->optUpdate = lpobj->optNew;
if (lpobj->optUpdate == oleupdate_oncall)
goto step3;
AdvisePict (lpobj, NULL);
WAIT_FOR_ASYNC_MSG (lpobj);
case 2:
SETSTEP (lpobj, 2);
if (ProcessErr (lpobj))
goto errRtn;
if (lpobj->optUpdate == oleupdate_onsave)
goto step3;
RequestPict (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 3:
errRtn:
step3:
ProcessErr (lpobj);
return EndAsyncCmd (lpobj);
default:
DEBUG_OUT ("Unexpected subroutine", 0);
return OLE_ERROR_GENERIC;
}
}
//AdvisePict: Sends advise for pict data
void INTERNAL AdvisePict (lpobj, aAdvItem)
LPOBJECT_LE lpobj;
ATOM aAdvItem;
{
int cftype;
if (cftype = GetPictType (lpobj))
AdviseOn (lpobj, cftype, aAdvItem);
}
//UnAdvisePict: Sends unadvise for pict data
void INTERNAL UnAdvisePict (lpobj)
LPOBJECT_LE lpobj;
{
int cftype;
SETERRHINT (lpobj, OLE_ERROR_ADVISE_PICT);
if (cftype = GetPictType (lpobj))
UnAdviseOn (lpobj, cftype);
}
// GetPictType: Given the object, returns the pict type.
int INTERNAL GetPictType (lpobj)
LPOBJECT_LE lpobj;
{
if (lpobj->lpobjPict)
return (int)(*lpobj->lpobjPict->lpvtbl->EnumFormats)
(lpobj->lpobjPict, NULL);
return NULL;
}
// AdviseOn : Sends advise for a given picture type
// Send advise only if the advise options is not on call.
void INTERNAL AdviseOn (lpobj, cftype, advItem)
LPOBJECT_LE lpobj;
int cftype;
ATOM advItem;
{
HANDLE hopt = NULL;
DDEADVISE FAR *lpopt = NULL;
ATOM item = NULL;
PEDIT_DDE pedit;
OLESTATUS retval;
if (cftype == (int)cfNative)
SETERRHINT (lpobj, OLE_ERROR_ADVISE_NATIVE);
else {
if (cftype == (int)cfBinary)
SETERRHINT (lpobj, OLE_ERROR_ADVISE_RENAME);
else
SETERRHINT (lpobj, OLE_ERROR_ADVISE_PICT);
}
if (lpobj->optUpdate == oleupdate_oncall)
return;
if(!(hopt = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, sizeof(DDEADVISE))))
goto errRtn;
retval = OLE_ERROR_MEMORY;
if(!(lpopt = (DDEADVISE FAR *) GlobalLock (hopt)))
goto errRtn;
pedit = lpobj->pDocEdit;
lpopt->fAckReq = TRUE;
// get data always. Currently there is no way for the
// deferred updates.
lpopt->fDeferUpd = 0;
lpopt->cfFormat = cftype;
GlobalUnlock (hopt);
pedit->hopt = hopt;
if (advItem == aStdDocName)
item = DuplicateAtom (advItem);
else
item = ExtendAtom (lpobj, lpobj->item);
retval = OLE_ERROR_COMM;
if (!PostMessageToServer(pedit, WM_DDE_ADVISE, MAKELONG (hopt, item)))
goto errRtn;
#ifdef FIREWALLS
ASSERT (!pedit->bTerminating, "trying to post while termination")
ASSERT (pedit->awaitAck == NULL, "Trying to Post msg while waiting for ack")
#endif
pedit->awaitAck = AA_ADVISE;
lpobj->bAsync = TRUE;
if (advItem == aClose)
lpobj->pDocEdit->nAdviseClose++;
else if (advItem == aSave)
lpobj->pDocEdit->nAdviseSave++;
return;
errRtn:
if (item)
GlobalDeleteAtom (item);
if (lpopt)
GlobalUnlock (hopt);
if (hopt)
GlobalFree (hopt);
lpobj->subErr = retval;
return ;
}
//UnAdviseOn: Sends unadvise for an item.
void INTERNAL UnAdviseOn (lpobj, cftype)
LPOBJECT_LE lpobj;
int cftype;
{
ATOM item;
PEDIT_DDE pedit;
pedit = lpobj->pDocEdit;
item = ExtendAtom (lpobj, lpobj->item);
if (!PostMessageToServer(pedit, WM_DDE_UNADVISE, MAKELONG (NULL, item)))
lpobj->subErr = OLE_ERROR_COMM;
else {
#ifdef FIREWALLS
ASSERT (!pedit->bTerminating, "trying to post while termination")
ASSERT (pedit->awaitAck == NULL, "Trying to Post msg while waiting for ack")
#endif
lpobj->bAsync = TRUE;
pedit->awaitAck = AA_UNADVISE;
}
}
// RequestOn: Semd WM_DDE_REQUEST for the item of the
// for a given type;
void INTERNAL RequestOn (lpobj, cftype)
LPOBJECT_LE lpobj;
int cftype;
{
ATOM item = NULL;
PEDIT_DDE pedit;
OLESTATUS retval = OLE_ERROR_COMM;
if (cftype == (int)cfNative)
SETERRHINT (lpobj, OLE_ERROR_REQUEST_NATIVE);
else
SETERRHINT (lpobj, OLE_ERROR_REQUEST_PICT);
pedit = lpobj->pDocEdit;
item = DuplicateAtom (lpobj->item);
if (!PostMessageToServer (pedit, WM_DDE_REQUEST, MAKELONG (cftype, item)))
goto errRtn;
#ifdef FIREWALLS
ASSERT (!pedit->bTerminating, "trying to post while termination")
ASSERT (pedit->awaitAck == NULL, "Trying to Post msg while waiting for ack")
#endif
lpobj->bAsync = TRUE;
pedit->awaitAck = AA_REQUEST;
return;
errRtn:
if (item)
GlobalDeleteAtom (item);
return ;
}
//RequestPict: Sends request for apicture type.
void INTERNAL RequestPict (lpobj)
LPOBJECT_LE lpobj;
{
int cftype;
if (cftype = GetPictType (lpobj))
RequestOn (lpobj, cftype);
}
// LeSetHostNames: Sets the host names. If the server is connected
// send the host names to the server.
OLESTATUS FARINTERNAL LeSetHostNames (lpobj, lpclientName, lpdocName)
LPOBJECT_LE lpobj;
LPSTR lpclientName;
LPSTR lpdocName;
{
OLESTATUS retval = OLE_ERROR_MEMORY;
if (lpobj->head.ctype != CT_EMBEDDED)
return OLE_ERROR_OBJECT;
PROBE_ASYNC (lpobj);
if ((retval = SetHostNamesHandle (lpobj, lpclientName, lpdocName))
!= OLE_OK)
return retval;
// If the server is connected poke the hostnames
InitAsyncCmd (lpobj, OLE_OTHER, NULL);
if ((retval = PokeHostNames (lpobj)) != OLE_WAIT_FOR_RELEASE)
CLEARASYNCCMD(lpobj);
return retval;
}
OLESTATUS FARINTERNAL LeSetTargetDevice (lpobj, hdata)
LPOBJECT_LE lpobj;
HANDLE hdata;
{
HANDLE hdup = NULL;
OLESTATUS retval;
PROBE_ASYNC (lpobj);
if (!hdata) {
// hdata == NULL means we should not make the target device sticky.
// This will give the flexibility to the client app. Note that this
// will not be effective till the next activation.
if (lpobj->htargetDevice) {
GlobalFree (lpobj->htargetDevice);
lpobj->htargetDevice = NULL;
}
return OLE_OK;
}
if(!(hdup = DuplicateGlobal (hdata, GMEM_MOVEABLE)))
return OLE_ERROR_MEMORY;
if (lpobj->htargetDevice)
GlobalFree (lpobj->htargetDevice);
lpobj->htargetDevice = hdup;
InitAsyncCmd (lpobj, OLE_OTHER, NULL);
if ((retval = PokeTargetDeviceInfo (lpobj)) != OLE_WAIT_FOR_RELEASE)
CLEARASYNCCMD(lpobj);
return retval;
}
OLESTATUS FARINTERNAL LeSetBounds(lpobj, lprcBounds)
LPOBJECT_LE lpobj;
LPRECT lprcBounds;
{
OLESTATUS retval = OLE_ERROR_MEMORY;
HANDLE hdata = NULL;
LPBOUNDSRECT lprc = NULL;
PROBE_ASYNC (lpobj);
if (lpobj->head.ctype != CT_EMBEDDED)
return OLE_ERROR_OBJECT;
if(!(hdata = GlobalAlloc (GMEM_MOVEABLE, (WORD)sizeof (BOUNDSRECT))))
return OLE_ERROR_MEMORY;
if (!(lprc = (LPBOUNDSRECT)GlobalLock (hdata)))
goto errrtn;
// Now set the data
lprc->defaultWidth = lprcBounds->right - lprcBounds->left;;
lprc->defaultHeight = -(lprcBounds->bottom - lprcBounds->top);
lprc->maxWidth = lprcBounds->right - lprcBounds->left;;
lprc->maxHeight = -(lprcBounds->bottom - lprcBounds->top);
GlobalUnlock (hdata);
if (lpobj->hdocDimensions)
GlobalFree (lpobj->hdocDimensions);
lpobj->hdocDimensions = hdata;
InitAsyncCmd (lpobj, OLE_OTHER, NULL);
if ((retval = PokeDocDimensions (lpobj)) != OLE_WAIT_FOR_RELEASE)
CLEARASYNCCMD(lpobj);
return retval;
errrtn:
if (lprc)
GlobalUnlock (hdata);
if (hdata)
GlobalFree (hdata);
return retval;
}
OLESTATUS FARINTERNAL LeSetData (lpobj, cfFormat, hData)
LPOBJECT_LE lpobj;
OLECLIPFORMAT cfFormat;
HANDLE hData;
{
OLESTATUS retVal = OLE_OK;
BOOL fKnown = FALSE;
PROBE_ASYNC (lpobj);
if ((cfFormat == cfObjectLink) || (cfFormat == cfOwnerLink))
return ChangeDocAndItem (lpobj, hData);
if (fKnown = (cfFormat && (cfFormat == ((WORD) GetPictType (lpobj))))) {
retVal = (*lpobj->lpobjPict->lpvtbl->ChangeData) (lpobj->lpobjPict,
hData, lpobj->head.lpclient, FALSE);
(*lpobj->lpobjPict->lpvtbl->GetData) (lpobj->lpobjPict,
cfFormat, &hData);
}
else if (fKnown = (cfFormat == cfNative)) {
retVal = LeChangeData (lpobj, hData, lpobj->head.lpclient, FALSE);
hData = lpobj->hnative;
}
if (retVal != OLE_OK)
return retVal;
if (fKnown)
ContextCallBack (lpobj, OLE_CHANGED);
if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj)) {
if (!fKnown)
return OLE_ERROR_NOT_OPEN;
return OLE_OK;
}
// except for the following formats all the other data will be copied
// into DDEPOKE block. So there is no need to duplicate the data of the
// other formats
if ((cfFormat == CF_METAFILEPICT) || (cfFormat == CF_BITMAP)
|| (cfFormat == CF_DIB)) {
if (!(hData = DuplicateGDIdata (hData, cfFormat)))
return OLE_ERROR_MEMORY;
}
// *** The last parameter must be NULL, don't change it ***
InitAsyncCmd (lpobj, OLE_SETDATA, NULL);
if ((retVal = SendPokeData (lpobj, lpobj->item, hData, cfFormat))
!= OLE_WAIT_FOR_RELEASE)
CLEARASYNCCMD(lpobj);
return retVal;
}
OLESTATUS FARINTERNAL LeSetColorScheme (lpobj, lplogpal)
LPOBJECT_LE lpobj;
LPLOGPALETTE lplogpal;
{
HANDLE hdup = NULL;
DWORD cblogpal;
OLESTATUS retval;
LPBYTE lptemp;
lptemp = (LPBYTE) lplogpal;
if (lpobj->head.ctype != CT_EMBEDDED)
return OLE_ERROR_OBJECT;
PROBE_ASYNC (lpobj);
if (!lplogpal) {
// lplogpal == NULL means we should not make color scheme sticky.
// This will give the flexibility to the client app. Note that this
// will not be effective till next activation.
if (lpobj->hlogpal) {
GlobalFree (lpobj->hlogpal);
lpobj->hlogpal = NULL;
}
return OLE_OK;
}
FARPROBE_READ(lptemp + (cblogpal = 2*sizeof(WORD)));
cblogpal += ((sizeof(PALETTEENTRY) * lplogpal->palNumEntries) -1);
if (!FarCheckPointer (lptemp + cblogpal, READ_ACCESS))
return OLE_ERROR_PALETTE;
if (!(hdup = CopyData ((LPSTR) lplogpal, cblogpal)))
return OLE_ERROR_MEMORY;
if (lpobj->hlogpal)
GlobalFree (lpobj->hlogpal);
lpobj->hlogpal = hdup;
InitAsyncCmd (lpobj, OLE_OTHER, NULL);
if ((retval = PokeColorScheme (lpobj)) != OLE_WAIT_FOR_RELEASE)
CLEARASYNCCMD(lpobj);
return retval;
}
//PokeHostNames: Pokes hostname data to the server
OLESTATUS INTERNAL PokeHostNames (lpobj)
LPOBJECT_LE lpobj;
{
OLESTATUS retVal = OLE_ERROR_MEMORY;
// if the server is connectd then poke the host names
if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj))
return OLE_OK;
if (!lpobj->hhostNames)
return OLE_OK;
aStdHostNames = GlobalAddAtom ("StdHostNames");
return SendPokeData (lpobj,aStdHostNames,lpobj->hhostNames,cfBinary);
}
OLESTATUS INTERNAL PokeTargetDeviceInfo (lpobj)
LPOBJECT_LE lpobj;
{
// if the server is connectd then poke the host names
if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj))
return OLE_OK;
if (!lpobj->htargetDevice)
return OLE_OK;
aStdTargetDevice = GlobalAddAtom ("StdTargetDevice");
return SendPokeData (lpobj, aStdTargetDevice,
lpobj->htargetDevice,
cfBinary);
}
OLESTATUS INTERNAL PokeDocDimensions (lpobj)
LPOBJECT_LE lpobj;
{
// if the server is connectd then poke the host names
if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj))
return OLE_OK;
if (!lpobj->hdocDimensions)
return OLE_OK;
aStdDocDimensions = GlobalAddAtom ("StdDocDimensions");
return SendPokeData (lpobj, aStdDocDimensions,
lpobj->hdocDimensions,
cfBinary);
}
OLESTATUS INTERNAL PokeColorScheme (lpobj)
LPOBJECT_LE lpobj;
{
// if the server is connected then poke the palette info
if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj))
return OLE_OK;
if (!lpobj->hlogpal)
return OLE_OK;
aStdColorScheme = GlobalAddAtom ("StdColorScheme");
return SendPokeData (lpobj, aStdColorScheme,
lpobj->hlogpal,
cfBinary);
}
OLESTATUS INTERNAL SendPokeData (lpobj, aItem, hdata, cfFormat)
LPOBJECT_LE lpobj;
ATOM aItem;
HANDLE hdata;
OLECLIPFORMAT cfFormat;
{
HANDLE hdde = NULL;
DDEPOKE FAR * lpdde = NULL;
LPSTR lpdst = NULL;
LPSTR lpsrc = NULL;
OLESTATUS retval = OLE_ERROR_MEMORY;
DWORD dwSize = NULL;
PEDIT_DDE pedit;
BOOL bGDIdata = FALSE;
pedit = lpobj->pDocEdit;
// If it is GDI data then we can stuff the handle into POKE block.
// Otherwise we have to copy the data into DDE data block. There
// is a special case with old MSDraw, that will be handled by
// the routine CanPutHandleInPokeBlock()
if (!(bGDIdata = CanPutHandleInPokeBlock (lpobj, cfFormat))) {
if (!(dwSize = GlobalSize (hdata)))
return OLE_ERROR_MEMORY;
if (!(lpsrc = (LPSTR) GlobalLock (hdata)))
return OLE_ERROR_MEMORY;
GlobalUnlock (hdata);
}
// Now allocate the DDE data block
if (!(hdde = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT,
(dwSize + sizeof(DDEPOKE) - sizeof(BYTE) + sizeof(HANDLE)))))
goto errRtn;
if (!(lpdde = (DDEPOKE FAR *)GlobalLock (hdde)))
goto errRtn;
GlobalUnlock (hdde);
// !!! We may want to set it TRUE, for performance reasons. But it
// will require some rework on the server side
lpdde->fRelease = 0;
lpdde->cfFormat = cfFormat;
if (bGDIdata)
*(LPHANDLE)lpdde->Value = hdata;
else {
lpdst = (LPSTR)lpdde->Value;
UtilMemCpy (lpdst, lpsrc, dwSize);
// For the CF_METAFILEPICT format, we would come here only if we are
// dealing with the old version of MSDraw. In that case we want to
// free the handle to METAFILEPICT strcuture, because we've already
// copied its contents to DDEPOKE structure.
// Note that that the old MSDraw expects the contents of METAFILEPICT
// structure to be part of DDEPOKE, rather than the handle to it.
if (cfFormat == CF_METAFILEPICT) {
GlobalFree (hdata);
hdata = NULL;
}
}
// *** From here onwards if there is an error call FreePokeData(), don't
// jump to errRtn
aItem = DuplicateAtom (aItem);
ASSERT(pedit->hData == NULL, "Poke data is not null");
pedit->hData = hdde;
if (!PostMessageToServer (pedit, WM_DDE_POKE, MAKELONG (hdde, aItem))) {
if (aItem)
GlobalDeleteAtom (aItem);
FreePokeData (lpobj, pedit);
return (lpobj->subErr = OLE_ERROR_COMM);
}
#ifdef FIREWALLS
ASSERT (!pedit->bTerminating, "trying to post while termination")
ASSERT (pedit->awaitAck == NULL, "Trying to Post msg while waiting for ack")
#endif
if (lpobj->asyncCmd == OLE_NONE)
lpobj->asyncCmd = OLE_OTHER;
lpobj->bAsync = TRUE;
pedit->awaitAck = AA_POKE;
// !!! after poke of the hostnames etc. we are not processing error.,
// Data is freed after the Poke is acknowledged. OLE_RELEASE will be sent
// to when ACK comes.
return OLE_WAIT_FOR_RELEASE;
errRtn:
if (hdata)
FreeGDIdata (hdata, cfFormat);
if (hdde)
GlobalFree (hdde);
pedit->hData = NULL;
return (lpobj->subErr = retval);
}
// FreePokeData: Frees the poked data.
void INTERNAL FreePokeData (lpobj, pedit)
LPOBJECT_LE lpobj;
PEDIT_DDE pedit;
{
DDEPOKE FAR * lpdde;
#ifdef FIREWALLS
ASSERT (pedit->hData, "Poke data handle is null");
#endif
if (lpdde = (DDEPOKE FAR *) GlobalLock (pedit->hData)) {
GlobalUnlock (pedit->hData);
// The old version of MSDraw expects the contents of METAFILEPICT
// structure to be part of DDEPOKE, rather than the handle to it.
if (!lpobj->bOleServer && (lpobj->app == aMSDraw)
&& (lpdde->cfFormat == CF_METAFILEPICT)) {
DeleteMetaFile (((LPMETAFILEPICT) ((LPSTR) &lpdde->Value))->hMF);
}
else {
FreeGDIdata (*(LPHANDLE)lpdde->Value, lpdde->cfFormat);
}
}
GlobalFree (pedit->hData);
pedit->hData = NULL;
}
BOOL INTERNAL SendSrvrMainCmd (lpobj, lptemplate)
LPOBJECT_LE lpobj;
LPSTR lptemplate;
{
WORD size;
WORD len;
OLESTATUS retval;
int cmd;
HANDLE hInst = NULL;
LPSTR lpdata= NULL;
HANDLE hdata = NULL;
BOOL bLaunch = TRUE;
Puts("Launch App and Send Sys command");
#ifdef FIREWALLS
ASSERT (lpobj->aServer, "Serevr is NULL");
#endif
if (!lpobj->aServer) {
retval = OLE_ERROR_REGISTRATION;
goto errRtn;
}
if (!lpobj->bOldLink) {
bLaunch = !(lpobj->fCmd & ACT_NOLAUNCH);
cmd = lpobj->fCmd & LN_MASK;
}
if (cmd == LN_LNKACT) {
// take care of network based document
char cDrive = lpobj->cDrive;
if ((retval = CheckNetDrive (lpobj, POPUP_NETDLG)) != OLE_OK) {
lpobj->cDrive = cDrive;
goto errRtn;
}
if (cDrive != lpobj->cDrive)
ContextCallBack (lpobj, OLE_RENAMED);
}
if (!InitSrvrConv (lpobj, hInst)) {
if (!bLaunch)
goto errRtn;
if (!(hInst = LeLaunchApp (lpobj))) {
// We failed to launch the app. If it is a linked object, see
// whether the docname is valid for new servers. We wouldn't
// have given the doc name on the command line for the old
// servers. So, there is no point in checking for file existance
// in that case.
if (lpobj->bOleServer && (lpobj->bOldLink || (cmd == LN_LNKACT))){
if ((retval = FileExists (lpobj)) != OLE_OK)
goto errRtn;
}
retval = OLE_ERROR_LAUNCH;
goto errRtn;
}
if (lpobj->bOldLink)
return TRUE;
if (lpobj->bOleServer && (cmd == LN_LNKACT)) {
// We are not using any data blocks if the object is old link.
// we launched with docname, and don't have to establish system
// level and also we don't have to send exec strings.
// for non-ole servers like excel, we do want to connect at
// the system level, so that we can send "StdOpen". We also
// have to send "StdExit" for the server to exit in the
// invisible launch case.
return TRUE;
}
retval = OLE_ERROR_COMM;
if(!InitSrvrConv (lpobj, hInst))
goto errRtn;
#ifdef OLD
if (!lpobj->bOleServer && (cmd == LN_LNKACT))
return TRUE;
#endif
}
if (!lpobj->bOldLink) {
cmd = lpobj->fCmd & LN_MASK;
len = lstrlen (srvrSysCmd[cmd >> LN_SHIFT]);
// for template and new, add the class name also
if (cmd == LN_NEW || cmd == LN_TEMPLATE)
len += GlobalGetAtomLen (lpobj->app);
// Now add the document length.
len += GlobalGetAtomLen (lpobj->topic);
// add the length of the template name
if (lptemplate)
len += lstrlen (lptemplate);
// now add the fudge factor for the Quotes etc.
len += LN_FUDGE;
// allocate the buffer and set the command.
hdata = GlobalAlloc (GMEM_DDESHARE, size = len);
retval = OLE_ERROR_MEMORY;
SETERRHINT(lpobj, OLE_ERROR_MEMORY);
if (hdata == NULL || (lpdata = (LPSTR)GlobalLock (hdata)) == NULL)
goto errRtn;
}
lstrcpy (lpdata, (LPSTR)"["); // [
lstrcat (lpdata, srvrSysCmd[cmd >> LN_SHIFT]); // [Std....
lstrcat (lpdata, "(\""); // [std...("
if (cmd == LN_NEW || cmd == LN_TEMPLATE) {
len = lstrlen (lpdata);
GlobalGetAtomName (lpobj->app, (LPSTR)lpdata + len, size - len);
// [std...("class
lstrcat (lpdata, "\",\""); // [std...("class", "
}
len = lstrlen (lpdata);
// now get the topic name.
GlobalGetAtomName (lpobj->topic, lpdata + len, (WORD)size - len);
// [std...("class","doc
if (lptemplate) {
lstrcat (lpdata, "\",\""); // [std...("class","doc","
lstrcat (lpdata, lptemplate); // [std...("class","doc","temp
}
lstrcat (lpdata, "\")]"); // [std...("class","doc","temp")]
GlobalUnlock (hdata);
// !!!optimize with mapping.
SETERRHINT(lpobj, (OLE_ERROR_TEMPLATE + (cmd >> LN_SHIFT)));
return SrvrExecute (lpobj, hdata);
errRtn:
if (lpdata)
GlobalUnlock (hdata);
if (hdata)
GlobalFree (hdata);
lpobj->subErr = retval;
return FALSE;
}
// ExtendAtom: Create a new atom, which is the old one plus extension
ATOM INTERNAL ExtendAtom (lpobj, item)
LPOBJECT_LE lpobj;
ATOM item;
{
char buffer[MAX_ATOM+1];
LPSTR lpext;
Puts("ExtendAtom");
buffer[0] = 0;
if (item)
GlobalGetAtomName (item, buffer, MAX_ATOM);
switch (lpobj->optUpdate) {
case oleupdate_always:
lpext = (LPSTR)"";
break;
case oleupdate_onsave:
lpext = (LPSTR)"/Save";
break;
case oleupdate_onclose:
lpext = (LPSTR)"/Close";
break;
default:
ASSERT (FALSE, "on call options not expected here");
break;
}
lstrcat (buffer, lpext);
if (buffer[0])
return GlobalAddAtom (buffer);
else
return NULL;
}
BOOL INTERNAL CreatePictObject (lhclientdoc, lpobjname, lpobj, optRender, cfFormat, lpclass)
LHCLIENTDOC lhclientdoc;
LPSTR lpobjname;
LPOBJECT_LE lpobj;
OLEOPT_RENDER optRender;
OLECLIPFORMAT cfFormat;
LPSTR lpclass;
{
LPOLEOBJECT lpPictObj = NULL;
ATOM aClass;
lpobj->lpobjPict = NULL;
if (optRender == olerender_format) {
switch (cfFormat) {
case NULL:
return FALSE;
case CF_METAFILEPICT:
if (!(lpPictObj = (LPOLEOBJECT) MfCreateBlank (lhclientdoc,
lpobjname, CT_PICTURE)))
return FALSE;
break;
case CF_DIB:
if (!(lpPictObj = (LPOLEOBJECT) DibCreateBlank (lhclientdoc,
lpobjname, CT_PICTURE)))
return FALSE;
break;
case CF_BITMAP:
if (!(lpPictObj = (LPOLEOBJECT) BmCreateBlank (lhclientdoc,
lpobjname, CT_PICTURE)))
return FALSE;
break;
default:
aClass = GlobalAddAtom (lpclass);
if (!(lpPictObj = (LPOLEOBJECT) GenCreateBlank (lhclientdoc,
lpobjname, CT_PICTURE, aClass)))
return FALSE;
((LPOBJECT_GEN)lpPictObj)->cfFormat = cfFormat;
break;
}
}
else if (optRender == olerender_draw) {
if (!(lpPictObj = (LPOLEOBJECT) MfCreateBlank (lhclientdoc,
lpobjname, CT_PICTURE)))
return FALSE;
#ifdef LATER
if (AdviseOn (lpobj, (cfFormat = CF_METAFILEPICT), NULL))
lpPictObj = (LPOLEOBJECT) MfCreateBlank (lhclientdoc,
lpobjname, CT_PICTURE);
// !!! for the time being take assume we need to get metafile.
else if (AdviseOn (lpobj, (cfFormat = CF_DIB), NULL))
lpPictObj = (LPOLEOBJECT) DibCreateBlank (lhclientdoc,
lpobjname, CT_PICTURE);
else if (AdviseOn (lpobj, (cfFormat = CF_BITMAP), NULL))
lpPictObj = (LPOLEOBJECT) BmCreateBlank (lhclientdoc,
lpobjname, CT_PICTURE);
else
goto errPict;
#endif
}
else
return (optRender == olerender_none);
if (lpobj->lpobjPict = lpPictObj)
lpobj->lpobjPict->lpParent = (LPOLEOBJECT) lpobj;
return TRUE;
}
OLESTATUS LnkChangeLnk (lpobj)
LPOBJECT_LE lpobj;
{
switch (lpobj->subRtn) {
case 0:
TermDocConv (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 1:
// delete the edit block
DeleteDocEdit (lpobj);
TermSrvrConv (lpobj);
WAIT_FOR_ASYNC_MSG (lpobj);
case 2:
// Do not set any errors, just delete the object.
// delete the server edit block
DeleteSrvrEdit (lpobj);
// now try to activate the new link.
SKIP_TO (!InitDocConv (lpobj, !POPUP_NETDLG), step3);
lpobj->fCmd = LN_LNKACT | ACT_ADVISE | ACT_REQUEST;
InitAsyncCmd (lpobj, OLE_SETDATA, LNKOPENUPDATE);
return LnkOpenUpdate (lpobj);
case 3:
step3:
return EndAsyncCmd (lpobj);
default:
DEBUG_OUT ("Unexpected subroutine", 0);
return OLE_ERROR_GENERIC;
}
}
OLESTATUS INTERNAL ChangeDocAndItem (lpobj, hinfo)
LPOBJECT_LE lpobj;
HANDLE hinfo;
{
LPSTR lpinfo;
ATOM aNewTopic, aNewItem = NULL, aOldTopic;
OLESTATUS retVal = OLE_ERROR_BLANK;
PROBE_SVRCLOSING(lpobj);
if (!(lpinfo = GlobalLock (hinfo)))
return OLE_ERROR_MEMORY;
lpinfo += lstrlen (lpinfo) + 1;
aNewTopic = GlobalAddAtom (lpinfo);
lpinfo += lstrlen (lpinfo) + 1;
if (*lpinfo)
aNewItem = GlobalAddAtom (lpinfo);
if (!aNewTopic && (lpobj->head.ctype == CT_LINK))
goto errRtn;
aOldTopic = lpobj->topic;
lpobj->topic = aNewTopic;
if ((retVal = SetNetName (lpobj)) != OLE_OK) {
if (lpobj->topic)
GlobalDeleteAtom (lpobj->topic);
lpobj->topic = aOldTopic;
goto errRtn;
}
if (aOldTopic)
GlobalDeleteAtom (aOldTopic);
if (lpobj->item)
GlobalDeleteAtom (lpobj->item);
lpobj->item = aNewItem;
// As the atoms have already changed, lpobj->hLink becomes irrelevant.
if (lpobj->hLink) {
GlobalFree (lpobj->hLink);
lpobj->hLink = NULL;
}
GlobalUnlock(hinfo);
// Now disconnect the old link and try to connect to the new one.
lpobj->fCmd = 0;
InitAsyncCmd (lpobj, OLE_SETDATA, LNKCHANGELNK);
return LnkChangeLnk (lpobj);
errRtn:
if (aNewItem)
GlobalDeleteAtom (aNewItem);
GlobalUnlock (hinfo);
return retVal;
}
BOOL QueryUnlaunch (lpobj)
LPOBJECT_LE lpobj;
{
if (!(lpobj->fCmd & ACT_UNLAUNCH))
return FALSE;
// only if we loaded the app
if (lpobj->pSysEdit && lpobj->pSysEdit->hClient && lpobj->pSysEdit->hInst)
return TRUE;
return FALSE;
}
BOOL QueryClose (lpobj)
LPOBJECT_LE lpobj;
{
if (!((lpobj->fCmd & ACT_UNLAUNCH) ||
(lpobj->head.ctype == CT_EMBEDDED)))
return FALSE;
// only if we loaded the documnet
if (lpobj->pSysEdit && lpobj->pSysEdit->hClient)
return TRUE;
return FALSE;
}
OLESTATUS INTERNAL SetHostNamesHandle (lpobj, lpclientName, lpdocName)
LPOBJECT_LE lpobj;
LPSTR lpclientName;
LPSTR lpdocName;
{
WORD cbClient;
WORD size;
HANDLE hhostNames = NULL;
LPHOSTNAMES lphostNames = NULL;
LPSTR lpdata;
// 4 bytes is for the two offsets
size = (cbClient = lstrlen(lpclientName)+1) + (lstrlen(lpdocName)+1) + 4;
if ((hhostNames = GlobalAlloc (GMEM_MOVEABLE, (DWORD) size))
== NULL)
goto errRtn;
if ((lphostNames = (LPHOSTNAMES)GlobalLock (hhostNames)) == NULL)
goto errRtn;
lphostNames->clientNameOffset = 0;
lphostNames->documentNameOffset = cbClient;
lpdata = (LPSTR)lphostNames->data;
lstrcpy (lpdata, lpclientName);
lstrcpy (lpdata + cbClient, lpdocName);
if (lpobj->hhostNames)
GlobalFree ( lpobj->hhostNames);
GlobalUnlock (hhostNames);
lpobj->hhostNames = hhostNames;
return OLE_OK;
errRtn:
if (lphostNames)
GlobalUnlock (hhostNames);
if (hhostNames)
GlobalFree (hhostNames);
return OLE_ERROR_MEMORY;
}
#if 0
OLESTATUS FARINTERNAL LeAbort (lpobj)
LPOBJECT_LE lpobj;
{
BOOL bAbort = FALSE;
PEDIT_DDE pedit;
// check whether the any transaction pending for
// the document level.
// channel open
// any transaction pending.
// and we are not in terminate mode.
if ((pedit = lpobj->pDocEdit) && pedit->hServer &&
pedit->awaitAck && !pedit->bTerminating) {
pedit->bAbort = bAbort = TRUE;
// delete any data we need to delete. Ricght now
// we kill only the timer. We can not delete any
// since the server could potentially look at the data.
DeleteAbortData (lpobj, pedit);
}
if ((pedit = lpobj->pSysEdit) && pedit->hServer &&
pedit->awaitAck && !pedit->bTerminating) {
pedit->bAbort = bAbort = TRUE;
DeleteAbortData (lpobj, pedit);
}
if (!bAbort)
return OLE_OK;
// Now send the EndAsync
lpobj->mainErr = OLE_ERROR_ABORT;
EndAsyncCmd (lpobj);
return OLE_OK;
}
#endif
OLESTATUS FARINTERNAL ProbeAsync(lpobj)
LPOBJECT_LE lpobj;
{
if (lpobj->asyncCmd == OLE_NONE)
return OLE_OK;
if (!IsServerValid (lpobj)) {
// Now send the EndAsync
lpobj->mainErr = OLE_ERROR_TASK;
EndAsyncCmd (lpobj);
return OLE_OK;
}
return OLE_BUSY;
}
BOOL INTERNAL IsWindowValid (hwnd)
HWND hwnd;
{
#define TASK_OFFSET 0x00FA
LPSTR lptask;
HANDLE htask;
if (!IsWindow (hwnd))
return FALSE;
if (bWLO)
return TRUE;
// now get the task handle and find out it is valid.
htask = GetWindowTask (hwnd);
if ((wWinVer == 0x0003) || !lpfnIsTask) {
lptask = (LPSTR)(MAKELONG (TASK_OFFSET, htask));
if (!FarCheckPointer(lptask, READ_ACCESS))
return FALSE;
// now check for the signature bytes of task block in kernel
if (*lptask++ == 'T' && *lptask == 'D')
return TRUE;
}
else {
// From win31 onwards the API IsTask can be used for task validation
if ((*lpfnIsTask)(htask))
return TRUE;
}
return FALSE;
}
BOOL INTERNAL IsServerValid (lpobj)
LPOBJECT_LE lpobj;
{
MSG msg;
BOOL retval = FALSE;
if (lpobj->pDocEdit && lpobj->pDocEdit->hServer) {
retval = TRUE;
if (!IsWindowValid (lpobj->pDocEdit->hServer)) {
if (!PeekMessage ((LPMSG)&msg, lpobj->pDocEdit->hClient, WM_DDE_TERMINATE, WM_DDE_TERMINATE,
PM_NOREMOVE | PM_NOYIELD)){
#ifdef FIREWALLS
ASSERT (FALSE, "Server truely died");
#endif
return FALSE;
}
}
}
if (lpobj->pSysEdit && lpobj->pSysEdit->hServer) {
retval = TRUE;
if (!IsWindowValid (lpobj->pSysEdit->hServer)) {
if (!PeekMessage ((LPMSG)&msg, lpobj->pSysEdit->hClient, WM_DDE_TERMINATE, WM_DDE_TERMINATE,
PM_NOREMOVE | PM_NOYIELD)){
#ifdef FIREWALLS
ASSERT (FALSE, "Server truely died");
#endif
return FALSE;
}
}
}
return retval;
}
OLESTATUS FARINTERNAL LeExecute (lpobj, hCmds, wReserve)
LPOBJECT_LE lpobj;
HANDLE hCmds;
WORD wReserve;
{
// Assumes all the creates are in order
PROBE_CREATE_ASYNC(lpobj);
PROBE_SVRCLOSING(lpobj);
if (!(lpobj = (*lpobj->head.lpvtbl->QueryProtocol) (lpobj,
PROTOCOL_EXECUTE)))
return OLE_ERROR_PROTOCOL;
if (!QueryOpen (lpobj))
return OLE_ERROR_NOT_OPEN;
if (!(hCmds = DuplicateGlobal (hCmds, GMEM_MOVEABLE|GMEM_DDESHARE)))
return OLE_ERROR_MEMORY;
InitAsyncCmd (lpobj, OLE_OTHER, NULL);
SETERRHINT(lpobj, OLE_ERROR_COMMAND);
if (DocExecute(lpobj, hCmds))
return OLE_WAIT_FOR_RELEASE;
else
return OLE_ERROR_COMMAND;
}
void INTERNAL FreeGDIdata (hData, cfFormat)
HANDLE hData;
OLECLIPFORMAT cfFormat;
{
if (cfFormat == CF_METAFILEPICT) {
LPMETAFILEPICT lpMfp;
if (lpMfp = (LPMETAFILEPICT) GlobalLock (hData)) {
GlobalUnlock (hData);
DeleteMetaFile (lpMfp->hMF);
}
GlobalFree (hData);
}
else if (cfFormat == CF_BITMAP)
DeleteObject (hData);
else if (cfFormat == CF_DIB)
GlobalFree (hData);
}
// This routine figures out whether the handle to data block can be copied
// to DDEPOKE block rather than the contents of the handle
BOOL INTERNAL CanPutHandleInPokeBlock (lpobj, cfFormat)
LPOBJECT_LE lpobj;
OLECLIPFORMAT cfFormat;
{
if (cfFormat == CF_BITMAP || cfFormat == CF_DIB)
return TRUE;
if (cfFormat == CF_METAFILEPICT) {
// The old version of MSDraw expects the contents of METAFILEPICT
// structure to be part of DDEPOKE, rather than the handle to it.
if (!lpobj->bOleServer && lpobj->app == aMSDraw)
return FALSE;
return TRUE;
}
return FALSE;
}