1161 lines
32 KiB
C
1161 lines
32 KiB
C
/****************************** Module Header ******************************\
|
|
* Module Name: Doc.c Document Main module
|
|
*
|
|
* Purpose: Includes All the document communication related routines.
|
|
*
|
|
* Created: Oct 1990.
|
|
*
|
|
* Copyright (c) 1990, 1991 Microsoft Corporation
|
|
*
|
|
* History:
|
|
* Raor (../10/1990) Designed, coded
|
|
* curts created portable version for WIN16/32
|
|
*
|
|
\***************************************************************************/
|
|
|
|
#include "windows.h"
|
|
#include "cmacs.h"
|
|
#include "ole.h"
|
|
#include "dde.h"
|
|
#include "srvr.h"
|
|
|
|
|
|
extern ATOM cfBinary;
|
|
extern ATOM aStdClose;
|
|
extern ATOM aStdShowItem;
|
|
extern ATOM aStdDoVerbItem;
|
|
extern ATOM aStdDocName;
|
|
extern ATOM aTrue;
|
|
extern ATOM aFalse;
|
|
|
|
extern FARPROC lpTerminateDocClients;
|
|
extern FARPROC lpSendRenameMsg;
|
|
extern FARPROC lpFindItemWnd;
|
|
extern FARPROC lpEnumForTerminate;
|
|
|
|
extern HANDLE hdllInst;
|
|
extern HANDLE hddeRename;
|
|
extern HWND hwndRename;
|
|
|
|
|
|
extern BOOL fAdviseSaveDoc;
|
|
|
|
// ### Do we have to create a seperate window for each doc conversation.
|
|
// EDF thinks so.
|
|
|
|
/***************************** Public Function ****************************\
|
|
*
|
|
* OLESTATUS FAR PASCAL OleRegisterServerDoc (lhsrvr, lpdocname, lpoledoc, lplhdoc)
|
|
*
|
|
* OleRegisterServerDoc: Registers the Document with the server lib.
|
|
*
|
|
* Parameters:
|
|
* 1. Server long handle(server with which the document should
|
|
* be registered)
|
|
* 2. Document name.
|
|
* 3. Handle to the doc of the server app (private to the server app).
|
|
* 4. Ptr for returning the Doc handle of the lib (private to the lib).
|
|
*
|
|
* return values:
|
|
* returns OLE_OK if the server is successfully registered .
|
|
* else returns the corresponding error.
|
|
*
|
|
* History:
|
|
* Raor: Wrote it,
|
|
\***************************************************************************/
|
|
|
|
OLESTATUS FAR PASCAL OleRegisterServerDoc (
|
|
LHSRVR lhsrvr, // handle we passed back as part of registration.
|
|
LPCSTR lpdocname, // document name
|
|
LPOLESERVERDOC lpoledoc, // Private doc handle of the server app.
|
|
LHDOC FAR * lplhdoc // where we will be passing our doc private handle
|
|
){
|
|
|
|
LPSRVR lpsrvr = NULL;
|
|
LPDOC lpdoc = NULL;
|
|
HANDLE hdoc = NULL;
|
|
|
|
|
|
Puts ("OleRegisterServerDoc");
|
|
|
|
if (!CheckServer (lpsrvr = (LPSRVR)lhsrvr))
|
|
return OLE_ERROR_HANDLE;
|
|
|
|
// server's termination has already started.
|
|
if (lpsrvr->bTerminate)
|
|
return OLE_ERROR_TERMINATE;
|
|
|
|
PROBE_READ(lpdocname);
|
|
PROBE_WRITE(lplhdoc);
|
|
|
|
// we are using the null from inside the server lib
|
|
if (lpoledoc)
|
|
PROBE_WRITE(lpoledoc);
|
|
|
|
hdoc = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_DDESHARE, sizeof (DOC));
|
|
|
|
if (!(hdoc && (lpdoc = (LPDOC)GlobalLock (hdoc))))
|
|
goto errReturn;
|
|
|
|
// set the signature, handle and the doc atom.
|
|
lpdoc->sig[0] = 'S';
|
|
lpdoc->sig[1] = 'D';
|
|
lpdoc->hdoc = hdoc;
|
|
lpdoc->aDoc = GlobalAddAtom (lpdocname);
|
|
lpdoc->lpoledoc = lpoledoc;
|
|
|
|
|
|
if (!(lpdoc->hwnd = CreateWindow ("DocWndClass", "Doc",
|
|
WS_CHILD,0,0,0,0,lpsrvr->hwnd,NULL, hdllInst, NULL)))
|
|
goto errReturn;
|
|
|
|
// save the ptr to the struct in the window.
|
|
SetWindowLongPtr (lpdoc->hwnd, 0, (LONG_PTR)lpdoc);
|
|
SetWindowWord (lpdoc->hwnd, WW_LE, WC_LE);
|
|
SetWindowLongPtr (lpdoc->hwnd, WW_HANDLE, GetWindowLongPtr(lpsrvr->hwnd, WW_HANDLE));
|
|
*lplhdoc = (LONG_PTR)lpdoc;
|
|
|
|
return OLE_OK;
|
|
|
|
errReturn:
|
|
if (lpdoc){
|
|
if (lpdoc->hwnd)
|
|
DestroyWindow (lpsrvr->hwnd);
|
|
|
|
if (lpdoc->aDoc)
|
|
GlobalDeleteAtom (lpdoc->aDoc);
|
|
|
|
GlobalUnlock(hdoc);
|
|
}
|
|
|
|
if (hdoc)
|
|
GlobalFree (hdoc);
|
|
|
|
return OLE_ERROR_MEMORY;
|
|
}
|
|
|
|
|
|
/***************************** Public Function ****************************\
|
|
* OLESTATUS FAR PASCAL OleRevokeServerDoc (lhdoc)
|
|
*
|
|
* OleRevokeServerDoc: Unregisters the document which has been registered.
|
|
*
|
|
* Parameters:
|
|
* 1. DLL Doc handle.
|
|
*
|
|
* return values:
|
|
* returns OLE_OK if the document is successfully unregisterd.
|
|
* ( It is Ok for the app to free the associated space).
|
|
* If the unregistration is intiated, returns OLE_STARTED.
|
|
* Calls the Doc class release entry point when the doc
|
|
* can be released. App should wait till the Release is called
|
|
*
|
|
* History:
|
|
* Raor: Wrote it,
|
|
\***************************************************************************/
|
|
|
|
OLESTATUS FAR PASCAL OleRevokeServerDoc (
|
|
LHDOC lhdoc
|
|
){
|
|
HWND hwndSrvr;
|
|
LPSRVR lpsrvr;
|
|
HWND hwndDoc;
|
|
LPDOC lpdoc;
|
|
|
|
Puts ("OleRevokeServerDoc");
|
|
|
|
if (!CheckServerDoc (lpdoc = (LPDOC)lhdoc))
|
|
return OLE_ERROR_HANDLE;
|
|
|
|
if (lpdoc->bTerminate && lpdoc->termNo)
|
|
return OLE_WAIT_FOR_RELEASE;
|
|
|
|
// ### this code is very similar to the srvr code.
|
|
// we should optimize.
|
|
|
|
hwndDoc = lpdoc->hwnd;
|
|
|
|
#ifdef FIREWALLS
|
|
ASSERT (hwndDoc, "No doc window")
|
|
#endif
|
|
|
|
hwndSrvr = GetParent (hwndDoc);
|
|
lpsrvr = (LPSRVR) GetWindowLongPtr (hwndSrvr, 0);
|
|
#ifdef FIREWALLS
|
|
ASSERT (hwndSrvr, "No srvr window")
|
|
ASSERT (lpsrvr, "No srvr structure")
|
|
#endif
|
|
|
|
// delete all the items(objects) for this doc
|
|
DeleteAllItems (lpdoc->hwnd);
|
|
|
|
// we are terminating.
|
|
lpdoc->bTerminate = TRUE;
|
|
lpdoc->termNo = 0;
|
|
|
|
// send ack if Revoke is done as a result of StdClose
|
|
if (lpdoc->fAckClose) { // Post the acknowledge to the client
|
|
LPARAM lparamNew = MAKE_DDE_LPARAM(WM_DDE_ACK, 0x8000, lpdoc->hDataClose);
|
|
|
|
if (!PostMessageToClient (lpdoc->hwndClose, WM_DDE_ACK, (WPARAM)lpdoc->hwnd,lparamNew))
|
|
{
|
|
// if the window died or post failed, delete the atom.
|
|
GlobalFree (lpdoc->hDataClose);
|
|
DDEFREE(WM_DDE_ACK,lparamNew);
|
|
}
|
|
}
|
|
|
|
// Post termination for each of the doc clients.
|
|
EnumProps(hwndDoc, (PROPENUMPROC)lpTerminateDocClients);
|
|
// post all the messages with yield which have been collected in enum
|
|
// UnblockPostMsgs (hwndDoc, TRUE);
|
|
|
|
#ifdef WAIT_DDE
|
|
if (lpdoc->termNo)
|
|
WaitForTerminate((LPSRVR)lpdoc);
|
|
#endif
|
|
|
|
return ReleaseDoc (lpdoc);
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************** Public Function ****************************\
|
|
* OLESTATUS FAR PASCAL OleRenameServerDoc (lhdoc, lpNewName)
|
|
*
|
|
* OleRenameServerDoc: Changes the name of the document
|
|
*
|
|
* Parameters:
|
|
* 1. DLL Doc handle.
|
|
* 2. New name for document
|
|
*
|
|
* return values:
|
|
* returns OLE_OK if the document is successfully renamed
|
|
*
|
|
* History:
|
|
* Srinik: Wrote it,
|
|
\***************************************************************************/
|
|
|
|
OLESTATUS FAR PASCAL OleRenameServerDoc (
|
|
LHDOC lhdoc,
|
|
LPCSTR lpNewName
|
|
){
|
|
LPDOC lpdoc;
|
|
OLESTATUS retVal = OLE_OK;
|
|
HANDLE hdata;
|
|
HWND hStdWnd;
|
|
|
|
if (!CheckServerDoc (lpdoc = (LPDOC)lhdoc))
|
|
return OLE_ERROR_HANDLE;
|
|
|
|
PROBE_READ(lpNewName);
|
|
|
|
if (!(hdata = MakeGlobal (lpNewName)))
|
|
return OLE_ERROR_MEMORY;
|
|
|
|
if (lpdoc->aDoc)
|
|
GlobalDeleteAtom (lpdoc->aDoc);
|
|
lpdoc->aDoc = GlobalAddAtom (lpNewName);
|
|
|
|
// if StdDocName item is present send rename to relevant clients
|
|
if (hStdWnd = SearchItem (lpdoc, (LPSTR) MAKEINTATOM(aStdDocName))) {
|
|
if (!MakeDDEData (hdata, cfBinary, (LPHANDLE)&hddeRename,FALSE))
|
|
retVal = OLE_ERROR_MEMORY;
|
|
else {
|
|
EnumProps(hStdWnd, (PROPENUMPROC)lpSendRenameMsg);
|
|
// post all the messages with yield which have been collected in enum
|
|
// UnblockPostMsgs (hStdWnd, FALSE);
|
|
GlobalFree (hddeRename);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
hwndRename = hStdWnd;
|
|
// Post termination for each of the doc clients.
|
|
EnumProps(lpdoc->hwnd, (PROPENUMPROC)lpEnumForTerminate);
|
|
// post all the messages with yield which have been collected in enum
|
|
// UnblockPostMsgs (lpdoc->hwnd, TRUE);
|
|
|
|
// If it was an embedded object, from now on it won't be
|
|
lpdoc->fEmbed = FALSE;
|
|
|
|
if (!hStdWnd || retVal != OLE_OK)
|
|
GlobalFree(hdata);
|
|
|
|
// Do link manager stuff
|
|
return retVal;
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************** Public Function ****************************\
|
|
* OLESTATUS FAR PASCAL OleSavedServerDoc (lhdoc)
|
|
*
|
|
* OleSavedServerDoc: Changes the name of the document
|
|
*
|
|
* Parameters:
|
|
* 1. DLL Doc handle.
|
|
*
|
|
* return values:
|
|
* returns OLE_OK if the link manager is successfully notified
|
|
*
|
|
* History:
|
|
* Srinik: Wrote it,
|
|
\***************************************************************************/
|
|
|
|
OLESTATUS FAR PASCAL OleSavedServerDoc (
|
|
LHDOC lhdoc
|
|
){
|
|
LPDOC lpdoc;
|
|
|
|
if (!CheckServerDoc (lpdoc = (LPDOC)lhdoc))
|
|
return OLE_ERROR_HANDLE;
|
|
|
|
fAdviseSaveDoc = TRUE;
|
|
EnumChildWindows (lpdoc->hwnd, (WNDENUMPROC)lpFindItemWnd,
|
|
MAKELONG (NULL, ITEM_SAVED));
|
|
|
|
if (lpdoc->fEmbed && !fAdviseSaveDoc)
|
|
return OLE_ERROR_CANT_UPDATE_CLIENT;
|
|
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************** Public Function ****************************\
|
|
* OLESTATUS FAR PASCAL OleRevertServerDoc (lhdoc)
|
|
*
|
|
* OleRevertServerDoc: Changes the name of the document
|
|
*
|
|
* Parameters:
|
|
* 1. DLL Doc handle.
|
|
*
|
|
* return values:
|
|
* returns OLE_OK if the link manager has been successfully informed
|
|
*
|
|
* History:
|
|
* Srinik: Wrote it,
|
|
\***************************************************************************/
|
|
|
|
OLESTATUS FAR PASCAL OleRevertServerDoc (
|
|
LHDOC lhdoc
|
|
){
|
|
LPDOC lpdoc;
|
|
|
|
if (!CheckServerDoc (lpdoc = (LPDOC)lhdoc))
|
|
return OLE_ERROR_HANDLE;
|
|
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
|
|
// TerminateDocClients: Call back for the document window for
|
|
// enumerating all the clients. Posts terminate for each of
|
|
// the clients.
|
|
|
|
BOOL FAR PASCAL TerminateDocClients (
|
|
HWND hwnd,
|
|
LPSTR lpstr,
|
|
HANDLE hdata
|
|
){
|
|
LPDOC lpdoc;
|
|
|
|
UNREFERENCED_PARAMETER(lpstr);
|
|
|
|
lpdoc = (LPDOC)GetWindowLongPtr (hwnd, 0);
|
|
if (IsWindowValid ((HWND)hdata)){
|
|
lpdoc->termNo++;
|
|
// irrespective of the post, incremet the count, so
|
|
// that client does not die.
|
|
PostMessageToClientWithBlock ((HWND)hdata, WM_DDE_TERMINATE, (WPARAM)hwnd, (LPARAM)0);
|
|
}
|
|
else
|
|
ASSERT(FALSE, "TERMINATE: Client's Doc channel is missing");
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// ReleaseDoc: If there are no more matching terminates pending
|
|
// Call the server for its release. (Server might be waiting for the
|
|
// docs to be terminated. Called thru OleRevokeServer).
|
|
|
|
|
|
int INTERNAL ReleaseDoc (
|
|
LPDOC lpdoc
|
|
){
|
|
HWND hwndSrvr;
|
|
HANDLE hdoc;
|
|
LPSRVR lpsrvr;
|
|
|
|
|
|
// release srvr is called only when everything is
|
|
// cleaned and srvr app can post WM_QUIT.
|
|
|
|
if (lpdoc->bTerminate && lpdoc->termNo)
|
|
return OLE_WAIT_FOR_RELEASE;
|
|
|
|
// Call Release for the app to release its space.
|
|
|
|
|
|
if (lpdoc->lpoledoc){
|
|
|
|
#ifdef FIREWALLS
|
|
if (!CheckPointer (lpdoc->lpoledoc, WRITE_ACCESS))
|
|
ASSERT (0, "Invalid LPOLESERVERDOC")
|
|
else if (!CheckPointer (lpdoc->lpoledoc->lpvtbl, WRITE_ACCESS))
|
|
ASSERT (0, "Invalid LPOLESERVERDOCVTBL")
|
|
else
|
|
ASSERT (lpdoc->lpoledoc->lpvtbl->Release,
|
|
"Invalid pointer to Release method")
|
|
#endif
|
|
(*lpdoc->lpoledoc->lpvtbl->Release) (lpdoc->lpoledoc);
|
|
|
|
}
|
|
|
|
if (lpdoc->aDoc) {
|
|
GlobalDeleteAtom (lpdoc->aDoc);
|
|
lpdoc->aDoc = (ATOM)0;
|
|
}
|
|
|
|
hwndSrvr = GetParent (lpdoc->hwnd);
|
|
DestroyWindow (lpdoc->hwnd);
|
|
|
|
lpsrvr = (LPSRVR)GetWindowLongPtr (hwndSrvr, 0);
|
|
|
|
// if the server is waiting for us, inform the server
|
|
// we are done
|
|
if (!lpsrvr->bTerminate) {
|
|
// if we are not in terminate mode, then send advise to the server
|
|
// if server can be revoked. raor (04/09)
|
|
|
|
if (QueryRelease (lpsrvr)){
|
|
|
|
#ifdef FIREWALLS
|
|
if (!CheckPointer (lpsrvr->lpolesrvr, WRITE_ACCESS))
|
|
ASSERT (0, "Invalid LPOLESERVER")
|
|
else if (!CheckPointer (lpsrvr->lpolesrvr->lpvtbl,
|
|
WRITE_ACCESS))
|
|
ASSERT (0, "Invalid LPOLESERVERVTBL")
|
|
else
|
|
ASSERT (lpsrvr->lpolesrvr->lpvtbl->Release,
|
|
"Invalid pointer to Release method")
|
|
#endif
|
|
|
|
(*lpsrvr->lpolesrvr->lpvtbl->Release) (lpsrvr->lpolesrvr);
|
|
}
|
|
|
|
} else
|
|
ReleaseSrvr (lpsrvr);
|
|
|
|
GlobalUnlock (hdoc = lpdoc->hdoc);
|
|
GlobalFree (hdoc);
|
|
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
//RevokeAllDocs : revokes all the documents attached to a given
|
|
//server.
|
|
|
|
int INTERNAL RevokeAllDocs (
|
|
LPSRVR lpsrvr
|
|
){
|
|
|
|
HWND hwnd;
|
|
HWND hwndnext;
|
|
|
|
hwnd = GetWindow (lpsrvr->hwnd, GW_CHILD);
|
|
|
|
// Go thru each of the child windows and revoke the corresponding
|
|
// document. Doc windows are child windows for the server window.
|
|
|
|
while (hwnd){
|
|
// sequence is important
|
|
hwndnext = GetWindow (hwnd, GW_HWNDNEXT);
|
|
OleRevokeServerDoc ((LHDOC)GetWindowLongPtr (hwnd, 0));
|
|
hwnd = hwndnext;
|
|
}
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
|
|
// FindDoc: Given a document, searches for the document
|
|
// in the given server document tree. returns true if the
|
|
// document is available.
|
|
|
|
|
|
LPDOC INTERNAL FindDoc (
|
|
LPSRVR lpsrvr,
|
|
LPSTR lpdocname
|
|
){
|
|
ATOM aDoc;
|
|
HWND hwnd;
|
|
LPDOC lpdoc;
|
|
|
|
aDoc = (ATOM)GlobalFindAtom (lpdocname);
|
|
hwnd = GetWindow (lpsrvr->hwnd, GW_CHILD);
|
|
|
|
while (hwnd){
|
|
lpdoc = (LPDOC)GetWindowLongPtr (hwnd, 0);
|
|
if (lpdoc->aDoc == aDoc)
|
|
return lpdoc;
|
|
hwnd = GetWindow (hwnd, GW_HWNDNEXT);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
// DocWndProc: document window procedure.
|
|
// ### We might be able to merge this code with
|
|
// the server window proc.
|
|
|
|
|
|
LRESULT FAR PASCAL DocWndProc (
|
|
HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
){
|
|
LPDOC lpdoc;
|
|
WORD status = 0;
|
|
BOOL fack;
|
|
HANDLE hdata = NULL;
|
|
OLESTATUS retval;
|
|
LPSRVR lpsrvr;
|
|
|
|
#ifdef FIREWALLS
|
|
HWND hwndClient;
|
|
#endif
|
|
|
|
if (AddMessage (hwnd, msg, wParam, lParam, (int)WT_DOC))
|
|
return 0L;
|
|
|
|
lpdoc = (LPDOC)GetWindowLongPtr (hwnd, 0);
|
|
|
|
switch (msg){
|
|
|
|
|
|
case WM_CREATE:
|
|
DEBUG_OUT ("doc create window", 0)
|
|
break;
|
|
|
|
case WM_DDE_INITIATE:
|
|
|
|
DEBUG_OUT ("doc: DDE init",0);
|
|
if (lpdoc->bTerminate){
|
|
DEBUG_OUT ("doc: No action due to termination process",0)
|
|
break;
|
|
}
|
|
|
|
// if we are the documnet then respond.
|
|
|
|
if (! (lpdoc->aDoc == (ATOM)(HIWORD(lParam))))
|
|
break;
|
|
|
|
// We can enterain this client. Put this window in the client list
|
|
// and acknowledge the initiate.
|
|
|
|
if (!AddClient (hwnd, (HWND)wParam, (HWND)wParam))
|
|
break;
|
|
|
|
lpdoc->cClients++;
|
|
lpsrvr = (LPSRVR) GetWindowLongPtr (GetParent(lpdoc->hwnd), 0);
|
|
|
|
lpsrvr->bnoRelease = FALSE;
|
|
|
|
// post the acknowledge
|
|
DuplicateAtom (LOWORD(lParam));
|
|
DuplicateAtom (HIWORD(lParam));
|
|
SendMessage ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, lParam);
|
|
|
|
break;
|
|
|
|
case WM_DDE_EXECUTE: {
|
|
|
|
HANDLE hData = GET_WM_DDE_EXECUTE_HDATA(wParam,lParam);
|
|
|
|
DEBUG_OUT ("doc: execute", 0)
|
|
#ifdef FIREWALLS
|
|
// find the client in the client list.
|
|
hwndClient = FindClient (lpdoc->hwnd, (HWND)wParam);
|
|
ASSERT (hwndClient, "Client is missing from the server")
|
|
#endif
|
|
// Are we terminating
|
|
if (lpdoc->bTerminate || !IsWindowValid ((HWND)wParam)) {
|
|
DEBUG_OUT ("doc: execute after terminate posted",0)
|
|
// !!! are we supposed to free the data
|
|
GlobalFree (hData);
|
|
break;
|
|
|
|
}
|
|
|
|
retval = DocExecute (hwnd, hData, (HWND)wParam);
|
|
SET_MSG_STATUS (retval, status);
|
|
|
|
#ifdef OLD
|
|
// if we posted the terminate because of execute, do not send
|
|
// ack.
|
|
|
|
if (lpdoc->bTerminate) {
|
|
// !!! We got close but, we are posting the
|
|
// the terminate. Excel does not complain about
|
|
// this. But powerpoint complains.
|
|
#ifdef POWERPNT_BUG
|
|
GlobalFree (hData);
|
|
#endif
|
|
break;
|
|
}
|
|
#endif
|
|
if (!lpdoc->bTerminate) { // Post the acknowledge to the client
|
|
LPARAM lparamNew = MAKE_DDE_LPARAM(WM_DDE_ACK, status, hData);
|
|
|
|
if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, lparamNew)){
|
|
// the window either died or post failed, delete the data
|
|
GlobalFree (hData);
|
|
DDEFREE(WM_DDE_ACK,lparamNew);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_DDE_TERMINATE:
|
|
DEBUG_OUT ("doc: DDE terminate",0)
|
|
|
|
#ifdef FIREWALLS
|
|
// find the client in the client list.
|
|
hwndClient = FindClient (lpdoc->hwnd,(HWND)wParam);
|
|
ASSERT(hwndClient || lpdoc->termNo, "Client is missing from the server")
|
|
#endif
|
|
// We do not need this client any more. Delete him from the
|
|
// client list.
|
|
|
|
DeleteClient (lpdoc->hwnd, (HWND)wParam);
|
|
lpdoc->cClients--;
|
|
|
|
if (lpdoc->bTerminate){
|
|
lpsrvr = (LPSRVR) GetWindowLongPtr (GetParent(lpdoc->hwnd), 0);
|
|
if (!--lpdoc->termNo)
|
|
// Release this Doc and may be the server also
|
|
// if the server is waiting to be released also.
|
|
ReleaseDoc (lpdoc);
|
|
} else {
|
|
if (lpdoc->termNo == 0){
|
|
|
|
// If client intiated the terminate. Post matching terminate
|
|
|
|
PostMessageToClient ((HWND)wParam, WM_DDE_TERMINATE,
|
|
(WPARAM)hwnd, (LPARAM)0);
|
|
} else
|
|
lpdoc->termNo--;
|
|
|
|
//Client initiated the termination. So, we shoudl take him
|
|
// out from any of our items client lists.
|
|
DeleteFromItemsList (lpdoc->hwnd, (HWND)wParam);
|
|
|
|
lpsrvr = (LPSRVR)GetWindowLongPtr (GetParent (lpdoc->hwnd), 0);
|
|
|
|
if (QueryRelease (lpsrvr)){
|
|
|
|
#ifdef FIREWALLS
|
|
if (!CheckPointer (lpsrvr->lpolesrvr, WRITE_ACCESS))
|
|
ASSERT (0, "Invalid LPOLESERVER")
|
|
else if (!CheckPointer (lpsrvr->lpolesrvr->lpvtbl,
|
|
WRITE_ACCESS))
|
|
ASSERT (0, "Invalid LPOLESERVERVTBL")
|
|
else
|
|
ASSERT (lpsrvr->lpolesrvr->lpvtbl->Release,
|
|
"Invalid pointer to Release method")
|
|
#endif
|
|
|
|
(*lpsrvr->lpolesrvr->lpvtbl->Release) (lpsrvr->lpolesrvr);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
DEBUG_OUT ("doc: Destroy window",0)
|
|
break;
|
|
|
|
case WM_DDE_POKE: {
|
|
int iStdItem;
|
|
LPARAM lparamNew;
|
|
ATOM aItem = GET_WM_DDE_POKE_ITEM(wParam,lParam);
|
|
HANDLE hData = GET_WM_DDE_POKE_HDATA(wParam,lParam);
|
|
|
|
DEBUG_OUT ("doc: Poke", 0)
|
|
|
|
if (lpdoc->bTerminate || !IsWindowValid ((HWND) wParam)) {
|
|
// we are getting pke message after we have posted the
|
|
// the termination or the client got deleted.
|
|
|
|
/*
|
|
* This path is valid for POKE, DATA, and ADVISE transactions
|
|
* only!
|
|
*/
|
|
FreePokeData (GET_WM_DDE_POKE_HDATA(wParam,lParam));
|
|
#ifdef OLD
|
|
GlobalFree (GET_WM_DDE_POKE_HDATA(wParam,lParam));
|
|
#endif
|
|
// !!! Are we supposed to delete the atoms also.
|
|
PokeErr1:
|
|
/*
|
|
* This path is valid for POKE, DATA, ADVISE and
|
|
* ACK transactions only!
|
|
*/
|
|
if (GET_WM_DDE_POKE_ITEM(wParam,lParam))
|
|
GlobalDeleteAtom (GET_WM_DDE_POKE_ITEM(wParam,lParam));
|
|
DDEFREE(msg,lParam);
|
|
break;
|
|
|
|
}
|
|
|
|
if (iStdItem = GetStdItemIndex (aItem))
|
|
retval = PokeStdItems (lpdoc, (HWND)wParam, hData, iStdItem);
|
|
else
|
|
retval = PokeData (lpdoc, (HWND)wParam, lParam);
|
|
|
|
SET_MSG_STATUS (retval, status);
|
|
// !!! If the fRelease is false and the post fails
|
|
// then we are not freeing the hdata. Are we supposed to
|
|
lparamNew = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem);
|
|
|
|
if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd,lparamNew))
|
|
{
|
|
DDEFREE(WM_DDE_ACK,lparamNew);
|
|
goto PokeErr1;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_DDE_ADVISE: {
|
|
ATOM aItem = GET_WM_DDE_ADVISE_ITEM(wParam, lParam);
|
|
|
|
DEBUG_OUT ("doc: Advise", 0)
|
|
|
|
fack = TRUE;
|
|
|
|
if (lpdoc->bTerminate || !IsWindowValid ((HWND)wParam))
|
|
goto PokeErr1;
|
|
|
|
if (IsAdviseStdItems (aItem))
|
|
retval = AdviseStdItems (lpdoc, (HWND)wParam, lParam, (BOOL FAR *)&fack);
|
|
else
|
|
// advise data will not have any OLE_BUSY
|
|
retval = AdviseData (lpdoc, (HWND)wParam, lParam, (BOOL FAR *)&fack);
|
|
|
|
SET_MSG_STATUS (retval, status);
|
|
|
|
if (fack) {
|
|
LPARAM lparamNew = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem);
|
|
|
|
if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, lparamNew))
|
|
{
|
|
DDEFREE(WM_DDE_ACK,lparamNew);
|
|
goto PokeErr1;
|
|
}
|
|
|
|
}
|
|
else if ((ATOM)(HIWORD (lParam)))
|
|
GlobalDeleteAtom (aItem);
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_DDE_UNADVISE: {
|
|
LPARAM lparamNew;
|
|
ATOM aItem = GET_WM_DDE_UNADVISE_ITEM(wParam, lParam);
|
|
|
|
DEBUG_OUT ("doc: Unadvise", 0)
|
|
|
|
if (lpdoc->bTerminate || !IsWindowValid ((HWND)wParam)) {
|
|
goto PokeErr1;
|
|
}
|
|
|
|
retval = UnAdviseData (lpdoc, (HWND)wParam, lParam);
|
|
SET_MSG_STATUS (retval, status);
|
|
|
|
lparamNew = MAKE_DDE_LPARAM(WM_DDE_ACK,status, aItem);
|
|
if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd,lparamNew))
|
|
{
|
|
DDEFREE(WM_DDE_ACK,lparamNew);
|
|
UnadviseErr:
|
|
/*
|
|
* This path is valid for UNADVISE and REQUEST transaction only!
|
|
*/
|
|
if (GET_WM_DDE_UNADVISE_ITEM(wParam,lParam))
|
|
GlobalDeleteAtom (GET_WM_DDE_UNADVISE_ITEM(wParam,lParam));
|
|
DDEFREE(msg,lParam);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_DDE_REQUEST: {
|
|
LPARAM lparamNew;
|
|
ATOM aItem = GET_WM_DDE_REQUEST_ITEM(wParam,lParam);
|
|
|
|
DEBUG_OUT ("doc: Request", 0)
|
|
|
|
if (lpdoc->bTerminate || !IsWindowValid ((HWND) wParam))
|
|
goto UnadviseErr;
|
|
|
|
retval = RequestData (lpdoc, (HWND)wParam, lParam, (HANDLE FAR *)&hdata);
|
|
|
|
if(retval == OLE_OK) { // post the data message and we are not asking for any
|
|
// acknowledge.
|
|
lparamNew = MAKE_DDE_LPARAM(WM_DDE_DATA,hdata,aItem);
|
|
|
|
if (!PostMessageToClient ((HWND)wParam, WM_DDE_DATA, (WPARAM)hwnd,
|
|
lparamNew)) {
|
|
GlobalFree (hdata);
|
|
DDEFREE(WM_DDE_DATA,lparamNew);
|
|
goto UnadviseErr;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (retval == OLE_BUSY)
|
|
status = 0x4000;
|
|
else
|
|
status = 0;
|
|
|
|
lparamNew = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem);
|
|
|
|
// if request failed, then acknowledge with error.
|
|
if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, lparamNew))
|
|
{
|
|
DDEFREE(WM_DDE_ACK,lparamNew);
|
|
goto UnadviseErr;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DEBUG_OUT("doc: Default message",0)
|
|
return DefWindowProc (hwnd, msg, wParam, lParam);
|
|
|
|
}
|
|
|
|
return 0L;
|
|
|
|
}
|
|
|
|
//DocExecute: Interprets the execute command for the
|
|
//document conversation.
|
|
|
|
|
|
OLESTATUS INTERNAL DocExecute(
|
|
HWND hwnd,
|
|
HANDLE hdata,
|
|
HWND hwndClient
|
|
){
|
|
|
|
ATOM acmd;
|
|
BOOL fShow;
|
|
BOOL fActivate;
|
|
|
|
HANDLE hdup = NULL;
|
|
int retval = OLE_ERROR_MEMORY;
|
|
LPDOC lpdoc;
|
|
LPOLESERVERDOC lpoledoc;
|
|
LPCLIENT lpclient = NULL;
|
|
|
|
LPSTR lpitemname;
|
|
LPSTR lpopt;
|
|
LPSTR lpnextarg;
|
|
LPSTR lpdata = NULL;
|
|
LPSTR lpverb = NULL;
|
|
UINT verb;
|
|
WORD wCmdType;
|
|
|
|
// !!!Can we modify the string which has been passed to us
|
|
// rather than duplicating the data. This will get some speed
|
|
// and save some space.
|
|
|
|
if(!(hdup = DuplicateData(hdata)))
|
|
goto errRtn;
|
|
|
|
if (!(lpdata = GlobalLock (hdup)))
|
|
goto errRtn;
|
|
|
|
DEBUG_OUT (lpdata, 0)
|
|
|
|
lpdoc = (LPDOC)GetWindowLongPtr (hwnd, 0);
|
|
|
|
#ifdef FIREWALLS
|
|
ASSERT (lpdoc, "doc: doc does not exist");
|
|
#endif
|
|
lpoledoc = lpdoc->lpoledoc;
|
|
|
|
retval = OLE_ERROR_SYNTAX;
|
|
|
|
if(*lpdata++ != '[') // commands start with the left sqaure bracket
|
|
goto errRtn;
|
|
|
|
// scan the command and scan upto the first arg.
|
|
if (!(wCmdType = ScanCommand(lpdata, WT_DOC, &lpnextarg, &acmd)))
|
|
goto errRtn;
|
|
|
|
if (wCmdType == NON_OLE_COMMAND) {
|
|
LPSRVR lpsrvr;
|
|
|
|
if (lpsrvr = (LPSRVR) GetWindowLongPtr (GetParent (hwnd), 0)) {
|
|
if (!UtilQueryProtocol (lpsrvr->aClass, PROTOCOL_EXECUTE))
|
|
retval = OLE_ERROR_PROTOCOL;
|
|
else {
|
|
#ifdef FIREWALLS
|
|
if (!CheckPointer (lpoledoc, WRITE_ACCESS))
|
|
ASSERT (0, "Invalid LPOLESERVERDOC")
|
|
else if (!CheckPointer (lpoledoc->lpvtbl, WRITE_ACCESS))
|
|
ASSERT (0, "Invalid LPOLESERVERDOCVTBL")
|
|
else
|
|
ASSERT (lpoledoc->lpvtbl->Execute,
|
|
"Invalid pointer to Execute method")
|
|
#endif
|
|
|
|
retval = (*lpoledoc->lpvtbl->Execute) (lpoledoc, hdata);
|
|
}
|
|
}
|
|
|
|
goto errRtn;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// [StdCloseDocument]
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (acmd == aStdClose){
|
|
|
|
// if not terminated by NULL error
|
|
if (*lpnextarg)
|
|
goto errRtn;
|
|
|
|
#ifdef FIREWALLS
|
|
if (!CheckPointer (lpoledoc, WRITE_ACCESS))
|
|
ASSERT (0, "Invalid LPOLESERVERDOC")
|
|
else if (!CheckPointer (lpoledoc->lpvtbl, WRITE_ACCESS))
|
|
ASSERT (0, "Invalid LPOLESERVERDOCVTBL")
|
|
else
|
|
ASSERT (lpoledoc->lpvtbl->Close,"Invalid pointer to Close method")
|
|
#endif
|
|
lpdoc->fAckClose = TRUE;
|
|
lpdoc->hwndClose = hwndClient;
|
|
lpdoc->hDataClose = hdata;
|
|
retval = (*lpoledoc->lpvtbl->Close) (lpoledoc);
|
|
lpdoc->fAckClose = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// [StdDoVerbItem("itemname", verb, BOOL, BOOL]
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (acmd == aStdDoVerbItem){
|
|
lpitemname = lpnextarg;
|
|
|
|
if(!(lpverb = ScanArg(lpnextarg)))
|
|
goto errRtn;
|
|
|
|
|
|
if(!(lpnextarg = ScanNumArg(lpverb, (LPINT)&verb)))
|
|
goto errRtn;
|
|
|
|
#ifdef FIREWALLS
|
|
ASSERT (verb < 9 , "Unexpected verb number");
|
|
#endif
|
|
|
|
// now scan the show BOOL
|
|
|
|
if (!(lpnextarg = ScanBoolArg (lpnextarg, (BOOL FAR *)&fShow)))
|
|
goto errRtn;
|
|
|
|
fActivate = FALSE;
|
|
|
|
// if activate BOOL is present, scan it.
|
|
|
|
if (*lpnextarg) {
|
|
if (!(lpnextarg = ScanBoolArg (lpnextarg, (BOOL FAR *)&fActivate)))
|
|
goto errRtn;
|
|
}
|
|
|
|
if (*lpnextarg)
|
|
goto errRtn;
|
|
|
|
|
|
retval = DocDoVerbItem (lpdoc, lpitemname, verb, fShow, !fActivate);
|
|
goto end;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// [StdShowItem("itemname"[, "true"])]
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (acmd != aStdShowItem)
|
|
goto errRtn;
|
|
|
|
lpitemname = lpnextarg;
|
|
|
|
if(!(lpopt = ScanArg(lpitemname)))
|
|
goto errRtn;
|
|
|
|
// Now scan for optional parameter.
|
|
|
|
fActivate = FALSE;
|
|
|
|
if (*lpopt) {
|
|
|
|
if(!(lpnextarg = ScanBoolArg (lpopt, (BOOL FAR *)&fActivate)))
|
|
goto errRtn;
|
|
|
|
if (*lpnextarg)
|
|
goto errRtn;
|
|
|
|
|
|
}
|
|
|
|
retval = DocShowItem (lpdoc, lpitemname, !fActivate);
|
|
|
|
end:
|
|
errRtn:
|
|
if (lpdata)
|
|
GlobalUnlock (hdup);
|
|
|
|
if (hdup)
|
|
GlobalFree (hdup);
|
|
|
|
return retval;
|
|
}
|
|
|
|
int INTERNAL DocShowItem (
|
|
LPDOC lpdoc,
|
|
LPSTR lpitemname,
|
|
BOOL fAct
|
|
){
|
|
LPCLIENT lpclient;
|
|
int retval;
|
|
|
|
if ((retval = FindItem (lpdoc, lpitemname, (LPCLIENT FAR *)&lpclient))
|
|
!= OLE_OK)
|
|
return retval;
|
|
|
|
#ifdef FIREWALLS
|
|
if (!CheckPointer (lpclient->lpoleobject->lpvtbl, WRITE_ACCESS))
|
|
ASSERT (0, "Invalid LPOLEOBJECTVTBL")
|
|
else
|
|
ASSERT (lpclient->lpoleobject->lpvtbl->Show,
|
|
"Invalid pointer to Show method")
|
|
#endif
|
|
|
|
// protocol sends false for activating and TRUE for not activating.
|
|
// for api send TRUE for avtivating and FALSE for not activating.
|
|
|
|
return (*lpclient->lpoleobject->lpvtbl->Show)(lpclient->lpoleobject, fAct);
|
|
}
|
|
|
|
|
|
int INTERNAL DocDoVerbItem (
|
|
LPDOC lpdoc,
|
|
LPSTR lpitemname,
|
|
UINT verb,
|
|
BOOL fShow,
|
|
BOOL fAct
|
|
){
|
|
LPCLIENT lpclient;
|
|
int retval = OLE_ERROR_PROTOCOL;
|
|
|
|
if ((retval = FindItem (lpdoc, lpitemname, (LPCLIENT FAR *)&lpclient))
|
|
!= OLE_OK)
|
|
return retval;
|
|
|
|
#ifdef FIREWALLS
|
|
if (!CheckPointer (lpclient->lpoleobject->lpvtbl, WRITE_ACCESS))
|
|
ASSERT (0, "Invalid LPOLEOBJECTVTBL")
|
|
else
|
|
ASSERT (lpclient->lpoleobject->lpvtbl->DoVerb,
|
|
"Invalid pointer to Run method")
|
|
#endif
|
|
|
|
// pass TRUE to activate and False not to activate. Differnt from
|
|
// protocol.
|
|
|
|
retval = (*lpclient->lpoleobject->lpvtbl->DoVerb)(lpclient->lpoleobject, verb, fShow, fAct);
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
|
|
// FreePokeData: Frees the poked dats.
|
|
void INTERNAL FreePokeData (
|
|
HANDLE hdde
|
|
){
|
|
DDEPOKE FAR * lpdde;
|
|
|
|
if (hdde) {
|
|
if (lpdde = (DDEPOKE FAR *) GlobalLock (hdde)) {
|
|
if (lpdde->cfFormat == CF_METAFILEPICT)
|
|
#ifdef _WIN64
|
|
FreeGDIdata (*(void* _unaligned*)lpdde->Value, lpdde->cfFormat);
|
|
#else
|
|
FreeGDIdata (*(LPHANDLE)lpdde->Value, lpdde->cfFormat);
|
|
#endif
|
|
else
|
|
FreeGDIdata (LongToHandle(*(LONG*)lpdde->Value), lpdde->cfFormat);
|
|
GlobalUnlock (hdde);
|
|
}
|
|
|
|
GlobalFree (hdde);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Returns TRUE if GDI format else returns FALSE
|
|
|
|
BOOL INTERNAL FreeGDIdata (
|
|
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);
|
|
else if (cfFormat == CF_ENHMETAFILE)
|
|
DeleteEnhMetaFile(hData);
|
|
else
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|