mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1653 lines
40 KiB
1653 lines
40 KiB
/***************************************************************************\
|
|
* Module Name: Doc.c Document Main module
|
|
*
|
|
* Purpose: Includes All the document level object communication related.
|
|
*
|
|
* Created: Oct 1990.
|
|
*
|
|
* Copyright (c) 1990, 1991 Microsoft Corporation
|
|
*
|
|
* History:
|
|
* Raor (../10/1990) Designed, coded (modified for 2.0)
|
|
*
|
|
\***************************************************************************/
|
|
|
|
#include "ole2int.h"
|
|
//#include "cmacs.h"
|
|
#include <dde.h>
|
|
|
|
#include "srvr.h"
|
|
#include "ddedebug.h"
|
|
#include "valid.h"
|
|
ASSERTDATA
|
|
|
|
extern ATOM aStdClose;
|
|
extern ATOM aStdShowItem;
|
|
extern ATOM aStdDoVerbItem;
|
|
extern ATOM aStdDocName;
|
|
extern ATOM aTrue;
|
|
extern ATOM aFalse;
|
|
|
|
extern HANDLE hddeRename;
|
|
extern HWND hwndRename;
|
|
|
|
#ifdef _CHICAGO_
|
|
#define szDDEViewObj "DDE ViewObj"
|
|
#else
|
|
#define szDDEViewObj L"DDE ViewObj"
|
|
#endif
|
|
|
|
|
|
// HRESULT DdeHandleIncomingCall(HWND hwndCli, WORD wCallType);
|
|
|
|
//
|
|
// Call CoHandleIncomingCall which will call the message filter
|
|
// Note: only call this functions with:
|
|
// - CALLTYPE_TOPLEVEL ... for synchranous calls
|
|
// - CALLTYPE_ASYNC ... for async calls
|
|
//
|
|
HRESULT DdeHandleIncomingCall(HWND hwndCli, WORD wCallType)
|
|
{
|
|
|
|
Assert(!"DdeHandleIncomingCall not implemented");
|
|
|
|
return(RPC_E_CALL_REJECTED);
|
|
|
|
// Review: bug: get the correcr hwnd
|
|
switch ( /* CoHandleIncomingCall(hwndCli, wCallType, NULL) */ wCallType) {
|
|
default:
|
|
case SERVERCALL_ISHANDLED: // call can be proccesed
|
|
return NOERROR;
|
|
|
|
case SERVERCALL_REJECTED: // call rejected
|
|
return ResultFromScode(RPC_E_CALL_REJECTED);
|
|
|
|
case SERVERCALL_RETRYLATER: // call should be retried later
|
|
return ResultFromScode(RPC_E_DDE_BUSY);
|
|
}
|
|
}
|
|
|
|
|
|
INTERNAL CDefClient::Create
|
|
(
|
|
LPSRVR lhOLESERVER,
|
|
LPUNKNOWN lpunkObj,
|
|
LPOLESTR lpdocName,
|
|
const BOOL fSetClientSite,
|
|
const BOOL fDoAdvise,
|
|
const BOOL fRunningInSDI, // optional
|
|
HWND FAR* phwnd // optional
|
|
)
|
|
{
|
|
LPSRVR lpsrvr = NULL;
|
|
LPCLIENT lpclient = NULL;
|
|
HANDLE hclient = NULL;
|
|
HRESULT hresult = NOERROR;
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"0 _IN CDefClient::Create(lpsrvr=%x,lpdocName=%ws)\n",
|
|
lhOLESERVER,WIDECHECK(lpdocName)));
|
|
|
|
// REVIEW: server's termination has already started. Are
|
|
// we going to see this condition in the synchronous mode.
|
|
lpsrvr = (LPSRVR)lhOLESERVER;
|
|
if (lpsrvr && lpsrvr->m_bTerminate)
|
|
{
|
|
Assert(0);
|
|
return ReportResult(0, RPC_E_DDE_REVOKE, 0, 0);
|
|
}
|
|
|
|
#ifdef FIREWALLS
|
|
PROBE_READ(lpunkObj);
|
|
PROBE_READ(lpmkObj);
|
|
PROBE_WRITE(lplhobj);
|
|
#endif
|
|
|
|
lpclient = new CDefClient (/*pUnkOuter==*/NULL);;
|
|
|
|
Assert(lpclient->m_pUnkOuter);
|
|
|
|
lpclient->m_aItem = wGlobalAddAtom (/*lpszObjName*/lpdocName);
|
|
lpclient->m_fRunningInSDI = fRunningInSDI;
|
|
lpclient->m_psrvrParent = lpsrvr;
|
|
// A doc has itself as its containing document
|
|
lpclient->m_pdoc = lpclient;
|
|
|
|
ErrRtnH (lpunkObj->QueryInterface (IID_IOleObject,
|
|
(LPLPVOID) &lpclient->m_lpoleObj));
|
|
|
|
ErrRtnH (lpunkObj->QueryInterface (IID_IDataObject,
|
|
(LPLPVOID) &lpclient->m_lpdataObj));
|
|
|
|
// Lock object; do after the QI so that ReleaseObjPtrs will unlock correctly
|
|
lpclient->m_fLocked =
|
|
(NOERROR==CoLockObjectExternal (lpunkObj, TRUE, /*dont care*/ FALSE));
|
|
|
|
if (!(lpclient->m_hwnd = DdeCreateWindowEx(0, gOleWindowClass,szDDEViewObj,
|
|
WS_CHILD,0,0,0,0,lpsrvr->m_hwnd,NULL, g_hinst, NULL)))
|
|
{
|
|
intrDebugOut((DEB_ITRACE,"CDefClient::Create() couldn't create window\n"));
|
|
goto errRtn;
|
|
}
|
|
|
|
// fix up the WindowProc entry point.
|
|
SetWindowLong(lpclient->m_hwnd, GWL_WNDPROC, (LONG)DocWndProc);
|
|
|
|
if (fDoAdvise)
|
|
{
|
|
// This is for Packager, in particular, and manual links.
|
|
// If client does not advise on any data, we still need
|
|
// to do an OLE advise so we can get OnClose notifications.
|
|
ErrRtnH (lpclient->DoOle20Advise (OLE_CLOSED, (CLIPFORMAT)0));
|
|
}
|
|
|
|
intrDebugOut((DEB_ITRACE," Doc window %x created\n",lpclient->m_hwnd));
|
|
|
|
// Set out parm (window)
|
|
if (phwnd != NULL)
|
|
{
|
|
*phwnd = lpclient->m_hwnd;
|
|
}
|
|
|
|
if (fSetClientSite)
|
|
{
|
|
// Should not set the client site if the object has not been
|
|
// initialized yet, by BindMoniker (i.e. PersistFile::Load)
|
|
// or PersistStorage::Load
|
|
if (lpclient->SetClientSite() != NOERROR)
|
|
{
|
|
goto errRtn;
|
|
}
|
|
}
|
|
|
|
Putsi(lpclient->m_cRef);
|
|
|
|
SetWindowLong (lpclient->m_hwnd, 0, (LONG)lpclient);
|
|
SetWindowWord (lpclient->m_hwnd, WW_LE, WC_LE);
|
|
SetWindowLong (lpclient->m_hwnd,WW_HANDLE,
|
|
(GetWindowLong (lpsrvr->m_hwnd, WW_HANDLE)));
|
|
|
|
hresult = NOERROR;
|
|
|
|
exitRtn:
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"0 _OUT CDefClient::Create(lpsrvr=%x,lpdocName=%ws) hr=%x\n",
|
|
lhOLESERVER,
|
|
WIDECHECK(lpdocName),
|
|
hresult));
|
|
|
|
|
|
return(hresult);
|
|
errRtn:
|
|
intrDebugOut((DEB_ITRACE,"CDefClient::Create() in error handling routine\n"));
|
|
if (lpclient)
|
|
{
|
|
if (lpclient->m_hwnd)
|
|
SSDestroyWindow (lpclient->m_hwnd);
|
|
|
|
if (lpclient->m_aItem)
|
|
GlobalDeleteAtom (lpclient->m_aItem);
|
|
delete lpclient;
|
|
}
|
|
hresult = E_OUTOFMEMORY;
|
|
goto exitRtn;
|
|
}
|
|
|
|
|
|
|
|
INTERNAL CDefClient::Revoke (BOOL fRelease)
|
|
{
|
|
Puts ("DefClient::Revoke "); Puth(this); Puta(m_aItem); Putn();
|
|
|
|
ChkC(this);
|
|
|
|
|
|
ReleaseObjPtrs();
|
|
|
|
// We are done with this CDefClient but someone may still have a reference
|
|
// to an instance of one of our nested classes. In particular, an advise
|
|
// holder may be holding on to our sink, or an item may have a pointer
|
|
// to us if we are its parent document. So we cannot actually do a
|
|
// "delete this".
|
|
// The corresponding AddRef is in CDefClient::Create
|
|
// or CDefClient::RegisterItem
|
|
|
|
m_pUnkOuter->Release();
|
|
|
|
Puts ("DefClient::Revoke done\r\n");
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
|
|
INTERNAL CDefClient::ReleaseObjPtrs
|
|
(void)
|
|
{
|
|
intrDebugOut((DEB_ITRACE,
|
|
"%p _IN CDefClient::ReleaseObjPtrs\n",
|
|
this));
|
|
|
|
ULONG ulResult;
|
|
|
|
if (m_lpoleObj && m_fLocked)
|
|
{
|
|
// Unlock object. Set m_fLocked to FALSE first to prevent reentrant
|
|
// problems (unlock causes close which causes this routine to be called)
|
|
|
|
m_fLocked = FALSE;
|
|
CoLockObjectExternal(m_lpoleObj, FALSE, TRUE);
|
|
}
|
|
if (m_lpoleObj)
|
|
{
|
|
if (m_fDidSetClientSite)
|
|
m_lpoleObj->SetClientSite(NULL);
|
|
DoOle20UnAdviseAll();
|
|
Assert (m_lpoleObj);
|
|
if (m_lpoleObj)
|
|
{
|
|
ulResult = m_lpoleObj->Release();
|
|
m_lpoleObj = NULL;
|
|
}
|
|
intrDebugOut((DEB_ITRACE,
|
|
"%p _OUT ::ReleaseObjPtrs lpoleObj ulResult=%x\n",
|
|
this,ulResult));
|
|
}
|
|
if (m_lpdataObj)
|
|
{
|
|
// Must do it this way because the Release can cause recursion
|
|
LPDATAOBJECT pdata = m_lpdataObj;
|
|
m_lpdataObj = NULL;
|
|
ulResult = pdata->Release();
|
|
intrDebugOut((DEB_ITRACE,
|
|
"%p _OUT ::ReleaseObjPtrs pdata ulResult=%x\n",
|
|
this,ulResult));
|
|
}
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"%p _OUT CDefClient::ReleaseObjPtrs\n",
|
|
this));
|
|
return NOERROR;
|
|
}
|
|
#if 000
|
|
//RevokeAllDocs : revokes all the doc objects attached to a given
|
|
//server.
|
|
|
|
INTERNAL_(HRESULT) CDDEServer::RevokeAllDocObjs ()
|
|
{
|
|
|
|
HWND hwnd;
|
|
HWND hwndnext;
|
|
LPCLIENT lpclient;
|
|
Puts ("RevokeAllDocObjs\r\n");
|
|
ChkS(this);
|
|
|
|
hwnd = GetWindow (m_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);
|
|
lpclient = ((LPCLIENT)GetWindowLong (hwnd, 0));
|
|
lpclient->Revoke();
|
|
hwnd = hwndnext;
|
|
}
|
|
return NOERROR;
|
|
}
|
|
#endif
|
|
|
|
// FindDoc: Given a doc obj, searches for the doc obj
|
|
// in the given class factory tree. returns true if the
|
|
// doc obj is available.
|
|
|
|
|
|
INTERNAL_(LPCLIENT) CDDEServer::FindDocObj
|
|
(
|
|
LPSTR lpdocname
|
|
)
|
|
{
|
|
ATOM aItem;
|
|
HWND hwnd;
|
|
LPCLIENT lpclient;
|
|
|
|
ChkS(this);
|
|
aItem = (ATOM)GlobalFindAtomA (lpdocname);
|
|
Assert (IsWindowValid (m_hwnd));
|
|
hwnd = GetWindow (m_hwnd, GW_CHILD);
|
|
Assert (NULL==hwnd || IsWindowValid (hwnd));
|
|
|
|
while (hwnd)
|
|
{
|
|
lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
|
|
if (lpclient->m_aItem == aItem)
|
|
{
|
|
intrDebugOut((DEB_ITRACE,
|
|
"FindDocObj found %s lpclient=%x\n",
|
|
lpdocname,
|
|
lpclient));
|
|
return lpclient;
|
|
}
|
|
hwnd = GetWindow (hwnd, GW_HWNDNEXT);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOL PostAckToClient(HWND hwndClient,HWND hwndServer,ATOM aItem,DWORD retval)
|
|
{
|
|
HRESULT hr = TRUE;
|
|
intrDebugOut((DEB_ITRACE,
|
|
"0 _IN PostAckToClient(hwndClient=%x,hwndServer=%x,aItem=%x(%ws)\n",
|
|
hwndClient,
|
|
hwndServer,
|
|
aItem,
|
|
wAtomName(aItem)));
|
|
|
|
DWORD status = 0;
|
|
SET_MSG_STATUS (retval, status);
|
|
|
|
LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem);
|
|
|
|
if (!PostMessageToClient (hwndClient,
|
|
WM_DDE_ACK,
|
|
(UINT)hwndServer,
|
|
lp))
|
|
{
|
|
DDEFREE(WM_DDE_ACK,lp);
|
|
hr = FALSE;
|
|
}
|
|
intrDebugOut((DEB_ITRACE,
|
|
"0 _OUT PostAckToClient returns %x\n",
|
|
hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: DocHandleIncomingCall
|
|
//
|
|
// Synopsis: Setup and call the CallControl to dispatch a call to the doc
|
|
//
|
|
// Effects: A call has been made from the client that requires us to call
|
|
// into our server. This must be routed through the call control.
|
|
// This routine sets up the appropriate data structures, and
|
|
// calls into the CallControl. The CallControl will in turn
|
|
// call DocDispatchIncomingCall to actually process the call.
|
|
//
|
|
// This routine should only be called by the DocWndProc
|
|
//
|
|
//
|
|
// Arguments: [pDocData] -- Points to DOCDISPATCHDATA for this call
|
|
// This contains all required information for
|
|
// handling the message.
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: If an error is returned, it is assumed that the Dispatch
|
|
// routine was not reached. DocDispatchIncomingCall() should
|
|
// not be returning an error.
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 6-05-94 kevinro Commented/cleaned
|
|
//
|
|
// Notes:
|
|
//
|
|
// This is a co-routine with DocDispatchIncomingCall. See that routine
|
|
// for more details
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
INTERNAL DocHandleIncomingCall(PDOCDISPATCHDATA pDocData)
|
|
{
|
|
HRESULT hresult = NOERROR;
|
|
DISPATCHDATA dispatchdata;
|
|
DWORD callcat;
|
|
|
|
intrAssert(pDocData != NULL);
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"0 _IN DocHandleIncomingCall lpclient=%x pDocData=%x\n",
|
|
pDocData->lpclient,
|
|
pDocData));
|
|
|
|
//
|
|
// TERMINATE messages must always be handled ASYNC, and cannot
|
|
// be rejected.
|
|
//
|
|
if (pDocData->msg == WM_DDE_TERMINATE)
|
|
{
|
|
callcat = CALLCAT_ASYNC;
|
|
}
|
|
else
|
|
{
|
|
callcat = CALLCAT_SYNCHRONOUS;
|
|
}
|
|
|
|
dispatchdata.pData = (LPVOID) pDocData;
|
|
pDocData->wDispFunc = DDE_DISP_DOCWNDPROC;
|
|
|
|
RPCOLEMESSAGE rpcMsg;
|
|
RPC_SERVER_INTERFACE RpcInterfaceInfo;
|
|
DWORD dwFault;
|
|
|
|
rpcMsg.iMethod = 0;
|
|
rpcMsg.Buffer = &dispatchdata;
|
|
rpcMsg.cbBuffer = sizeof(dispatchdata);
|
|
rpcMsg.reserved2[1] = &RpcInterfaceInfo;
|
|
*MSG_TO_IIDPTR(&rpcMsg) = GUID_NULL;
|
|
|
|
|
|
IRpcStubBuffer * pStub = &(pDocData->lpclient->m_pCallMgr);
|
|
IRpcChannelBuffer * pChannel = &(pDocData->lpclient->m_pCallMgr);
|
|
hresult = STAInvoke(&rpcMsg, callcat, pStub, pChannel, NULL, &dwFault);
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"0 _OUT DocHandleIncomingCall hresult=%x\n",
|
|
hresult));
|
|
|
|
return(hresult);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: DocDispatchIncomingCall
|
|
//
|
|
// Synopsis: Dispatch a call into the client.
|
|
//
|
|
// Effects: This is a co-routine to DocHandleIncomingCall. This routine
|
|
// is called to implement functions that call into the CDefClient
|
|
// object. It is dispatched by the call control stuff, and helps
|
|
// to insure the server is ready to accept these calls.
|
|
//
|
|
// This routine is coded as a continuation of the DocWndProc.
|
|
// There is a switch on the message. Each message does slightly
|
|
// different things. The code to handle each message was snatched
|
|
// from the original DocWndProc, before it was converted to the
|
|
// new call control mechanism.
|
|
//
|
|
//
|
|
// Arguments: [pDocData] -- Points to Doc Dispatch Data, which are the
|
|
// parameters to DocWndProc which need processing
|
|
//
|
|
// Requires:
|
|
// pDocData cannot be NULL
|
|
//
|
|
// Returns:
|
|
// This routine will always return NOERROR. There are no useful
|
|
// error returns to be made from here. If you decide to return
|
|
// an error, check the DocHandleIncomingCall and DocWndProc to be
|
|
// sure the error paths are correctly handled. Some of the
|
|
// cases do additional error processing in the DocWndProc on
|
|
// error.
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 6-05-94 kevinro Commented/cleaned
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
INTERNAL DocDispatchIncomingCall(PDOCDISPATCHDATA pDocData)
|
|
{
|
|
LPCLIENT lpclient = pDocData->lpclient;
|
|
BOOL fack;
|
|
HANDLE hdata = pDocData->hdata;
|
|
ATOM aItem = pDocData->aItem;
|
|
WPARAM wParam = pDocData->wParam;
|
|
HWND hwnd = pDocData->hwnd;
|
|
HRESULT retval;
|
|
|
|
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"0 _IN DocDispatchIncomingCall pDocData(%x)\n",
|
|
pDocData));
|
|
|
|
intrAssert(pDocData);
|
|
|
|
//
|
|
// This switch statement is intended to continue the functionality found
|
|
// in the DocWndProc. These routines are directly interrelated to the
|
|
// same cases in DocWndProc, and need special care before changing.
|
|
//
|
|
switch (pDocData->msg)
|
|
{
|
|
case WM_DDE_TERMINATE:
|
|
{
|
|
intrDebugOut((DEB_ITRACE,
|
|
"DDIC: WM_DDE_TERMINATE hwnd=%x \n",
|
|
pDocData->hwnd));
|
|
|
|
//
|
|
// Here is a fine hack for you. 32-bit applications appear to shut
|
|
// down slightly differently than 16-bit applications. There is a
|
|
// problem with Lotus Notes interacting with 32-bit OFFICE apps.
|
|
// When notes has done an OleCreateFromFile, it starts the
|
|
// 32-bit hidden, and does a normal DDE conversation. However,
|
|
// on termination, the 32-bit Doc Window was going away during
|
|
// this routine. Since the world is now multi-tasking, Lotus
|
|
// Notes was seeing its server window die because we get
|
|
// pre-empted during DeleteItemsFromList giving the 16-bit app a
|
|
// chance to run. Since Lotus is in the
|
|
// standard OleQueryReleaseStatus() loop, it will detect that the
|
|
// server has shutdown BEFORE it gets the terminate message.
|
|
// Go figure. So, insure that we post the reply DDE_TERMINATE
|
|
// before destroying our window, or the 16-bit applications
|
|
// won't like us.
|
|
//
|
|
PostMessageToClient ((HWND)wParam, WM_DDE_TERMINATE,
|
|
(UINT) hwnd, NULL);
|
|
|
|
// Client initiated the termination. So, we should remove
|
|
// his window from any of our doc or items' lists.
|
|
lpclient->DeleteFromItemsList ((HWND)wParam
|
|
/*, lpclient->m_fEmbed*/);
|
|
|
|
ChkC (lpclient);
|
|
|
|
|
|
// REVIEW: If the termination is sent from the client side,
|
|
// lpoleObj will not be NULL.
|
|
if (lpclient->m_cClients == 0 && lpclient->m_fEmbed)
|
|
{
|
|
Assert (lpclient->m_chk==chkDefClient);
|
|
lpclient->ReleaseAllItems ();
|
|
Assert (lpclient->m_chk==chkDefClient);
|
|
Assert (NULL==lpclient->m_lpoleObj &&
|
|
NULL==lpclient->m_lpdataObj) ;
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_DDE_EXECUTE:
|
|
{
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"DDIC: WM_DDE_EXECUTE hwnd=%x hdata=%x\n",
|
|
pDocData->hwnd,
|
|
pDocData->hdata));
|
|
|
|
//
|
|
// The following state variables appear to be used by
|
|
// the execute code.
|
|
//
|
|
lpclient->m_ExecuteAck.f = TRUE; // assume we will need to
|
|
lpclient->m_ExecuteAck.hdata = hdata;
|
|
lpclient->m_ExecuteAck.hwndFrom = (HWND)wParam;
|
|
lpclient->m_ExecuteAck.hwndTo = hwnd;
|
|
|
|
//
|
|
// In the event that the command is a StdClose, we need
|
|
// to force the client to stay around for the duration of
|
|
// the call.
|
|
//
|
|
lpclient->m_pUnkOuter->AddRef();
|
|
|
|
retval = lpclient->DocExecute (hdata);
|
|
|
|
if (lpclient->m_ExecuteAck.f)
|
|
{
|
|
lpclient->SendExecuteAck (retval);
|
|
}
|
|
|
|
lpclient->m_pUnkOuter->Release();
|
|
break;
|
|
|
|
}
|
|
case WM_DDE_POKE:
|
|
{
|
|
int iStdItem;
|
|
intrDebugOut((DEB_ITRACE,
|
|
"DDIC: WM_DDE_POKE hwnd=%x aItem=%x(%ws) hdata=%x\n",
|
|
hwnd,
|
|
aItem,
|
|
wAtomName(aItem),
|
|
hdata));
|
|
|
|
if (iStdItem = GetStdItemIndex (aItem))
|
|
{
|
|
retval = lpclient->PokeStdItems ((HWND)wParam,
|
|
aItem,
|
|
hdata,
|
|
iStdItem);
|
|
}
|
|
else
|
|
{
|
|
retval = lpclient->PokeData ((HWND)wParam,
|
|
aItem,
|
|
hdata);
|
|
// This is allowed to fail. PowerPoint tries to poke
|
|
// data with cfFormat=="StdSave" and "StdFont"
|
|
}
|
|
|
|
if (!PostAckToClient((HWND)wParam,hwnd,aItem,retval))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
break;
|
|
}
|
|
case WM_DDE_ADVISE:
|
|
{
|
|
intrDebugOut((DEB_ITRACE,
|
|
"DDIC: WM_DDE_ADVISE hwnd=%x aItem=%x(%ws) hdata=%x\n",
|
|
hwnd,
|
|
aItem,
|
|
wAtomName(aItem),
|
|
hdata));
|
|
|
|
if (IsAdviseStdItems (aItem))
|
|
{
|
|
retval = lpclient->AdviseStdItems ((HWND)wParam,
|
|
aItem,
|
|
hdata,
|
|
(BOOL FAR *)&fack);
|
|
}
|
|
else
|
|
{
|
|
retval = lpclient->AdviseData ((HWND)wParam,
|
|
aItem,
|
|
hdata,
|
|
(BOOL FAR *)&fack);
|
|
}
|
|
|
|
if (fack)
|
|
{
|
|
if (!PostAckToClient((HWND)wParam,hwnd,aItem,retval))
|
|
{
|
|
GlobalFree(hdata);
|
|
}
|
|
}
|
|
else if (aItem != NULL)
|
|
{
|
|
GlobalDeleteAtom (aItem);
|
|
}
|
|
break;
|
|
}
|
|
case WM_DDE_UNADVISE:
|
|
{
|
|
intrDebugOut((DEB_ITRACE,
|
|
"DDIC: WM_DDE_UNADVISE hwnd=%x aItem=%x(%ws)\n",
|
|
hwnd,
|
|
aItem,
|
|
wAtomName(aItem)));
|
|
|
|
retval = lpclient->UnAdviseData ((HWND)wParam, aItem);
|
|
|
|
if (!PostAckToClient((HWND)wParam,hwnd,aItem,retval))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
break;
|
|
}
|
|
case WM_DDE_REQUEST:
|
|
{
|
|
intrDebugOut((DEB_ITRACE,
|
|
"DDIC: WM_DDE_REQUEST hwnd=%x aItem=%x(%ws) cfFormat=%x\n",
|
|
hwnd,
|
|
aItem,
|
|
wAtomName(aItem),
|
|
(USHORT)LOWORD(pDocData->lParam)));
|
|
|
|
retval = lpclient->RequestData ((HWND)wParam,
|
|
aItem,
|
|
LOWORD(pDocData->lParam),
|
|
(HANDLE FAR *)&hdata);
|
|
|
|
if (retval == NOERROR)
|
|
{
|
|
// post the data message and we are not asking for any
|
|
// acknowledge.
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"DDIC: posting WM_DDE_DATA\n"));
|
|
|
|
LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_DATA,hdata,aItem);
|
|
if (!PostMessageToClient ((HWND)wParam, WM_DDE_DATA, (UINT) hwnd,lp))
|
|
{
|
|
// hdata will be freed by the client because fRelease
|
|
// was set to true by MakeDdeData (called by RequestData)
|
|
|
|
DDEFREE(WM_DDE_DATA,lp);
|
|
goto errRtn;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!PostAckToClient((HWND)wParam,hwnd,aItem,retval))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
//
|
|
// Whoops, this is very bad. We should never get here.
|
|
//
|
|
intrAssert(!"Unknown MSG in DocWndProc: Very Bad indeed");
|
|
|
|
|
|
}
|
|
|
|
exitRtn:
|
|
intrDebugOut((DEB_ITRACE,
|
|
"0 _OUT DocDispatchIncomingCall pDocData(%x) hr = 0\n",
|
|
pDocData));
|
|
|
|
return(NOERROR);
|
|
errRtn:
|
|
intrDebugOut((DEB_IERROR,
|
|
"***** ERROR DDIC pDocData(%x) Post ACK failed. \n",
|
|
pDocData));
|
|
|
|
if (aItem != NULL)
|
|
{
|
|
GlobalDeleteAtom (aItem);
|
|
}
|
|
goto exitRtn;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: DocWndProc
|
|
//
|
|
// Synopsis: Document Window Procedure
|
|
//
|
|
// Effects: Processes DDE messages for a document window.
|
|
//
|
|
// Arguments: [hwnd] --
|
|
// [msg] --
|
|
// [wParam] --
|
|
// [lParam] --
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 6-05-94 kevinro Commented/cleaned
|
|
//
|
|
// Notes:
|
|
//
|
|
// When running in a VDM, it is possible that this window was dispatched
|
|
// without having a full window handle. This happens when the getmessage
|
|
// was dispatched from 16-bit. Therefore, we need to convert the hwnd to
|
|
// a full hwnd before doing any comparision functions.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDAPI_(LRESULT) DocWndProc (
|
|
HWND hwndIn,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
|
|
//
|
|
// Since this is the DocWndProc, we aren't going to initialize
|
|
// any of the local variables. This function is called as a WNDPROC,
|
|
// which is pretty often.
|
|
//
|
|
|
|
DOCDISPATCHDATA docData;
|
|
LPCLIENT lpclient;
|
|
WORD status=0;
|
|
HANDLE hdata;
|
|
ATOM aItem;
|
|
HRESULT retval;
|
|
LPOLEOBJECT lpoleObj;
|
|
HWND hwnd;
|
|
DebugOnly (HWND hwndClient;)
|
|
|
|
// REVIEW: We need to take care of the bug, related to
|
|
// Excel. Excel does the sys level connection and sends
|
|
// terminates immediately before making the connection
|
|
// to the doc level. If we send release to classfactory
|
|
// app may revoke the classfactory.
|
|
|
|
|
|
// REVIEW: It may not be necessary to do the blocking.
|
|
// ReVIEW: For fixing the ref count right way for
|
|
// CreateInstance Vs. WM_DDE_INIT
|
|
|
|
#ifdef LATER
|
|
if (AddMessage (hwnd, msg, wParam, lParam, WT_DOC))
|
|
return 0L;
|
|
#endif
|
|
|
|
switch (msg){
|
|
|
|
case WM_CREATE:
|
|
intrDebugOut((DEB_ITRACE,
|
|
"DocWndProc: CreateWindow hwndIn=%x\n",
|
|
hwndIn));
|
|
break;
|
|
|
|
|
|
case WM_DDE_INITIATE:
|
|
hwnd = ConvertToFullHWND(hwndIn);
|
|
intrAssert(IsWindowValid(hwnd));
|
|
lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"DocWndProc: WM_DDE_INITIATE hwnd=%x\n",
|
|
hwnd));
|
|
|
|
ChkC(lpclient);
|
|
|
|
|
|
// REVIEW: We may not allow initiates to get thru
|
|
// while we are waiting for terminates. So, this case
|
|
// may not arise
|
|
|
|
// Need to verify that m_pCI is not NULL during incoming
|
|
// calls from the client.
|
|
//
|
|
if (lpclient->m_fCallData)
|
|
{
|
|
intrDebugOut((DEB_ITRACE,
|
|
"DocWndProc: No initiates while waiting on terminate\n"));
|
|
|
|
break;
|
|
}
|
|
// if we are the document then respond.
|
|
|
|
if (! (lpclient->m_aItem == (ATOM)(HIWORD(lParam))))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// We can enterain this client. Put this window in the client list
|
|
// and acknowledge the initiate.
|
|
|
|
if (!AddClient ((LPHANDLE)&lpclient->m_hcli, (HWND)wParam, (HWND)wParam))
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
// post the acknowledge
|
|
DuplicateAtom (LOWORD(lParam));
|
|
DuplicateAtom (HIWORD(lParam));
|
|
SSSendMessage ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, lParam);
|
|
|
|
lpclient->m_cClients++;
|
|
lpclient->m_fCreatedNotConnected = FALSE;
|
|
lpoleObj = lpclient->m_lpoleObj;
|
|
|
|
// we have added an addref because of createinstance.
|
|
|
|
if (lpclient->m_bCreateInst)
|
|
{
|
|
lpclient->m_bCreateInst = FALSE;
|
|
}
|
|
|
|
return 1L; // fAckSent
|
|
break;
|
|
|
|
|
|
case WM_DDE_EXECUTE:
|
|
{
|
|
hwnd = ConvertToFullHWND(hwndIn);
|
|
intrAssert(IsWindowValid(hwnd));
|
|
lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
|
|
|
|
hdata = GET_WM_DDE_EXECUTE_HDATA(wParam,lParam);
|
|
intrDebugOut((DEB_ITRACE,
|
|
"DocWndProc: WM_DDE_EXECUTE hwnd=%x hdata=%x\n",
|
|
hwnd,
|
|
hdata));
|
|
|
|
ChkC(lpclient);
|
|
|
|
#ifdef FIREWALLS
|
|
// find the client in the client list.
|
|
hwndClient = FindClient (lpclient->m_hcli, (HWND)wParam, FALSE);
|
|
AssertSz (hwndClient, "Client is missing from the server");
|
|
#endif
|
|
if (!IsWindowValid ((HWND)wParam) || lpclient->m_fCallData)
|
|
{
|
|
if (lpclient->m_fCallData)
|
|
{
|
|
// This means the terminate has already been sent
|
|
// to this window (from AdviseSink::OnClose) so
|
|
// we can ignore the StdCloseDocument.
|
|
}
|
|
else
|
|
{
|
|
intrAssert(!"Execute received from dead sending window");
|
|
}
|
|
// Since we are not sending an ACK, the sender will not
|
|
// have the chance to free the hCommands handle.
|
|
DDEFREE(WM_DDE_ACK,lParam);
|
|
// GlobalFree (hdata);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Fill in the used items in DocData
|
|
//
|
|
docData.hwnd = hwnd;
|
|
docData.msg = msg;
|
|
docData.wParam = wParam;
|
|
docData.hdata = hdata;
|
|
docData.lpclient = lpclient;
|
|
|
|
retval = DocHandleIncomingCall(&docData);
|
|
|
|
//
|
|
// If error return, then we didn't call DocDispatchIncomingCall
|
|
// and therefore need to send a NACK
|
|
//
|
|
if (retval != NOERROR)
|
|
{
|
|
lpclient->SendExecuteAck (retval);
|
|
}
|
|
break;
|
|
}
|
|
case WM_DDE_TERMINATE:
|
|
hwnd = ConvertToFullHWND(hwndIn);
|
|
intrAssert(IsWindowValid(hwnd));
|
|
lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"DocWndProc: WM_DDE_TERMINATE hwnd=%x\n",
|
|
hwnd));
|
|
|
|
ChkC(lpclient);
|
|
|
|
//
|
|
// If m_fCallData, then we are are waiting for a terminate, which
|
|
// means we generated the original terminate message. If
|
|
// this is so, then we are waiting for a reply to the
|
|
// terminate. Set the AckState and break;
|
|
//
|
|
if (lpclient->m_fCallData)
|
|
{
|
|
lpclient->SetCallState(SERVERCALLEX_ISHANDLED);
|
|
break;
|
|
}
|
|
|
|
|
|
#ifdef _DEBUG
|
|
// find the client in the client list.
|
|
hwndClient = (HWND)FindClient (lpclient->m_hcli,(HWND)wParam, FALSE);
|
|
AssertSz(hwndClient, "Client is missing from the server");
|
|
#endif
|
|
AssertIsDoc (lpclient);
|
|
Assert (lpclient->m_cClients > 0);
|
|
lpclient->m_cClients--;
|
|
|
|
// Necessary safety bracket
|
|
lpclient->m_pUnkOuter->AddRef();
|
|
|
|
// terminate has to be handled always
|
|
// The DocHandleIncomingCall() routine will set the
|
|
// calltype to be CALLTYPE_ASYNC
|
|
// async calls are never rejected
|
|
|
|
docData.hwnd = hwnd;
|
|
docData.msg = msg;
|
|
docData.wParam = wParam;
|
|
docData.lpclient = lpclient;
|
|
|
|
retval = DocHandleIncomingCall(&docData);
|
|
|
|
intrAssert(retval == NOERROR);
|
|
|
|
// Necessary safety bracket
|
|
lpclient->m_pUnkOuter->Release();
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"DocWndProc: WM_DESTROY\n"));
|
|
break;
|
|
|
|
case WM_DDE_POKE:
|
|
{
|
|
hwnd = ConvertToFullHWND(hwndIn);
|
|
intrAssert(IsWindowValid(hwnd));
|
|
lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
|
|
hdata = GET_WM_DDE_POKE_HDATA(wParam,lParam);
|
|
aItem = GET_WM_DDE_POKE_ITEM(wParam,lParam);
|
|
ChkC(lpclient);
|
|
|
|
if (!IsWindowValid ((HWND) wParam) || lpclient->m_fCallData)
|
|
{
|
|
// The sending window is invalid or we have already sent a
|
|
// TERMINATE to it (as indicated by m_pCI != NULL).
|
|
// We cannot ACK the message, so we must free any
|
|
// handles or atoms.
|
|
Warn ("Ignoring message");
|
|
|
|
FreePokeData (hdata);
|
|
LDeleteAtom:
|
|
|
|
if (aItem != NULL)
|
|
{
|
|
GlobalDeleteAtom (aItem);
|
|
}
|
|
break;
|
|
}
|
|
|
|
docData.hwnd = hwnd;
|
|
docData.msg = msg;
|
|
docData.wParam = wParam;
|
|
docData.hdata = hdata;
|
|
docData.aItem = aItem;
|
|
docData.lpclient = lpclient;
|
|
|
|
retval = DocHandleIncomingCall(&docData);
|
|
if (retval != NOERROR)
|
|
{
|
|
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
|
|
|
|
// REVIEW: The assumption is
|
|
LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem);
|
|
if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (UINT) hwnd,lp))
|
|
{
|
|
DDEFREE(WM_DDE_ACK,lp);
|
|
goto LDeleteAtom;
|
|
}
|
|
}
|
|
// johannp: set the busy bit here in the status word
|
|
break;
|
|
}
|
|
|
|
|
|
case WM_DDE_ADVISE:
|
|
{
|
|
hwnd = ConvertToFullHWND(hwndIn);
|
|
intrAssert(IsWindowValid(hwnd));
|
|
lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
|
|
HANDLE hOptions = GET_WM_DDE_ADVISE_HOPTIONS(wParam,lParam);
|
|
aItem = GET_WM_DDE_ADVISE_ITEM(wParam,lParam);
|
|
|
|
ChkC(lpclient);
|
|
if (!IsWindowValid ((HWND)wParam) || lpclient->m_fCallData)
|
|
{
|
|
AdviseErr:
|
|
Warn ("Ignoring advise message");
|
|
//
|
|
// GlobalFree wants a handle, we are giving it a DWORD.
|
|
//
|
|
GlobalFree (hOptions);
|
|
break;
|
|
}
|
|
docData.hwnd = hwnd;
|
|
docData.msg = msg;
|
|
docData.wParam = wParam;
|
|
docData.hdata = hOptions;
|
|
docData.aItem = aItem;
|
|
docData.lpclient = lpclient;
|
|
|
|
retval = DocHandleIncomingCall(&docData);
|
|
|
|
if (retval != NOERROR)
|
|
{
|
|
SET_MSG_STATUS (retval, status);
|
|
|
|
LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem);
|
|
|
|
if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (UINT) hwnd,lp))
|
|
{
|
|
DDEFREE(WM_DDE_ACK,lp);
|
|
goto AdviseErr;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case WM_DDE_UNADVISE:
|
|
{
|
|
hwnd = ConvertToFullHWND(hwndIn);
|
|
intrAssert(IsWindowValid(hwnd));
|
|
lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
|
|
|
|
aItem = HIWORD(lParam);
|
|
ChkC(lpclient);
|
|
if (!IsWindowValid ((HWND)wParam) || lpclient->m_fCallData)
|
|
{
|
|
goto LDeleteAtom;
|
|
}
|
|
docData.hwnd = hwnd;
|
|
docData.msg = msg;
|
|
docData.wParam = wParam;
|
|
docData.aItem = aItem;
|
|
docData.lpclient = lpclient;
|
|
|
|
retval = DocHandleIncomingCall(&docData);
|
|
|
|
if (retval != NOERROR)
|
|
{
|
|
SET_MSG_STATUS (retval, status);
|
|
LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem);
|
|
|
|
if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (UINT) hwnd,lp))
|
|
{
|
|
DDEFREE(WM_DDE_ACK,lp);
|
|
goto LDeleteAtom;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case WM_DDE_REQUEST:
|
|
{
|
|
hwnd = ConvertToFullHWND(hwndIn);
|
|
intrAssert(IsWindowValid(hwnd));
|
|
lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
|
|
|
|
aItem = HIWORD(lParam);
|
|
|
|
ChkC(lpclient);
|
|
if (!IsWindowValid ((HWND) wParam) || lpclient->m_fCallData)
|
|
{
|
|
goto LDeleteAtom;
|
|
}
|
|
docData.hwnd = hwnd;
|
|
docData.msg = msg;
|
|
docData.wParam = wParam;
|
|
docData.lParam = lParam;
|
|
docData.aItem = aItem;
|
|
docData.lpclient = lpclient;
|
|
|
|
retval = DocHandleIncomingCall(&docData);
|
|
if (retval != NOERROR)
|
|
{
|
|
if (retval == RPC_E_DDE_BUSY)
|
|
{
|
|
status = 0x4000;
|
|
}
|
|
else
|
|
{
|
|
status = 0; // negative acknowledge
|
|
}
|
|
|
|
LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem);
|
|
// if request failed, then acknowledge with error.
|
|
if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (UINT) hwnd,lp))
|
|
{
|
|
DDEFREE(WM_DDE_ACK,lp);
|
|
goto LDeleteAtom;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
return SSDefWindowProc (hwndIn, msg, wParam, lParam);
|
|
|
|
}
|
|
|
|
return 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INTERNAL_(void) CDefClient::SendExecuteAck
|
|
(HRESULT hresult)
|
|
{
|
|
AssertIsDoc (this);
|
|
WORD status = NULL;
|
|
SET_MSG_STATUS (hresult, status);
|
|
|
|
m_ExecuteAck.f = FALSE;
|
|
|
|
LPARAM lParam = MAKE_DDE_LPARAM (WM_DDE_ACK,status,
|
|
(UINT) m_ExecuteAck.hdata);
|
|
// Post the acknowledge to the client
|
|
if (!PostMessageToClient (m_ExecuteAck.hwndFrom, WM_DDE_ACK,
|
|
(UINT) m_ExecuteAck.hwndTo, lParam))
|
|
{
|
|
Assert (0);
|
|
// the window either died or post failed, delete the data
|
|
DDEFREE (WM_DDE_ACK,lParam);
|
|
GlobalFree (m_ExecuteAck.hdata);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//DocExecute: Interprets the execute command for the
|
|
//document conversation.
|
|
|
|
|
|
INTERNAL CDefClient::DocExecute
|
|
(HANDLE hdata)
|
|
{
|
|
|
|
ATOM acmd;
|
|
BOOL fShow;
|
|
BOOL fActivate;
|
|
|
|
HANDLE hdup = NULL;
|
|
HRESULT retval = ReportResult(0, S_OOM, 0, 0);
|
|
|
|
LPSTR lpitemname;
|
|
LPSTR lpopt;
|
|
LPSTR lpnextarg;
|
|
LPSTR lpdata = NULL;
|
|
LPSTR lpverb = NULL;
|
|
INT verb;
|
|
WORD wCmdType;
|
|
|
|
ChkC(this);
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"%p _IN CDefClient::DocExecute(hdata=%x)\n",
|
|
this,
|
|
hdata));
|
|
|
|
// !!!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 = UtDupGlobal(hdata,GMEM_MOVEABLE)))
|
|
goto errRtn;
|
|
|
|
if (!(lpdata = (LPSTR)GlobalLock (hdup)))
|
|
goto errRtn;
|
|
|
|
retval = ReportResult(0, RPC_E_DDE_SYNTAX_EXECUTE, 0, 0);
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"%p _IN CDefClient::DocExecute command=(%s)\n",
|
|
this,
|
|
lpdata));
|
|
|
|
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) {
|
|
|
|
#ifdef LATER
|
|
if (lpsrvr = (LPSRVR) GetWindowLong (GetParent (hwnd), 0)) {
|
|
if (!UtilQueryProtocol (lpsrvr->aClass, PROTOCOL_EXECUTE))
|
|
retval = OLE_ERROR_PROTOCOL;
|
|
else {
|
|
#ifdef FIREWALLS
|
|
if (!CheckPointer (lpoledoc, WRITE_ACCESS))
|
|
AssertSz (0, "Invalid LPOLESERVERDOC");
|
|
else if (!CheckPointer (lpoledoc->lpvtbl, WRITE_ACCESS))
|
|
AssertSz (0, "Invalid LPOLESERVERDOCVTBL");
|
|
else
|
|
AssertSz (lpoledoc->lpvtbl->Execute,
|
|
"Invalid pointer to Execute method");
|
|
#endif
|
|
|
|
retval = (*lpoledoc->lpvtbl->Execute) (lpoledoc, hdata);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
AssertSz(0, "Doc level execute is being called");
|
|
|
|
goto errRtn;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// [StdCloseDocument]
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (acmd == aStdClose){
|
|
|
|
LPCLIENT lpclient=NULL;
|
|
// if not terminated by NULL error
|
|
if (*lpnextarg)
|
|
goto errRtn;
|
|
|
|
if ((retval = FindItem (NULL, (LPCLIENT FAR *)&lpclient)) != NOERROR)
|
|
return retval;
|
|
|
|
|
|
lpclient->m_fGotStdCloseDoc = TRUE;
|
|
retval = lpclient->m_lpoleObj->Close (OLECLOSE_SAVEIFDIRTY);
|
|
goto end;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// [StdDoVerbItem("itemname", verb, BOOL, BOOL]
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (acmd == aStdDoVerbItem){
|
|
lpitemname = lpnextarg;
|
|
|
|
if(!(lpverb = ScanArg(lpnextarg)))
|
|
goto errRtn;
|
|
|
|
|
|
if(!(lpnextarg = ScanNumArg(lpverb, &verb)))
|
|
goto errRtn;
|
|
|
|
#ifdef FIREWALLS
|
|
AssertSz (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;
|
|
|
|
if (m_fEmbed)
|
|
{
|
|
// This is a totally bogus call to SetHostNames whose only
|
|
// purpose is to notify the server that this is an embedded
|
|
// (not linked) object.
|
|
if (!m_fDidRealSetHostNames)
|
|
{
|
|
Puts ("Bogus call to SetHostNames before DoVerb\r\n");
|
|
m_lpoleObj->SetHostNames (OLESTR("Container"), OLESTR("Object"));
|
|
}
|
|
}
|
|
// REVIEW: We are assuming that calling the Docdoverb method
|
|
// will not post any more DDE messahes.
|
|
|
|
retval = DocDoVerbItem (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;
|
|
|
|
|
|
}
|
|
|
|
if (m_fEmbed)
|
|
{
|
|
// This is a totally bogus call to SetHostNames whose only
|
|
// purpose is to notify the server that this is an embedded
|
|
// (not linked) object.
|
|
// REVIEW LINK
|
|
if (!m_fDidRealSetHostNames)
|
|
{
|
|
Puts ("Bogus call to SetHostNames before ShowItem\r\n");
|
|
m_lpoleObj->SetHostNames (OLESTR("Container"), OLESTR("Object"));
|
|
}
|
|
}
|
|
|
|
retval = DocShowItem (lpitemname, !fActivate);
|
|
|
|
end:
|
|
errRtn:
|
|
if (lpdata)
|
|
GlobalUnlock (hdup);
|
|
|
|
if (hdup)
|
|
GlobalFree (hdup);
|
|
|
|
intrDebugOut((DEB_ITRACE,
|
|
"%p _OUT CDefClient::DocExecute(hdata=%x) hresult=%x\n",
|
|
this,
|
|
hdata,
|
|
retval));
|
|
|
|
return (HRESULT)retval;
|
|
}
|
|
|
|
|
|
|
|
INTERNAL_(HRESULT) CDefClient::DocShowItem
|
|
(
|
|
LPSTR lpAnsiitemname,
|
|
BOOL fAct
|
|
)
|
|
{
|
|
LPCLIENT lpclient;
|
|
HRESULT retval;
|
|
LPOLEOBJECT lpoleObj;
|
|
|
|
ChkC(this);
|
|
WCHAR lpitemname[MAX_STR];
|
|
|
|
if (MultiByteToWideChar(CP_ACP,0,lpAnsiitemname,-1,lpitemname,MAX_STR) == FALSE)
|
|
{
|
|
Assert(!"Unable to convert characters");
|
|
return(E_UNEXPECTED);
|
|
}
|
|
|
|
if ((retval = FindItem (lpitemname, (LPCLIENT FAR *)&lpclient))
|
|
!= NOERROR)
|
|
return retval;
|
|
|
|
ChkC(lpclient);
|
|
|
|
lpoleObj = lpclient->m_lpoleObj;
|
|
|
|
|
|
#ifdef FIREWALLS1
|
|
if (!CheckPointer (lpoleObj->lpvtbl, WRITE_ACCESS))
|
|
AssertSz (0, "Invalid LPOLEOBJECTVTBL");
|
|
else
|
|
AssertSz (lpoleObj->lpvtbl->DoVerb,
|
|
"Invalid pointer to DoVerb 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->m_lpoleObj->DoVerb(OLEVERB_SHOW, NULL, NULL, NULL, NULL, NULL);
|
|
}
|
|
|
|
|
|
|
|
INTERNAL_(HRESULT) CDefClient::DocDoVerbItem
|
|
(
|
|
LPSTR lpAnsiitemname,
|
|
WORD verb,
|
|
BOOL fShow,
|
|
BOOL fAct
|
|
)
|
|
{
|
|
LPCLIENT lpclient;
|
|
HRESULT retval;
|
|
|
|
WCHAR lpitemname[MAX_STR];
|
|
|
|
if (MultiByteToWideChar(CP_ACP,0,lpAnsiitemname,-1,lpitemname,MAX_STR) == FALSE)
|
|
{
|
|
Assert(!"Unable to convert characters");
|
|
return(E_UNEXPECTED);
|
|
}
|
|
|
|
ChkC(this);
|
|
Puts ("DefClient::DocDoVerbItem\r\n");
|
|
if ((retval = FindItem (lpitemname, (LPCLIENT FAR *)&lpclient))
|
|
!= NOERROR)
|
|
return retval;
|
|
ChkC(lpclient);
|
|
|
|
#ifdef FIREWALLS1
|
|
if (!CheckPointer (lpclient->lpoleObj->lpvtbl, WRITE_ACCESS))
|
|
AssertSz (0, "Invalid LPOLEOBJECTVTBL");
|
|
else
|
|
AssertSz (lpclient->lpoleObj->lpvtbl->DoVerb,
|
|
"Invalid pointer to DoVerb method");
|
|
#endif
|
|
|
|
// pass TRUE to activate and False not to activate. Differnt from
|
|
// protocol.
|
|
|
|
retval = lpclient->m_lpoleObj->DoVerb(verb, NULL, &m_OleClientSite, NULL, NULL, NULL);
|
|
// Apparently an obsolete version of Lotus Notes is the only
|
|
// container (other than Cltest) that sets fShow=FALSE
|
|
if (!fShow && lpclient->m_lpoleObj && lpclient->m_fEmbed)
|
|
lpclient->m_lpoleObj->DoVerb(OLEIVERB_HIDE, NULL, &m_OleClientSite, NULL, NULL, NULL);
|
|
return retval;
|
|
}
|
|
|
|
INTERNAL CDefClient::DoInitNew()
|
|
{
|
|
HRESULT hresult;
|
|
ATOM aClass;
|
|
LPPERSISTSTORAGE pPersistStg=NULL;
|
|
|
|
hresult = m_lpoleObj->QueryInterface(IID_IPersistStorage,
|
|
(LPLPVOID)&pPersistStg);
|
|
if (hresult == NOERROR)
|
|
{
|
|
CLSID clsid;
|
|
RetZ (pPersistStg);
|
|
ErrRtnH (CreateILockBytesOnHGlobal ((HGLOBAL)NULL,
|
|
/*fDeleteOnRelease*/ TRUE,
|
|
&m_plkbytNative));
|
|
ErrZS (m_plkbytNative, E_OUTOFMEMORY);
|
|
|
|
ErrRtnH (StgCreateDocfileOnILockBytes
|
|
(m_plkbytNative,
|
|
grfCreateStg, 0,
|
|
&m_pstgNative));
|
|
|
|
ErrZS (m_pstgNative, E_OUTOFMEMORY);
|
|
|
|
aClass = m_psrvrParent->m_cnvtyp == cnvtypTreatAs ? m_psrvrParent->m_aOriginalClass
|
|
: m_psrvrParent->m_aClass;
|
|
// Write appropriate class tag
|
|
ErrZS (CLSIDFromAtom (aClass,(LPCLSID)&clsid),
|
|
REGDB_E_CLASSNOTREG);
|
|
ErrRtnH (WriteClassStg (m_pstgNative, clsid));
|
|
|
|
// Provide server with a storage to use for its persistent
|
|
// storage, i.e., native data. We remember this IStorage and the
|
|
// ILockBytes it is built on.
|
|
ErrRtnH (pPersistStg->InitNew(m_pstgNative));
|
|
m_fGotEditNoPokeNativeYet = FALSE;
|
|
|
|
// Now that we have initialized the object, we are allowed to
|
|
// set the client site, and advise.
|
|
ErrRtnH (SetClientSite());
|
|
|
|
// This is for Packager, in particular. If client does not advise
|
|
// on any data, we still need to do an OLE advise so we can get
|
|
// OnClose notifications.
|
|
DoOle20Advise (OLE_CLOSED, (CLIPFORMAT)0);
|
|
}
|
|
else
|
|
{
|
|
AssertSz (0, "Can't get IPersistStorage from OleObj\r\n");
|
|
}
|
|
|
|
m_fEmbed = TRUE;
|
|
|
|
errRtn:
|
|
if (pPersistStg)
|
|
pPersistStg->Release();
|
|
return hresult;
|
|
}
|
|
|
|
|
|
// FreePokeData: Frees the poked dats.
|
|
INTERNAL_(void) FreePokeData
|
|
(
|
|
HANDLE hdde
|
|
)
|
|
{
|
|
DDEPOKE FAR * lpdde;
|
|
Puts ("FreePokeData\r\n");
|
|
|
|
if (hdde) {
|
|
if (lpdde = (DDEPOKE FAR *) GlobalLock (hdde)) {
|
|
GlobalUnlock (hdde);
|
|
FreeGDIdata (*(LPHANDLE)lpdde->Value, lpdde->cfFormat);
|
|
}
|
|
|
|
GlobalFree (hdde);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Returns TRUE if GDI format else returns FALSE
|
|
|
|
INTERNAL_(BOOL) FreeGDIdata
|
|
(
|
|
HANDLE hData,
|
|
CLIPFORMAT cfFormat
|
|
)
|
|
{
|
|
Puts ("FreeGDIData\r\n");
|
|
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
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|