|
|
/****************************** Module Header ******************************\
* Module Name: DDE.C (Extensible Compound Documents -DDE) * * Copyright (c) 1985 - 1991 Microsoft Corporation * * PURPOSE: Handles all API routines for the dde sub-dll of the ole dll. * * History: * Raor,Srinik (../../90,91) Designed and coded * curts created portable version for WIN16/32 * \***************************************************************************/
#include <windows.h>
#include "dde.h"
#include "dll.h"
#include "strsafe.h"
/* #define GRAPHBUG */
// ### may not need seperate wndproc for system topic!
HANDLE GetDDEDataHandle (DDEDATA FAR *, UINT, HANDLE);
extern ATOM aSystem; extern ATOM aOle; extern HANDLE hInstDLL;
// DocWndProc: Window procedure used to document DDE conversations
LRESULT FAR PASCAL DocWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ){ PEDIT_DDE pedit = NULL; LPOBJECT_LE lpobj = NULL;
Puts("DocWndProc");
if (lpobj = (LPOBJECT_LE) GetWindowLongPtr (hwnd, 0)) { pedit = lpobj->pDocEdit; } else { // Can't cope so just pass this message on
DEBUG_OUT ("SYS: doc conv block missing",0); return DefWindowProc (hwnd, message, wParam, lParam); }
switch (message){
case WM_DDE_ACK: DEBUG_OUT ("WM_DDE_ACK ", 0); if (pedit->bTerminating){ // ### this error recovery may not be correct.
DEBUG_OUT ("No action due to termination process",0) break; }
switch(pedit->awaitAck){
case AA_INITIATE: HandleAckInitMsg (pedit, (HWND)wParam); if (LOWORD(lParam)) GlobalDeleteAtom (LOWORD(lParam)); if (HIWORD(lParam)) GlobalDeleteAtom (HIWORD(lParam)); break;
case AA_REQUEST: Puts("Request"); HandleAck (lpobj, pedit, wParam, lParam); break;
case AA_UNADVISE: Puts("Unadvise"); HandleAck (lpobj, pedit, wParam, lParam); break;
case AA_EXECUTE: Puts("Execute"); HandleAck (lpobj, pedit, wParam, lParam); break;
case AA_ADVISE: Puts("Advise"); HandleAck (lpobj, pedit, wParam, lParam); break;
case AA_POKE:
// freeing pokedata is done in handleack
Puts("Poke"); HandleAck (lpobj, pedit, wParam, lParam); break;
default: DEBUG_OUT ("received ACK We don't know how to handle ",0) break;
} // end of switch
break;
case WM_TIMER: HandleTimerMsg (lpobj, pedit); break;
case WM_DDE_DATA: DEBUG_OUT ("WM_DDE_DATA",0); HandleDataMsg (lpobj, GET_WM_DDE_DATA_HDATA(wParam,lParam), GET_WM_DDE_DATA_ITEM(wParam,lParam)); DDEFREE(message, lParam); break;
case WM_DDE_TERMINATE:
DEBUG_OUT ("WM_DDE_TERMINATE",0); HandleTermMsg (lpobj, pedit, (HWND)wParam, TRUE); break;
case WM_DESTROY:
DEBUG_OUT ("Client window being destroyed", 0) pedit->hClient = NULL; break;
default: return DefWindowProc (hwnd, message, wParam, lParam);
} return 0L; }
// SrvrWndProc: Window Procedure for System Topic DDE conversations
// wndproc for system topic
LRESULT FAR PASCAL SrvrWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ){ PEDIT_DDE pedit = NULL; LPOBJECT_LE lpobj = NULL;
Puts("SysWndProc");
if (lpobj = (LPOBJECT_LE) GetWindowLongPtr (hwnd, 0)) { pedit = lpobj->pSysEdit; } else { // Can't cope so just pass this message on
DEBUG_OUT ("SYS: conv edit block missing",0); return DefWindowProc (hwnd, message, wParam, lParam); }
switch (message){
case WM_DDE_ACK:
DEBUG_OUT ("SYS: WM_DDE_ACK",0);
if(pedit->bTerminating){ //### Error recovery may not be OK.
DEBUG_OUT ("No action due to termination process",0) break; }
switch (pedit->awaitAck) {
case AA_INITIATE:
#ifdef HISTORY
if (GETWINDOWUINT((HWND)wParam, GWW_HINSTANCE) == pedit->hInst || IsSrvrDLLwnd ((HWND)wParam, pedit->hInst)) { // For exact instance match or for
// DLL instance match, keep the new one
pedit->hServer = (HWND)wParam; } else {
++pedit->extraTerm; // This post directly is alright since we are
// terminating extra initiates.
PostMessage ((HWND)wParam, WM_DDE_TERMINATE, hwnd, 0); } #else
HandleAckInitMsg (pedit, (HWND)wParam); #endif
if (LOWORD(lParam)) GlobalDeleteAtom (LOWORD(lParam)); if (HIWORD(lParam)) GlobalDeleteAtom (HIWORD(lParam));
break;
case AA_EXECUTE: HandleAck(lpobj, pedit, wParam, lParam); break;
default: DEBUG_OUT ("received ACK We don't know how to handle ",0) break;
}
break;
case WM_TIMER:
HandleTimerMsg (lpobj, pedit); break;
case WM_DDE_TERMINATE:
HandleTermMsg (lpobj, pedit, (HWND)wParam, FALSE); break;
case WM_DESTROY: DEBUG_OUT ("destroy window for the sys connection", 0); pedit->hClient = NULL; break;
default: return DefWindowProc (hwnd, message, wParam, lParam);
} return 0L; }
void INTERNAL HandleTimerMsg ( LPOBJECT_LE lpobj, PEDIT_DDE pedit ){
// Since there is only one timer for each client, just
// repost the message and delete the timer.
KillTimer (pedit->hClient, 1); pedit->wTimer = 0;
if (PostMessageToServer(pedit, pedit->msg, pedit->lParam)) return ; // return something.
// Postmessage failed. We need to getback to the main stream of
// commands for the object.
HandleAck (lpobj, pedit, (WPARAM)NULL, pedit->lParam); return ; }
void INTERNAL HandleTermMsg (lpobj, pedit, hwndPost, bDoc) LPOBJECT_LE lpobj; PEDIT_DDE pedit; HWND hwndPost; BOOL bDoc; { UINT asyncCmd; BOOL bBusy;
if (pedit->hServer != hwndPost){ DEBUG_OUT ("Got terminate for extra conversation",0) if (--pedit->extraTerm == 0 && pedit->bTerminating) ScheduleAsyncCmd (lpobj); return;
}
if (!pedit->bTerminating){
// If we are waiting for any ack, then goto next step with error
// delete any data if we were in busy mode.
bBusy = DeleteBusyData (lpobj, pedit);
asyncCmd = lpobj->asyncCmd; PostMessageToServer(pedit, WM_DDE_TERMINATE, 0); pedit->hServer = NULL; if (pedit->awaitAck || bBusy) { // Set error and goto next step.
lpobj->subErr = OLE_ERROR_COMM; pedit->awaitAck = 0; ScheduleAsyncCmd (lpobj); }
// If the command is delete, do not delete
// the edit blocks. It will be deleted
// in the OleLnkDelete routine and for delete it is
// possible that by the time we come here, the object
// may not exist at all.
if (asyncCmd != OLE_DELETE){ // QueryOpen() is done because excel is sending WM_DDE_TERMINATE
// for system without sending for doc in case of failure.
if (bDoc || QueryOpen (lpobj)) { // if the termination is for document and no async command
// terminate the server conversation also.
if ((asyncCmd == OLE_NONE) || (asyncCmd == OLE_REQUESTDATA) || (asyncCmd == OLE_OTHER) || (asyncCmd == OLE_SETDATA) || (asyncCmd == OLE_RUN) || (asyncCmd == OLE_SHOW) || (asyncCmd == OLE_SETUPDATEOPTIONS)) { if (lpobj->pDocEdit && lpobj->pDocEdit->awaitAck) // we are waiting for an ack on Doc channel. So start
// the unlaunch process after we get the ack.
lpobj->bUnlaunchLater = TRUE; else CallEmbLnkDelete (lpobj); } else { if (bDoc) DeleteDocEdit (lpobj);
} }else DeleteSrvrEdit (lpobj);
} } else { pedit->hServer = NULL; if (pedit->extraTerm == 0) ScheduleAsyncCmd (lpobj); } }
// HandleAckInitMsg: Handles WM_DDE_ACKs received while in initiate state. If
// this is the first reply, save its window handle. If multiple replies
// are received, take the one with the prefered instance, if there is
// one. Keep a count of WM_DDE_TERMINATEs we send so that we don't shut
// the window until we get all of the responses for WM_DDE_TERMINATEs.
void INTERNAL HandleAckInitMsg ( PEDIT_DDE pedit, HWND hserver ){
Puts("HandleAckInitMsg");
if (pedit->hServer){ // just take the very first one. Direct post is OK
PostMessage (hserver, WM_DDE_TERMINATE, (WPARAM)pedit->hClient, 0); ++pedit->extraTerm; } else pedit->hServer = hserver;
}
// HandleAck: returns 0 if <ack> is not positive, else non-0. Should probably be
// a macro.
BOOL INTERNAL HandleAck ( LPOBJECT_LE lpobj, PEDIT_DDE pedit, WPARAM wParam, LPARAM lParam ){ WORD wStatus = GET_WM_DDE_ACK_STATUS(wParam,lParam); HANDLE hData = NULL; BOOL retval = TRUE;
UNREFERENCED_PARAMETER(wParam);
// check for busy bit
if ((wStatus & 0x4000) && ContextCallBack ((LPOLEOBJECT)lpobj, OLE_QUERY_RETRY)){ // we got busy from the server. create a timer and wait for time out.
// We do not need makeprocinstance since, DLLs are single insance, all
// we need to do is export for this function.
if ((pedit->wTimer = SetTimer (pedit->hClient, 1, 3000, NULL))) return TRUE; }
// even if the client got terminate we have to go thru this path.
if (pedit->wTimer) { KillTimer (pedit->hClient, 1); pedit->wTimer = 0; }
if (pedit->awaitAck == AA_POKE) // We have to free the data first. Handleack can trigger
// another Poke (like pokehostnames)
FreePokeData (lpobj, pedit);
if (pedit->awaitAck == AA_EXECUTE) { hData = GET_WM_DDE_EXECACK_HDATA(wParam,lParam); if (hData) GlobalFree (hData); } else { ATOM aItem = GET_WM_DDE_ACK_ITEM(wParam,lParam);
ASSERT (CheckAtomValid(aItem),"Invalid atom in ACK")
if (aItem) GlobalDeleteAtom (aItem); }
if (!(wStatus & 0x8000)) { // error case. set the error
DEBUG_OUT ("DDE ACK with failure", 0)
if (lpobj->errHint){ lpobj->subErr = lpobj->errHint; lpobj->errHint = OLE_OK; } else lpobj->subErr = OLE_ERROR_COMM;
retval = FALSE;
if (pedit->awaitAck == AA_ADVISE) {
#ifdef ASSERT
ASSERT (pedit->hopt, "failed advise, options block missing"); #endif
GlobalFree (pedit->hopt); } }
pedit->hopt = NULL; pedit->awaitAck = 0; ScheduleAsyncCmd (lpobj); return retval; }
// HandleDataMsg: Called for WM_DDE_DATA message. If data is from an
// ADVISE-ON-CLOSE and this is there are no more outstanding
// ADVISE-ON-CLOSE requests, close the document and end the
// conversation.
void INTERNAL HandleDataMsg ( LPOBJECT_LE lpobj, HANDLE hdata, ATOM aItem ){ DDEDATA far *lpdata = NULL; BOOL fAck; BOOL fRelease; int options; PEDIT_DDE pedit;
Puts("HandleDataMsg");
if (ScanItemOptions (aItem, (int far *)&options) != OLE_OK) { DEBUG_OUT (FALSE, "Improper item options"); return; }
pedit = lpobj->pDocEdit;
if (hdata) { if (!(lpdata = (DDEDATA FAR *) GlobalLock(hdata))) return;
fAck = lpdata->fAckReq; fRelease = lpdata->fRelease;
if (pedit->bTerminating) { DEBUG_OUT ("Got DDE_DATA in terminate sequence",0) fRelease = TRUE; } else { if ((OLECLIPFORMAT)lpdata->cfFormat == cfBinary && aItem == aStdDocName) { ChangeDocName (lpobj, (LPSTR)lpdata->Value); } else SetData (lpobj, hdata, options);
// important that we post the acknowledge first. Otherwist the
// messages are not in sync.
if (fAck) { LPARAM lparamNew = MAKE_DDE_LPARAM(WM_DDE_ACK,POSITIVE_ACK,aItem); PostMessageToServer (pedit, WM_DDE_ACK, lparamNew); } else if (aItem) GlobalDeleteAtom (aItem);
if ((lpdata->fResponse) && (pedit->awaitAck == AA_REQUEST)) { // we sent the request. So, schedule next step.
pedit->awaitAck = 0; ScheduleAsyncCmd (lpobj); } }
GlobalUnlock (hdata); if (fRelease) GlobalFree (hdata); } else { if (CanCallback (lpobj, options)) { if (options != OLE_CLOSED) ContextCallBack ((LPOLEOBJECT)lpobj, options); else lpobj->bSvrClosing = FALSE;
} }
// PREfix COM+ 27104
// The call to ScheduleAsyncCmd above can cause EmbLnkDelete to be called.
// In that case lpobj->pDocEdit has already been deleted, and we don't need
// to start another EmbLinkDelete.
if ((options == OLE_CLOSED) && (lpobj->pDocEdit)) { if ((lpobj->pDocEdit->nAdviseClose <= 2) && (lpobj->asyncCmd == OLE_NONE)) { InitAsyncCmd (lpobj, OLE_SERVERUNLAUNCH, EMBLNKDELETE); EmbLnkDelete (lpobj); } } }
HANDLE GetDDEDataHandle ( DDEDATA far *lpdata, UINT cfFormat, HANDLE hdata ){
if (cfFormat == CF_METAFILEPICT) { #ifdef _WIN64
return (*(void* _unaligned*)lpdata->Value); #else
return LongToHandle(*(LONG*)lpdata->Value); #endif
}
if (cfFormat == CF_BITMAP || cfFormat == CF_ENHMETAFILE) return LongToHandle(*(LONG*)lpdata->Value);
if (cfFormat == CF_DIB) return GlobalReAlloc (LongToHandle(*(LONG*)lpdata->Value), 0L, GMEM_MODIFY|GMEM_SHARE);
return CopyData (((LPSTR)lpdata)+4, (DWORD)(GlobalSize (hdata) - 4)); }
// SetData: Given the DDEDATA structure from a WM_DDE_DATA message, set up the
// appropriate data in lpobj. If the native is in native format, add
// that field, otherwise, if it is in picture format, ask the picture
// to add it itself.
void INTERNAL SetData ( LPOBJECT_LE lpobj, HANDLE hdata, int options ){ DDEDATA far *lpdata = NULL; OLESTATUS retVal = OLE_ERROR_MEMORY; HANDLE hdataDDE;
Puts("SetData");
if (!(lpdata = (DDEDATA far *) (GlobalLock (hdata)))) goto errrtn;
if (!(hdataDDE = GetDDEDataHandle (lpdata, lpdata->cfFormat, hdata))) goto errrtn;
if ((OLECLIPFORMAT)lpdata->cfFormat == cfNative) { retVal = (*lpobj->head.lpvtbl->ChangeData) ( (LPOLEOBJECT)lpobj, hdataDDE, lpobj->head.lpclient, TRUE); // use this data, don't copy
} else if ((BOOL)lpdata->cfFormat && (lpdata->cfFormat == (int)GetPictType (lpobj))) {
retVal = (*lpobj->lpobjPict->lpvtbl->ChangeData) (lpobj->lpobjPict, hdataDDE, lpobj->head.lpclient, lpdata->fRelease);
} else { // case of extra data in the object.
DeleteExtraData (lpobj); lpobj->cfExtra = lpdata->cfFormat; lpobj->hextraData = hdataDDE; goto end; }
if (retVal == OLE_OK) { SetExtents (lpobj); if (CanCallback (lpobj, options)) { if (options == OLE_CLOSED) { ContextCallBack ((LPOLEOBJECT)lpobj, OLE_CHANGED); ContextCallBack ((LPOLEOBJECT)lpobj, OLE_CLOSED); lpobj->bSvrClosing = FALSE; } else ContextCallBack ((LPOLEOBJECT)lpobj, options); } }
end: errrtn: if (lpdata) GlobalUnlock (hdata);
return; }
// SysStartConvDDE: Starts a system conversation. Returns a handle to that
// conversation, or NULL.
BOOL INTERNAL InitSrvrConv ( LPOBJECT_LE lpobj, HANDLE hInst ){ HANDLE hedit = NULL; PEDIT_DDE pedit = NULL;
Puts("InitSrvrConv");
if (!lpobj->hSysEdit) { hedit = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (EDIT_DDE));
if (hedit == NULL || ((pedit = (PEDIT_DDE) LocalLock (hedit)) == NULL)) goto errRtn;
} else { hedit = lpobj->hSysEdit; pedit = lpobj->pSysEdit; UtilMemClr ((PSTR) pedit, sizeof (EDIT_DDE)); }
if((pedit->hClient = CreateWindow ("OleSrvrWndClass", "", WS_OVERLAPPED,0,0,0,0,NULL,NULL, hInstDLL, NULL)) == NULL) goto errRtn;
lpobj->hSysEdit = hedit; lpobj->pSysEdit = pedit; pedit->hInst = hInst; pedit->awaitAck = AA_INITIATE;
SetWindowLongPtr (pedit->hClient, 0, (LONG_PTR)lpobj); SendMessage ((HWND)-1, WM_DDE_INITIATE, (WPARAM)pedit->hClient, MAKELPARAM (lpobj->app, aOle));
ASSERT (CheckAtomValid(aOle),"systopic invalid atom")
pedit->awaitAck = 0; if (pedit->hServer == NULL) { pedit->awaitAck = AA_INITIATE; // Now try the System topic
SendMessage ((HWND)-1, WM_DDE_INITIATE, (WPARAM)pedit->hClient, MAKELPARAM (lpobj->app, aSystem));
ASSERT (CheckAtomValid(aSystem),"systopic invalid atom")
pedit->awaitAck = 0; if (pedit->hServer == NULL) { DEBUG_OUT ("Srver connection failed", 0); goto errRtn; } }
// Put the long ptr handle in the object.
return TRUE;
errRtn:
if (pedit) { if (pedit->hClient) DestroyWindow (pedit->hClient); LocalUnlock (hedit); }
if (hedit) LocalFree (hedit);
lpobj->hSysEdit = NULL; lpobj->pSysEdit = NULL;
return FALSE; }
// TermSrvrConv: Ends conversation indicated by hedit.
void INTERNAL TermSrvrConv (LPOBJECT_LE lpobj) { PEDIT_DDE pedit;
Puts("TermSrvrConv");
if (!(pedit = lpobj->pSysEdit)) return;
if (PostMessageToServer (pedit, WM_DDE_TERMINATE, 0)){ lpobj->bAsync = TRUE; pedit->bTerminating = TRUE; } else { pedit->bTerminating = FALSE; lpobj->subErr = OLE_ERROR_TERMINATE; } return; }
void INTERNAL DeleteAbortData ( LPOBJECT_LE lpobj, PEDIT_DDE pedit ){ UNREFERENCED_PARAMETER(lpobj);
// kill if any timer active.
if (pedit->wTimer) { KillTimer (pedit->hClient, 1); pedit->wTimer = 0; } return;
}
BOOL INTERNAL DeleteBusyData ( LPOBJECT_LE lpobj, PEDIT_DDE pedit ){ UNREFERENCED_PARAMETER(lpobj);
// kill if any timer active.
if (pedit->wTimer) { KillTimer (pedit->hClient, 1); pedit->wTimer = 0;
if (pedit->hData) { GlobalFree (pedit->hData); pedit->hData = NULL; }
if (pedit->hopt) { GlobalFree (pedit->hopt); pedit->hopt = NULL; }
if (pedit->awaitAck && (HIWORD(pedit->lParam))) { if (pedit->awaitAck == AA_EXECUTE) { HANDLE hData = GET_WM_DDE_EXECACK_HDATA(pedit->wParam, pedit->lParam); if (hData) GlobalFree (hData); } else { ASSERT (CheckAtomValid(HIWORD(pedit->lParam)), "Invalid atom in ACK") if (HIWORD(pedit->lParam)) GlobalDeleteAtom (HIWORD(pedit->lParam)); }
// we want to wipe out the HIWORD of lParam
pedit->lParam &= 0x0000FFFF; }
return TRUE; }
return FALSE; }
void INTERNAL DeleteSrvrEdit ( LPOBJECT_LE lpobj ){
PEDIT_DDE pedit;
Puts("deleteSrvrEdit");
if (!(pedit = lpobj->pSysEdit)) return;
// delete any data if we were in busy mode.
DeleteBusyData (lpobj, pedit);
if (pedit->hClient) DestroyWindow (pedit->hClient);
if (lpobj->pSysEdit) LocalUnlock (lpobj->hSysEdit);
if (lpobj->hSysEdit) LocalFree (lpobj->hSysEdit);
lpobj->hSysEdit = NULL; lpobj->pSysEdit = NULL;
return; }
void INTERNAL SendStdExit ( LPOBJECT_LE lpobj ){
Puts("SendSrvrExit");
if (!lpobj->pSysEdit) return;
SrvrExecute (lpobj, MapStrToH ("[StdExit]"));
}
void INTERNAL SendStdClose ( LPOBJECT_LE lpobj ){
Puts("SendDocClose");
if (!lpobj->pDocEdit) return;
DocExecute (lpobj, MapStrToH ("[StdCloseDocument]"));
}
// SrvrExecute: Sends execute command to system conversation.
BOOL INTERNAL SrvrExecute ( LPOBJECT_LE lpobj, HANDLE hdata ){ PEDIT_DDE pedit = NULL; int retval = FALSE;
Puts("SrvrExecute");
pedit = lpobj->pSysEdit;
if (hdata == NULL || pedit == NULL) { lpobj->subErr = OLE_ERROR_MEMORY; return FALSE; }
if (lpobj->bOldLink) { GlobalFree (hdata); return TRUE; }
if (PostMessageToServer (pedit, WM_DDE_EXECUTE, (LPARAM)hdata)) { // data is being freed in the acknowledge
lpobj->bAsync = TRUE; pedit->awaitAck = AA_EXECUTE; return TRUE; } else { lpobj->subErr = OLE_ERROR_COMMAND; GlobalFree (hdata); return FALSE; } }
// StartConvDDE: Starts the document conversation for an object based on
// .app and .topic atoms.
BOOL FARINTERNAL InitDocConv ( LPOBJECT_LE lpobj, BOOL fNetDlg ){
// ### This routine looks very similar to IitSrvrConv
// combine with the it
HANDLE hedit = NULL; PEDIT_DDE pedit = NULL; char buf[MAX_NET_NAME]; int nDrive = 2; // drive C
char cOldDrive;
Puts("InitDocConv");
if (QueryOpen (lpobj)){ DEBUG_OUT ("Attempt to start already existing conversation",0); return FALSE; }
cOldDrive = lpobj->cDrive; if (CheckNetDrive (lpobj, fNetDlg) != OLE_OK) return FALSE;
if (!lpobj->pDocEdit) { hedit = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (EDIT_DDE));
if (hedit == NULL || ((pedit = (PEDIT_DDE) LocalLock (hedit)) == NULL)){ lpobj->subErr = OLE_ERROR_MEMORY; goto errRtn; } } else { hedit = lpobj->hDocEdit; pedit = lpobj->pDocEdit; UtilMemClr ((PSTR) pedit, sizeof (EDIT_DDE)); }
if ((pedit->hClient = CreateWindow ("OleDocWndClass", "Window Name", WS_OVERLAPPED,0,0,0,0,NULL,NULL, hInstDLL, NULL)) == NULL) { lpobj->subErr = OLE_ERROR_MEMORY; goto errRtn; } lpobj->hDocEdit = hedit; lpobj->pDocEdit = pedit; SetWindowLongPtr (pedit->hClient, 0, (LONG_PTR)lpobj);
// buf will filled by netname in the first call to SetNextNetDrive()
buf[0] = '\0'; do { pedit->awaitAck = AA_INITIATE;
// !!! Where are the atom counts bumped?
SendMessage ((HWND)-1, WM_DDE_INITIATE, (WPARAM)pedit->hClient, MAKELPARAM (lpobj->app, lpobj->topic));
pedit->awaitAck = 0;
if (pedit->hServer) { if ((cOldDrive != lpobj->cDrive) && (lpobj->asyncCmd != OLE_CREATEFROMFILE)) ContextCallBack ((LPOLEOBJECT)lpobj, OLE_RENAMED); return TRUE; }
} while ((lpobj->head.ctype == CT_LINK) && (lpobj->aNetName) && SetNextNetDrive (lpobj, &nDrive, buf)) ;
errRtn: if (cOldDrive != lpobj->cDrive) { // put back the old drive
lpobj->cDrive = cOldDrive; ChangeTopic (lpobj); }
if (pedit && pedit->hClient) DestroyWindow (pedit->hClient);
if (pedit) LocalUnlock (hedit);
if (hedit) LocalFree (hedit);
lpobj->hDocEdit = NULL; lpobj->pDocEdit = NULL; return FALSE; }
// Execute: Sends an execute string WM_DDE_EXECUTE to the document conversation.
BOOL INTERNAL DocExecute( LPOBJECT_LE lpobj, HANDLE hdata ){ PEDIT_DDE pedit;
Puts("DocExecute"); pedit = lpobj->pDocEdit;
if (hdata == NULL || pedit == NULL) return FALSE;
if (lpobj->bOldLink) { GlobalFree (hdata); return TRUE; }
if (PostMessageToServer (pedit, WM_DDE_EXECUTE, (LPARAM)hdata)) { // data is being freed in the execute command
pedit->awaitAck = AA_EXECUTE; lpobj->bAsync = TRUE; return TRUE; } else { lpobj->subErr = OLE_ERROR_COMMAND; GlobalFree (hdata); return FALSE; } }
// EndConvDDE: terminates the doc level conversation.
void INTERNAL TermDocConv ( LPOBJECT_LE lpobj ){ PEDIT_DDE pedit;
Puts ("TermDocConv");
DEBUG_OUT ("About to terminate convs from destroy",0)
if (!(pedit = lpobj->pDocEdit)) return;
if (PostMessageToServer (pedit, WM_DDE_TERMINATE, 0)) { pedit->bTerminating = TRUE; lpobj->bAsync = TRUE; } else lpobj->subErr = OLE_ERROR_TERMINATE;
return;
}
// Deletes the document conversdation memory.
void INTERNAL DeleteDocEdit (lpobj) LPOBJECT_LE lpobj; {
PEDIT_DDE pedit;
Puts ("DeleteDocEdit");
if (!(pedit = lpobj->pDocEdit)) return;
// delete any data if we were in busy mode.
DeleteBusyData (lpobj, pedit);
// Delete if any data blocks.
if (pedit->hClient) DestroyWindow (pedit->hClient);
if (lpobj->pDocEdit) LocalUnlock (lpobj->hDocEdit);
if (lpobj->hDocEdit) LocalFree (lpobj->hDocEdit);
lpobj->hDocEdit = NULL; lpobj->pDocEdit = NULL;
return; }
// LeLauchApp: Launches app based on the ClassName in lpobj.
// History:
// curts changed LoadModule calls to WinExec
//
HANDLE INTERNAL LeLaunchApp (LPOBJECT_LE lpobj) { // struct CMDSHOW
// {
// WORD first;
// WORD second;
// } cmdShow = {2, SW_SHOWNORMAL};
//
// struct
// {
// WORD wEnvSeg;
// LPSTR lpcmdline;
// struct CMDSHOW FAR *lpCmdShow;
// DWORD dwReserved;
// } paramBlock;
WORD cmdShow = SW_SHOWNORMAL; char cmdline[MAX_STR]; char exeName[MAX_STR]; char lpstr[2*MAX_STR]; HANDLE hInst;
#define EMB_STR " -Embedding "
Puts("LeLaunchApp");
if (!GlobalGetAtomName (lpobj->aServer, exeName, MAX_STR)) { return NULL; }
cmdline[0] = ' '; if (lpobj->bOldLink) { cmdShow = SW_SHOWMINIMIZED; if (!GlobalGetAtomName (lpobj->topic, cmdline + 1, MAX_STR - 1)) { cmdline[1] = '\0'; } } else { StringCchCopy ((LPSTR)cmdline+1, sizeof(cmdline)-1, (LPSTR) EMB_STR);
// For all link servers we want to give the filename on the command
// line. But Excel is not registering the document before returning
// from WinMain, if it has auto load macros. So, we want send StdOpen
// for the old servers, instead of giving the file name on the command
// line.
if (lpobj->bOleServer && (lpobj->fCmd & LN_MASK) == LN_LNKACT) { if (!GlobalGetAtomName (lpobj->topic, cmdline+sizeof(EMB_STR), MAX_STR-sizeof(EMB_STR)-1)) cmdline[sizeof(EMB_STR)] = '\0'; } if (lpobj->fCmd & ACT_MINIMIZE) cmdShow = SW_SHOWMINIMIZED; else if (!(lpobj->fCmd & (ACT_SHOW | ACT_DOVERB)) // we want to launch with show in create invisible case
// even though ACT_SHOW flag will be false
&& ((lpobj->fCmd & LN_MASK) != LN_NEW)) cmdShow = SW_HIDE; }
// paramBlock.wEnvSeg = NULL;
// paramBlock.lpcmdline = (LPSTR)cmdline;
// paramBlock.lpCmdShow = &cmdShow;
// paramBlock.dwReserved = NULL;
if (FAILED(StringCchCopy(lpstr, sizeof(lpstr), exeName))) return NULL; if (FAILED(StringCchCat(lpstr, sizeof(lpstr), cmdline))) return NULL;
if ((hInst = (HANDLE)ULongToPtr(WinExec(lpstr, cmdShow))) < (HANDLE)32) hInst = NULL;
if (!hInst) { LPSTR lptmp; char ch;
// strip off the path and try again
lptmp = (LPSTR)exeName; lptmp += lstrlen ((LPSTR) exeName); ch = *lptmp; while (ch != '\\' && ch != ':') { if (lptmp == (LPSTR) exeName) { // exe did not have path in it's name. we already tried
// loading and it failed, no point trying again.
return NULL; } else ch = *--lptmp; }
if (FAILED(StringCchCopy(lpstr, sizeof(lpstr), ++lptmp))) return NULL; if (FAILED(StringCchCat(lpstr, sizeof(lpstr), cmdline))) return NULL;
if ((hInst = (HANDLE)ULongToPtr(WinExec(lpstr,cmdShow))) < (HANDLE)32) hInst = NULL; }
return hInst; }
//ScanItemOptions: Scan for the item options like Close/Save etc.
int INTERNAL ScanItemOptions ( ATOM aItem, int far *lpoptions ){
ATOM aModifier;
LPSTR lpbuf; char buf[MAX_STR] = {0};
*lpoptions = OLE_CHANGED;
if (!aItem) { // NULL item with no modifier means OLE_CHANGED for NULL item
return OLE_OK; }
if(GlobalGetAtomName (aItem, (LPSTR)buf, MAX_STR) == 0) { return OLE_ERROR_SYNTAX; } lpbuf = (LPSTR)buf;
while ( *lpbuf && *lpbuf != '/') lpbuf++;
// no modifier same as /change
if (*lpbuf == '\0') return OLE_OK;
*lpbuf++ = '\0'; // seperate out the item string
// We are using this in the caller.
if (!(aModifier = GlobalFindAtom (lpbuf))) return OLE_ERROR_SYNTAX;
if (aModifier == aChange) return OLE_OK;
// Is it a save?
if (aModifier == aSave){ *lpoptions = OLE_SAVED; return OLE_OK; } // Is it a Close?
if (aModifier == aClose){ *lpoptions = OLE_CLOSED; return OLE_OK; }
// unknown modifier
return OLE_ERROR_SYNTAX;
}
void INTERNAL ChangeDocName ( LPOBJECT_LE lpobj, LPSTR lpdata
){ ATOM aOldTopic; OLESTATUS retVal;
aOldTopic = lpobj->topic; lpobj->topic = GlobalAddAtom (lpdata); if ((retVal = SetNetName (lpobj)) != OLE_OK) { if (lpobj->topic) GlobalDeleteAtom (lpobj->topic); lpobj->topic = aOldTopic; return; // !!! what should we do in case of error? Currently, we will not
// change the topic if SetNetName fails.
}
if (aOldTopic) GlobalDeleteAtom (aOldTopic);
// Delete the link data block
if (lpobj->hLink) { GlobalFree (lpobj->hLink); lpobj->hLink = NULL; }
ContextCallBack ((LPOLEOBJECT)lpobj, OLE_RENAMED);
}
BOOL INTERNAL CanCallback ( LPOBJECT_LE lpobj, int options ){ LPINT lpCount;
if (options == OLE_CLOSED) { lpobj->bSvrClosing = TRUE; lpCount = &(lpobj->pDocEdit->nAdviseClose); } else if (options == OLE_SAVED) { if (lpobj->head.ctype == CT_LINK) return TRUE; lpCount = &(lpobj->pDocEdit->nAdviseSave); } else { // it must be due to request
if ((lpobj->pDocEdit->awaitAck == AA_REQUEST) && lpobj->pDocEdit->bCallLater) return FALSE;
return TRUE; }
switch (*lpCount) { case 1: break;
case 2: ++(*lpCount); return FALSE;
case 3: --(*lpCount); break;
default: return FALSE; }
return TRUE; }
void FARINTERNAL CallEmbLnkDelete ( LPOBJECT_LE lpobj ){ InitAsyncCmd (lpobj, OLE_SERVERUNLAUNCH,EMBLNKDELETE); EmbLnkDelete (lpobj);
if (lpobj->head.ctype == CT_EMBEDDED) { lpobj->bSvrClosing = TRUE; ContextCallBack ((LPOLEOBJECT)lpobj, OLE_CLOSED); if (FarCheckObject ((LPOLEOBJECT)lpobj)) lpobj->bSvrClosing = FALSE; } }
|