summaryrefslogtreecommitdiffstats
path: root/private/ole32/com/remote/dde
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ole32/com/remote/dde
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to '')
-rw-r--r--private/ole32/com/remote/dde/client/cnct_tbl.cxx182
-rw-r--r--private/ole32/com/remote/dde/client/cnct_tbl.h27
-rw-r--r--private/ole32/com/remote/dde/client/daytona/makefile10
-rw-r--r--private/ole32/com/remote/dde/client/daytona/sources83
-rw-r--r--private/ole32/com/remote/dde/client/ddechc.cxx265
-rw-r--r--private/ole32/com/remote/dde/client/ddechc.hxx135
-rw-r--r--private/ole32/com/remote/dde/client/ddecnvrt.cxx348
-rw-r--r--private/ole32/com/remote/dde/client/ddedo.cxx954
-rw-r--r--private/ole32/com/remote/dde/client/ddeioc.cxx213
-rw-r--r--private/ole32/com/remote/dde/client/ddemnker.cxx527
-rw-r--r--private/ole32/com/remote/dde/client/ddeoo.cxx770
-rw-r--r--private/ole32/com/remote/dde/client/ddeproxy.cxx2899
-rw-r--r--private/ole32/com/remote/dde/client/ddeproxy.h608
-rw-r--r--private/ole32/com/remote/dde/client/ddestg.cxx535
-rw-r--r--private/ole32/com/remote/dde/client/ddewnd.cxx363
-rw-r--r--private/ole32/com/remote/dde/client/ddeworkr.cxx1331
-rw-r--r--private/ole32/com/remote/dde/client/dirs37
-rw-r--r--private/ole32/com/remote/dde/client/modallp.cxx201
-rw-r--r--private/ole32/com/remote/dde/client/packmnkr.cxx273
-rw-r--r--private/ole32/com/remote/dde/client/packmnkr.h63
-rw-r--r--private/ole32/com/remote/dde/client/trgt_dev.h19
-rw-r--r--private/ole32/com/remote/dde/dirs36
-rw-r--r--private/ole32/com/remote/dde/server/daytona/makefile10
-rw-r--r--private/ole32/com/remote/dde/server/daytona/sources83
-rw-r--r--private/ole32/com/remote/dde/server/ddeadv.cxx132
-rw-r--r--private/ole32/com/remote/dde/server/ddeatoms.h42
-rw-r--r--private/ole32/com/remote/dde/server/ddedebug.h99
-rw-r--r--private/ole32/com/remote/dde/server/ddeerr.h78
-rw-r--r--private/ole32/com/remote/dde/server/ddeint.h179
-rw-r--r--private/ole32/com/remote/dde/server/ddepack.h20
-rw-r--r--private/ole32/com/remote/dde/server/ddesink.cxx251
-rw-r--r--private/ole32/com/remote/dde/server/ddesite.cxx89
-rw-r--r--private/ole32/com/remote/dde/server/ddesrvr.cxx839
-rw-r--r--private/ole32/com/remote/dde/server/ddesrvr.h26
-rw-r--r--private/ole32/com/remote/dde/server/ddeutils.cxx1015
-rw-r--r--private/ole32/com/remote/dde/server/dirs37
-rw-r--r--private/ole32/com/remote/dde/server/doc.cxx1680
-rw-r--r--private/ole32/com/remote/dde/server/item.cxx1210
-rw-r--r--private/ole32/com/remote/dde/server/item2.cxx1400
-rw-r--r--private/ole32/com/remote/dde/server/itemutil.cxx516
-rw-r--r--private/ole32/com/remote/dde/server/itemutil.h14
-rw-r--r--private/ole32/com/remote/dde/server/srvr.cxx2369
-rw-r--r--private/ole32/com/remote/dde/server/srvr.h522
-rw-r--r--private/ole32/com/remote/dde/server/srvrmain.cxx388
44 files changed, 20878 insertions, 0 deletions
diff --git a/private/ole32/com/remote/dde/client/cnct_tbl.cxx b/private/ole32/com/remote/dde/client/cnct_tbl.cxx
new file mode 100644
index 000000000..bc7200223
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/cnct_tbl.cxx
@@ -0,0 +1,182 @@
+// cnct_tbl.cpp
+//
+// class CConnectionTable
+//
+// CConnectionTable maps connection numbers (as returned by ::Advise())
+// to clipformat's for DDE advise connections.
+
+#include "ddeproxy.h"
+#include "cnct_tbl.h"
+
+ASSERTDATA
+
+#define grfMemFlags (GMEM_MOVEABLE | GMEM_ZEROINIT)
+
+// number of INFO entries to grow by
+#define cinfoBlock 10
+
+typedef struct INFO
+{
+ BOOL fUsed; // is this table entry used?
+ DWORD dwConnection; // search key
+ CLIPFORMAT cf; // corresponding cf, for use in DDE_(UN)ADVISE
+ DWORD grfAdvf; // ON_CHANGE or ON_SAVE or ON_CLOSE
+} INFO, FAR* PINFO;
+
+
+
+CDdeConnectionTable::CDdeConnectionTable ()
+{
+ m_h = GlobalAlloc (grfMemFlags, cinfoBlock * sizeof(INFO));
+ Assert (m_h);
+ m_cinfo=cinfoBlock;
+}
+
+
+CDdeConnectionTable::~CDdeConnectionTable ()
+{
+ Assert(m_h);
+ m_h =GlobalFree (m_h);
+ Assert (m_h==NULL);
+ m_cinfo=0;
+}
+
+
+
+
+INTERNAL CDdeConnectionTable::Add
+ (DWORD dwConnection,
+ CLIPFORMAT cf,
+ DWORD grfAdvf)
+{
+ Start:
+ PINFO rginfo;
+
+ if (NULL==(rginfo = (PINFO) GlobalLock(m_h)))
+ {
+ Puts ("ERROR: CDdeConnectionTable::Add out of memory\n");
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+ // Look for an empty table entry
+ for (DWORD i=0; i<m_cinfo; i++)
+ {
+ if (!rginfo[i].fUsed)
+ {
+ rginfo[i].fUsed = TRUE;
+ rginfo[i].dwConnection = dwConnection;
+ rginfo[i].cf = cf;
+ rginfo[i].grfAdvf = grfAdvf;
+ break;
+ }
+ else
+ {
+ Assert (rginfo[i].dwConnection != dwConnection);
+ }
+ }
+ GlobalUnlock (m_h);
+ if (i==m_cinfo) // if no empty entry found
+ {
+ Puts ("Growing the connection table\n");
+ m_h = GlobalReAlloc (m_h,(m_cinfo += cinfoBlock) * sizeof(INFO),
+ grfMemFlags);
+ if (m_h==NULL)
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ goto Start;
+ }
+ else
+ {
+ return NOERROR;
+ }
+}
+
+
+
+
+INTERNAL CDdeConnectionTable::Subtract
+ (DWORD dwConnection,
+ CLIPFORMAT FAR* pcf, // out parm
+ DWORD FAR* pgrfAdvf) // out parm
+{
+ PINFO rginfo;
+ if (dwConnection==0)
+ {
+ Puts ("CDdeConnectionTable::Subtract called with dwConnection==0\n");
+ return ReportResult(0, E_INVALIDARG, 0, 0);
+ }
+
+ if (NULL==(rginfo = (PINFO) GlobalLock(m_h)))
+ {
+ Assert (0);
+ Puts ("ERROR: CDdeConnectionTable::Subtract out of memory\n");
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ for (DWORD i=0; i<m_cinfo; i++)
+ {
+ if (rginfo[i].fUsed && rginfo[i].dwConnection == dwConnection)
+ {
+ Assert (pcf);
+ *pcf = rginfo[i].cf;
+ Assert (pgrfAdvf);
+ *pgrfAdvf = rginfo[i].grfAdvf;
+ rginfo[i].fUsed = FALSE; // remove this connection
+ GlobalUnlock (m_h);
+ return NOERROR;
+ }
+ }
+ GlobalUnlock (m_h);
+ return ReportResult(0, S_FALSE, 0, 0); // not found
+}
+
+
+
+
+INTERNAL CDdeConnectionTable::Lookup
+ (CLIPFORMAT cf, // search key
+ LPDWORD pdwConnection) // out parm. May be NULL on input
+{
+ PINFO rginfo;
+
+ if (NULL==(rginfo = (PINFO) GlobalLock(m_h)))
+ {
+ Puts ("ERROR: CDdeConnectionTable::Lookup out of memory\n");
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ for (DWORD i=0; i<m_cinfo; i++)
+ {
+ if (rginfo[i].fUsed &&
+ rginfo[i].cf == cf)
+ {
+ if (pdwConnection)
+ *pdwConnection = rginfo[i].dwConnection;
+ GlobalUnlock (m_h);
+ return NOERROR;
+ }
+ }
+ GlobalUnlock (m_h);
+ return ReportResult(0, S_FALSE, 0, 0); // not found
+}
+
+
+
+INTERNAL CDdeConnectionTable::Erase
+ (void)
+{
+ PINFO rginfo;
+ Assert (wIsValidHandle(m_h, NULL));
+ if (NULL==(rginfo = (PINFO) GlobalLock(m_h)))
+ {
+ Puts ("ERROR: CDdeConnectionTable::Lookup out of memory\n");
+ Assert (0);
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ for (DWORD i=0; i<m_cinfo; i++)
+ {
+ rginfo[i].fUsed = FALSE;
+ }
+ GlobalUnlock (m_h);
+ return NOERROR;
+}
+
diff --git a/private/ole32/com/remote/dde/client/cnct_tbl.h b/private/ole32/com/remote/dde/client/cnct_tbl.h
new file mode 100644
index 000000000..656b9ce89
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/cnct_tbl.h
@@ -0,0 +1,27 @@
+// cnct_tbl.h
+
+// CConnectionTable maps connection numbers (as returned by ::Advise())
+// to clipformat's for DDE advise connections.
+
+#ifndef fCnct_tbl_h
+#define fCnct_tbl_h
+
+class FAR CDdeConnectionTable : public CPrivAlloc
+{
+ public:
+ CDdeConnectionTable();
+ ~CDdeConnectionTable();
+
+ INTERNAL Add (DWORD dwConnection, CLIPFORMAT cf, DWORD grfAdvf);
+ INTERNAL Subtract (DWORD dwConnection, CLIPFORMAT FAR* pcf, DWORD FAR* pgrfAdvf);
+ INTERNAL Lookup (CLIPFORMAT cf, LPDWORD pdwConnection);
+ INTERNAL Erase (void);
+
+ private:
+ HANDLE m_h; // handle to the table
+ DWORD m_cinfo; // total number of INFO entries
+};
+
+
+#endif
+
diff --git a/private/ole32/com/remote/dde/client/daytona/makefile b/private/ole32/com/remote/dde/client/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/ole32/com/remote/dde/client/daytona/sources b/private/ole32/com/remote/dde/client/daytona/sources
new file mode 100644
index 000000000..468aff4b2
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/daytona/sources
@@ -0,0 +1,83 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# This is the name of the target built from the source files specified
+# below. The name should include neither the path nor the file extension.
+#
+
+TARGETNAME= ddecli
+
+#
+# This specifies where the target is to be built. A private target of
+# type LIBRARY or DYNLINK should go to obj, whereas a public target of
+# type LIBRARY or DYNLINK should go to $(BASEDIR)\public\sdk\lib.
+#
+
+TARGETPATH= obj
+
+#
+# This specifies the type of the target, such as PROGRAM, DYNLINK, LIBRARY,
+# etc.
+#
+
+TARGETTYPE= LIBRARY
+
+INCLUDES = ..\..\server;..\..\..\..\..\common\daytona;..\..\..\..\..\ih;..\..\..;..\..\..\..\inc;..\..\..\..\idl\daytona;..\..\..\..\class;..\..\..\..\objact;..\..\..\..\..\ole232\inc;..\..\..;
+
+!include ..\..\..\..\..\daytona.inc
+
+C_DEFINES= -DOLE_DDE_NO_GLOBAL_TRACKING=1\
+ $(C_DEFINES) \
+
+
+SOURCES= \
+ ..\cnct_tbl.cxx \
+ ..\ddedo.cxx \
+ ..\ddeioc.cxx \
+ ..\ddemnker.cxx \
+ ..\ddeoo.cxx \
+ ..\ddeproxy.cxx \
+ ..\ddechc.cxx \
+ ..\ddestg.cxx \
+ ..\ddewnd.cxx \
+ ..\ddeworkr.cxx \
+ ..\modallp.cxx \
+ ..\packmnkr.cxx
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+# PRECOMPILED_INCLUDE= ..\headers.cxx
+
+
diff --git a/private/ole32/com/remote/dde/client/ddechc.cxx b/private/ole32/com/remote/dde/client/ddechc.cxx
new file mode 100644
index 000000000..0034b5ef3
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/ddechc.cxx
@@ -0,0 +1,265 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: DdeChC.cxx
+//
+// Contents: CDdeChannelControl implementation for DDE. This
+// implementation requires no instance data, therefore it is
+// intended to be static.
+//
+// Functions:
+//
+// History: 08-May-94 Johann Posch (johannp) Created
+// 10-May-94 KevinRo Made simpler
+// 29-May-94 KevinRo Added DDE Server support
+//
+//--------------------------------------------------------------------------
+#include "ddeproxy.h"
+
+//
+// All threads can use a single instance of this class. Therefore, we
+// provide the following global variable that generates the instance.
+//
+
+CDdeChannelControl g_CDdeChannelControl;
+
+STDMETHODIMP CDdeChannelControl::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
+{
+ if (IsEqualIID(riid, IID_IUnknown)
+// || IsEqualIID(riid, IID_IChannelControl)
+ )
+ {
+ *ppvObj = (IChannelControl *) this;
+ }
+ else
+ {
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP_(ULONG) CDdeChannelControl::Release( THIS )
+{
+ return(1);
+}
+
+STDMETHODIMP_(ULONG) CDdeChannelControl::AddRef( THIS )
+{
+ return 1;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeChannelControl::DispatchCall
+//
+// Synopsis: DispatchCall is called to handle incoming calls.
+//
+// Effects: Dispatches a call to the specified in the DispatchData.
+// This function is the result of a call in OnData(), which
+// processes incoming calls from the OLE 1.0 server.
+//
+// Arguments: [pDispData] -- Points to the dispatch data structure
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-16-94 JohannP Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+STDMETHODIMP CDdeChannelControl::DispatchCall( PDISPATCHDATA pDispData )
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeChannelControl::DispatchCall(%x,pDispData=%x)\n",
+ this,
+ pDispData));
+
+ intrAssert(pDispData != NULL);
+ POLE1DISPATCHDATA pData = (POLE1DISPATCHDATA)pDispData->pData;
+ intrAssert(pData != NULL);
+
+ switch (pData->wDispFunc)
+ {
+ case DDE_DISP_SENDONDATACHANGE: // OnDataChange
+ {
+ PDDEDISPATCHDATA pDData = (PDDEDISPATCHDATA)pDispData->pData;
+ return pDData->pCDdeObject->SendOnDataChange(pDData->iArg);
+ }
+
+ case DDE_DISP_OLECALLBACK: // OleCallBack
+ {
+ PDDEDISPATCHDATA pDData = (PDDEDISPATCHDATA)pDispData->pData;
+ return pDData->pCDdeObject->OleCallBack(pDData->iArg,NULL);
+ }
+
+ //
+ // The server window has an incoming call. Look in dde\server\srvr.cxx
+ //
+ case DDE_DISP_SRVRWNDPROC:
+ return(SrvrDispatchIncomingCall((PSRVRDISPATCHDATA)pDispData->pData));
+ //
+ // This dispatches to a Document window
+ //
+ case DDE_DISP_DOCWNDPROC:
+ return(DocDispatchIncomingCall((PDOCDISPATCHDATA)pDispData->pData));
+
+ default:
+ intrAssert(!"Unknown wDispFunc");
+ }
+ return E_FAIL;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeChannelControl::OnEvent
+//
+// Synopsis: OnEvent should never be called on this channel
+//
+// Effects:
+//
+// Arguments: [pCallData] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-16-94 JohannP Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+STDMETHODIMP CDdeChannelControl::OnEvent( PCALLDATA pCallData )
+{
+ // should be never called
+
+ intrAssert(!"CDdeChannelControl::OnEvent( PCALLDATA pCallData ) not implemented\n");
+ return E_FAIL;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeChannelControl::TransmitCall
+//
+// Synopsis: Transmit the parameters to the server.
+//
+// Effects: This function transmits the pCallData to the server. This
+// may be called multiple times, if a retry is required.
+//
+// A by product of the way the DDE channel was implemented
+// atop existing code is that the existing code may transmit
+// the first round of data on its own. If it does this, it
+// will set the fInitialSend to TRUE. Therefore, if this
+// routine sees the flag as true, it will not send the data,
+// but will set the flag to FALSE for a possible retry later.
+//
+// Arguments: [pCallData] -- Points to the DDE specific call data
+//
+// Requires:
+//
+// Returns: If the Post fails, this function returns E_FAIL
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-16-94 JohannP Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+STDMETHODIMP CDdeChannelControl::TransmitCall( PCALLDATA pCallData )
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeChannelControl::TransmitCall(%x,pCallData=%x)\n",
+ this,
+ pCallData));
+ // reset the event
+ pCallData->Event = 0;
+ pCallData->fDirectedYield = FALSE;
+
+ PDDECALLDATA pDdeCD = (PDDECALLDATA)pCallData->pRpcMsg;
+
+ //
+ // If the routine wPostServerMessage has already posted the
+ // first send, then fInitialSend will be TRUE. In that case,
+ // don't TransmitCall() this time, but reset the flag for
+ // future retries.
+ //
+
+ if (!pDdeCD->fInitialSend)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::TransmitCall(%x) PostMessage(%x,%x,%x,%x)\n",
+ this,
+ pDdeCD->hwndSvr,
+ pDdeCD->wMsg,
+ (WPARAM) pDdeCD->hwndCli,
+ pDdeCD->lParam));
+
+ if(!PostMessage (pDdeCD->hwndSvr,
+ pDdeCD->wMsg,
+ (WPARAM) pDdeCD->hwndCli,
+ pDdeCD->lParam))
+ {
+ return(E_FAIL);
+ }
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::TransmitCall(%x) Already Posted Message\n",
+ this));
+
+ pDdeCD->fInitialSend = FALSE;
+ }
+
+ //
+ // Figure out if we want the call control to do a directed yield.
+ // Do this only if the server is in the same VDM as us.
+ //
+
+
+ if (IsWOWProcess())
+ {
+ DWORD dwPID, dwTID;
+ dwTID = GetWindowThreadProcessId(pDdeCD->hwndSvr, &dwPID);
+
+ if (dwPID == GetCurrentProcessId())
+ {
+ // Make sure we have the right thread id to yield to
+ pCallData->TIDCallee = dwTID;
+
+ // same VDM so do directed yield
+ pCallData->fDirectedYield = TRUE;
+ }
+ }
+
+ return NOERROR;
+}
diff --git a/private/ole32/com/remote/dde/client/ddechc.hxx b/private/ole32/com/remote/dde/client/ddechc.hxx
new file mode 100644
index 000000000..d896f2378
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/ddechc.hxx
@@ -0,0 +1,135 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: DdeChC.cxx
+//
+// Contents: CDdeChannelControl implementation for DDE. This
+// implementation requires no instance data, therefore it is
+// intended to be static.
+//
+// Functions:
+//
+// History: 08-May-94 Johann Posch (johannp) Created
+// 10-May-94 KevinRo Made simpler and commented
+//
+//--------------------------------------------------------------------------
+#ifndef __DDECHC_HXX__
+#define __DDECHC_HXX__
+
+class CDdeObject;
+//
+// The following are the possible callbacks that would be supported by
+// the CDdeObject
+//
+
+typedef enum
+{
+ DDE_DISP_SENDONDATACHANGE = 1,
+ DDE_DISP_OLECALLBACK = 2 ,
+ DDE_DISP_SRVRWNDPROC = 3 ,
+ DDE_DISP_DOCWNDPROC = 4
+} DDE_DISPATCH_FUNC;
+
+
+//
+// The following defines a base class for the OLE 1.0 support
+//
+
+typedef struct tagOLE1DISPATCHDATA
+{
+ DDE_DISPATCH_FUNC wDispFunc;
+}OLE1DISPATCHDATA, *POLE1DISPATCHDATA;
+
+//
+// The following structure is used by OLE 1.0 server support code
+//
+
+typedef struct tagDDEDISPATCHDATA : public CPrivAlloc, public OLE1DISPATCHDATA
+{
+ CDdeObject *pCDdeObject;
+ UINT iArg;
+} DDEDISPATCHDATA, *PDDEDISPATCHDATA;
+
+
+//
+// The following structure is used by the OLE 1.0 client support code
+// to dispatch incoming calls to Execute from the server window.
+//
+
+typedef struct tagSRVRDISPATCHDATA : public OLE1DISPATCHDATA,public CPrivAlloc
+{
+ HWND hwnd;
+ HANDLE hData;
+ HWND wParam;
+ LPSRVR lpsrvr;
+} SRVRDISPATCHDATA, *PSRVRDISPATCHDATA;
+
+INTERNAL SrvrDispatchIncomingCall(PSRVRDISPATCHDATA psdd);
+
+
+//
+// The following structure is used by the OLE 1.0 client support code
+// to dispatch incoming calls to a document window
+//
+
+typedef struct tagDOCDISPATCHDATA : public OLE1DISPATCHDATA,public CPrivAlloc
+{
+ HWND hwnd;
+ ULONG msg;
+ WPARAM wParam;
+ LPARAM lParam;
+ HANDLE hdata; // If already determined, these two hold
+ ATOM aItem; // valid data. All depends on the message
+ LPCLIENT lpclient;
+} DOCDISPATCHDATA, *PDOCDISPATCHDATA;
+
+INTERNAL DocDispatchIncomingCall(PDOCDISPATCHDATA psdd);
+
+
+
+//
+// DDECALLDATA is all the information needed to transmit the outbound call
+// to the server. Since this DDE channel uses PostMessage, the members
+// should look amazingly alot like the parameters to PostMessage.
+//
+// The hwndCli is used for setting callback information.
+// fInitialSend is used by IChannelControl::Transmit().
+//
+typedef struct tagDDECALLDATA : public CPrivAlloc
+{
+ HWND hwndSvr; // Server DDE window
+ WORD wMsg; // Post parameters
+ WPARAM wParam;
+ LPARAM lParam;
+
+ HWND hwndCli; // Handle to client side window
+ BOOL fInitialSend; // True if the first post has been made
+ // already.
+} DDECALLDATA, *PDDECALLDATA;
+
+
+class CDdeChannelControl : public IChannelControl
+{
+ public:
+ // IUnknown methods
+ STDMETHOD (QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHOD_(ULONG,AddRef) ( void );
+ STDMETHOD_(ULONG,Release) ( void );
+
+ // IChannelControl
+ STDMETHOD (DispatchCall)( PDISPATCHDATA );
+ STDMETHOD (OnEvent) ( PCALLDATA );
+ STDMETHOD (TransmitCall)( PCALLDATA );
+};
+
+//
+// All threads can use a single instance of this class. Therefore, we
+// provide the following global variable
+//
+
+extern CDdeChannelControl g_CDdeChannelControl;
+
+#endif // __DDECHC__HXX__
+
diff --git a/private/ole32/com/remote/dde/client/ddecnvrt.cxx b/private/ole32/com/remote/dde/client/ddecnvrt.cxx
new file mode 100644
index 000000000..119c67d15
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/ddecnvrt.cxx
@@ -0,0 +1,348 @@
+
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddecnvrt.cpp
+
+Abstract:
+
+ This module contains the code to read/write PBrush, MSDraw native data
+ formats. This module also contains PBrush native format <->DIbFile stream,
+ and MSDraw native format <-> placeable metafile stream conversion routines.
+
+Author:
+
+ Srini Koppolu (srinik) 06/29/1993
+
+Revision History:
+
+--*/
+
+#ifndef _MAC
+
+
+/************************ FILE FORMATS **********************************
+
+
+Normal Metafile (memory or disk based):
+
+ ------------ ---------------
+ | METAHEADER | Metafile bits |
+ ------------ ---------------
+
+Placeable Metafile:
+
+ --------------------- -----------------
+ | PLACEABLEMETAHEADER | Normal metafile |
+ --------------------- -----------------
+
+Memory Based DIB:
+
+ ------------------ --------------- ----------
+ | BITMAPINFOHEADER | RGBQUAD array | DIB bits |
+ ------------------ --------------- ----------
+
+DIB file format:
+
+ ------------------ ------------------
+ | BITMAPFILEHEADER | Memory based DIB |
+ ------------------ ------------------
+
+Ole10NativeStream Format:
+
+ -------- ----------------------
+ | dwSize | Object's Native data |
+ -------- ----------------------
+
+PBrush Native data format:
+
+ -----------------
+ | Dib File format |
+ -----------------
+
+MSDraw Native data format:
+
+ --------------------- ------------- ------------- -----------------
+ | mapping mode (WORD) | xExt (WORD) | yExt (WORD) | Normal metafile |
+ --------------------- ------------- ------------- -----------------
+
+
+*****************************************************************************/
+
+#include <ole2int.h>
+
+INTERNAL UtGetHMFPICTFromMSDrawNativeStm
+ (LPSTREAM pstm, DWORD dwSize, HANDLE FAR* lphdata)
+{
+ HRESULT error;
+ WORD mfp[3]; // mm, xExt, yExt
+ HMETAFILE hMF = NULL;
+
+ *lphdata = NULL;
+
+ if (error = pstm->Read(mfp, sizeof(mfp), NULL))
+ return error;
+
+ dwSize -= sizeof(mfp);
+
+ if (error = UtGetHMFFromMFStm(pstm, dwSize, FALSE, (void **)&hMF))
+ return error;
+
+ AssertSz(mfp[0] == MM_ANISOTROPIC, "invalid map mode in MsDraw native data");
+
+ if (*lphdata = UtGetHMFPICT(hMF, TRUE, (int) mfp[1], (int) mfp[2]))
+ return NOERROR;
+
+ return ResultFromScode(E_OUTOFMEMORY);
+}
+
+
+INTERNAL UtPlaceableMFStmToMSDrawNativeStm
+ (LPSTREAM pstmPMF, LPSTREAM pstmMSDraw)
+{
+ DWORD dwSize; // size of metafile bits excluding the placeable MF header
+ LONG xExt;
+ LONG yExt;
+ WORD wBuf[5]; // dwSize(DWORD), mm(int), xExt(int), yExt(int)
+ HRESULT error;
+
+ if (error = UtGetSizeAndExtentsFromPlaceableMFStm(pstmPMF, &dwSize,
+ &xExt, &yExt))
+ return error;
+
+ *((DWORD FAR*) wBuf) = dwSize + 3*sizeof(WORD);
+ wBuf[2] = MM_ANISOTROPIC;
+ wBuf[3] = (int) xExt;
+ wBuf[4] = (int) yExt;
+
+ if (error = pstmMSDraw->Write(wBuf, sizeof(wBuf), 0))
+ return error;
+
+ ULARGE_INTEGER ularge_int;
+ ULISet32(ularge_int, dwSize);
+ if ((error = pstmPMF->CopyTo(pstmMSDraw, ularge_int,
+ NULL, NULL)) == NOERROR)
+ StSetSize(pstmMSDraw);
+
+ return error;
+
+}
+
+
+INTERNAL UtDIBFileStmToPBrushNativeStm
+ (LPSTREAM pstmDIBFile, LPSTREAM pstmPBrush)
+{
+ BITMAPFILEHEADER bfh;
+ HRESULT error;
+
+ if (error = pstmDIBFile->Read(&bfh, sizeof(bfh), 0))
+ return error;
+
+ // seek to the begining of the stream
+ LARGE_INTEGER large_int;
+ LISet32( large_int, 0);
+ if (error = pstmDIBFile->Seek(large_int, STREAM_SEEK_SET, 0))
+ return error;
+
+ if (error = pstmPBrush->Write(&(bfh.bfSize), sizeof(DWORD), 0))
+ return error;
+
+ ULARGE_INTEGER ularge_int;
+ ULISet32(ularge_int, bfh.bfSize);
+
+ if ((error = pstmDIBFile->CopyTo(pstmPBrush, ularge_int,
+ NULL, NULL)) == NOERROR)
+ StSetSize(pstmPBrush);
+
+ return error;
+}
+
+
+
+INTERNAL UtContentsStmTo10NativeStm
+ (LPSTORAGE pstg, REFCLSID rclsid, BOOL fDeleteSrcStm, UINT FAR* puiStatus)
+{
+ CLIPFORMAT cf;
+ LPOLESTR lpszUserType = NULL;
+ HRESULT error;
+ LPSTREAM pstmSrc = NULL;
+ LPSTREAM pstmDst = NULL;
+
+ *puiStatus = NULL;
+
+ if (error = ReadFmtUserTypeStg(pstg, &cf, &lpszUserType))
+ return error;
+
+
+ if (! ((cf == CF_DIB && rclsid == CLSID_PBrush)
+ || (cf == CF_METAFILEPICT && rclsid == CLSID_MSDraw))) {
+ error = ResultFromScode(DV_E_CLIPFORMAT);
+ goto errRtn;
+ }
+
+ if (error = pstg->OpenStream(CONTENTS_STREAM, NULL,
+ (STGM_READ|STGM_SHARE_EXCLUSIVE),
+ 0, &pstmSrc)) {
+ *puiStatus |= CONVERT_NOSOURCE;
+
+ // check whether OLE10_NATIVE_STREAM exists
+ if (pstg->OpenStream(OLE10_NATIVE_STREAM, NULL,
+ (STGM_READ|STGM_SHARE_EXCLUSIVE), 0, &pstmDst))
+ *puiStatus |= CONVERT_NODESTINATION;
+ else {
+ pstmDst->Release();
+ pstmDst = NULL;
+ }
+
+ goto errRtn;
+ }
+
+ if (error = OpenOrCreateStream(pstg, OLE10_NATIVE_STREAM, &pstmDst)) {
+ *puiStatus |= CONVERT_NODESTINATION;
+ goto errRtn;
+ }
+
+ if (cf == CF_METAFILEPICT)
+ error = UtPlaceableMFStmToMSDrawNativeStm(pstmSrc, pstmDst);
+ else
+ error = UtDIBFileStmToPBrushNativeStm(pstmSrc, pstmDst);
+
+errRtn:
+ if (pstmDst)
+ pstmDst->Release();
+
+ if (pstmSrc)
+ pstmSrc->Release();
+
+ if (error == NOERROR) {
+ LPOLESTR lpszProgId = NULL;
+ ProgIDFromCLSID(rclsid, &lpszProgId);
+
+ error = WriteFmtUserTypeStg(pstg,
+ RegisterClipboardFormat(lpszProgId),
+ lpszUserType);
+
+ if (lpszProgId)
+ delete lpszProgId;
+ }
+
+ if (error == NOERROR) {
+ if (fDeleteSrcStm)
+ pstg->DestroyElement(CONTENTS_STREAM);
+ } else {
+ pstg->DestroyElement(OLE10_NATIVE_STREAM);
+ }
+
+ if (lpszUserType)
+ delete lpszUserType;
+
+ return error;
+}
+
+
+
+INTERNAL Ut10NativeStmToContentsStm
+ (LPSTORAGE pstg, REFCLSID rclsid, BOOL fDeleteSrcStm)
+{
+ extern CLIPFORMAT cfPBrush;
+ extern CLIPFORMAT cfMSDraw;
+
+ CLIPFORMAT cfOld;
+ CLIPFORMAT cfNew;
+ LPOLESTR lpszUserType = NULL;
+ HRESULT error;
+ LPSTREAM pstmSrc = NULL;
+ LPSTREAM pstmDst = NULL;
+
+
+ if (error = ReadFmtUserTypeStg(pstg, &cfOld, &lpszUserType))
+ return error;
+
+ if (rclsid == CLSID_StaticDib)
+ cfNew = CF_DIB;
+ else if (rclsid == CLSID_StaticMetafile)
+ cfNew = CF_METAFILEPICT;
+ else {
+ AssertSz(FALSE, "Internal Error: this routine shouldn't have been called for this class");
+ return ResultFromScode(E_FAIL);
+ }
+
+ if (cfOld == cfPBrush) {
+ if (cfNew != CF_DIB) {
+ error = ResultFromScode(DV_E_CLIPFORMAT);
+ goto errRtn;
+ }
+ } else if (cfOld == cfMSDraw) {
+ if (cfNew != CF_METAFILEPICT) {
+ error = ResultFromScode(DV_E_CLIPFORMAT);
+ goto errRtn;
+ }
+ } else {
+ // Converted to static object from some class other than PBrush or
+ // MSDraw. The data must be in a proper format in the CONTENTS
+ // stream.
+ return NOERROR;
+ }
+
+ if (error = pstg->OpenStream(OLE10_NATIVE_STREAM, NULL,
+ (STGM_READ|STGM_SHARE_EXCLUSIVE),
+ 0, &pstmSrc))
+ goto errRtn;
+
+ if (error = OpenOrCreateStream(pstg, CONTENTS_STREAM, &pstmDst))
+ goto errRtn;
+
+ DWORD dwSize;
+ if (error = pstmSrc->Read(&dwSize, sizeof(DWORD), NULL))
+ goto errRtn;
+
+ if (cfOld == cfMSDraw) {
+ WORD mfp[3]; // mm, xExt, yExt
+
+ if (error = pstmSrc->Read(mfp, sizeof(mfp), NULL))
+ goto errRtn;
+
+ dwSize -= sizeof(mfp);
+
+ error = UtMFStmToPlaceableMFStm(pstmSrc, dwSize,
+ (LONG) mfp[1], (LONG) mfp[2], pstmDst);
+
+ } else {
+ // The PBrush native data format is DIB File format. So all we got to
+ // do is CopyTo.
+
+ ULARGE_INTEGER ularge_int;
+ ULISet32(ularge_int, dwSize);
+ if ((error = pstmSrc->CopyTo(pstmDst, ularge_int, NULL,
+ NULL)) == NOERROR)
+ StSetSize(pstmDst);
+ }
+
+errRtn:
+ if (pstmDst)
+ pstmDst->Release();
+
+ if (pstmSrc)
+ pstmSrc->Release();
+
+ if (error == NOERROR) {
+ error = WriteFmtUserTypeStg(pstg, cfNew, lpszUserType);
+
+ if (fDeleteSrcStm)
+ pstg->DestroyElement(OLE10_NATIVE_STREAM);
+
+ } else {
+ pstg->DestroyElement(CONTENTS_STREAM);
+ }
+
+ if (lpszUserType)
+ delete lpszUserType;
+
+ return error;
+}
+
+#endif
+
diff --git a/private/ole32/com/remote/dde/client/ddedo.cxx b/private/ole32/com/remote/dde/client/ddedo.cxx
new file mode 100644
index 000000000..b982d6245
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/ddedo.cxx
@@ -0,0 +1,954 @@
+/*
+ddedo.cpp
+DDE Data Object
+
+copyright (c) 1992 Microsoft Corporation
+
+Abstract:
+
+ This module contains the methods for DdeObject::DataObject
+
+Author:
+
+ Jason Fuller (jasonful) 24-July-1992
+
+*/
+
+#include "ddeproxy.h"
+#include <stddef.h>
+#include "trgt_dev.h"
+
+
+#define f10UserModel
+// Should we ignore a request by a 2.0 client to get advise-on-change,
+// so that the user must do an explicit File/Update or File/Close?
+// Probably yes, because:
+// 1) Advise-on-change can be expensive for apps like PaintBrush.
+// 2) It is confusing if the container asks for change updates
+// ONLY on presentation and not on native because when the user
+// closes the server and is asked "Do you want to update?" he'll say no
+// because the picture LOOKS correct even though the container does not
+// have the native data.
+// 3) Excel: if A1 is the first cell you create, changes to other cells
+// will not be sent to the client until you change A1 again.
+// If advises are only sent explicitly, then all the cells extant at that
+// time will be considered part of the object.
+
+
+ASSERTDATA
+
+
+//
+// DataObject methods
+//
+
+STDUNKIMPL_FORDERIVED(DdeObject, DataObjectImpl)
+
+
+static inline INTERNAL_(BOOL) NotEqual
+ (DVTARGETDEVICE FAR* ptd1,
+ DVTARGETDEVICE FAR* ptd2)
+{
+ if (NULL==ptd1 && NULL==ptd2)
+ return FALSE;
+ else if ((ptd1 && !ptd2)
+ || (ptd2 && !ptd1)
+ || (ptd1->tdSize != ptd2->tdSize))
+ {
+ return TRUE;
+ }
+ else
+#ifdef WIN32
+ return 0 != memcmp(ptd1, ptd2, (size_t)ptd1->tdSize);
+#else
+ return 0 != _fmemcmp(ptd1, ptd2, (size_t)ptd1->tdSize);
+#endif
+}
+
+
+
+// GetData
+//
+// The data is copied out of a private cache consisting of
+// DdeObject::m_hNative, DdeObject::m_hPict, and DdeObject::m_hExtra.
+// If the cache is empty, data is requested using WM_DDE_REQUEST.
+// The cache should only be empty before the first DDE_DATA message
+// is received.
+// See DdeObject::KeepData()
+//
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::GetData
+ (LPFORMATETC pformatetcIn,
+ LPSTGMEDIUM pmedium)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetData(%x,pformatetcIn=%x)\n",
+ this,pformatetcIn));
+
+lStart:
+ intrDebugOut((DEB_ITRACE,"::GetData(%x)lStart\n",this));
+
+ LPSTR lpGlobal=NULL;
+ HRESULT hres;
+ VDATEPTROUT (pmedium, STGMEDIUM);
+ pmedium->tymed = TYMED_NULL;
+ pmedium->pUnkForRelease = NULL;
+
+ if ((hres = wVerifyFormatEtc (pformatetcIn)) != NOERROR)
+ {
+ goto exitRtn;
+ }
+
+ hres = E_UNEXPECTED; // assume error unless a clipboard format is found.
+
+ if (DVASPECT_ICON & pformatetcIn->dwAspect)
+ {
+ hres = GetDefaultIcon(m_pDdeObject->m_clsid, NULL, &pmedium->hGlobal);
+ if (hres != NOERROR)
+ {
+ goto exitRtn;
+ }
+ hres = NOERROR;
+ goto lDone;
+ }
+ if (m_pDdeObject->m_fGotCloseData)
+ {
+ // If we already got DDE_DATA on close, don't try requesting more
+ // data. (MSDraw will give a bogus metafile.)
+ hres=OLE_E_NOTRUNNING;
+ goto exitRtn;
+ }
+
+ if (NotEqual (pformatetcIn->ptd, m_pDdeObject->m_ptd))
+ {
+ // If caller is asking for a different target device
+ // (We assume a different pointer points to a different target device)
+
+ if (NOERROR!=m_pDdeObject->SetTargetDevice (pformatetcIn->ptd))
+ {
+ // 1.0 server did not accept target device
+ hres=DATA_E_FORMATETC;
+ goto exitRtn;
+ }
+
+ Assert (hres!=NOERROR); // Must do RequestData with new target device
+ }
+ else
+ {
+ // Pick a member handle (H) to return, based on clipboard format CF.
+ // If caller did not pass in its own medium, we must allocate a new
+ // handle.
+
+
+ #define macro(CF,H) \
+ if (pformatetcIn->cfFormat == CF) { \
+ if (m_pDdeObject->H) { \
+ if (pmedium->tymed == TYMED_NULL) { \
+ intrDebugOut((DEB_ITRACE,"::GetData giving cf==%x hData=%x\n",CF,m_pDdeObject->H)); \
+ pmedium->hGlobal = m_pDdeObject->H; \
+ m_pDdeObject->H = NULL; \
+ } \
+ hres = NOERROR; /* found data in right format */ \
+ } \
+ }
+
+ macro (g_cfNative, m_hNative)
+ else macro (m_pDdeObject->m_cfPict, m_hPict )
+ else macro (m_pDdeObject->m_cfExtra,m_hExtra )
+
+ // If we gave away our picture, we must forget its format.
+ if (pformatetcIn->cfFormat == m_pDdeObject->m_cfPict)
+ m_pDdeObject->m_cfPict = 0;
+ #undef macro
+ }
+
+ if (hres!=NOERROR)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::GetData(%x) posting DDE_REQUEST for cf==%x\n",
+ this,
+ (ULONG)pformatetcIn->cfFormat));
+
+ // Didn't find a handle for the requested format,
+ // or handle was NULL, so request it.
+ // The sequence should be:
+ // GetData -> DDE_REQUEST -> DDE_DATA -> OnData -> return to GetData
+
+ if (hres=m_pDdeObject->RequestData (pformatetcIn->cfFormat) != NOERROR)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::GetData(%x) RequestData returns error %x\n",
+ this,hres));
+
+ hres = DV_E_CLIPFORMAT;
+ goto exitRtn;
+ }
+
+ // By now, a KeepData() should have been done with the right cf,
+ // so try again.
+ intrDebugOut((DEB_ITRACE,
+ "::GetData(%x) KeepData should have been called. Go again\n",
+ this));
+
+ Puts ("KeepData should have been called. Trying GetData again.\n");
+ goto lStart;
+ }
+ lDone:
+ Puts ("pmedium->hGlobal =="); Puth(pmedium->hGlobal); Putn();
+ pmedium->pUnkForRelease = NULL; // Let caller release medium
+ // Must set tymed _after_ the goto loop.
+ // Otherwise it'll be changed the second time around.
+
+ // tell caller what we're returning
+ pmedium->tymed = UtFormatToTymed (pformatetcIn->cfFormat);
+
+
+ intrDebugOut((DEB_ITRACE,
+ "::GetData(%x)tymed=%x cfFormat=%x hGlobal=%x\n",
+ this,
+ pmedium->tymed,
+ (USHORT)pformatetcIn->cfFormat,
+ pmedium->hGlobal));
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "::GetData(%x)hres=%x\n",
+ this,
+ hres));
+ return hres;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::GetDataHere
+ (LPFORMATETC pformatetcIn,
+ LPSTGMEDIUM pmedium)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetDataHere(%x,pformatetcIn=%x)\n",
+ this,
+ pformatetcIn));
+
+ HRESULT hresult = NOERROR;
+ STGMEDIUM medium;
+ if (!(pformatetcIn->tymed & TYMED_HGLOBAL))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::GetDataHere(%x)DV_E_TYMED(%x)\n",
+ this,DV_E_TYMED));
+ // Cannot GetDataHere for GDI objects
+ hresult = DV_E_TYMED;
+ goto exitRtn;
+ }
+ RetErr (GetData (pformatetcIn, &medium));
+ if (medium.tymed != TYMED_HGLOBAL)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::GetDataHere(%x)medium.tymed != TYMED_HGLOBAL\n",
+ this));
+ hresult = ResultFromScode (DV_E_TYMED);
+ goto errRtn;
+ }
+ pmedium->tymed = medium.tymed;
+ pmedium->pUnkForRelease = medium.pUnkForRelease;
+ ErrRtnH (wHandleCopy (pmedium->hGlobal, medium.hGlobal));
+
+ errRtn:
+ ReleaseStgMedium (&medium);
+
+ exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetDataHere(%x) returning %x\n",
+ this,hresult));
+ return hresult;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::QueryGetData
+ (LPFORMATETC pformatetcIn)
+{
+ HRESULT hr;
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDdeObject::QueryGetData(pformatetcIn=%x)\n",
+ this,
+ pformatetcIn));
+
+ hr = wVerifyFormatEtc (pformatetcIn);
+
+ if (hr != NOERROR)
+ {
+ goto exitRtn;
+ }
+ if (pformatetcIn->cfFormat == g_cfEmbeddedObject
+ || pformatetcIn->cfFormat == g_cfEmbedSource
+ || pformatetcIn->cfFormat == g_cfLinkSource
+ || pformatetcIn->cfFormat == g_cfFileName
+ || pformatetcIn->cfFormat == g_cfCustomLinkSource
+ || pformatetcIn->cfFormat == g_cfObjectDescriptor
+ || pformatetcIn->cfFormat == g_cfLinkSrcDescriptor)
+ {
+ hr = S_FALSE;
+ }
+
+ hr = m_pDdeObject->IsFormatAvailable (pformatetcIn);
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDdeObject::QueryGetData returning %x\n",
+ this,hr));
+ return(hr);
+
+}
+
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::SetData
+ (LPFORMATETC pformatetc,
+ STGMEDIUM FAR* pmedium,
+ BOOL fRelease)
+{
+ HANDLE hDdePoke;
+ HRESULT hresult;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDdeObject::SetData(pformatetc=%x)\n",
+ this,
+ pformatetc));
+
+ hresult = wVerifyFormatEtc (pformatetc);
+
+ if (hresult != NOERROR)
+ {
+ goto exitRtn;
+ }
+ intrDebugOut((DEB_ITRACE,
+ "%x ::SetData(pformatetc->cfFormat=%x)\n",
+ this,
+ (ULONG)pformatetc->cfFormat));
+
+ if (pformatetc->dwAspect & DVASPECT_ICON)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "%x ::SetData dwAspect & DVASPECT_ICON\n",
+ this));
+ hresult = DV_E_DVASPECT;
+ goto exitRtn;
+ }
+
+
+ if (pformatetc->ptd != m_pDdeObject->m_ptd)
+ {
+ // If caller is setting with a different target device
+ // (We assume a different pointer points to a different target device)
+
+ if (NOERROR != m_pDdeObject->SetTargetDevice (pformatetc->ptd))
+ {
+ intrDebugOut((DEB_IERROR,
+ "%x ::SetData server did not accept target device\n",
+ this));
+ hresult = DV_E_DVTARGETDEVICE;
+ goto exitRtn;
+ }
+ }
+
+ if (hDdePoke = wPreparePokeBlock (pmedium->hGlobal,
+ pformatetc->cfFormat,
+ m_pDdeObject->m_aClass,
+ m_pDdeObject->m_bOldSvr))
+ {
+ hresult = m_pDdeObject->Poke (m_pDdeObject->m_aItem, hDdePoke);
+ if (fRelease)
+ ReleaseStgMedium (pmedium);
+ goto exitRtn;
+ }
+ else
+ {
+ hresult = E_OUTOFMEMORY;
+ }
+exitRtn:
+
+ intrDebugOut((DEB_ITRACE,"%x _OUT ::SetData returns %x\n",this,hresult));
+ return(hresult);
+
+}
+
+
+
+
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::DAdvise
+ (FORMATETC FAR* pformatetc,
+ DWORD grfAdvf,
+ IAdviseSink FAR* pAdvSink,
+ DWORD FAR* pdwConnection)
+{
+ HRESULT hresult;
+ HRESULT hresLookup;
+ FORMATETC formatetc;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDdeObject::DAdvise(pformatetc=%x,grfAdvf=%x,pAdvSink=%x)\n",
+ this,
+ pformatetc,
+ grfAdvf,
+ pAdvSink));
+
+ VDATEPTROUT (pdwConnection, DWORD);
+ *pdwConnection = 0;
+
+ wNormalize (pformatetc, &formatetc);
+
+ hresult =wVerifyFormatEtc (&formatetc);
+
+ if ( hresult != NOERROR)
+ {
+ goto errRtn;
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "%x ::DAdvise pformatetc->cfFormat=%x\n",
+ this,
+ pformatetc->cfFormat));
+
+ if (NotEqual (formatetc.ptd, m_pDdeObject->m_ptd))
+ {
+ if (NOERROR != m_pDdeObject->SetTargetDevice (formatetc.ptd))
+ {
+ hresult= DV_E_DVTARGETDEVICE;
+ goto errRtn;
+ }
+ }
+
+ hresLookup = m_pDdeObject->m_ConnectionTable.Lookup (formatetc.cfFormat, NULL);
+ if (hresLookup != NOERROR)
+ {
+ // We have not already done a DDE advise for this format
+
+ Puts (" m_iAdvChange = "); Puti (m_pDdeObject->m_iAdvChange); Puts("\n");
+
+ if (m_pDdeObject->m_ulObjType == OT_LINK)
+ {
+ ErrRtnH (m_pDdeObject->AdviseOn (formatetc.cfFormat, ON_CHANGE));
+ ErrRtnH (m_pDdeObject->AdviseOn (formatetc.cfFormat, ON_SAVE));
+ }
+ else
+ {
+ ErrRtnH (m_pDdeObject->AdviseOn (formatetc.cfFormat, ON_SAVE));
+ ErrRtnH (m_pDdeObject->AdviseOn (formatetc.cfFormat, ON_CLOSE));
+ }
+ }
+
+ ErrZS (m_pDdeObject->m_pDataAdvHolder, E_OUTOFMEMORY);
+ hresult = m_pDdeObject->m_pDataAdvHolder->Advise (this, pformatetc, grfAdvf,
+ pAdvSink, pdwConnection);
+
+ m_pDdeObject->m_ConnectionTable.Add (*pdwConnection, formatetc.cfFormat,
+ grfAdvf);
+
+ errRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDdeObject::DAdvise hresult=%x\n",
+ this,
+ hresult));
+ return hresult;
+}
+
+
+
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::DUnadvise
+ (DWORD dwConnection)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::DUnadvise(%x,dwConnection=%x)\n",
+ this,
+ dwConnection));
+
+ CLIPFORMAT cf;
+ HRESULT hres;
+ DWORD grfAdvf;
+
+ // Remove connection from table. Lookup the cf for this connection.
+ if (m_pDdeObject->m_ConnectionTable.Subtract (dwConnection, &cf, &grfAdvf)
+ == NOERROR)
+ {
+ // If there is not another connection that needs this format
+ if (m_pDdeObject->m_ConnectionTable.Lookup (cf, NULL) != NOERROR)
+ {
+ // We did a DDE advise for this connection, so undo it.
+ if (m_pDdeObject->m_ulObjType == OT_LINK)
+ {
+ if (NOERROR != (hres=m_pDdeObject->UnAdviseOn (cf, ON_CHANGE)))
+ {
+ intrDebugOut((DEB_IWARN,
+ "::DUnadvise(%x,dwConnection=%x) ON_CHANGE failed\n",
+ this,
+ dwConnection));
+ }
+ if (NOERROR != (hres=m_pDdeObject->UnAdviseOn (cf, ON_SAVE)))
+ {
+ intrDebugOut((DEB_IWARN,
+ "::DUnadvise(%x,dwConnection=%x) ON_SAVE failed\n",
+ this,
+ dwConnection));
+ }
+ }
+ else
+ {
+ if (NOERROR != (hres=m_pDdeObject->UnAdviseOn (cf, ON_SAVE)))
+ {
+ intrDebugOut((DEB_IWARN,
+ "::DUnadvise(%x,dwConnection=%x) ON_SAVE failed\n",
+ this,
+ dwConnection));
+ }
+ if (NOERROR != (hres=m_pDdeObject->UnAdviseOn (cf, ON_CLOSE)))
+ {
+ intrDebugOut((DEB_IWARN,
+ "::DUnadvise(%x,dwConnection=%x) ON_CLOSE failed\n",
+ this,
+ dwConnection));
+ }
+ }
+ }
+ }
+
+ // Delegate rest of the work to the DataAdviseHolder
+ RetZS (m_pDdeObject->m_pDataAdvHolder, E_OUTOFMEMORY);
+ return m_pDdeObject->m_pDataAdvHolder->Unadvise (dwConnection);
+}
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::EnumDAdvise
+ (THIS_ LPENUMSTATDATA FAR* ppenumAdvise)
+{
+ RetZS (m_pDdeObject->m_pDataAdvHolder, E_OUTOFMEMORY);
+ return m_pDdeObject->m_pDataAdvHolder->EnumAdvise(ppenumAdvise);
+}
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::EnumFormatEtc
+ (DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)
+{
+ return OleRegEnumFormatEtc (m_pDdeObject->m_clsid, dwDirection,
+ ppenumFormatEtc);
+}
+
+
+
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::GetCanonicalFormatEtc
+(LPFORMATETC pformatetc, LPFORMATETC pformatetcOut)
+{
+ VDATEPTROUT (pformatetcOut, FORMATETC);
+ memcpy (pformatetcOut, pformatetc, sizeof (FORMATETC));
+ return ReportResult(0, DATA_S_SAMEFORMATETC, 0, 0);
+ // We must be very conservative and assume data will be different for
+ // every formatetc
+}
+
+
+
+INTERNAL CDdeObject::RequestData
+ (CLIPFORMAT cf)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::RequestData(%x,cf=%x)\n",
+ this,cf));
+
+ LPARAM lparam;
+ RetZ (m_pDocChannel);
+ intrAssert(wIsValidAtom(m_aItem));
+ ATOM aItem = wDupAtom (m_aItem);
+ intrAssert(wIsValidAtom(aItem));
+
+ lparam = MAKE_DDE_LPARAM (WM_DDE_REQUEST,cf, aItem);
+
+ if (!wPostMessageToServer (m_pDocChannel,
+ WM_DDE_REQUEST,
+ lparam,
+ TRUE))
+ {
+
+ if (aItem)
+ GlobalDeleteAtom (aItem);
+
+ return RPC_E_SERVER_DIED;
+ }
+
+ return WaitForReply(m_pDocChannel, AA_REQUEST);
+}
+
+
+// special name
+const char achSpecialName[] = "DISPLAY";
+
+//
+// Return a 1.0 target device for the screen
+//
+
+static INTERNAL DefaultTargetDevice (HANDLE FAR* ph)
+{
+ intrDebugOut((DEB_ITRACE,
+ "DefaultTargetDevice(ph=%x)\n",ph));
+
+ VDATEPTROUT ((LPVOID) ph, HANDLE);
+ LPOLETARGETDEVICE p1=NULL;
+ *ph = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, sizeof (*p1) + 10);
+ RetZS (*ph, E_OUTOFMEMORY);
+ p1 = (LPOLETARGETDEVICE) GlobalLock (*ph);
+ RetZS (p1, E_OUTOFMEMORY);
+ p1->otdDeviceNameOffset = 8;
+ p1->otdDriverNameOffset = 0; // The driver name is at otdData
+ p1->otdPortNameOffset = 9;
+ p1->otdExtDevmodeOffset = 0;
+ p1->otdExtDevmodeSize = 0;
+ p1->otdEnvironmentOffset= 0;
+ p1->otdEnvironmentSize = 0;
+
+ //
+ // Note that memcpy is moving a constant string. Therefore, sizeof()
+ // will include the NULL terminator
+ //
+ //
+ memcpy((LPSTR)p1->otdData, achSpecialName,sizeof(achSpecialName));
+ p1->otdData[8] = 0; // NULL the otdDeviceName
+ p1->otdData[9] = 0; // NULL the PortNameOffset
+ GlobalUnlock (*ph);
+ return NOERROR;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: Convert20TargetDevice
+//
+// Synopsis: Converts a 2.0 TargetDevice into a 1.0 OLETARGETDEVICE
+//
+// Effects: First converts the 2.0 UNICODE target device into ANSI,
+// then converts that into a 1.0 OLETARGETDEVICE. The astute
+// reader would say: Why not just 2.0 UNICODE to OLETARGETDEVICE?
+//
+// Two reasons: time before we ship vs time needed elsewhere.
+//
+// If you can spare some time, please change this to go
+// directly from one to the other.
+//
+// Arguments: [ptd] --
+// [phTD1] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-03-94 kevinro Created
+//
+// Notes:
+//
+// BUGBUG: the NT version of the OLE 1.0 used UINT as the size of the
+// structures members. This was baaaad, since we really need them to be
+// a fixed size. I am currently in the works of changing the NT 1.0 header
+// file to reflect what we really need it to be, which is USHORT's
+//
+//
+// We have a DVTARGETDEVICE, but we want a OLETARGETDEVICE, which looks like
+//
+// typedef struct _OLETARGETDEVICE {
+// USHORT otdDeviceNameOffset;
+// USHORT otdDriverNameOffset;
+// USHORT otdPortNameOffset;
+// USHORT otdExtDevmodeOffset;
+// USHORT otdExtDevmodeSize;
+// USHORT otdEnvironmentOffset;
+// USHORT otdEnvironmentSize;
+// BYTE otdData[1];
+// } OLETARGETDEVICE;
+//
+// A couple things to note:
+//
+// 1) The Names in the OLETARGETDEVICE need to be Ansi
+// 2) The Environment member doens't exist in the DVTARGETDEVICE, and will
+// be created in this conversion
+// 3) The ExtDevmode also needs to be ANSI
+//
+//----------------------------------------------------------------------------
+INTERNAL Convert20TargetDevice
+ (const DVTARGETDEVICE FAR* ptd, // in parm
+ HANDLE FAR* phTD1) // out parm
+{
+ const size_t cbHeader = SIZEOF_DVTARGETDEVICE_HEADER;
+ HRESULT hr;
+ LPOLETARGETDEVICE ptd1 = NULL;
+ size_t cbTD1;
+ size_t cbDevmode;
+ size_t cbOffset;
+ LPDEVMODEA pdevmode;
+
+ intrDebugOut((DEB_ITRACE,
+ "Convert20TargetDevice(ptd=%x)\n",ptd));
+
+ VDATEPTROUT ((LPVOID) phTD1, HANDLE);
+ *phTD1 = NULL;
+
+ //
+ // If no device specified, then return the default
+ //
+
+ if (NULL==ptd)
+ {
+ return DefaultTargetDevice (phTD1);
+ }
+
+ //
+ // Compute information for doing conversion using routines in utils.cpp
+ // The following structure will get the sizes
+ //
+
+ DVTDINFO dvtdInfo;
+
+ hr = UtGetDvtd32Info(ptd,&dvtdInfo);
+
+ if (hr != NOERROR)
+ {
+ return DV_E_DVTARGETDEVICE;
+ }
+
+ //
+ // The conversion routines require us to allocate memory to pass in.
+ //
+
+ DVTARGETDEVICE *pdvtdAnsi = (DVTARGETDEVICE *) PrivMemAlloc(dvtdInfo.cbConvertSize);
+
+ if (pdvtdAnsi == NULL)
+ {
+ return(E_OUTOFMEMORY);
+ }
+
+ //
+ // Convert the UNICODE target device into an ANSI target device
+ //
+
+ hr = UtConvertDvtd32toDvtd16(ptd,&dvtdInfo,pdvtdAnsi);
+
+ if (hr != NOERROR)
+ {
+ goto errRtn;
+ }
+
+ //
+ // pdvtdAnsi now holds an ANSI version of the DVTARGETDEVICE. Turns
+ // out the structure we really want is the DVTARGETDEVICE, plus a
+ // couple of extra header bytes. Therefore, we can just do a block
+ // copy of the DVTARGETDEVICE's data, and fix up our OLETARGETDEVICE
+ // header to have the correct offsets in the data.
+ //
+ // offset of data block from beginning of 2.0 target device
+ //
+ cbOffset = offsetof (DVTARGETDEVICE, tdData);
+
+ //
+ // Calculate a pointer to the DEVMODEA
+ //
+ pdevmode = pdvtdAnsi->tdExtDevmodeOffset ?
+ (LPDEVMODEA)((LPBYTE)pdvtdAnsi + pdvtdAnsi->tdExtDevmodeOffset)
+ : NULL;
+
+ //
+ // Quick sanity check on the resulting pointer.
+ //
+ if (pdevmode && IsBadReadPtr (pdevmode, sizeof(DEVMODEA)))
+ {
+ hr = DV_E_DVTARGETDEVICE;
+ goto errRtn;
+ }
+
+ //
+ // Calculate the size of the devmode part.
+ //
+
+ cbDevmode = (pdevmode ? pdevmode->dmSize + pdevmode->dmDriverExtra:0);
+
+ //
+ // Calculate the total size needed. The DVTARGETDEVICE header has 12 bytes,
+ // and the OLETARGETDEVICE has 14 bytes. We also need to make an extra copy
+ // of the cbDevmode structure to fill in the environment. Therefore, there is
+ // an extra cbDevmode, and a sizeof(USHORT) added to the size. The size includes
+ // the size of the DVTARGETHEADER
+ //
+
+ cbTD1 = (size_t) pdvtdAnsi->tdSize +
+ cbDevmode + // For extra Environment data
+ sizeof (USHORT); // for Environment Size field
+
+ *phTD1 = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, cbTD1);
+ if (NULL== *phTD1)
+ {
+ intrAssert (!"GlobalAlloc Failed");
+ hr = E_OUTOFMEMORY;
+ goto errRtn;
+ }
+
+ ptd1 = (LPOLETARGETDEVICE) GlobalLock (*phTD1);
+ if (NULL== ptd1)
+ {
+ intrAssert (!"GlobalLock Failed");
+ hr = E_OUTOFMEMORY;
+ goto errRtn;
+ }
+
+ // Set x1 (1.0 offset) based on x2 (2.0 offset)
+ //
+ // Note that the OLETARGETDEVICE offsets are relative to the array of bytes,
+ // where the DVTARGETDEVICE is relative to the start of the structure. Thats
+ // why cbOffset is subtracted
+ //
+
+ #define ConvertOffset(x1, x2) (x1 = (x2 ? x2 - cbOffset : 0))
+
+ //
+ // Using the above macro, and assuming
+ //
+
+ ConvertOffset (ptd1->otdDeviceNameOffset, pdvtdAnsi->tdDeviceNameOffset);
+ ConvertOffset (ptd1->otdDriverNameOffset, pdvtdAnsi->tdDriverNameOffset);
+ ConvertOffset (ptd1->otdPortNameOffset , pdvtdAnsi->tdPortNameOffset );
+ ConvertOffset (ptd1->otdExtDevmodeOffset, pdvtdAnsi->tdExtDevmodeOffset);
+ ptd1->otdExtDevmodeSize = cbDevmode;
+
+ //
+ // I found this in the OLE 2 information on OLETARGETDEVICE:
+ //
+ // The otdDeviceNameOffset, otdDriverNameOffset, and otdPortNameOffset
+ // members should be null-terminated. In Windows 3.1, the ability to
+ // connect multiple printers to one port has made the environment
+ // obsolete. The environment information retrieved by the
+ // GetEnvironment function can occasionally be incorrect. To ensure that the
+ // OLETARGETDEVICE structure is initialized correctly, the application
+ // should copy information from the DEVMODEA structure retrieved by a
+ // call to the ExtDeviceMode function to the environment position of
+ // the OLETARGETDEVICE structure.
+ //
+ //
+
+ //
+ // Adjust the environment offset to the end of the converted structure, and
+ // set the size. the sizeof(USHORT) accounts for the addition of the
+ // otdEnvironmentSize field. The offsetof accounts for the fact that the
+ // OLETARGETDEVICE offsets are based from the otdData array.
+ //
+ ptd1->otdEnvironmentOffset = (USHORT) pdvtdAnsi->tdSize +
+ sizeof(USHORT) -
+ offsetof(OLETARGETDEVICE,otdData);
+
+ ptd1->otdEnvironmentSize = cbDevmode;
+
+ // Copy data block
+ if(IsBadWritePtr (ptd1->otdData, (size_t) pdvtdAnsi->tdSize - cbHeader))
+ {
+ hr = E_UNEXPECTED;
+ goto errRtn;
+ }
+ memcpy (ptd1->otdData, pdvtdAnsi->tdData, (size_t) pdvtdAnsi->tdSize - cbHeader);
+
+ if (cbDevmode != 0)
+ {
+ if(IsBadWritePtr (ptd1->otdData, sizeof (DEVMODEA)))
+ {
+ hr = E_UNEXPECTED;
+ goto errRtn;
+ }
+
+ // Copy 2.0 Devmode into 1.0 environment
+
+ memcpy (ptd1->otdData + ptd1->otdEnvironmentOffset,
+ pdvtdAnsi->tdData + pdvtdAnsi->tdExtDevmodeOffset,
+ cbDevmode);
+ }
+
+ hr = NOERROR;
+
+errRtn:
+
+ if (ptd1 != NULL)
+ {
+ GlobalUnlock(*phTD1);
+ }
+
+ if (pdvtdAnsi != NULL)
+ {
+ PrivMemFree(pdvtdAnsi);
+ }
+ intrDebugOut((DEB_ITRACE,
+ "Convert20TargetDevice(ptd=%x) returns %x\n",ptd,hr));
+ return(hr);
+}
+
+
+
+static INTERNAL CopyTargetDevice
+ (const DVTARGETDEVICE FAR* ptd,
+ DVTARGETDEVICE FAR* FAR* pptd)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CopyTargetDevice(ptd=%x)\n",ptd));
+
+ if (*pptd)
+ {
+ delete *pptd; // delete old target device
+ }
+ if (NULL==ptd)
+ {
+ *pptd = NULL;
+ }
+ else
+ {
+ *pptd = (DVTARGETDEVICE FAR*) operator new ((size_t) (ptd->tdSize));
+ if (NULL==*pptd)
+ {
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+ _fmemcpy (*pptd, ptd, (size_t) ptd->tdSize);
+ }
+ return NOERROR;
+}
+
+
+
+INTERNAL CDdeObject::SetTargetDevice
+ (const DVTARGETDEVICE FAR* ptd)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::SetTargetDevice(%x,ptd=%x)\n",
+ this,
+ ptd));
+
+ HANDLE hTD1 = NULL;
+ HANDLE hDdePoke=NULL;
+
+ RetErr (Convert20TargetDevice (ptd, &hTD1));
+
+ Assert (hTD1);
+ Verify (hDdePoke = wPreparePokeBlock (hTD1, g_cfBinary, m_aClass, m_bOldSvr));
+ if (hTD1)
+ {
+ GlobalFree (hTD1);
+ }
+ // Poke new target device to 1.0 server
+ aStdTargetDevice = GlobalAddAtom (L"StdTargetDevice");
+ intrAssert(wIsValidAtom(aStdTargetDevice));
+ RetErr (Poke (aStdTargetDevice, hDdePoke));
+
+ // Remember current target device
+ RetErr (CopyTargetDevice (ptd, &m_ptd));
+ // Flush the cache because it contains a picture for the wrong
+ // target device.
+ if (m_hPict)
+ wFreeData (m_hPict, m_cfPict);
+ m_cfPict = (CLIPFORMAT)0;
+ m_hPict = NULL;
+
+ return NOERROR;
+}
diff --git a/private/ole32/com/remote/dde/client/ddeioc.cxx b/private/ole32/com/remote/dde/client/ddeioc.cxx
new file mode 100644
index 000000000..cb97a244b
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/ddeioc.cxx
@@ -0,0 +1,213 @@
+/*
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddeLink.cpp
+
+Abstract:
+
+ This module contains the DdeObject::OleItemContainer methods
+ and other Link-related code
+
+Author:
+
+ Jason Fuller (jasonful) 19-October-1992
+
+*/
+
+#include "ddeproxy.h"
+// #include <limits.h>
+// #include <utils.h>
+// #include <moniker.h>
+
+
+ASSERTDATA
+
+
+
+STDUNKIMPL_FORDERIVED (DdeObject, OleItemContainerImpl)
+
+
+static INTERNAL_(void) wSkipDelimiter
+ (LPOLESTR * psz)
+{
+ if (wcschr (L"!\"'*+,./:;<=>?@[\\]`|" , **psz))
+ (*psz)++;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::ParseDisplayName
+ (LPBC pbc,
+ LPOLESTR lpszDisplayName,
+ ULONG * pchEaten,
+ LPMONIKER * ppmkOut)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::ParseDisplayName(%x,lpsz=%ws)\n",
+ this,
+ lpszDisplayName));
+
+ LPUNKNOWN pUnk = NULL;
+ VDATEPTROUT(ppmkOut,LPMONIKER);
+ *ppmkOut = NULL;
+ VDATEIFACE(pbc);
+ VDATEPTRIN(lpszDisplayName, char);
+ VDATEPTROUT(pchEaten,ULONG);
+
+ *pchEaten = lstrlenW(lpszDisplayName);
+ wSkipDelimiter (&lpszDisplayName);
+ // Validate the item name
+ RetErr (GetObject (lpszDisplayName, BINDSPEED_INDEFINITE, pbc,
+ IID_IUnknown, (LPLPVOID) &pUnk));
+ if (pUnk)
+ pUnk->Release();
+ return CreateItemMoniker (L"!", lpszDisplayName, ppmkOut);
+}
+
+
+
+STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::EnumObjects
+ (DWORD grfFlags,
+ LPENUMUNKNOWN FAR* ppenumUnk)
+
+{
+ // OLE 1.0 provides no way to enumerate all the items in a document.
+ // This method is unlikely to be called since our implementation of
+ // file and item monikers does not call it.
+ Puts ("OleItemContainer::EnumObjects\r\n");
+ if (ppenumUnk)
+ {
+ *ppenumUnk = NULL;
+ return E_NOTIMPL;
+ }
+
+ return E_INVALIDARG;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::LockContainer
+ (BOOL fLock)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::LockContainer(%x,fLock=%x)\n",
+ this,
+ fLock));
+
+ return NOERROR;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::GetObject
+ (LPOLESTR lpszItem,
+ DWORD dwSpeedNeeded,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID * ppvObject)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetObject(%x,szItem=%ws)\n",
+ this,
+ lpszItem));
+
+
+ HRESULT hresult = NOERROR;
+ VDATEPTROUT (ppvObject, LPVOID);
+ *ppvObject=NULL;
+ LPUNKNOWN pUnk = NULL; // These refer to the
+ CDdeObject FAR* pdde = NULL; // same object
+
+ RetZS (pUnk =CDdeObject::Create (NULL,m_pDdeObject->m_clsid,OT_LINK,
+ m_pDdeObject->m_aTopic,lpszItem,&pdde),
+ E_OUTOFMEMORY);
+
+ // For handling invisible updates--propagate information from document
+ // to item.
+ pdde->DeclareVisibility (m_pDdeObject->m_fVisible);
+ pdde->m_fDidLaunchApp = m_pDdeObject->m_fDidLaunchApp;
+ pdde->m_fDidStdOpenDoc = m_pDdeObject->m_fDidStdOpenDoc;
+
+ intrAssert(wIsValidAtom(pdde->m_aItem));
+ ErrZ (0==lstrcmpW(lpszItem, wAtomName(pdde->m_aItem)));
+
+ // OPTIMIZATION: Could use a mini Running Object Table to map lpszItem to
+ // LPUNKNOWN and avoiding the Connect() and DDE_REQUEST.
+
+ // Open a DocChannel
+ ErrRtnH (pdde->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL));
+
+ // Request Native data in order to see if the item name is valid
+ Assert (pdde->m_pDocChannel);
+ LPARAM lp;
+ if (!wPostMessageToServer (pdde->m_pDocChannel,
+ WM_DDE_REQUEST,
+ lp=MAKE_DDE_LPARAM (WM_DDE_REQUEST,g_cfNative, wDupAtom(pdde->m_aItem)),TRUE))
+ {
+ Assert (pdde->m_refs==1);
+ hresult = ResultFromScode (MK_E_NOOBJECT);
+ goto errRtn;
+ }
+ if (NOERROR != pdde->WaitForReply (pdde->m_pDocChannel, AA_REQUESTAVAILABLE))
+ {
+ // Try metafile. Excel can't render large metafiles
+ // but it can render native.
+ if (!wPostMessageToServer (pdde->m_pDocChannel,
+ WM_DDE_REQUEST,
+ lp=MAKE_DDE_LPARAM (WM_DDE_REQUEST,CF_METAFILEPICT, wDupAtom(pdde->m_aItem)),TRUE))
+ {
+ Assert (pdde->m_refs==1);
+ hresult = ResultFromScode (MK_E_NOOBJECT);
+ goto errRtn;
+ }
+ if (NOERROR != pdde->WaitForReply (pdde->m_pDocChannel, AA_REQUESTAVAILABLE))
+ {
+ Assert (pdde->m_refs==1);
+ hresult = ResultFromScode (MK_E_NOOBJECT);
+ goto errRtn;
+ }
+ }
+
+ // Item name is valid
+ hresult = pdde->m_pUnkOuter->QueryInterface (riid, (LPLPVOID) ppvObject);
+ if (NOERROR==hresult)
+ {
+ m_pDdeObject->m_fDidGetObject = TRUE;
+ }
+ errRtn:
+ if (pUnk)
+ pUnk->Release();
+ return hresult;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::GetObjectStorage
+ (LPOLESTR lpszItem,
+ LPBINDCTX ptc,
+ REFIID riid,
+ LPVOID * ppvStorage)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetObjectStorage(%x,szItem=%ws)\n",
+ this,
+ lpszItem));
+ return MK_E_NOSTORAGE;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::IsRunning
+ (LPOLESTR szItem)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::IsRunning(%x,szItem=%ws)\n",
+ this,
+ szItem));
+
+ // By definition, all items are running
+ return NOERROR;
+}
diff --git a/private/ole32/com/remote/dde/client/ddemnker.cxx b/private/ole32/com/remote/dde/client/ddemnker.cxx
new file mode 100644
index 000000000..2331b02ad
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/ddemnker.cxx
@@ -0,0 +1,527 @@
+/*
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddeLink.cpp
+
+Abstract:
+
+ This module implements:
+ DdeBindToObject
+ DdeIsRunning
+
+Author:
+
+ Jason Fuller (jasonful) 19-October-1992
+
+*/
+#include "ddeproxy.h"
+// #include <ctype.h>
+
+
+INTERNAL DdeBindToObject
+ (LPCOLESTR szFileIn,
+ REFCLSID clsid,
+ BOOL fPackageLink,
+ REFIID iid,
+ LPLPVOID ppv)
+{
+ intrDebugOut((DEB_ITRACE,
+ "DdeBindToObject szFileIn(%ws) fPackageLink(%x)\n",
+ szFileIn,
+ fPackageLink));
+
+
+ LPUNKNOWN punk;
+ *ppv = NULL;
+ CDdeObject FAR* pdde=NULL;
+ HRESULT hresult = E_UNEXPECTED;
+ BOOL fSysConnection = FALSE;
+ WCHAR wszTmpFile [MAX_STR+5];
+
+ //
+ // This protocol doesn't handle the fact that there are two names for
+ // every file. This is a bit of a problem. So, we are going to choose
+ // the short name as the one to look for. This means that DDE objects
+ // using the long filename will not work very well.
+ //
+ WCHAR szFile[MAX_PATH];
+ if ((lstrlenW(szFileIn) == 0) || (GetShortPathName(szFileIn,szFile,MAX_PATH) == 0))
+ {
+ //
+ // Unable to determine a short path for this object. Use whatever we were
+ // handed.
+ //
+ intrDebugOut((DEB_ITRACE,"No conversion for short path. Copy szFileIn\n"));
+ lstrcpyW(szFile,szFileIn);
+ }
+ intrDebugOut((DEB_ITRACE,"Short file szFile(%ws)\n",szFile));
+
+ RetZS (punk=CDdeObject::Create (NULL,clsid,OT_LINK,wGlobalAddAtom(szFile),
+ NULL,&pdde),E_OUTOFMEMORY);
+ RetZ (pdde);
+
+ // Document already running?
+
+ if (NOERROR != (hresult = pdde->DocumentLevelConnect (NULL) ))
+ {
+ if (GetScode (hresult) != S_FALSE)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "DdeBindToObject szFile(%ws) DLC returns %x \n",
+ szFile,hresult));
+ goto exitRtn;
+ }
+
+
+ // If not already running, try to make a sys level connection
+
+ if (!pdde->m_pSysChannel) {
+ if (!pdde->AllocDdeChannel (&pdde->m_pSysChannel, SYS_CLASSA))
+ {
+ intrAssert( !"Out of memory");
+ hresult = E_OUTOFMEMORY;
+ goto exitRtn;
+ }
+ }
+
+ hresult = ReportResult (0, E_UNEXPECTED, 0, 0);
+
+ if (fPackageLink) {
+ lstrcpyW (wszTmpFile, szFile);
+ lstrcatW (wszTmpFile, L"/Link");
+ pdde->SetTopic (wGlobalAddAtom(wszTmpFile));
+ }
+
+ if (pdde->InitSysConv())
+ {
+ fSysConnection = TRUE;
+
+ // Try to make the server open the document
+ ErrRtnH (pdde->PostSysCommand (pdde->m_pSysChannel, (LPSTR)&achStdOpenDocument,FALSE));
+ pdde->m_fDidStdOpenDoc = TRUE;
+
+ }
+ else
+ {
+ // launch the server
+ if (!pdde->LaunchApp())
+ {
+ hresult = CO_E_APPNOTFOUND;
+ goto errRtn;
+ }
+ }
+
+ if (fPackageLink)
+ pdde->SetTopic (wGlobalAddAtom(szFile));
+
+ // Connect to document
+ hresult = pdde->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL);
+ if (hresult != NOERROR)
+ {
+ // Excel does not register its document in time if it loads
+ // startup macros. So we force it to open the document.
+ if (pdde->InitSysConv())
+ {
+ fSysConnection = TRUE;
+ // Try to make the server open the document.
+ ErrRtnH (pdde->PostSysCommand (pdde->m_pSysChannel,
+ (LPSTR)&achStdOpenDocument,
+ FALSE));
+ pdde->m_fDidStdOpenDoc = TRUE;
+ }
+ else
+ {
+ ErrRtnH (ResultFromScode (CO_E_APPDIDNTREG));
+ }
+ // Try connecting to document again. Should succeed.
+ hresult = pdde->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL);
+ }
+ }
+ else
+ {
+ // Already running, so assume visible
+ pdde->DeclareVisibility (TRUE);
+ }
+
+errRtn:
+ if (pdde->m_pSysChannel) {
+ if (fSysConnection)
+ pdde->TermConv (pdde->m_pSysChannel);
+ else
+ pdde->DeleteChannel (pdde->m_pSysChannel);
+ }
+
+ if (hresult == NOERROR) {
+ hresult = punk->QueryInterface (iid, ppv);
+ }
+ pdde->m_pUnkOuter->Release();
+ if (hresult!=NOERROR)
+ {
+ Warn ("DdeBindToObject failed");
+ }
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "DdeBindToObject szFile(%ws) returns %x \n",
+ szFile,hresult));
+
+ return hresult;
+}
+
+
+//
+// BUGBUG: This won't work in a multi-threaded world.
+//
+static LPOLESTR szOriginalUNCName;
+static WCHAR cOriginalDrive;
+
+static INTERNAL InitializeIterator
+ (LPCOLESTR wszFile)
+{
+ WCHAR wszDrive[] = L"A:\\";
+
+ if ((wszFile == NULL) || (wszFile[1] != ':'))
+ {
+ return(S_FALSE);
+ }
+
+ wszDrive[0] = (WCHAR)CharUpperW((LPWSTR)wszFile[0]);
+
+ if (GetDriveType(wszDrive) == DRIVE_REMOTE)
+ {
+
+ DWORD cb = MAX_STR;
+ wszDrive[2] = '\0';
+ if (NULL==szOriginalUNCName)
+ {
+ szOriginalUNCName = new WCHAR [MAX_STR];
+ }
+
+
+ if (WN_SUCCESS == OleWNetGetConnection (wszDrive, szOriginalUNCName, &cb))
+ {
+ cOriginalDrive = (WCHAR)CharUpperW((LPWSTR)wszFile[0]);
+ return NOERROR;
+ }
+ }
+ // szFile is not a network file
+ return ReportResult (0, S_FALSE, 0, 0);
+}
+
+
+
+// NextEquivalentNetDrive
+//
+// Change the drive letter of szFile to the next (modulo 'Z') drive letter
+// that is connected to the same net drive
+// Return S_FALSE when there are no more equivalent drives
+//
+static INTERNAL NextEquivalentNetDrive
+ (LPOLESTR szFile)
+{
+ #define incr(c) (c=='Z' ? c='A' : ++c)
+ WCHAR wszDrive[3]= L"A:";
+ Assert (szFile && szFile[1]==':');
+
+ char cDrive = (char)CharUpperW((LPWSTR)szFile[0]);
+
+ while (cOriginalDrive != incr(cDrive))
+ {
+
+ DWORD cb = MAX_PATH;
+ WCHAR szUNCName [MAX_PATH];
+ wszDrive[0] = cDrive;
+
+ Assert (cDrive >= 'A' && cDrive <= 'Z');
+ Assert (szOriginalUNCName);
+
+ if (WN_SUCCESS == OleWNetGetConnection (wszDrive,szUNCName, &cb) &&
+ (0 == lstrcmpW (szUNCName, szOriginalUNCName)))
+ {
+ szFile[0] = cDrive;
+ return NOERROR;
+ }
+ }
+ // We've gone through all the drives
+ return ReportResult (0, S_FALSE, 0, 0);
+}
+
+
+
+// Dde_IsRunning
+//
+// Attempt to open a document-level conversation using the
+// filename as a topic. If the conversation is established we
+// know the file is running and terminate the conversation.
+// Otherwise it is not running.
+//
+INTERNAL DdeIsRunning
+ (CLSID clsid,
+ LPCOLESTR szFileIn,
+ LPBC pbc,
+ LPMONIKER pmkToLeft,
+ LPMONIKER pmkNewlyRunning)
+{
+ intrDebugOut((DEB_ITRACE,
+ "DdeIsRunning szFileIn(%ws)\n",szFileIn));
+
+ ATOM aTopic;
+ CDdeObject FAR* pdde=NULL;
+ HRESULT hres = ReportResult(0, S_FALSE, 0, 0);
+
+ if (NULL==szFileIn || '\0'==szFileIn[0])
+ {
+ // A NULL filename is invalid for our purposes.
+ // But if we did a DDE_INITIATE, NULL would mean "any topic",
+ // and if we were called by RunningMoniker() with CLSID_NULL,
+ // then we would be INITIATEing on "any app, any topic" and
+ // SHELL (if not others) would respond.
+ intrDebugOut((DEB_ITRACE,
+ "DdeIsRunning NULL szFileIn\n"));
+
+ hres = S_FALSE;
+ goto exitRtn;
+ }
+ //
+ // This protocol doesn't handle the fact that there are two names for
+ // every file. This is a bit of a problem. So, we are going to choose
+ // the short name as the one to look for. This means that DDE objects
+ // using the long filename will not work very well.
+ //
+ WCHAR szFile[MAX_PATH];
+ if ((lstrlenW(szFileIn) == 0) || (GetShortPathName(szFileIn,szFile,MAX_PATH) == 0))
+ {
+ //
+ // Unable to determine a short path for this object. Use whatever we were
+ // handed.
+ //
+ intrDebugOut((DEB_ITRACE,"No conversion for short path. Copy szFileIn\n"));
+ lstrcpyW(szFile,szFileIn);
+ }
+ intrDebugOut((DEB_ITRACE,"Short file szFile(%ws)\n",szFile));
+
+#ifdef KEVINRO_OLDCODE
+
+We have removed SzFixNet from the system, since the file system is
+capable of dealing with UNC names now. Therefore, I have removed the
+following lines. I am pretty sure this is going to work, but I am
+leaving this code here until we decide that it is a good decision.
+If you find this, and I haven't removed it, chances are that I forgot
+to remove this code.
+ HRESULT hresFixNet;
+ UINT dummy;
+
+ // If UNC name, change to drive letter
+ LPOLESTR szFile = NULL;
+ dummy = 0xFFFF;
+
+ hresFixNet = SzFixNet (pbc, szFile, &szFile, &dummy);
+ // SzFixNet may return NOERROR and szFile==NULL
+ if (szFile==NULL || hresFixNet != NOERROR)
+ {
+ aTopic = wGlobalAddAtom(szFile);
+ intrAssert(wIsValidAtom(aTopic));
+ }
+ else
+ {
+ aTopic = wGlobalAddAtom (szFile);
+ intrAssert(wIsValidAtom(aTopic));
+ delete szFile;
+ }
+#else
+ aTopic = wGlobalAddAtom (szFile);
+ intrAssert(wIsValidAtom(aTopic));
+#endif // KEVINRO_OLDCODE
+
+
+ ErrZ (CDdeObject::Create (NULL, clsid, OT_LINK, aTopic, NULL, &pdde));
+
+ if (NOERROR == pdde->DocumentLevelConnect (pbc))
+ {
+ // It is running!
+ // Immediately terminate conversation. We just wanted to know
+ // if it was running.
+ hres = NOERROR;
+ }
+ else
+ {
+ // Not running
+ hres = ReportResult(0, S_FALSE, 0, 0);
+ }
+
+ errRtn:
+
+ if (aTopic)
+ intrAssert(wIsValidAtom(aTopic));
+ GlobalDeleteAtom (aTopic);
+ if (pdde)
+ {
+ Assert (pdde->m_refs==1);
+ pdde->m_pUnkOuter->Release();
+ }
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "DdeIsRunning szFile(%ws) returns %x\n",szFile,hres));
+ return hres;
+}
+
+
+#if 0
+INTERNAL DdeIsRunning
+ (CLSID clsid,
+ LPCSTR cszFile,
+ LPBC pbc,
+ LPMONIKER pmkToLeft,
+ LPMONIKER pmkNewlyRunning)
+{
+ HRESULT hresult = NOERROR;
+ LPSTR szFile = NULL;
+
+ // Normal case
+ if (NOERROR == Dde_IsRunning (clsid, cszFile, pbc, pmkToLeft,
+ pmkNewlyRunning))
+ {
+ return NOERROR;
+ }
+
+ if (cszFile[0]=='\\' && cszFile[1]=='\\')
+ {
+ RetErr (SzFixNet (pbc, (LPSTR)cszFile, &szFile));
+ // Try with a drive letter instead of a UNC name
+ if (NOERROR==Dde_IsRunning (clsid, szFile, pbc, pmkToLeft,
+ pmkNewlyRunning))
+ {
+ hresult = NOERROR;
+ goto errRtn;
+ }
+ }
+ else
+ {
+ szFile = UtDupString (cszFile); // so it can be deleted
+ }
+
+ // If failure, see if the file is running under a different net
+ // drive letter that is mapped to the same drive.
+
+ if (InitializeIterator (szFile) != NOERROR)
+ {
+ // file is probably not on a network drive
+ hresult = ResultFromScode (S_FALSE);
+ goto errRtn;
+ }
+
+ while (NOERROR==NextEquivalentNetDrive (szFile))
+ {
+ if (NOERROR == Dde_IsRunning (clsid, szFile, pbc, pmkToLeft,
+ pmkNewlyRunning))
+ {
+ hresult = NOERROR;
+ goto errRtn;
+ }
+ }
+ // not running
+ hresult = ResultFromScode (S_FALSE);
+
+ errRtn:
+ delete szFile;
+ return hresult;
+}
+#endif
+
+
+
+// CDdeObject::DocumentLevelConnect
+//
+// Try to connect to document (m_aTopic) even if the document is running
+// under a different drive letter that is mapped to the same network drive.
+//
+INTERNAL CDdeObject::DocumentLevelConnect
+ (LPBINDCTX pbc)
+{
+ ATOM aOriginal;
+ ATOM aTopic;
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::DocumentLevelConnect(%x)\n",this));
+ HRESULT hresult = NOERROR;
+
+ // Normal case
+ if (NOERROR==m_ProxyMgr.Connect (IID_NULL, CLSID_NULL))
+ {
+ goto exitRtn;
+ }
+
+
+ WCHAR szFile[MAX_STR];
+ WCHAR szUNCFile[MAX_STR];
+
+ Assert (wIsValidAtom (m_aTopic));
+ if (GlobalGetAtomName (m_aTopic, szFile, MAX_STR) == 0)
+ {
+ hresult = E_UNEXPECTED;
+ goto exitRtn;
+ }
+ aOriginal = wDupAtom (m_aTopic);
+ intrAssert(wIsValidAtom(aOriginal));
+
+ intrDebugOut((DEB_ITRACE,
+ "::DocumentLevelConnect(szFile=%ws)\n",this,szFile));
+ if (NOERROR != InitializeIterator (szFile))
+ {
+ // szFile probably not a network file
+ hresult = ResultFromScode (S_FALSE);
+ goto errRtn;
+ }
+
+ while (NOERROR == NextEquivalentNetDrive (szFile))
+ {
+ SetTopic (aTopic = wGlobalAddAtom (szFile));
+ if (NOERROR==m_ProxyMgr.Connect (IID_NULL, CLSID_NULL))
+ {
+ // Inform client of new drive letter
+ ChangeTopic (wAtomNameA(aTopic));
+ hresult = NOERROR;
+ goto errRtn;
+ }
+ else
+ {
+ SetTopic ((ATOM)0);
+ }
+ }
+
+ // Try with full UNC name
+ lstrcpyW (szUNCFile, szOriginalUNCName);
+ lstrcatW (szUNCFile, szFile+2); // skip X:
+ SetTopic (aTopic = wGlobalAddAtom (szUNCFile));
+ if (NOERROR==m_ProxyMgr.Connect (IID_NULL, CLSID_NULL))
+ {
+ // Inform client of new name
+ ChangeTopic (wAtomNameA(aTopic));
+ hresult = NOERROR;
+ goto errRtn;
+ }
+ else
+ {
+ SetTopic ((ATOM)0);
+ }
+
+ // Not running
+ hresult = S_FALSE;
+
+errRtn:
+ if (NOERROR != hresult)
+ SetTopic (aOriginal);
+ delete szOriginalUNCName;
+ szOriginalUNCName = NULL;
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::DocumentLevelConnect(%x) returns %x\n",
+ this,hresult));
+
+ return hresult;
+}
diff --git a/private/ole32/com/remote/dde/client/ddeoo.cxx b/private/ole32/com/remote/dde/client/ddeoo.cxx
new file mode 100644
index 000000000..491756634
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/ddeoo.cxx
@@ -0,0 +1,770 @@
+/*
+ddeoo.cpp
+DDE Ole Object
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddeoo.cpp
+
+Abstract:
+
+ This module contains the methods for DdeObject::OleObject
+
+Author:
+
+ Jason Fuller (jasonful) 24-July-1992
+
+*/
+
+#include "ddeproxy.h"
+#include <limits.h>
+
+ASSERTDATA
+
+//
+// OleObject methods
+//
+
+STDUNKIMPL_FORDERIVED(DdeObject, OleObjectImpl)
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetClientSite
+ (IOleClientSite FAR* pClientSite)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::SetClientSite(%x,pClientSite=%x)\n",
+ this,
+ pClientSite));
+
+ ChkD (m_pDdeObject);
+
+ if (m_pDdeObject->m_pOleClientSite)
+ m_pDdeObject->m_pOleClientSite->Release();
+
+ // we've decided to keep the pointer that's been passed to us. So we
+ // must AddRef()
+ if (m_pDdeObject->m_pOleClientSite = pClientSite)
+ pClientSite->AddRef();
+
+ // this pointer need not be sent to the server, because we will always
+ // send our &m_MyDataSite as the client site
+ return NOERROR;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetClientSite
+ (IOleClientSite FAR* FAR* ppClientSite)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetClientSite(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+ // we've been asked to give the pointer so we should AddRef()
+ if (*ppClientSite = m_pDdeObject->m_pOleClientSite)
+ m_pDdeObject->m_pOleClientSite->AddRef();
+ return NOERROR;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::EnumVerbs
+ (IEnumOLEVERB FAR* FAR* ppenumOleVerb)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::EnumVerbs(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+ return ReportResult(0, OLE_S_USEREG, 0, 0);
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Update
+( void )
+{
+ HRESULT hr;
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::Update(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+
+ hr = m_pDdeObject->Update(TRUE);
+ if (hr == NOERROR)
+ {
+ hr = m_pDdeObject->Save(m_pDdeObject->m_pstg);
+ }
+
+ return hr;
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::IsUpToDate
+( void )
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::IsUpToDate(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+ // There is no way to know if a 1.0 server has edited its embedded
+ // object, so we assume it has, to be on the safe side.
+ return ResultFromScode (m_pDdeObject->m_ulObjType==OT_EMBEDDED
+ ? S_FALSE : S_OK);
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetUserClassID
+ (CLSID FAR* pClsid)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetUserClassID(%x)\n",
+ this));
+
+ *pClsid = m_pDdeObject->m_clsid;
+ return NOERROR;
+}
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetUserType
+ (DWORD dwFormOfType,
+ LPOLESTR * pszUserType)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetUserType(%x)\n",
+ this));
+
+ return ReportResult (0, OLE_S_USEREG, 0, 0);
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetExtent
+( DWORD dwAspect, LPSIZEL lpsizel)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::SetExtent(%x)\n",
+ this));
+
+ HANDLE hDdePoke;
+ LPRECT16 lprc;
+
+ ChkD (m_pDdeObject);
+ Puts ("OleObject::SetExtent\n");
+ if (!(dwAspect // at least one bit
+ && !(dwAspect & (dwAspect-1)) // exactly one bit
+ && (dwAspect & DVASPECT_CONTENT))) // a bit we support
+ {
+ return ResultFromScode (DV_E_DVASPECT);
+ }
+
+#ifdef OLD
+ m_pDdeObject->m_cxContentExtent = lpsizel->cx;
+ m_pDdeObject->m_cyContentExtent = lpsizel->cy;
+#endif
+
+ if (!m_pDdeObject->m_pDocChannel)
+ {
+ return OLE_E_NOTRUNNING;
+ }
+
+ lprc = (LPRECT16) wAllocDdePokeBlock (sizeof(RECT16), g_cfBinary, &hDdePoke);
+ lprc->left = lprc->right = (SHORT) min(INT_MAX,lpsizel->cx);
+ lprc->top = lprc->bottom= (SHORT) min(INT_MAX,lpsizel->cy);
+ aStdDocDimensions = GlobalAddAtom (OLESTR("StdDocDimensions"));
+ intrAssert(wIsValidAtom(aStdDocDimensions));
+ GlobalUnlock (hDdePoke);
+ return m_pDdeObject->Poke(aStdDocDimensions, hDdePoke);
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetExtent
+( DWORD dwAspect, LPSIZEL lpsizel)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetExtent(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+
+
+#ifdef OLD
+ VDATEPTROUT (lpsizel, SIZEL);
+ if (!(dwAspect // at least one bit
+ && !(dwAspect & (dwAspect-1)) // exactly one bit
+ && !(dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON)))) // a bit we support
+ {
+ return ResultFromScode (DV_E_DVASPECT);
+ }
+
+ if (dwAspect & DVASPECT_CONTENT)
+ {
+ lpsizel->cx = m_pDdeObject->m_cxContentExtent;
+ lpsizel->cy = m_pDdeObject->m_cyContentExtent;
+ }
+
+ return NOERROR;
+#endif
+ return ResultFromScode(E_NOTIMPL);
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::DoVerb
+//
+// Synopsis: Send the server a message asking it to do a verb.
+//
+// Effects: OLE1.0 servers only know how to do a couple of
+// verbs. Specifically, it will respond to PRIMARY,
+// HIDE, OPEN, and SHOW. All others return error
+//
+//
+// Arguments: [iVerb] -- Verb number
+// [lpmsg] -- Window message (ignored)
+// [pActiveSite] -- ActiveSite (ignored)
+// [lindex] -- Index (ignored)
+// [hwndParent] -- (ignored)
+// [lprcPosRect] -- (ignored)
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Created
+//
+// Notes:
+//
+// ANSI ALERT!
+//
+// The server is going to accept a command string from us. This string
+// needs to be done in ANSI, since we are going to pass it to old
+// servers. Therefore, the following code generates an ANSI string
+// The following are the supported verb strings
+//
+// [StdShowItem("aItem",FALSE)]
+// [StdDoVerbItem("aItem",verb,FALSE,FALSE)]
+//
+//----------------------------------------------------------------------------
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::DoVerb
+ (LONG iVerb, LPMSG lpmsg, LPOLECLIENTSITE pActiveSite,
+ LONG lindex, HWND hwndParent, const RECT FAR* lprcPosRect)
+{
+ WORD len;
+ ULONG size;
+ LPSTR lpdata = NULL;
+ LPSTR lpdataStart = NULL;
+ HANDLE hdata = NULL;
+ BOOL bShow;
+ HRESULT hresult;
+
+ ChkD (m_pDdeObject);
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::DoVerb(%x,iVerb=%x,lindex=%x)\n",
+ this,iVerb,lindex));
+
+ if (iVerb < OLEIVERB_HIDE)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::DoVerb(%x)Returning invalid verb\n",
+ this));
+ return OLEOBJ_E_INVALIDVERB;
+ }
+
+
+ if (iVerb == OLEIVERB_HIDE)
+ {
+ intrDebugOut((DEB_ITRACE,"::DoVerb(%x) OLEIVERB_HIDE\n",this));
+
+ if (m_pDdeObject->m_fVisible || OT_LINK==m_pDdeObject->m_ulObjType)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DoVerb(%x) CANNOT_DOVERB_NOW\n",this));
+ return OLEOBJ_S_CANNOT_DOVERB_NOW;
+ }
+
+ intrDebugOut((DEB_ITRACE,"::DoVerb(%x) returns NOERROR\n",this));
+ return NOERROR;
+ }
+
+ //
+ // Calculate the number of bytes needed to pass the
+ // execute command to the server.
+ //
+ if (bShow = (iVerb == OLEIVERB_SHOW
+ || iVerb == OLEIVERB_OPEN
+ || m_pDdeObject->m_bOldSvr))
+ {
+ //
+ // [StdShowItem("aItem",FALSE)]
+ //
+
+ len = 23 + wAtomLenA (m_pDdeObject->m_aItem) + 1;
+
+ }
+ else
+ {
+ // [StdDoVerbItem("aItem",verb,FALSE,FALSE)]
+ len = 32 + 10 /* for verb */ + wAtomLenA (m_pDdeObject->m_aItem) + 1;
+
+ }
+
+ if (!(hdata = GlobalAlloc (GMEM_DDESHARE, size = len)))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DoVerb(%x) cannot alloc %x bytes\n",
+ this,size));
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+
+ if (!(lpdata = (LPSTR)GlobalLock (hdata)))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DoVerb(%x) cannot lock\n",
+ this));
+ GlobalFree (hdata);
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ lpdataStart = lpdata;
+
+
+ strcpy (lpdata, bShow ? "[StdShowItem(\"" : "[StdDoVerbItem(\"");
+ len = strlen (lpdata);
+ lpdata += len;
+
+ // For links
+ if (m_pDdeObject->m_aItem)
+ lpdata += GlobalGetAtomNameA (m_pDdeObject->m_aItem, lpdata, size - len);
+
+ if (!bShow) {
+ wsprintfA (lpdata,"\",%lu,TRUE,FALSE)]", iVerb);
+ } else {
+ strcpy (lpdata, "\")]");
+ // apps like excel and wingraph do not support activate at item level.
+ }
+
+ intrDebugOut((DEB_ITRACE,"::DoVerb(%x)lpdata(%s)\n",this,lpdataStart));
+
+ Assert (strlen(lpdata) < size);
+
+ GlobalUnlock (hdata);
+
+ hresult = m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel, hdata);
+
+ if (NOERROR==hresult)
+ {
+ // Assume doing a verb makes the server visible.
+ // This is not strictly true.
+ m_pDdeObject->DeclareVisibility (TRUE);
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DoVerb(%x)Execute returned %x\n",
+ this,
+ hresult));
+ }
+ return hresult;
+}
+
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::SetHostNames
+//
+// Synopsis: Sets the host names
+//
+// Effects:
+//
+// Arguments: [szContainerApp] -- Name of container app
+// [szContainerObj] -- Name of contained object
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Created
+//
+// Notes:
+// ANSI ALERT!
+//
+// The server is going to accept a command string from us. This string
+// needs to be done in ANSI, since we are going to pass it to old
+// servers. Therefore, the following code generates an ANSI string
+//
+//----------------------------------------------------------------------------
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetHostNames
+(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::SetHostNames(%x,App=%ws,Obj=%ws)\n",
+ this,szContainerApp,szContainerObj));
+
+ WORD cbName;
+ WORD wSize;
+ LPSTR lpBuf;
+ HANDLE hDdePoke;
+
+ ChkD (m_pDdeObject);
+
+ VDATEPTRIN (szContainerApp, char);
+
+ if (!m_pDdeObject->m_pDocChannel)
+ return NOERROR;
+ if (szContainerObj==NULL)
+ szContainerObj=OLESTR("");
+
+ if (szContainerApp[0]=='\0')
+ szContainerApp = OLESTR("Container Application");
+
+ //
+ // The OLE 1.0 server is going to want ANSI strings.
+ // convert the two that we have
+ //
+
+ char pszContainerApp[MAX_STR];
+ char pszContainerObj[MAX_STR];
+
+ if (WideCharToMultiByte(CP_ACP,
+ 0,
+ szContainerApp,
+ -1,
+ pszContainerApp,
+ MAX_STR,
+ NULL,
+ NULL) == FALSE)
+ {
+ intrDebugOut((DEB_ERROR,
+ "::SetHostNames(%x) can't convert szContainerApp(%ws) err=%x\n",
+ this,szContainerApp,GetLastError()));
+
+ //
+ // Couldn't convert string
+ //
+ return(E_UNEXPECTED);
+ }
+ if (WideCharToMultiByte(CP_ACP,
+ 0,
+ szContainerObj,
+ -1,
+ pszContainerObj,
+ MAX_STR,
+ NULL,
+ NULL) == FALSE)
+ {
+ intrDebugOut((DEB_ERROR,
+ "::SetHostNames(%x) can't convert szContainerObj(%ws) err=%x\n",
+ this,szContainerObj,GetLastError));
+
+ //
+ // Couldn't convert string
+ //
+ return(E_UNEXPECTED);
+ }
+
+
+ //
+ // We have found through experience that some OLE applications, like
+ // Clipart, use a fixed size buffer for these names. Therefore, we
+ // are going to limit the sizes of the strings, in case they are
+ // too long to send. We do this by always sticking a NULL at offset
+ // 80 in the file.
+ //
+ pszContainerApp[80]=0;
+ pszContainerObj[80]=0;
+
+ WORD cbObj;
+
+ wSize = (cbName = strlen(pszContainerApp)+1)
+ + (cbObj = strlen(pszContainerObj)+1)
+ + 2 * sizeof(WORD); // for the two offsets
+
+ lpBuf = wAllocDdePokeBlock ((DWORD)wSize, g_cfBinary, &hDdePoke);
+ ((WORD FAR*)lpBuf)[0] = 0;
+ ((WORD FAR*)lpBuf)[1] = cbName;
+ lpBuf += 2*sizeof(WORD);
+ memcpy (lpBuf,pszContainerApp,cbName);
+ memcpy (lpBuf+cbName, pszContainerObj,cbObj);
+ GlobalUnlock (hDdePoke);
+ aStdHostNames = GlobalAddAtom (OLESTR("StdHostNames"));
+ intrAssert(wIsValidAtom(aStdHostNames));
+ m_pDdeObject->Poke(aStdHostNames, hDdePoke);
+ return NOERROR;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Close
+ (DWORD dwSaveOption)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::Close(%x,dwSaveOption=%x)\n",
+ this,dwSaveOption));
+
+
+ ChkDR (m_pDdeObject);
+
+ HRESULT hresult;
+ if (m_pDdeObject->m_fDidSendOnClose)
+ return ResultFromScode (RPC_E_CANTCALLOUT_INASYNCCALL);
+
+ if (((OLECLOSE_SAVEIFDIRTY == dwSaveOption) ||
+ (OLECLOSE_PROMPTSAVE==dwSaveOption)) &&
+ (m_pDdeObject->m_clsid != CLSID_Package))
+ {
+ // Packager gives truncated native data (header info with no
+ // actual embedded file) if you DDE_REQUEST it. Bug 3103
+ Update(); // IOleObject::Update
+ m_pDdeObject->OleCallBack (ON_SAVE,NULL);
+ }
+ RetZ (m_pDdeObject->m_pDocChannel);
+ hresult=m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel,
+ wNewHandle ((LPSTR)&achStdCloseDocument,sizeof(achStdCloseDocument)),
+ TRUE);
+ if (NOERROR==hresult)
+ m_pDdeObject->m_fDidStdCloseDoc = TRUE;
+
+ // Client sends StdCloseDocument. Srvr sends ACK. Srvr may or may not
+ // send Terminate. We may interpret the TERMINATE the server sends
+ // as the reply to ours even if he posted first. But since some servers
+ // post first and others wait for the client, this is what we need to do.
+
+ BOOL fVisible = m_pDdeObject->m_fWasEverVisible; // TermConv clears this flag
+ m_pDdeObject->TermConv (m_pDdeObject->m_pDocChannel);
+ if (!fVisible)
+ m_pDdeObject->MaybeUnlaunchApp();
+
+ return hresult;
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetMoniker
+ (DWORD dwWhichMoniker, LPMONIKER pmk)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::SetMoniker(%x,dwWhichMoniker=%x)\n",
+ this,dwWhichMoniker));
+
+ ChkD (m_pDdeObject);
+ Puts ("OleObject::SetMoniker\r\n");
+ // we ignore this always
+ return NOERROR;
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetMoniker
+ (DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetMoniker(%x,dwWhichMoniker=%x)\n",
+ this,dwWhichMoniker));
+
+ ChkD (m_pDdeObject);
+ if (m_pDdeObject->m_pOleClientSite)
+ return m_pDdeObject->m_pOleClientSite->GetMoniker(dwAssign,
+ dwWhichMoniker, ppmk);
+ else {
+ // no client site
+ *ppmk = NULL;
+ return ReportResult(0, E_UNSPEC, 0, 0);
+ }
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::InitFromData
+ (LPDATAOBJECT pDataObject, BOOL fCreation, DWORD dwReserved)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::InitFromData(%x)\n",
+ this));
+
+ Puts ("OleObject::InitFromData\r\n");
+ return ReportResult(0, E_NOTIMPL, 0, 0);
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetClipboardData
+ (DWORD dwReserved, LPDATAOBJECT FAR* ppDataObject)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetClipboardData(%x)\n",
+ this));
+
+ Puts ("OleObject::GetClipboardData\r\n");
+ return ReportResult(0, E_NOTIMPL, 0, 0);
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Advise
+ (IAdviseSink FAR* pAdvSink,
+ DWORD FAR* pdwConnection)
+{
+ HRESULT hres;
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::Advise(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+ Puts ("OleObject::Advise\n");
+ // Esstablish a DDE advise connection.
+ if (m_pDdeObject->m_ulObjType == OT_EMBEDDED
+ && !m_pDdeObject->m_fDidAdvNative)
+ {
+ // Embedded case.
+ // Always advise on Save and Close.
+ if (hres = m_pDdeObject->AdviseOn (g_cfNative, ON_SAVE))
+ return hres;
+ if (hres = m_pDdeObject->AdviseOn (g_cfNative, ON_CLOSE))
+ return hres;
+ if (m_pDdeObject->m_clsid == CLSID_MSDraw)
+ {
+ // MSDraw has (another) bug. If you do not do an Advise on
+ // presentation, then File.Update does not work, and you
+ // cannot close the app unless you answer "no" to the update
+ // dialog. This would happen when you "Display As Icon"
+ // because ordinarily there is no need to advise on presentation.
+ // The following "unnecessary" advise fixes this problem.
+ if (hres = m_pDdeObject->AdviseOn (CF_METAFILEPICT, ON_SAVE))
+ return hres;
+ if (hres = m_pDdeObject->AdviseOn (CF_METAFILEPICT, ON_CLOSE))
+ return hres;
+ }
+ }
+ else {
+ /* Linked case */
+ if (hres = m_pDdeObject->AdviseOn (g_cfBinary, ON_RENAME))
+ return hres;
+ }
+ RetZS (m_pDdeObject->m_pOleAdvHolder, E_OUTOFMEMORY);
+ return m_pDdeObject->m_pOleAdvHolder->Advise (pAdvSink, pdwConnection);
+}
+
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Unadvise
+ (DWORD dwConnection)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::Unadvise(%x,dwConnection=%x)\n",
+ this,dwConnection));
+
+ HRESULT hres;
+ ChkD (m_pDdeObject);
+
+ // Terminate the DDE advise connection
+ if (m_pDdeObject->m_ulObjType == OT_EMBEDDED)
+ {
+ // Embedded case.
+ if (hres = m_pDdeObject->UnAdviseOn (g_cfNative, ON_SAVE))
+ return hres;
+ if (hres = m_pDdeObject->UnAdviseOn (g_cfNative, ON_CLOSE))
+ return hres;
+ }
+ else
+ {
+ /* Linked case */
+ if (hres = m_pDdeObject->UnAdviseOn (g_cfBinary, ON_RENAME))
+ return hres;
+ }
+ RetZS (m_pDdeObject->m_pOleAdvHolder, E_OUTOFMEMORY);
+ return m_pDdeObject->m_pOleAdvHolder->Unadvise (dwConnection);
+}
+
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::EnumAdvise
+ (THIS_ LPENUMSTATDATA FAR* ppenumAdvise)
+{
+ ChkD (m_pDdeObject);
+ RetZS (m_pDdeObject->m_pOleAdvHolder, E_OUTOFMEMORY);
+ return m_pDdeObject->m_pOleAdvHolder->EnumAdvise(ppenumAdvise);
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetMiscStatus
+ (DWORD dwAspect,
+ DWORD FAR* pdwStatus)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetMiscStatus(%x)\n",
+ this));
+
+ VDATEPTRIN (pdwStatus, DWORD);
+ *pdwStatus = 0L;
+ return ResultFromScode (OLE_S_USEREG);
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetColorScheme
+ (LPLOGPALETTE lpLogpal)
+{
+ HANDLE hDdePoke;
+ LPLOGPALETTE lptmpLogpal;
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::SetColorScheme(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+
+ if (!m_pDdeObject->m_pDocChannel)
+ return NOERROR;
+
+ aStdColorScheme = GlobalAddAtom (OLESTR("StdColorScheme"));
+ intrAssert(wIsValidAtom(aStdColorScheme));
+
+ DWORD dwSize = (lpLogpal->palNumEntries - 1) * sizeof(PALETTEENTRY)
+ + sizeof(LOGPALETTE);
+ lptmpLogpal = (LPLOGPALETTE) wAllocDdePokeBlock (dwSize, g_cfBinary, &hDdePoke);
+ memcpy(lptmpLogpal, lpLogpal, dwSize);
+ GlobalUnlock(hDdePoke);
+
+ return m_pDdeObject->Poke(aStdColorScheme, hDdePoke);
+}
+
+
+
+#ifdef _DEBUG
+STDMETHODIMP_(void) NC(CDdeObject,CDebug)::Dump( IDebugStream FAR * pdbstm)
+{
+}
+
+STDMETHODIMP_(BOOL) NC(CDdeObject,CDebug)::IsValid( BOOL fSuspicious )
+{
+ if( m_pDdeObject->m_refs > 0 && m_pDdeObject->m_chk == chkDdeObj )
+ return TRUE;
+ else
+ return FALSE;
+}
+#endif
diff --git a/private/ole32/com/remote/dde/client/ddeproxy.cxx b/private/ole32/com/remote/dde/client/ddeproxy.cxx
new file mode 100644
index 000000000..f02ee8137
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/ddeproxy.cxx
@@ -0,0 +1,2899 @@
+/*
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddeproxy.cpp
+
+Abstract:
+
+ This module contains the code for the dde proxy (wrapper)
+
+Author:
+
+ Srini Koppolu (srinik) 22-June-1992
+ Jason Fuller (jasonful) 24-July-1992
+*/
+#include "ddeproxy.h"
+#include <tls.h>
+
+DebugOnly (static UINT v_cDdeObjects=0;)
+/*
+ * IMPLEMENTATION of CDdeObject
+ *
+ */
+
+#ifdef OLD
+#define UpdateExtent(old,new) do { if ((long)new!=old) {old=(long)new; } } while (0)
+#endif
+
+//+---------------------------------------------------------------------------
+//
+// Function: CreateDdeClientHwnd
+//
+// Synopsis: Creates a per thread ClientDde window.
+//
+// Effects: This window is created so we can keep a list of windows that
+// need to be cleaned up in the event the thread dies or OLE32 is
+// unloaded. In the case of DLL unload, we will fault if we don't
+// cleanup this window, since user will dispatch messages to
+// non-existant code. The easy way to track these windows is to
+// make them children of a common per thread window.
+//
+// This routine is called by the TLSGetDdeClient() routine to
+// create a window per thread. This window doesn't need to respond
+// to DDE Initiates.
+//
+// Arguments: [void] --
+//
+// Returns: HWND to DdeClientWindow.
+//
+// History: 12-10-94 kevinro Created
+//
+//----------------------------------------------------------------------------
+
+HWND CreateDdeClientHwnd(void)
+{
+ return SSCreateWindowExA(0,"STATIC","DdeClientHwnd",WS_DISABLED,
+ 0,0,0,0,NULL,NULL,hinstSO,NULL);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetDdeCallControlInterface
+//
+// Synopsis: Gets the thread specific instance of the DDE CallControl
+//
+// Effects: If there is already a per thread CallControl interface,
+// AddRef() it and return the value. Otherwise, get one and
+// set it in the TLS data structure. The TLS structure is
+// a global per thread structure that contains various values.
+//
+// Each threads per instance version of the CallControl will
+// be stored in a global place. ReleaseDdeCallControlInterface
+// is used to free up instances of the interface.
+//
+// Arguments: (none)
+//
+// Requires:
+//
+// Returns: Per thread instance of ICallControl. NULL if error
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-13-94 kevinro Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+PCALLCONTROL GetDdeCallControlInterface()
+{
+ PCALLCONTROL pDdeControl = (PCALLCONTROL)TLSGetDdeCallControl();
+
+ if (pDdeControl != NULL)
+ {
+ pDdeControl->AddRef();
+ return(pDdeControl);
+ }
+ //
+ // There wasn't one in the TLS data. Create one, and return it.
+ //
+ ORIGINDATA origindata;
+
+ //
+ // There is a single channel control (static implementation)
+ // for all DDE windows in the process. The hwndCli is set
+ // to NULL, since DDE messages are handled specially by
+ // the MessageFilter code.
+ //
+ origindata.pChCont = (PCHANNELCONTROL)&g_CDdeChannelControl;
+ origindata.CallOrigin = CALLORIGIN_DDE;
+ origindata.hwnd = (HWND)0;
+ origindata.wFirstMsg = WM_DDE_FIRST;
+ origindata.wLastMsg = WM_DDE_LAST;
+
+ if(CoGetCallControl(&origindata, &pDdeControl) == NOERROR)
+ {
+ TLSSetDdeCallControl(pDdeControl);
+ }
+ else
+ {
+ intrAssert(!"Could not CoGetCallControl");
+ pDdeControl = NULL;
+ }
+ return(pDdeControl);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: ReleaseDdeCallControlInterface
+//
+// Synopsis: This function will release the per thread CallControl
+// interface. If the Release() returns zero, then the
+// function will set the per thread instance to NULL.
+//
+// Effects:
+//
+// Arguments: (none)
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-13-94 kevinro Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+void ReleaseDdeCallControlInterface()
+{
+ PCALLCONTROL pDdeControl = (PCALLCONTROL)TLSGetDdeCallControl();
+
+ intrAssert(pDdeControl != NULL);
+#if DBG == 1
+ if (pDdeControl == NULL)
+ {
+ DebugBreak();
+ }
+#endif
+ if ((pDdeControl != NULL) && (pDdeControl->Release() == 0))
+ {
+ TLSSetDdeCallControl(NULL);
+ }
+}
+
+
+// CreateDdeProxy
+//
+// This corresponds to ProxyManager::Create in 2.0
+//
+
+
+INTERNAL_ (LPUNKNOWN) CreateDdeProxy
+ (IUnknown * pUnkOuter,
+ REFCLSID clsid)
+{
+ LPUNKNOWN punk;
+ intrDebugOut((DEB_ITRACE,"CreateDdeProxy(pUnkOuter=%x)\n",pUnkOuter));
+ punk = CDdeObject::Create (pUnkOuter, clsid);
+ intrDebugOut((DEB_ITRACE,
+ "CreateDdeProxy(pUnkOuter=%x) returns %x\n",
+ pUnkOuter,
+ punk));
+ return punk;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::Create
+//
+// Synopsis: Creates a CDdeObject
+//
+// Effects:
+//
+// Arguments: [pUnkOuter] -- Controlling IUnknown
+// [clsid] -- OLE1 ClassID
+// [ulObjType] -- Object type. Optional: def to OT_EMBEDDED
+// [aTopic] -- Atom of link. Optional: def to NULL
+// [szItem] -- String for link object (def to NULL)
+// [ppdde] -- Output pointer to CDdeObject (def to NULL)
+// [fAllowNullClsid] -- Is NULL clsid OK? Default: false
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History:
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL_(LPUNKNOWN) CDdeObject::Create
+ (IUnknown * pUnkOuter,
+ REFCLSID clsid,
+ ULONG ulObjType,// optional, default OT_EMBEDDED
+ ATOM aTopic, // optional, only relevant if ulObjType==OT_LINK
+ LPOLESTR szItem, // optional, only relevant if ulObjType==OT_LINK
+ CDdeObject * * ppdde, // optional, thing created
+ BOOL fAllowNullClsid) // default FALSE
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::Create(%x,ulObjType=%x)\n",
+ pUnkOuter,
+ ulObjType));
+
+ CDdeObject * pDdeObject;
+ static int iTopic=1; // used to make topic names unique
+ WCHAR szTopic[30];
+ Assert (ulObjType==OT_LINK || ulObjType==OT_EMBEDDED);
+
+ Assert (ulObjType != OT_LINK || wIsValidAtom(aTopic));
+ if (ppdde)
+ *ppdde = NULL;
+
+ if (NULL==(pDdeObject = new CDdeObject (pUnkOuter))
+ || NULL == pDdeObject->m_pDataAdvHolder
+ || NULL == pDdeObject->m_pOleAdvHolder)
+ {
+ Assert (!"new CDdeObject failed");
+ return NULL;
+ }
+
+ pDdeObject->m_refs = 1;
+ pDdeObject->m_clsid = clsid;
+ pDdeObject->m_aClass = wAtomFromCLSID(clsid);
+
+#ifdef OLE1INTEROP
+
+ pDdeObject->m_fOle1interop = TRUE;
+
+#endif
+
+ if (ulObjType==OT_LINK)
+ {
+
+ pDdeObject->m_aTopic = wDupAtom (aTopic);
+ pDdeObject->m_aItem = wGlobalAddAtom (szItem);
+ // Never close a linked document
+ pDdeObject->m_fNoStdCloseDoc = TRUE;
+ }
+ else
+ {
+ // This string may actually be visible in the Window Title Bar for a sec.
+ InterlockedIncrement((long *)&iTopic);
+ wsprintf (szTopic,OLESTR("Embedded Object #%u"), iTopic);
+ Assert (lstrlenW(szTopic) < 30);
+ pDdeObject->m_aItem = NULL;
+ pDdeObject->m_aTopic = wGlobalAddAtom (szTopic);
+ }
+ pDdeObject->m_bOldSvr = wIsOldServer (pDdeObject->m_aClass);
+ pDdeObject->m_ulObjType = ulObjType;
+
+ // we can only run if we have a MFI
+ pDdeObject->m_aExeName = wGetExeNameAtom(clsid);
+
+ intrDebugOut((DEB_ITRACE,
+ "::Create(%x,aTopic=%x,aItem=%x,szItem=%ws,aExeName=%x)\n",
+ pDdeObject,
+ pDdeObject->m_aTopic,
+ pDdeObject->m_aItem,
+ szItem?szItem:L"<NULL>",
+ pDdeObject->m_aExeName));
+
+ if (ppdde)
+ *ppdde = pDdeObject;
+ return &pDdeObject->m_Unknown;
+}
+
+
+
+// Constructor
+CDdeObject::CDdeObject (IUnknown * pUnkOuter) :
+ m_Unknown(this),
+ CONSTRUCT_DEBUG
+ m_Data(this),
+ m_Ole(this),
+ m_PersistStg(this),
+ m_ProxyMgr(this),
+ m_OleItemContainer(this)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::CDdeObject(%x)\n",this));
+ if (!pUnkOuter)
+ pUnkOuter = &m_Unknown;
+
+ m_pUnkOuter = pUnkOuter;
+ m_bRunning = FALSE;
+ m_pOleClientSite = NULL;
+ m_pstg = NULL;
+ m_pSysChannel = NULL;
+ m_pDocChannel = NULL;
+ m_bInitNew = NULL;
+ m_hNative = NULL;
+ m_hPict = NULL;
+ m_hExtra = NULL;
+ m_cfExtra = NULL;
+ m_cfPict = 0;
+ m_aItem = NULL;
+ m_iAdvSave = 0;
+ m_iAdvClose = 0;
+ m_iAdvChange = 0;
+ m_fDidAdvNative = FALSE;
+ m_pOleAdvHolder = NULL;
+ m_pDataAdvHolder = NULL;
+ m_fDidSendOnClose = FALSE;
+ m_fNoStdCloseDoc = FALSE;
+ m_fDidStdCloseDoc = FALSE;
+ m_fDidStdOpenDoc = FALSE;
+ m_fDidGetObject = FALSE;
+ m_fDidLaunchApp = FALSE;
+ m_fUpdateOnSave = TRUE;
+ m_fVisible = FALSE;
+ m_fWasEverVisible = FALSE;
+ m_fCalledOnShow = FALSE;
+ m_fGotCloseData = FALSE;
+ m_cLocks = 1; // connections are initially locked
+ m_chk = chkDdeObj;
+ m_ptd = NULL;
+ m_fDoingSendOnDataChange = FALSE;
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ _DelayDelete = NoDelay;
+#endif // _CHICAGO_
+
+ CreateOleAdviseHolder (&m_pOleAdvHolder);
+ Assert (m_pOleAdvHolder);
+ CreateDataAdviseHolder (&m_pDataAdvHolder);
+ Assert (m_pDataAdvHolder);
+
+#ifdef OLD
+ m_cxContentExtent = 2000; // 2 centimeters , totally random default
+ m_cyContentExtent = 2000;
+#endif
+
+ m_wTerminate = Terminate_None;
+
+ DebugOnly (v_cDdeObjects++;)
+ Putsi (v_cDdeObjects);
+}
+
+
+
+CDdeObject::~CDdeObject
+ (void)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::~CDdeObject(%x)\n",this));
+
+ if (m_pDocChannel)
+ {
+ intrDebugOut((DEB_IWARN , "Abnormal situation: Doc Channel not deleted. Server died?"));
+ delete m_pDocChannel;
+ }
+ if (m_pSysChannel)
+ {
+ Warn ("Abnormal situation: Sys Channel not deleted. Server died?");
+ delete m_pSysChannel;
+ }
+ if (m_hNative)
+ {
+ GlobalFree(m_hNative);
+ }
+
+ if (m_hPict)
+ {
+ wFreeData (m_hPict, m_cfPict, TRUE);
+ }
+
+ if (m_hExtra)
+ {
+ wFreeData (m_hExtra, m_cfExtra, TRUE);
+ }
+
+ // release all the pointers that we remember
+
+ if (m_pOleClientSite)
+ {
+ DeclareVisibility (FALSE);
+ m_pOleClientSite->Release();
+ }
+
+ if (m_pDataAdvHolder)
+ m_pDataAdvHolder->Release();
+
+ if (m_pOleAdvHolder)
+ m_pOleAdvHolder->Release();
+
+ if (m_pstg)
+ m_pstg->Release();
+
+ if (m_aExeName)
+ GlobalDeleteAtom (m_aExeName);
+
+ if (m_aClass)
+ GlobalDeleteAtom (m_aClass);
+
+ if (m_aTopic)
+ GlobalDeleteAtom (m_aTopic);
+
+ if (m_aItem)
+ GlobalDeleteAtom (m_aItem);
+
+ if (m_ptd)
+ delete m_ptd;
+
+ m_chk = 0;
+ DebugOnly (v_cDdeObjects--;)
+ Putsi (v_cDdeObjects);
+}
+
+
+
+
+// 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.
+
+
+INTERNAL_(void) CDdeObject::OnInitAck (LPDDE_CHANNEL pChannel, HWND hwndSvr)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::OnInitAck(%x,hwndSvr=%x)\n",this,hwndSvr));
+#ifdef _MAC
+#else
+ if (!IsWindow (hwndSvr))
+ {
+ Assert (0);
+ return;
+ }
+ if (pChannel->hwndSvr) { // if we already have a handle
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::OnInitAck(%x,hwndSvr=%x) Already have hwndSvr=%x\n",
+ this,
+ hwndSvr,
+ pChannel->hwndSvr));
+ // just take the very first one. Direct post is OK
+ MPostWM_DDE_TERMINATE(hwndSvr,pChannel->hwndCli);
+ // Expect an extra WM_DDE_TERMINATE
+ ++pChannel->iExtraTerms;
+ } else {
+ // this is the server we want
+ pChannel->hwndSvr = hwndSvr;
+ pChannel->iExtraTerms = NULL;
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::OnInitAck(%x,hwndSvr=%x) Established Connection\n",
+ this,
+ hwndSvr,
+ pChannel->hwndSvr));
+ }
+#endif _MAC
+}
+
+INTERNAL_(BOOL) CDdeObject::OnAck (LPDDE_CHANNEL pChannel, LONG lParam)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::OnAck(%x,lParam=%x)\n",this,lParam));
+
+ BOOL retval = TRUE;
+ ATOM aItem;
+ WORD wStatus;
+ HANDLE hData;
+
+ if( pChannel->iAwaitAck == AA_EXECUTE)
+ {
+ wStatus = GET_WM_DDE_EXECACK_STATUS( NULL, lParam );
+ hData = GET_WM_DDE_EXECACK_HDATA( NULL, lParam );
+ }
+ else
+ {
+ wStatus = GET_WM_DDE_ACK_STATUS( NULL, lParam );
+ aItem = GET_WM_DDE_ACK_ITEM( NULL, lParam );
+ }
+
+
+ // check for busy bit
+ if (wStatus & 0x4000)
+ {
+ // we got busy from the server.
+ pChannel->fRejected = TRUE;
+ // tell the wait loop that we got a busy ack
+ //CoSetAckState(pChannel->pCI , FALSE,TRUE, SERVERCALLEX_RETRYLATER);
+ intrDebugOut((DEB_ITRACE,"::OnAck(%x) Busy SetCallState(SERVERCALLEX_RETRYLATER)\n",this));
+ pChannel->pCallCont->SetCallState(pChannel->pCD, SERVERCALLEX_RETRYLATER, NOERROR);
+ return TRUE;
+ }
+
+ // just reset the flag always
+ m_wTerminate = Terminate_None;
+
+ intrDebugOut((DEB_ITRACE,
+ "::OnAck(%x)aItem=%x(%ws) wStatus=\n",
+ this,
+ aItem,
+ wAtomName(aItem),
+ wStatus));
+
+ if (pChannel->iAwaitAck == AA_EXECUTE)
+ {
+ GlobalFree (hData);
+ pChannel->hCommands = NULL;
+ }
+ else
+ {
+ if (hData)
+ GlobalDeleteAtom ((ATOM)hData);
+ }
+
+
+ // even if the client got terminate we have to go thru this path.
+
+ if (pChannel->wTimer) {
+ KillTimer (pChannel->hwndCli, 1);
+ pChannel->wTimer = 0;
+ }
+
+
+ if (pChannel->iAwaitAck == AA_POKE)
+ // We have to free the data first. OnAck can trigger
+ // another Poke (like pokehostnames)
+ wFreePokeData (pChannel, (m_bOldSvr && m_aClass==aMSDraw));
+
+
+ if (!(wStatus & POSITIVE_ACK))
+ {
+ intrDebugOut((DEB_ITRACE,"::OnAck(%x) OnAck got an ack with fAck==FALSE.\n",this));
+
+ // A negative ack is OK when doing a temporary advise from
+ // IsFormatAvailable(). Also, apps don't seem to positively
+ // ack all unadvises.
+
+ // review: johannp : this is the case were have to inform the reply rejected call
+
+ retval = FALSE;
+ // we got the ack and can leave the wait loop
+ //CoSetAckState(pChannel->pCI, FALSE);
+
+ intrDebugOut((DEB_ITRACE,
+ "::OnAck(%x) ***_ NACK _*** SetCallState(ISHANDLED,RPC_E_DDE_NACK)\n",
+ this));
+
+ pChannel->pCallCont->SetCallState(pChannel->pCD, SERVERCALLEX_ISHANDLED, RPC_E_DDE_NACK);
+
+ // MSDraw frees hOptions even on a NACK, despite official DDE rules.
+ if (pChannel->iAwaitAck == AA_ADVISE && m_clsid != CLSID_MSDraw)
+ GlobalFree (pChannel->hopt);
+ }
+ else
+ {
+ // we got the ack and can leave the wait loop
+ // CoSetAckState(pChannel->pCI, FALSE);
+ intrDebugOut((DEB_ITRACE,
+ "::OnAck(%x) POSITIVE_ACK SetCallState(SERVERCALLEX_ISHANDLED)\n",
+ this));
+ pChannel->pCallCont->SetCallState(pChannel->pCD, SERVERCALLEX_ISHANDLED, NOERROR);
+ }
+
+ pChannel->hopt = NULL;
+ pChannel->iAwaitAck = NULL;
+ return retval;
+
+}
+
+
+
+
+
+INTERNAL_(void) CDdeObject::OnTimer (LPDDE_CHANNEL pChannel)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::OnTimer(%x)\n",this));
+ // Since there is only one timer for each client, just
+ // repost the message and delete the timer.
+#ifdef _MAC
+#else
+ KillTimer (pChannel->hwndCli, 1);
+ pChannel->wTimer = 0;
+
+ if (wPostMessageToServer(pChannel, pChannel->wMsg, pChannel->lParam,FALSE))
+ return ;
+
+ // Postmessage failed. We need to getback to the main stream of
+ // commands for the object.
+ OnAck (pChannel, pChannel->lParam);
+#endif _MAC
+}
+
+
+
+// Called when we get a WM_DDE_DATA message in reponse to
+// a DDE_REQUEST we sent to check if a format is available.
+//
+INTERNAL CDdeObject::OnDataAvailable
+ (LPDDE_CHANNEL pChannel,
+ HANDLE hDdeData,
+ ATOM aItem)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::OnDataAvailable(%x)\n",this));
+ CLIPFORMAT cf;
+ Assert (AA_REQUESTAVAILABLE == pChannel->iAwaitAck);
+ intrAssert( wIsValidAtom(aItem));
+
+ DDEDATA * pDdeData = (DDEDATA *) GlobalLock (hDdeData);
+ RetZS (pDdeData, E_OUTOFMEMORY);
+ if (!pDdeData->fAckReq && aItem)
+ {
+ GlobalDeleteAtom (aItem);
+ }
+ cf = pDdeData->cfFormat;
+ GlobalUnlock (hDdeData);
+ wFreeData (wHandleFromDdeData (hDdeData), cf);
+ return NOERROR;
+}
+
+
+
+// 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.
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::OnData
+//
+// Synopsis: Called when a WM_DDE_DATA message is recieved. If the data
+// is from an ADVISE_ON_CLOSE, and there are no more
+// outstanding ADVISE_ON_CLOSE request, close the document
+// and end the conversation.
+//
+// Effects: The effects of this routine are complex.
+//
+// Wow! What else can be said. This routine does alot of stuff in response
+// to an incoming WM_DDE_DATA message. There are basically two flavors of
+// response here. First is when we were expecting to get this result,
+// in which case we know what we wanted to do with the data. Second is
+// when the data just arrives, but we didn't expect it. These cases could
+// indicate that the server is shutting down.
+//
+//
+// Arguments: [pChannel] -- The DDE channel recieving the message
+// [hDdeData] -- Handle to the data
+// [aItem] -- Atom to the item
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-16-94 kevinro Restructured and commented
+//
+// Notes:
+//
+//
+// Be extra careful you change this routine.
+// This is especially neccesary if you are going to exit early. The
+// way that hDdeData is free'd or kept should be understood before
+// changing.
+//
+//
+//----------------------------------------------------------------------------
+INTERNAL CDdeObject::OnData
+ (LPDDE_CHANNEL pChannel,
+ HANDLE hDdeData,
+ ATOM aItem)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::OnData(%x,pChannel=%x,hDdeData=%x,aItem=%x(%s)iAwaitAck=%x\n",
+ this,
+ pChannel,
+ hDdeData,
+ aItem,
+ wAtomNameA(aItem),
+ pChannel->iAwaitAck));
+#ifdef _MAC
+#else
+ DDEDATA * lpDdeData = NULL;
+ BOOL fAck = TRUE;
+ int iAdvOpt;
+ BOOL fCallBack;
+ HRESULT hresult = NOERROR;
+
+ ICallControl *lpCallCont = pChannel->pCallCont;
+ intrAssert(lpCallCont != NULL);
+ BOOL fRequested = FALSE;
+
+ intrAssert(wIsValidAtom(aItem));
+
+ int iAwaitAck = pChannel->iAwaitAck;
+
+ //
+ // If we were waiting for this data, then we are sitting in the
+ // modal loop. Set the call state on the call control interface
+ // to indicate that a response was recieved. Pass NOERROR to indicate
+ // that there was success. If an error is determined later, then
+ // the state will be set a second time.
+ //
+
+ if ((AA_REQUEST == iAwaitAck) || (AA_REQUESTAVAILABLE == iAwaitAck))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OnData(%x) AA_REQUEST/AVAILABLE pCD->id=%x\n",
+ this,
+ pChannel->pCD?pChannel->pCD->id:0xBAD));
+
+ //
+ // Regardless of the outcome of this call, we have recieved a
+ // response. Set the Awaiting Ack state to nothing.
+ //
+ pChannel->iAwaitAck = AA_NONE;
+
+ //
+ // Determine if this channels call data is valid, and is in use.
+ // If the channel is in use, then then its id will not be
+ // CALLDATAID_UNUSED. If the call data isn't valid, then something
+ // is wrong, but there isn't a good way to recover.
+ //
+
+ if (pChannel->pCD && (pChannel->pCD->id != CALLDATAID_UNUSED))
+ {
+ // call only if there is a call id
+ //CoSetAckState(pChannel->pCI, FALSE); // clear waiting flag
+ intrDebugOut((DEB_ITRACE,"::OnData(%x) SetCallState(SERVERCALLEX_ISHANDLED)\n",this));
+ pChannel->pCallCont->SetCallState(pChannel->pCD,
+ SERVERCALLEX_ISHANDLED,
+ NOERROR);
+ }
+ }
+
+
+ //
+ // Check the string for aItem, looking for advise options. The variable
+ // iAdvOpt will be set to indicate what type of data we just got, such
+ // as ON_CHANGE, etc. If the option is invalid, then we won't know
+ // what to do with it.
+ //
+
+ if ((hresult=wScanItemOptions (aItem, (int *) &iAdvOpt)) != NOERROR)
+ {
+ intrAssert(!"Item found with unknown advise option\n");
+ LPARAM lp;
+ if(!wPostMessageToServer (pChannel,
+ WM_DDE_ACK,
+ lp = MAKE_DDE_LPARAM (WM_DDE_ACK,NEGATIVE_ACK, aItem),TRUE))
+ {
+ hresult = RPC_E_SERVER_DIED;
+
+ }
+
+ //
+ // Did we need to free hDdeData here? No, according to the DDE spec, if the
+ // receiever responds with a NACK, then the sender is responsible for
+ // freeing the data.
+ //
+ return hresult;
+ }
+
+ //
+ // If the server sent no data, there ain't much we can do about it.
+ //
+
+ if (hDdeData == NULL)
+ {
+ intrDebugOut((DEB_IERROR,
+ "::OnData(%x)hDdeData is NULL!\n",
+ this));
+
+ return(RPC_E_INVALID_PARAMETER);
+ }
+
+ //
+ // Lock the data into memory so we can use it. Be careful, the way
+ // this routine was written originally, there are places that free
+ // and realloc hDdeData. Specifically, the call to KeepData. Carefully
+ // evaluate each place where you are returning, to insure the memory
+ // isn't leaked. (if you have time, please restructure this routine
+ // so it is easier to understand.
+ //
+ if (!(lpDdeData = (DDEDATA FAR *) GlobalLock(hDdeData)))
+ {
+ intrDebugOut((DEB_IERROR,
+ "::OnData(%x)GlobalLock on lpDdeData failed\n",
+ this));
+ //
+ // BUGBUG: (KevinRo)Did we need to free hDdeData here? I think
+ // we should have if the fRelease flag was set. The old code
+ // didn't. Need to research this further (ie you figure it out!)
+ //
+ return ResultFromScode (E_OUTOFMEMORY);
+ }
+
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x) lpDdeData->cfFormat=%x\n",
+ this,
+ (UINT)lpDdeData->cfFormat));
+
+ //
+ // The server will set fAckReq if it wants a response.
+ // don't call HIC for call where not acknoewledge is requested
+ //
+ fAck = lpDdeData->fAckReq;
+
+ if (pChannel->bTerminating) {
+ intrDebugOut((INTR_DDE,"::OnData(%x) Got DDE_DATA in terminate sequence\n",this));
+ //
+ // BUGBUG: this is very dangerous since the pointer on the
+ // hDocWnd does not get deleted and a further will
+ // DDE message will GPF - we need to fix this!!!
+ //
+ GlobalUnlock (hDdeData);
+ GlobalFree (hDdeData);
+ goto exitRtn;
+ }
+
+ //
+ // (KevinRo) Found this comment:
+ //
+ // important that we post the acknowledge first. Otherwise the
+ // messages are not in sync.
+ //
+ // The above comment might be intended to mean that the acknowledge needs to be
+ // send now, because we may call one of the advise functions below, which in
+ // turn may send another message to the OLE 1.0 server. Therefore, we ACK now,
+ // so the messages to the OLE 1.0 server are in the correct order.
+ //
+ if (fAck)
+ {
+ LPARAM lp;
+ if(!wPostMessageToServer (pChannel,
+ WM_DDE_ACK,
+ lp=MAKE_DDE_LPARAM(WM_DDE_ACK,POSITIVE_ACK, aItem),TRUE))
+ {
+ return(RPC_E_SERVER_DIED);
+ }
+ }
+
+ //
+ // this call is now an async call and can not be rejected be HandleIncomingMessage
+ //
+
+ if ((AA_REQUESTAVAILABLE == pChannel->iAwaitAck) && (lpDdeData->fResponse))
+ {
+ //
+ // For some reasons, OnDataAvailable will be the one to delete this data.
+ // I don't understand it, but lets roll with it. (KevinRo)
+ //
+ GlobalUnlock (hDdeData);
+ return OnDataAvailable (pChannel, hDdeData, aItem);
+ }
+
+ //
+ // If the clipboard format is binary, and the topic is aStdDocName, then this
+ // OnData is a RENAME
+ //
+ if (lpDdeData->cfFormat == (short)g_cfBinary && aItem== aStdDocName)
+ {
+ // ON_RENAME
+ //
+ // The data should be the new name, in ANSI.
+ //
+ ChangeTopic ((LPSTR)lpDdeData->Value);
+ GlobalUnlock (hDdeData);
+ GlobalFree (hDdeData);
+ return(NOERROR);
+ }
+
+ //
+ // Based on iAdvOpt, determine if we can callback. This one is a little
+ // hard to understand. I don't either. CanCallBack appears to return
+ // true if the count is 0,1, or 3, but returns FALSE if its 2 or
+ // greater than 3. There are no comments in the old code as to why
+ // this is. I am leaving it, since it must have been put there for
+ // a reason. See CanCallBack in ddeworker.cxx for futher (ie no) details
+ //
+ switch (iAdvOpt)
+ {
+ case ON_SAVE:
+ fCallBack = CanCallBack(&m_iAdvSave);
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x)ON_SAVE m_iAdvSave=%x\n",
+ this,
+ m_iAdvSave));
+
+ break;
+ case ON_CLOSE:
+ fCallBack = CanCallBack(&m_iAdvClose);
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x)ON_CLOSE m_iAdvClose=%x\n",
+ this,
+ m_iAdvClose));
+ break;
+ case ON_CHANGE:
+ fCallBack = TRUE;
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x)ON_CHANGE m_iAdvClose=%x\n",
+ this,
+ m_iAdvClose));
+ break;
+ default:
+ intrAssert( !"Unknown iAdvOpt: Somethings really broke");
+ }
+
+ // Keep the data in a cache for a future GetData call
+ // which may be triggered a few lines later by the
+ // SendOnDataChange().
+
+ fRequested = lpDdeData->fResponse;
+
+
+ // The call to KeepData will change hDdeData and
+ // invalidate lpDdeData. Check out KeepData for details. The net
+ // result is that hDdeData is no longer valid
+
+ GlobalUnlock (hDdeData);
+ lpDdeData=NULL;
+
+ hresult = KeepData (pChannel, hDdeData);
+
+ //
+ // This is unpleasant, but if KeepData fails, we need to
+ // call SetCallState again, resetting the error code. This
+ // code is such a mess that rearranging it to do
+ // it in a rational way is going to be too much work given
+ // the amount of time I have until shipping.
+ //
+ // If you have time, please simplify this code. Thanks
+ //
+ if (hresult != NOERROR)
+ {
+ //
+ // At this point, hDdeData has been unlocked, and deleted by
+ // the KeepData routine. Therefore, the return here doesn't
+ // need to be concerned with cleaning up after hDdeData
+ //
+ intrDebugOut((DEB_ITRACE,
+ "::OnData(%x) KeepData failed %x\n",
+ this,
+ hresult));
+ //
+ // Reset the error code on the call control
+ //
+ if ((AA_REQUEST == iAwaitAck) || (AA_REQUESTAVAILABLE == iAwaitAck))
+ {
+ if (pChannel->pCD && (pChannel->pCD->id != CALLDATAID_UNUSED))
+ {
+ pChannel->pCallCont->SetCallState(pChannel->pCD,
+ SERVERCALLEX_ISHANDLED,
+ hresult);
+ }
+ }
+ goto exitRtn;
+ }
+
+ if (fRequested)
+ {
+ // We REQUESTed the data. So, we are no longer waiting.
+ // Do NOT call SendOnDataChange because the data hasn't
+ // really changed again, we just requested it to satisfy
+ // a call to GetData, which was probably called by the
+ // real SendOnDataChange.
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x) fRequested DATA\n",
+ this));
+
+ iAwaitAck = NULL;
+ hresult = NOERROR;
+ goto exitRtn;
+
+ }
+
+ //
+ // Now we have decided this is data we had not asked for. This makes
+ // it a change/close/saved notificiation.
+ //
+ intrDebugOut((INTR_DDE,"::OnData(%x) Non requested DATA\n",this));
+ pChannel->AddReference();
+ if (fCallBack && iAdvOpt != ON_CHANGE)
+ {
+ // ON_CHANGE will be handled by OleCallback, below
+
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x)Dispatching SendOnDataChange\n",
+ this));
+
+
+ //
+ // There are a couple of things to note about the following. First,
+ // the iid of the call doesn't matter. Since OLE 1.0 servers don't
+ // do nested calls, the original LID (Logical ID) can be any random
+ // value. Therefore, we don't initalize it.
+ //
+ // According to JohannP, the calltype of these calls is supposed
+ // to be CALLTYPE_SYNC. I don't fully understand why they are.
+ // I am taking is decision on faith.
+ //
+ // Using the new call control interfaces, we do the following.
+ //
+ IID iid;
+
+ DDEDISPATCHDATA ddedispdata;
+ DISPATCHDATA dispatchdata;
+ INTERFACEINFO32 ifInfo;
+
+ ifInfo.pUnk = m_pDataAdvHolder;
+ ifInfo.iid = IID_IDataAdviseHolder;
+ //
+ // We are about to call method #6 in the interface,
+ // which is SendOnDataChange
+ //
+ ifInfo.wMethod = 6;
+ ifInfo.callcat = CALLCAT_SYNCHRONOUS;
+
+ //dispatchdata.scode = S_OK;
+ dispatchdata.pData = (LPVOID) &ddedispdata;
+
+ ddedispdata.pCDdeObject = this;
+ ddedispdata.wDispFunc = DDE_DISP_SENDONDATACHANGE;
+ ddedispdata.iArg = iAdvOpt;
+
+ lpCallCont->HandleDispatchCall((DWORD)GetWindowTask(pChannel->hwndSvr),
+ iid,
+ &ifInfo,
+ &dispatchdata);
+
+ }
+ if (fCallBack && (pChannel->pCallCont != NULL))
+ {
+ // in 1.0 ON_CLOSE comes with data
+ if (iAdvOpt==ON_CLOSE)
+ {
+
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x) iAdvOpt == ON_CLOSE, send ON_SAVE\n",
+ this));
+
+ m_fGotCloseData = TRUE;
+
+ hresult = OleCallBack(ON_SAVE,pChannel);
+ if (hresult != NOERROR)
+ {
+ goto errRel;
+ }
+
+ //ErrRtnH (DdeHandleIncomingCall(pChannel->hwndSvr, CALLTYPE_TOPLEVEL) );
+ //ErrRtnH (OleCallBack (ON_SAVE));
+ }
+
+ // check if app can handle this call
+ // we do not need to call HIC for SendOnClose
+
+ hresult = OleCallBack (iAdvOpt,pChannel);
+ }
+
+errRel:
+ // Don't use pChannel after this. It can get deleted. (srinik)
+ if (pChannel->ReleaseReference() == 0)
+ {
+ m_pDocChannel = NULL;
+ }
+
+exitRtn:
+ if (!fAck && aItem)
+ {
+ GlobalDeleteAtom (aItem);
+ }
+ return hresult;
+#endif _MAC
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::OleCallBack
+//
+// Synopsis: Send all the right notifications whan a Save or Close happens.
+//
+// Effects: OleCallBack is a double duty function. It is called in two
+// different cases.
+//
+// First, is to setup the callback, and call HandleIncomingCall.
+// Second is from DispatchCall() in the CDdeChannelControl.
+//
+// The reason for doing it this way is we localize the setup
+// and processing of these calls to one routine. Therefore,
+// we can go to one spot in the code to find all of the call
+// back information.
+//
+// Arguments: [iAdvOpt] -- Which Advise operation to perform
+// [pChannel] -- Which channel is being called back
+//
+// Requires: pChannel == NULL, and the AdviseHolders are called.
+// pChannel != NULL, and the call is setup, and HandleIncomingCall
+// is setup.
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-23-94 kevinro Created
+//
+// Notes:
+//
+// WARNING: This code sucks completely. One of the major problems you need
+// to know about is that the CDdeObject may go away as part of the normal
+// processing of some of the below. Be very careful about any processing
+// that might occur after an ON_CLOSE
+//
+//----------------------------------------------------------------------------
+INTERNAL CDdeObject::OleCallBack (int iAdvOpt, LPDDE_CHANNEL pChannel)
+{
+ HRESULT hresult = NOERROR;
+ IID iid;
+ DDEDISPATCHDATA ddedispdata;
+ DISPATCHDATA dispatchdata;
+ INTERFACEINFO32 ifInfo;
+ ICallControl *lpCallCont = NULL;
+
+ //
+ // If the channel isn't NULL, then setup the data structures for calling
+ // off to the call control.
+ //
+ if (pChannel != NULL)
+ {
+ lpCallCont = pChannel->pCallCont;
+
+ if (lpCallCont == NULL)
+ {
+ return(E_UNEXPECTED);
+ }
+ //
+ // Only do this work if we really have to
+ //
+
+ dispatchdata.scode = S_OK;
+ dispatchdata.pData = (LPVOID) &ddedispdata;
+ ddedispdata.pCDdeObject = this;
+ ddedispdata.wDispFunc = DDE_DISP_OLECALLBACK;
+ ddedispdata.iArg = iAdvOpt;
+
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::OleCallBack(%x,iAdvOpt=%x,pChannel=%x,lpCallCont=%x)\n",
+ this,
+ iAdvOpt,
+ pChannel,
+ lpCallCont));
+
+ //
+ // Determine what needs to be done, based on the iAdvOpt. This should be
+ // one of the handled cases below, otherwise its an error.
+ //
+ switch (iAdvOpt)
+ {
+ case ON_CLOSE:
+ if (pChannel != NULL)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OleCallBack(%x) setup for ON_CLOSE\n",
+ this));
+
+ ifInfo.pUnk = m_pOleAdvHolder;
+ ifInfo.iid = IID_IOleAdviseHolder;
+ // IOleAdviseHolder::SendOnClose is method 8
+ ifInfo.wMethod = 8;
+ ifInfo.callcat = CALLCAT_SYNCHRONOUS;
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE,"::OleCallBack(%x) ON_CLOSE\n",this));
+ DeclareVisibility (FALSE);
+ RetZ (!m_fDidSendOnClose); // This SendOnClose should happen 1st
+ // Don't let OnTerminate() do it too
+ hresult = SendOnClose();
+
+ //
+ // WARNING WARNING WARNING: SendOnClose() may have caused the
+ // destruction of this CDdeObject. Touch nothing on the way
+ // out. Actually, if you have time, which I currently don't,
+ // see what you can do with reference counting tricks to
+ // insure this object doesn't die during this callback.
+ // Its a tricky problem, and we are shipping in 2 weeks.
+ // (KevinRo 8/6/94)
+ //
+ }
+ break;
+
+ case ON_SAVE:
+ if (pChannel != NULL)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OleCallBack(%x) setup for ON_SAVE\n",
+ this));
+
+ if (m_pOleClientSite == NULL)
+ {
+ ifInfo.pUnk = m_pOleClientSite;
+ ifInfo.iid = IID_IOleClientSite;
+ // IOleClientSite::SaveObject method 7
+ ifInfo.wMethod = 7;
+ ifInfo.callcat = CALLCAT_SYNCHRONOUS;
+ }
+ else
+ {
+ // Going to call the IOleAdviseHolder
+
+ ifInfo.pUnk = m_pOleAdvHolder;
+ ifInfo.iid = IID_IOleAdviseHolder;
+ // IOleAdviseHolder::SendOnSave method 7
+ // (Yes, same ordinal as above, I double checked)
+ ifInfo.wMethod = 7;
+ ifInfo.callcat = CALLCAT_SYNCHRONOUS;
+ }
+ }
+ else
+ {
+
+ intrDebugOut((DEB_ITRACE,"::OleCallBack(%x) ON_SAVE\n",this));
+ if (m_pOleClientSite)
+ {
+ // We just got data from the server, so we don't want to
+ // ask him for it again when the container does a save.
+ m_fUpdateOnSave = FALSE;
+ m_pOleClientSite->SaveObject();
+ // SendOnSave is called in PS::SaveCompleted
+ m_fUpdateOnSave = TRUE;
+ }
+ else
+ {
+ // Link case
+ RetZS (m_pOleAdvHolder, E_OUTOFMEMORY);
+ m_pOleAdvHolder->SendOnSave();
+ }
+ }
+ break;
+
+ case ON_CHANGE:
+ if (pChannel != NULL)
+ {
+ // Going to call the IDataAdviseHolder
+
+ ifInfo.pUnk = m_pDataAdvHolder;
+ ifInfo.iid = IID_IDataAdviseHolder;
+ // IDataAdviseHolder::SendOnDataChange method 6
+ ifInfo.wMethod = 6;
+ ifInfo.callcat = CALLCAT_SYNCHRONOUS;
+
+ }
+ else
+ {
+ RetZS (m_pDataAdvHolder, E_OUTOFMEMORY);
+ intrDebugOut((DEB_ITRACE,"::OleCallBack(%x) ON_CHANGE\n",this));
+ hresult = SendOnDataChange (ON_CHANGE);
+ }
+ break;
+
+ default:
+
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::OleCallBack(%x,iAdvOpt=%x) UNKNOWN iAdvOpt\n",
+ this,
+ iAdvOpt));
+ intrAssert(!"Unexpected iAdvOpt");
+ return(E_UNEXPECTED);
+ break;
+ }
+
+ //
+ // There are a couple of things to note about the following. First,
+ // the iid of the call doesn't matter. Since OLE 1.0 servers don't
+ // do nested calls, the original LID (Logical ID) can be any random
+ // value. Therefore, we don't initalize it.
+ //
+ // According to JohannP, the calltype of these calls is supposed
+ // to be CALLTYPE_SYNCHRONOUS. I don't fully understand why they are.
+ // I am taking is decision on faith.
+ //
+ //
+ // Its possible that during the handling of this call that this object
+ // will get deleted. This is a pain in the butt. This means that anything
+ // used after this call MUST be protected. lpCallCont happens to be one of
+ // these. We have been having problems with lpCallCont being released as
+ // part of the object cleanup. The call control code will access member
+ // variables on its way out of the HandleDispatch. We need to bracket
+ // the call below so this doesn't happen.
+ //
+ if (pChannel != NULL)
+ {
+ //
+ // We normally keep a per thread copy of the call control interface.
+ // When the reference count for that copy goes to zero, we need to
+ // flush that copy. We can do the addref here, because the current
+ // reference is the same value that would be returned by
+ // GetDdeCallControlInterface. The balancing call, however, needs
+ // to be ReleaseDdeCallControlInterface, since it may need to flush
+ // the TLS value.
+ //
+
+ lpCallCont->AddRef();
+
+ hresult = lpCallCont->HandleDispatchCall((DWORD)GetWindowTask(pChannel->hwndSvr),
+ iid,
+ &ifInfo,
+ &dispatchdata);
+
+ ReleaseDdeCallControlInterface();
+ }
+
+ return hresult;
+}
+
+
+INTERNAL CDdeObject::SendOnDataChange
+ (int iAdvOpt)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::SendOnDataChange(%x)\n",this));
+ HRESULT hresult;
+ RetZS (m_pDataAdvHolder, E_OUTOFMEMORY);
+ m_fDoingSendOnDataChange = TRUE;
+ hresult = m_pDataAdvHolder->SendOnDataChange (&m_Data,
+ DVASPECT_CONTENT,
+ 0);
+ if (ON_CLOSE==iAdvOpt)
+ {
+ hresult = m_pDataAdvHolder->SendOnDataChange (&m_Data,
+ DVASPECT_CONTENT,
+ ADVF_DATAONSTOP);
+ }
+ m_fDoingSendOnDataChange = FALSE;
+ return hresult;
+}
+
+
+
+
+INTERNAL CDdeObject::SendOnClose
+ (void)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::SendOnClose(%x)\n",this));
+ RetZS (m_pOleAdvHolder, E_OUTOFMEMORY);
+ m_fDidSendOnClose = TRUE;
+ RetErr (m_pOleAdvHolder->SendOnClose() );
+ return NOERROR;
+}
+
+
+
+
+INTERNAL CDdeObject::OnTerminate
+ (LPDDE_CHANNEL pChannel,
+ HWND hwndPost)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::OnTerminate(%x,pChannel=%x,hwndPost=%x)\n",
+ this,
+ pChannel,
+ hwndPost));
+
+ //
+ // If the hwndPost and hwndSvr are different, then it is one of two
+ // cases. We could have recieved more than one Acknowlege during our
+ // initiate, in which case the count iExtraTerms would have been
+ // incremented, and this terminate is accounted for iExtraTerms.
+ //
+ // The other case is that we were terminated by a window that was
+ // NOT the window we were conversing with.
+ //
+ if (pChannel->hwndSvr != hwndPost)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OnTerminate(%x) Extra terms is 0x%x \n",
+ this,
+ pChannel->iExtraTerms));
+
+ //
+ // iExtraTerms shouldn't go below zero. If it does, something
+ // has gone wrong. We have been seeing some problems with the
+ // HWND mapping layer in the past. If the following condition
+ // ever trips, then it is possible that another mapping
+ // problem has been seen.
+ //
+#if DBG == 1
+ if((pChannel->iExtraTerms == 0 ) &&
+ (((DWORD)pChannel->hwndSvr) & (0xffff)) == ((DWORD)hwndPost & (0xffff)))
+ {
+ intrDebugOut((DEB_ERROR,
+ "*** OnTerminate expected hwnd=%x got hwnd=%x ***\n",
+ pChannel->hwndSvr,hwndPost));
+
+ intrDebugOut((DEB_ERROR,
+ "\n*** Call KevinRo or SanfordS ***\n\n",
+ pChannel->hwndSvr,hwndPost));
+
+ }
+#endif
+ --pChannel->iExtraTerms;
+
+ intrAssert((pChannel->iExtraTerms >= 0) && "Call KevinRo or SanfordS");
+ return NOERROR;
+ }
+ if (m_wTerminate == Terminate_Detect) {
+ // we should only detect the call but not execute the code
+ // set the state to Received
+ m_wTerminate = Terminate_Received;
+ pChannel->iAwaitAck = NULL;
+ // Since Excel incorrectly did not send an ACK, we need to
+ // delete the handle in the DDE message ourselves.
+ if (pChannel->hCommands)
+ {
+ GlobalFree (pChannel->hCommands);
+ pChannel->hCommands = NULL;
+ }
+ //CoSetAckState(pChannel->pCI, FALSE);
+ intrDebugOut((DEB_ITRACE,
+ "::OnTerminate(%x) Terminate_Detect SERVERCALLEX_ISHANDLED\n",
+ this));
+ pChannel->pCallCont->SetCallState(pChannel->pCD, SERVERCALLEX_ISHANDLED, RPC_E_SERVER_DIED);
+ return NOERROR;
+ }
+
+ RetZ (pChannel);
+ ChkDR (this);
+
+ if (!pChannel->bTerminating)
+ {
+ // Got unprompted terminate
+ BOOL bBusy;
+
+ // Necessary safety bracket
+ m_pUnkOuter->AddRef();
+
+ bBusy = wClearWaitState (pChannel);
+
+ if (pChannel->iAwaitAck || bBusy)
+ {
+ pChannel->iAwaitAck = NULL;
+ //CoSetAckState(pChannel->pCI, FALSE);
+ intrDebugOut((DEB_ITRACE,"::OnTerminate(%x) !bTerminating SERVERCALLEX_ISHANDLED,RPC_E_DDE_UNEXP_MSG\n",this));
+ pChannel->pCallCont->SetCallState(pChannel->pCD, SERVERCALLEX_ISHANDLED, RPC_E_DDE_UNEXP_MSG);
+ }
+
+ if (!m_fDidSendOnClose)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OnTerminate(%x) SendOnClose from terminate\n",
+ this));
+
+ BOOL f= m_fNoStdCloseDoc;
+ m_fNoStdCloseDoc = TRUE;
+
+ DeclareVisibility (FALSE);
+ SendOnClose();
+
+ m_fNoStdCloseDoc = f;
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OnTerminate(%x) Already did SendOnClose\n",
+ this));
+ Puts ("Already did SendOnClose\n");
+ }
+ intrDebugOut((DEB_ITRACE,
+ "::OnTerminate(%x) Posting DDE_TERMINATE as reply\n",
+ this));
+
+ wPostMessageToServer (pChannel, WM_DDE_TERMINATE, NULL,FALSE);
+
+ // The terminate that we are sending itself is a reply, so we don't
+ // need to do WaitForReply.
+ DeleteChannel (pChannel);
+
+ // Necessary safety bracket
+ m_pUnkOuter->Release();
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OnTerminate(%x) Received DDE_TERMINATE in reply\n",
+ this));
+
+ // We sent the WM_DDE_TERMINATE and we got the acknowledge for it
+ pChannel->hwndSvr = NULL;
+ pChannel->iExtraTerms == NULL;
+ pChannel->iAwaitAck = NULL;
+ //CoSetAckState(pChannel->pCI, FALSE);
+ intrDebugOut((DEB_ITRACE,"::OnTerminate(%x) bTerminating SERVERCALLEX_ISHANDLED\n",this));
+ pChannel->pCallCont->SetCallState(pChannel->pCD, SERVERCALLEX_ISHANDLED, NOERROR);
+ }
+ Puts ("OnTerminate() done.\n");
+ return NOERROR;
+}
+
+
+
+
+INTERNAL_(BOOL) CDdeObject::AllocDdeChannel
+ (LPDDE_CHANNEL * lplpChannel, LPSTR lpszWndClass)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::AllocDdeChannel(%x,WndClass=%s)\n",
+ this,
+ lpszWndClass));
+
+ //
+ // Try to get the global call control interface
+ //
+
+ PCALLCONTROL pCallCont = GetDdeCallControlInterface();
+
+ if (pCallCont == NULL)
+ {
+ //
+ // Couldn't allocate a CallControl. Fail.
+ //
+
+ intrAssert(pCallCont != NULL);
+ return(FALSE);
+ }
+
+ //
+ // Now try to allocate a channel
+ //
+
+ if (!(*lplpChannel = (LPDDE_CHANNEL) new DDE_CHANNEL ))
+ {
+ //
+ // This failed, so give back the CallControl
+ //
+ intrAssert(*lplpChannel != NULL);
+ ReleaseDdeCallControlInterface();
+ return FALSE;
+ }
+
+ (*lplpChannel)->m_cRefs = 1;
+ (*lplpChannel)->hwndSvr = NULL;
+ (*lplpChannel)->bTerminating = FALSE;
+ (*lplpChannel)->wTimer = NULL;
+ (*lplpChannel)->hDdePoke = NULL;
+ (*lplpChannel)->hCommands = NULL;
+ (*lplpChannel)->hopt = NULL;
+ (*lplpChannel)->dwStartTickCount= 0;
+ (*lplpChannel)->msgFirst = 0;
+ (*lplpChannel)->msgLast = 0;
+ (*lplpChannel)->fRejected = FALSE;
+ (*lplpChannel)->wChannelDeleted = 0;
+ //(*lplpChannel)->pCI = NULL;
+ (*lplpChannel)->pCD = NULL;
+ (*lplpChannel)->pCallCont = pCallCont;
+ (*lplpChannel)->pChanCont = &g_CDdeChannelControl;
+
+ if (!((*lplpChannel)->hwndCli = SSCreateWindowExA(0,
+ lpszWndClass,
+ "DDE Channel",
+ WS_CHILD,
+ 0,0,0,0,
+ (HWND)TLSGetDdeClientWindow(),
+ NULL,
+ hinstSO,
+ NULL)))
+ {
+ intrAssert (!"Could not create AllocDdeChannel window");
+
+ //
+ // DeleteChannel will give back the CallControl
+ //
+
+ DeleteChannel(*lplpChannel);
+ *lplpChannel = NULL;
+ return FALSE;
+ }
+
+ SetWindowLong ((*lplpChannel)->hwndCli, 0, (LONG) this);
+ return TRUE;
+}
+
+
+
+INTERNAL_(BOOL) CDdeObject::InitSysConv()
+{
+ DWORD dwResult;
+ intrDebugOut((DEB_ITRACE,"CDdeObject::InitSysConv(%x)\n",this));
+
+ dwResult = wInitiate (m_pSysChannel, m_aClass, aOLE);
+ if (!dwResult)
+ {
+ intrDebugOut((DEB_ITRACE,"\t::InitSysConv(%x) Try aSysTopic\n",this));
+ dwResult = wInitiate (m_pSysChannel, m_aClass, aSysTopic);
+ }
+
+ if (!dwResult)
+ {
+ intrDebugOut((DEB_ITRACE,"\t::InitSysConv(%x) is failing\n",this));
+ }
+ return(dwResult);
+}
+
+
+
+INTERNAL_(void) CDdeObject::SetTopic(ATOM aTopic)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::SetTopic(%x)\n",this));
+ intrAssert(wIsValidAtom(aTopic));
+ if (m_aTopic)
+ GlobalDeleteAtom (m_aTopic);
+
+ m_aTopic = aTopic;
+}
+
+
+
+INTERNAL CDdeObject::TermConv
+ (LPDDE_CHANNEL pChannel,
+ BOOL fWait) // Default==TRUE. FALSE only in ProxyManager::Disconnect
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::TermConv(%x,pChannel=%x)\n",
+ this,
+ pChannel));
+
+ HRESULT hres;
+ if (!pChannel)
+ {
+ return NOERROR;
+ }
+
+ if (!wPostMessageToServer (pChannel, WM_DDE_TERMINATE, 0,FALSE))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::TermConv(%x) Server Probably Died\n",
+ this));
+ hres = RPC_E_SERVER_DIED;
+ }
+ else
+ {
+ pChannel->bTerminating = TRUE;
+ Putsi (fWait);
+ hres = fWait ? WaitForReply (pChannel,
+ AA_TERMINATE,
+ /*fStdCloseDoc*/FALSE,
+ /*fDetectTerminate*/ FALSE) : NOERROR;
+ if (pChannel==m_pDocChannel)
+ {
+ DeclareVisibility (FALSE);
+ if (!m_fDidSendOnClose)
+ {
+ SendOnClose();
+ }
+ }
+ }
+
+ DeleteChannel (pChannel);
+ intrDebugOut((DEB_ITRACE,"::TermConv(%x) returns %x\n",this,hres));
+ return hres;
+}
+
+
+
+
+INTERNAL_(void) CDdeObject::DeleteChannel (LPDDE_CHANNEL pChannel)
+{
+ BOOL fDocChannel = FALSE;
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::DeleteChannel(%x,pChannel=%x)\n",
+ this,
+ pChannel));
+
+ if (pChannel == NULL)
+ {
+ return;
+ }
+
+ if (pChannel == m_pDocChannel)
+ fDocChannel = TRUE;
+
+
+
+ // delete any data if we were in busy mode.
+ wClearWaitState (pChannel);
+
+ if (pChannel == m_pDocChannel)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DeleteChannel(%x)Clean up pDocChannel\n",
+ this));
+
+ // Cleanup per-conversation information
+ m_fDidSendOnClose = FALSE;
+ m_fDidStdCloseDoc = FALSE;
+ m_ConnectionTable.Erase();
+ m_iAdvSave = 0;
+ m_iAdvClose= 0;
+ m_fWasEverVisible = FALSE;
+ m_fGotCloseData = FALSE;
+ if (m_ptd)
+ {
+ delete m_ptd;
+ m_ptd = NULL;
+ }
+ if (m_pstg)
+ {
+ m_pstg->Release();
+ m_pstg = NULL;
+ }
+ if (m_pDataAdvHolder)
+ {
+ Verify (0==m_pDataAdvHolder->Release());
+ }
+ CreateDataAdviseHolder (&m_pDataAdvHolder);
+ if (m_pOleAdvHolder)
+ {
+ m_pOleAdvHolder->Release(); // may not return 0 if we are
+ // in a SendOnClose
+ }
+ CreateOleAdviseHolder (&m_pOleAdvHolder);
+ }
+
+ if (pChannel->hwndCli)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DeleteChannel(%x)Destroy hwndCli(%x)\n",
+ this,
+ pChannel->hwndCli));
+
+ Assert (IsWindow (pChannel->hwndCli));
+ Assert (this==(CDdeObject *)GetWindowLong (pChannel->hwndCli, 0));
+ Verify (SSDestroyWindow (pChannel->hwndCli));
+ }
+
+ if (pChannel == m_pDocChannel)
+ {
+ m_pDocChannel = NULL;
+ }
+ else
+ {
+ intrAssert(pChannel == m_pSysChannel);
+ m_pSysChannel = NULL;
+ }
+
+
+ if (pChannel->pCallCont != NULL)
+ {
+ ReleaseDdeCallControlInterface();
+ pChannel->pCallCont = NULL;
+ }
+
+ // Channel will be deleted in the modallp.cpp
+ // if flag is on.
+
+ if (pChannel->wChannelDeleted == Channel_InModalloop)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DeleteChannel(%x) Channel(%x) in Modal Loop\n",
+ this,pChannel));
+
+ pChannel->wChannelDeleted = Channel_DeleteNow;
+ }
+ else
+ {
+ if (pChannel->ReleaseReference() == 0)
+ pChannel = NULL;
+ }
+
+ if (fDocChannel)
+ m_pDocChannel = pChannel;
+}
+
+const WCHAR EMB_STR[]= OLESTR(" -Embedding ") ;
+
+INTERNAL_(BOOL) CDdeObject::LaunchApp (void)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::LaunchApp(%x)\n",this));
+
+ STARTUPINFO startInfo;
+ PROCESS_INFORMATION procInfo;
+ BOOL fProcStarted;
+ WCHAR cmdline[MAX_PATH + sizeof(EMB_STR)];
+ WCHAR exeName[MAX_PATH + sizeof(cmdline)];
+ //
+ // Init all fields of startInfo to zero
+ //
+ memset((void *)&startInfo,0,sizeof(startInfo));
+
+ //
+ // The normal startup is set here.
+ //
+ startInfo.wShowWindow = SW_NORMAL;
+ startInfo.dwFlags = STARTF_USESHOWWINDOW;
+
+ m_fDidLaunchApp = FALSE;
+
+
+ DWORD dw;
+
+ //
+ // Do our best to find the path
+ //
+ intrAssert(wIsValidAtom(m_aExeName));
+
+ if (m_aExeName == 0)
+ {
+ //
+ // There is no exe name to execute. Can't start it.
+ //
+ return(FALSE);
+ }
+
+ dw = SearchPath(NULL,wAtomName(m_aExeName),NULL,MAX_PATH,exeName, NULL);
+
+ if ((dw == 0) || (dw > MAX_PATH))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::LaunchApp(%x) SearchPath failed. Do Default",this));
+ //
+ // SearchPath failed. Use the default
+ //
+ GlobalGetAtomName (m_aExeName, exeName, MAX_PATH);
+ }
+
+ memcpy(cmdline, EMB_STR,sizeof(EMB_STR));
+
+ if (m_ulObjType == OT_LINK)
+ {
+ intrAssert(wIsValidAtom(m_aTopic));
+ // File name
+ Assert (wAtomName (m_aTopic));
+
+ lstrcatW (cmdline, wAtomName (m_aTopic));
+ }
+
+ if (m_clsid == CLSID_ExcelWorksheet // Stupid apps that show themselves
+ || m_clsid == CLSID_ExcelMacrosheet // when they're not supposed to
+ || m_clsid == CLSID_ExcelChart
+ || m_clsid == CLSID_PBrush)
+ {
+ startInfo.wShowWindow = SW_SHOWMINNOACTIVE;
+ }
+
+ //
+ // According to the spec, the most robust way to start the app is to
+ // only use a cmdline that consists of the exe name, followed by the
+ // command line arguments.
+ //
+
+ lstrcatW(exeName,cmdline);
+
+ Assert((lstrlenW(exeName)+1) < sizeof(exeName));
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::LaunchApp(%x) Starting '%ws' \n",
+ this,
+ exeName));
+
+ if (IsWOWThreadCallable())
+ {
+ HRESULT hr;
+
+ hr = g_pOleThunkWOW->WinExec16(exeName, startInfo.wShowWindow);
+
+ fProcStarted = SUCCEEDED(hr);
+
+#if DBG==1
+ if (!fProcStarted)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::LaunchApp(%x) in Wow FAILED(%x) TO START %ws \n",
+ this,
+ hr,
+ exeName));
+ }
+#endif
+ }
+ else
+ {
+ fProcStarted = CreateProcess(NULL,
+ exeName,
+ NULL,
+ NULL,
+ FALSE,
+ 0,
+ NULL,
+ NULL,
+ &startInfo,
+ &procInfo);
+ if (fProcStarted)
+ {
+ //
+ // Let's give the server a chance to register itself. On NT,
+ // CreateProcess gets the other process going, but returns
+ // to let it run asynchronously. This isn't good, since we
+ // need some way of knowing when it has started, so we can
+ // send the DDE_INITIATES 'after' they create their DDE
+ // window.
+ //
+ // Maximum timeout we want here shall be set at 30 seconds.
+ // This should give enough time for even a 16bit WOW app to
+ // start. This number was picked by trial and error. Normal
+ // apps that go into an InputIdle state will return as soon
+ // as they are ready. Therefore, we normally won't wait
+ // the full duration.
+ //
+
+ ULONG ulTimeoutDuration = 30000L;
+
+ //
+ // Now modify this start time to handle classes
+ // that have known problems. This list includes:
+ //
+
+ switch(WaitForInputIdle(procInfo.hProcess, ulTimeoutDuration))
+ {
+ case 0:
+ intrDebugOut((DEB_ITRACE,
+ "::LaunchApp, %ws started\n",
+ exeName));
+ break;
+ case WAIT_TIMEOUT:
+ intrDebugOut((DEB_ITRACE,
+ "::LaunchApp, %ws wait timeout at %u (dec) ms. Go Anyway\n",
+ exeName,
+ ulTimeoutDuration));
+ break;
+ default:
+ intrDebugOut((DEB_ITRACE,
+ "::LaunchApp, %ws unknown condition (%x)\n",
+ exeName,
+ GetLastError()));
+ }
+ //
+ // We are already done with the Process and Thread handles
+ //
+ CloseHandle(procInfo.hProcess);
+ CloseHandle(procInfo.hThread);
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::LaunchApp(%x) FAILED(%x) TO START %ws \n",
+ this,
+ GetLastError(),
+ exeName));
+ }
+ }
+
+ if (fProcStarted)
+ {
+ // If we ran the server, it should not be visible yet.
+ DeclareVisibility (FALSE);
+ m_fDidLaunchApp = TRUE;
+ }
+
+ return fProcStarted;
+}
+
+
+INTERNAL CDdeObject::MaybeUnlaunchApp (void)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::MaybeUnlaunchApp(%x)\n",this));
+ if (m_fDidLaunchApp
+ && !m_fDidGetObject
+ && (m_clsid == CLSID_ExcelWorksheet
+ || m_clsid == CLSID_ExcelMacrosheet
+ || m_clsid == CLSID_ExcelChart))
+ {
+ return UnlaunchApp();
+ }
+ return NOERROR;
+}
+
+
+
+
+INTERNAL CDdeObject::UnlaunchApp (void)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::UnlaunchApp(%x)\n",this));
+ HANDLE hCommands;
+ HRESULT hresult = NOERROR;
+ RetZS (AllocDdeChannel (&m_pSysChannel, SYS_CLASSA), E_OUTOFMEMORY);
+ ErrZS (InitSysConv(), E_UNEXPECTED);
+ ErrRtnH (PostSysCommand (m_pSysChannel,(LPSTR) &achStdExit, /*bStdNew*/FALSE,
+ /*fWait*/FALSE));
+ hCommands = m_pSysChannel->hCommands;
+ hresult = TermConv (m_pSysChannel);
+
+ // Since Excel incorrectly did not send an ACK, we need to
+ // delete the handle ("[StdExit]") in the DDE message ourselves.
+ if (hCommands)
+ GlobalFree (hCommands);
+
+ return hresult;
+
+ errRtn:
+ DeleteChannel (m_pSysChannel);
+ return hresult;
+}
+
+
+
+
+INTERNAL CDdeObject::Execute
+ (LPDDE_CHANNEL pChannel,
+ HANDLE hdata,
+ BOOL fStdCloseDoc,
+ BOOL fWait,
+ BOOL fDetectTerminate)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::Execute(%x,hdata=%x)\n",this,hdata));
+
+ LPARAM lp;
+
+#ifdef _CHICAGO_
+ //POSTPPC
+ if (fWait && (CanMakeOutCall(pChannel) == FALSE))
+ {
+ intrDebugOut((DEB_ERROR, "::Execute(%x) can not call out\n", this));
+ GlobalFree (hdata);
+ return ResultFromScode (E_UNEXPECTED);
+ }
+#endif
+
+ if (wPostMessageToServer (pChannel,
+ WM_DDE_EXECUTE,
+ lp=MAKE_DDE_LPARAM(WM_DDE_EXECUTE,0, hdata),TRUE))
+ {
+ if (fStdCloseDoc)
+ {
+ // Prepare to free the handle if Excel does not send an Ack
+ pChannel->hCommands = hdata;
+ }
+ return fWait ? WaitForReply (pChannel, AA_EXECUTE, fStdCloseDoc,
+ fDetectTerminate)
+ : NOERROR ;
+ }
+ GlobalFree (hdata);
+ return ReportResult(0, RPC_E_DDE_POST, 0, 0);
+}
+
+
+
+
+INTERNAL_(HRESULT) CDdeObject::AdviseOn (CLIPFORMAT cfFormat, int iAdvOn)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::AdviseOn(%x,cfFormat=%x,iAdvOn=%x)\n",
+ this,
+ cfFormat,
+ iAdvOn));
+
+ HANDLE hopt=NULL;
+ DDEADVISE * lpopt=NULL;
+ ATOM aItem=(ATOM)0;
+ HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0);
+
+ RetZ (m_pDocChannel);
+
+ if (NOERROR == m_ConnectionTable.Lookup (cfFormat, NULL))
+ {
+ // We already got a call to DataObject::Advise on this format.
+ intrDebugOut((DEB_ITRACE,
+ "::AdviseOn(%x) Advise had been done on cfFormat=%x\n",
+ this,
+ cfFormat));
+ return NOERROR;
+ }
+
+ UpdateAdviseCounts (cfFormat, iAdvOn, +1);
+
+ if (m_fDidSendOnClose)
+ {
+ intrDebugOut((DEB_ITRACE,"::AdviseOn(%x)Ignoring Advise because we are closing\n",this));
+ return NOERROR;
+ }
+
+ if (!(hopt = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, sizeof(DDEADVISE))))
+ {
+ intrDebugOut((DEB_ITRACE,"::AdviseOn(%x)GlobalAlloc returned NULL\n",this));
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+
+ if (!(lpopt = (DDEADVISE FAR *) GlobalLock (hopt)))
+ {
+ intrDebugOut((DEB_ITRACE,"::AdviseOn(%x)GlobalLock returned NULL\n",this));
+ GlobalFree (hopt);
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ lpopt->fAckReq = TRUE;
+ lpopt->fDeferUpd = FALSE;
+ lpopt->cfFormat = cfFormat;
+ m_pDocChannel->hopt = hopt;
+
+ if (iAdvOn == ON_RENAME)
+ {
+ aItem = wDupAtom (aStdDocName);
+ intrAssert(wIsValidAtom(aItem));
+ }
+ else
+ {
+ intrAssert(wIsValidAtom(m_aItem));
+ aItem = wExtendAtom (m_aItem, iAdvOn);
+ intrAssert(wIsValidAtom(aItem));
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "::AdviseOn(%x) lpopt->cfFormat = %x, aItem=%x (%ws)\n",
+ this,
+ lpopt->cfFormat,
+ aItem,
+ wAtomName(aItem)));
+
+ GlobalUnlock (hopt);
+
+ LPARAM lp;
+ if (FALSE==wPostMessageToServer (m_pDocChannel, WM_DDE_ADVISE,
+ lp=MAKE_DDE_LPARAM(WM_DDE_ADVISE,hopt,aItem),TRUE))
+ {
+ intrDebugOut((DEB_ITRACE,"::AdviseOn(%x)wPostMessageToServer failed\n",this));
+ if (aItem)
+ GlobalDeleteAtom (aItem);
+ if (hopt)
+ GlobalFree (hopt);
+ return ResultFromScode (RPC_E_DDE_POST);
+ }
+ ErrRtnH (WaitForReply (m_pDocChannel, AA_ADVISE));
+
+ return NOERROR;
+
+errRtn:
+ hresult = (RPC_E_DDE_NACK == hresult) ? DV_E_CLIPFORMAT : hresult;
+ intrDebugOut((DEB_ITRACE,
+ "::AdviseOn(%x) errRet, AdviseRejected, returning %x\n",
+ this,hresult));
+ return hresult;
+}
+
+INTERNAL CDdeObject::UpdateAdviseCounts
+ (CLIPFORMAT cf,
+ int iAdvOn,
+ signed int cDelta)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::UpdateAdviseCounts(%x)\n",this));
+ if (cf==g_cfBinary)
+ return NOERROR;
+
+ // Update m_iAdv* flags
+ #define macro(Notif, NOTIF) \
+ if (iAdvOn == ON_##NOTIF) \
+ m_iAdv##Notif += cDelta; \
+ if (m_iAdv##Notif < 0) \
+ m_iAdv##Notif = 0; \
+ else if (m_iAdv##Notif > 2) \
+ m_iAdv##Notif = 2;
+
+ macro (Close, CLOSE)
+ macro (Save, SAVE)
+ macro (Change,CHANGE)
+ #undef macro
+
+ Assert (m_iAdvClose < 3 && m_iAdvSave < 3 && m_iAdvChange < 3);
+ Assert (m_iAdvClose >= 0 && m_iAdvSave >= 0 && m_iAdvChange >= 0);
+
+ if (cf == g_cfNative)
+ {
+ if (iAdvOn != ON_CHANGE)
+ m_fDidAdvNative = (cDelta > 0);
+ else
+ intrDebugOut((DEB_ITRACE,
+ "::UpdateAdviseCounts(%x)Asked advise on cfNative\n",
+ this));
+ }
+
+ return NOERROR;
+}
+
+
+
+
+INTERNAL CDdeObject::UnAdviseOn (CLIPFORMAT cfFormat, int iAdvOn)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::UnAdviseOn(%x,cfFormat=%x,iAdvOn=%x)\n",
+ this,cfFormat,iAdvOn));
+ HRESULT hr;
+ ATOM aItem= (ATOM)0;
+
+ RetZ (m_pDocChannel);
+ UpdateAdviseCounts (cfFormat, iAdvOn, -1);
+ if (m_fDidSendOnClose)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::UnAdviseOn(%x) Ignored because closing\n",
+ this));
+ return NOERROR;
+ }
+ if (wTerminateIsComing (m_pDocChannel))
+ {
+ // We already did a StdCloseDocument, so the server is not willing
+ // to do an unadvise even though the default hanlder asked us to.
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::UnAdviseOn(%x) Terminate coming\n",
+ this));
+ return NOERROR;
+ }
+
+ if (iAdvOn == ON_RENAME)
+ {
+ aItem = wDupAtom (aStdDocName);
+ intrAssert(wIsValidAtom(aItem));
+ }
+ else
+ {
+ intrAssert(wIsValidAtom(m_aItem));
+ aItem = wExtendAtom (m_aItem, iAdvOn);
+ intrAssert(wIsValidAtom(aItem));
+ }
+
+
+ if (!wPostMessageToServer(m_pDocChannel, WM_DDE_UNADVISE,
+ MAKE_DDE_LPARAM (WM_DDE_UNADVISE,cfFormat,aItem),FALSE))
+ {
+ if (aItem)
+ GlobalDeleteAtom (aItem);
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::UnAdviseOn(%x) wPostMessage failed\n",
+ this));
+ return RPC_E_DDE_POST;
+ }
+
+ // Wait For Reply
+ hr = WaitForReply (m_pDocChannel, AA_UNADVISE, FALSE);
+ if (hr != NOERROR && hr != RPC_E_DDE_NACK)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::UnAdviseOn(%x)WaitForReply returns %x\n",
+ this));
+ return hr;
+ }
+
+
+ if (cfFormat==m_cfPict)
+ {
+ if (m_hPict)
+ {
+ // Invalidate the cache so when someone explicitly asks for
+ // the data, they will get fresh data.
+ wFreeData (m_hPict, m_cfPict, TRUE);
+ m_hPict = (HANDLE)0;
+ m_cfPict = 0;
+ }
+ }
+
+ // Due to a bug in the OLE1 libraries, unadvising on a presentation
+ // format effectively unadvises on native.
+ if (cfFormat != g_cfNative && m_fDidAdvNative)
+ {
+ if (iAdvOn == ON_SAVE)
+ {
+ // to reflect the fact that the native advise connection was lost
+ m_iAdvSave--;
+ m_fDidAdvNative = FALSE;
+ RetErr (AdviseOn (g_cfNative, ON_SAVE)); // re-establish
+ }
+ else if (iAdvOn == ON_CLOSE)
+ {
+ // to reflect the fact that the native advise connection was lost
+ m_iAdvClose--;
+ m_fDidAdvNative = FALSE;
+ RetErr (AdviseOn (g_cfNative, ON_CLOSE));
+ }
+ }
+
+ return NOERROR;
+}
+
+
+//
+// Post a message to a 1.0 server (callee) and wait for the acknowledge
+//
+
+
+INTERNAL CDdeObject::Poke
+ (ATOM aItem, HANDLE hDdePoke)
+{
+ HRESULT hr;
+
+ intrDebugOut((DEB_ITRACE,"CDdeObject::Poke(%x)\n",this));
+
+ ATOM aTmpItem;
+
+ intrAssert(wIsValidAtom(aItem));
+
+ aTmpItem = wDupAtom (aItem);
+
+ intrAssert(wIsValidAtom(aTmpItem));
+
+ m_pDocChannel->hDdePoke = hDdePoke;
+
+ LPARAM lp;
+ if (hr = wPostMessageToServer (m_pDocChannel,
+ WM_DDE_POKE,
+ lp=MAKE_DDE_LPARAM(WM_DDE_POKE,hDdePoke,aTmpItem),TRUE))
+ {
+ hr = WaitForReply (m_pDocChannel, AA_POKE);
+ intrDebugOut((DEB_ITRACE,"::Poke(%x) returning %x\n",this,hr));
+ return hr;
+ }
+
+ intrDebugOut((DEB_ITRACE,"::Poke(%x)wPostMessage failed %x\n",this,hr));
+ // Error case
+ if (aTmpItem)
+ GlobalDeleteAtom (aTmpItem);
+ wFreePokeData (m_pDocChannel, m_bOldSvr && m_aClass==aMSDraw);
+ hr = RPC_E_DDE_POST;
+ intrDebugOut((DEB_ITRACE,"::Poke(%x)wPostMessage returns %x\n",this,hr));
+ return hr;
+
+}
+
+INTERNAL CDdeObject::PostSysCommand
+ (LPDDE_CHANNEL pChannel,
+ LPCSTR szCmd,
+ BOOL fStdNew,
+ BOOL fWait)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::PostSysCommand(%x,szCmd=%s,fStdNew=%x,fWait=%x)\n",
+ this,
+ szCmd,
+ fStdNew,
+ fWait));
+
+ ULONG size;
+ WORD len;
+ LPSTR lpdata= NULL;
+ HANDLE hdata = NULL;
+ HRESULT hresult;
+
+
+ #define LN_FUDGE 16 // [],(), 3 * 3 (2 double quotes and comma)
+
+ len = strlen (szCmd);
+
+ // for StdNewDocument command add class name
+ if (fStdNew)
+ len += wAtomLenA (m_aClass);
+
+ // Now add the document length.
+ len += wAtomLenA (m_aTopic);
+
+ // now add the fudge factor for the Quotes etc.
+ len += LN_FUDGE;
+
+ // allocate the buffer and set the command.
+ if (!(hdata = GlobalAlloc (GMEM_DDESHARE, size = len)))
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+
+ if (!(lpdata = (LPSTR)GlobalLock (hdata))) {
+ Assert (0);
+ GlobalFree (hdata);
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ strcpy (lpdata, (LPSTR)"["); // [
+ strcat (lpdata, szCmd); // [StdCmd
+ if (strcmp (szCmd, "StdExit"))
+ {
+ strcat (lpdata, "(\""); // [StdCmd("
+
+ if (fStdNew)
+ {
+ len = strlen (lpdata);
+ GlobalGetAtomNameA (m_aClass, (LPSTR)lpdata + len, size-len);
+ // [StdCmd("class
+ strcat (lpdata, "\",\""); // [StdCmd("class","
+ }
+
+ len = strlen (lpdata);
+ // now get the topic name.
+ GlobalGetAtomNameA (m_aTopic, lpdata + len, (WORD)size - len);
+ // [StdCmd("class","topic
+ strcat (lpdata, "\")"); // [StdCmd("class","topic")
+ }
+ strcat (lpdata, "]");
+ Assert (strlen(lpdata) < size);
+ intrDebugOut((DEB_ITRACE,"::PostSysCommand(%x) hData(%s)\n",this,lpdata));
+ GlobalUnlock (hdata);
+
+ // return Execute (m_pSysChannel, hdata, /*fStdClose*/FALSE, fWait);
+ // REVIEW: this fixed bug 1856 (johannp)
+ // JasonFul - does it break something else?
+
+ hresult = Execute (m_pSysChannel,
+ hdata,
+ /*fStdClose*/FALSE,
+ fWait,
+ /*fDetectTerminate*/ TRUE);
+
+ intrDebugOut((DEB_ITRACE,"::PostSysCommand(%x) returns \n",this,hresult));
+ return hresult;
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::KeepData
+//
+// Synopsis: Given the DDEDATA structure from a WM_DDE_DATA message, extract
+// the real data and keep it till GetData or Save is done.
+//
+//
+// Effects:
+//
+// Arguments: [pChannel] --
+// [hDdeData] --
+//
+// Requires:
+//
+// Returns: E_OUTOFMEMORY or E_HANDLE if failure, NOERROR if success
+//
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-14-94 kevinro Commented
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL CDdeObject::KeepData
+ (LPDDE_CHANNEL pChannel, HANDLE hDdeData)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::KeepData(%x)\n",this));
+
+ DDEDATA * lpDdeData = NULL;
+ HANDLE hData;
+ CLIPFORMAT cfFormat;
+
+
+
+ if (!(lpDdeData = (DDEDATA *) (GlobalLock (hDdeData))))
+ {
+ return E_OUTOFMEMORY;;
+ }
+
+
+ cfFormat = lpDdeData->cfFormat;
+ intrDebugOut((DEB_ITRACE,
+ "::KeepData(%x) Keeping cfFormat=%x\n",
+ this,
+ cfFormat));
+
+ GlobalUnlock (hDdeData);
+
+ // Possible Side effect of wHandleFromDdeData() is the freeing of hDdeData
+ if (!(hData = wHandleFromDdeData (hDdeData))
+ || !wIsValidHandle (hData, cfFormat) )
+ {
+ Assert(0);
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ if (cfFormat == g_cfNative) {
+ if (m_hNative)
+ GlobalFree (m_hNative);
+ // Keep the native data
+ RetErr (wTransferHandle (&m_hNative, &hData, cfFormat));
+ }
+ else if (cfFormat == CF_METAFILEPICT ||
+ cfFormat == CF_BITMAP ||
+ cfFormat == CF_DIB)
+ {
+ if (m_hPict)
+ wFreeData (m_hPict, m_cfPict, TRUE);
+ m_cfPict = cfFormat;
+ // Keep the presentation data
+ RetErr (wTransferHandle (&m_hPict, &hData, cfFormat));
+
+#ifdef OLD
+ // Remember size of picture so we can return
+ // a reasonable answer for GetExtent
+ if (cfFormat == CF_METAFILEPICT)
+ {
+ LPMETAFILEPICT lpMfp = (LPMETAFILEPICT) GlobalLock (m_hPict);
+ if (NULL==lpMfp)
+ return E_HANDLE;
+ UpdateExtent (m_cxContentExtent, lpMfp->xExt);
+ UpdateExtent (m_cyContentExtent, lpMfp->yExt);
+ GlobalUnlock (m_hPict);
+ }
+ else if (cfFormat==CF_BITMAP)
+ {
+ BITMAP bm;
+ if (0==GetObject (m_hPict, sizeof(BITMAP), (LPVOID) &bm))
+ return E_HANDLE;
+ UpdateExtent (m_cxContentExtent,
+ wPixelsToHiMetric (bm.bmWidth, giPpliX));
+ UpdateExtent (m_cyContentExtent,
+ wPixelsToHiMetric (bm.bmHeight,giPpliY));
+ }
+ else if (cfFormat==CF_DIB)
+ {
+ BITMAPINFOHEADER * pbminfohdr;
+ pbminfohdr = (BITMAPINFOHEADER *) GlobalLock (m_hPict);
+ if (NULL==pbminfohdr)
+ return E_HANDLE;
+ UpdateExtent (m_cxContentExtent,
+ wPixelsToHiMetric (pbminfohdr->biWidth, giPpliX));
+ UpdateExtent (m_cyContentExtent,
+ wPixelsToHiMetric (pbminfohdr->biHeight,giPpliY));
+ GlobalUnlock (m_hPict);
+ }
+#endif
+
+ }
+ else
+ {
+ if (m_hExtra)
+ wFreeData (m_hExtra, m_cfExtra, TRUE);
+ m_cfExtra = cfFormat;
+ wTransferHandle (&m_hExtra, &hData, cfFormat);
+ }
+
+ return NOERROR;
+}
+
+
+// IsFormatAvailable
+//
+// Does a temporary DDE_REQUEST to see if server supports a format
+// Returns NOERROR if format is available.
+//
+
+
+INTERNAL CDdeObject::IsFormatAvailable
+ (LPFORMATETC pformatetc)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::IsFormatAvailable(%x)\n",this));
+ ATOM aItem=(ATOM)0;
+ HRESULT hresult;
+
+ Puts ("DdeObject::IsFormatAvailable\n");
+
+ if (!HasValidLINDEX(pformatetc))
+ {
+ intrDebugOut((DEB_IERROR, "\t!HasValidLINDEX(pformatetc)\n"));
+ return(DV_E_LINDEX);
+ }
+
+ if (0==pformatetc->cfFormat)
+ return ResultFromScode (E_INVALIDARG);
+
+ if (pformatetc->dwAspect & DVASPECT_ICON)
+ {
+ if (pformatetc->cfFormat==CF_METAFILEPICT)
+ {
+ // This is always available. we get it from the exe.
+ return NOERROR;
+ }
+ // an icon must be a metafile
+ return ResultFromScode (S_FALSE);
+ }
+ if (!(pformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_DOCPRINT)))
+ {
+ // 1.0 does not support Thumb.
+ return ReportResult(0, S_FALSE, 0, 0);
+ }
+
+ if (NOERROR == (hresult=m_ConnectionTable.Lookup (pformatetc->cfFormat, NULL)))
+ {
+ // We already got a call to DataObject::Advise on this format,
+ // so it must be available.
+ Puts ("DataObject::Advise had been done on this format.\n");
+ return NOERROR;
+ }
+ else
+ {
+ // Lookup () didn't find this format.
+ ErrZ (GetScode(hresult)==S_FALSE);
+ }
+
+ intrAssert(wIsValidAtom(m_aItem));
+ aItem = wDupAtom (m_aItem);
+ intrAssert(wIsValidAtom(aItem));
+
+ LPARAM lp;
+ if(!wPostMessageToServer (m_pDocChannel, WM_DDE_REQUEST,
+ lp = MAKE_DDE_LPARAM (WM_DDE_REQUEST,pformatetc->cfFormat,aItem),TRUE))
+ {
+
+ return(RPC_E_DDE_POST);
+ }
+
+ if (NOERROR==WaitForReply (m_pDocChannel, AA_REQUESTAVAILABLE))
+ return NOERROR;
+
+ // Last ditch effort: Advise
+ if (NOERROR== AdviseOn (pformatetc->cfFormat, ON_SAVE))
+ {
+ // We cannot Unadvise because an OLE 1.0 bug
+ // terminates DDE advise connections for ALL formats.
+ //// UnAdviseOn (pformatetc->cfFormat, ON_SAVE);
+ // Instead, just remember we did this advise.
+ m_ConnectionTable.Add (0, pformatetc->cfFormat, ADVFDDE_ONSAVE);
+ return NOERROR;
+ }
+ return ResultFromScode (S_FALSE);
+
+errRtn:
+ AssertSz (0, "Error in CDdeObject::IsFormatAvailable");
+ Puth (hresult); Putn();
+ if (aItem)
+ GlobalDeleteAtom (aItem);
+
+ return hresult;
+}
+
+
+
+
+INTERNAL CDdeObject::ChangeTopic
+ (LPSTR lpszTopic)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::ChangeTopic(%x,lpszTopic=%s)\n",this,lpszTopic));
+ HRESULT hresult;
+ LPMONIKER pmkFile=NULL;
+ LPMONIKER pmkItem=NULL;
+ LPMONIKER pmkComp=NULL;
+ LPMONIKER pmkNewName=NULL;
+ ATOM aTopic = wGlobalAddAtomA (lpszTopic);
+ intrAssert(wIsValidAtom(aTopic));
+
+ // Yet-Another-Excel-Hack
+ // Excel 4.0 sends StdDocumentName every time it saves,
+ // whether or not the file name has actually changed. Bug 2957
+ if (aTopic != m_aTopic)
+ {
+ ErrRtnH (CreateOle1FileMoniker (wAtomName(aTopic), m_clsid, &pmkFile));
+ if (m_aItem)
+ {
+ intrAssert (wIsValidAtom (m_aItem));
+ ErrRtnH (CreateItemMoniker (OLESTR("!"), wAtomName (m_aItem), &pmkItem));
+ ErrRtnH (CreateGenericComposite (pmkFile, pmkItem, &pmkComp));
+ (pmkNewName = pmkComp)->AddRef();
+ }
+ else
+ {
+ (pmkNewName = pmkFile)->AddRef();
+ }
+ RetZS (m_pOleAdvHolder, E_OUTOFMEMORY);
+ RetZ (pmkNewName);
+ ErrRtnH (m_pOleAdvHolder->SendOnRename (pmkNewName));
+ }
+ SetTopic (aTopic);
+ hresult = NOERROR;
+
+ errRtn:
+ if (pmkFile)
+ pmkFile->Release();
+ if (pmkItem)
+ pmkItem->Release();
+ if (pmkComp)
+ pmkComp->Release();
+ if (pmkNewName)
+ pmkNewName->Release();
+ return hresult;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::ChangeItem
+//
+// Synopsis: Changes the m_aItem atom, using an Ansi string
+//
+// Effects:
+//
+// Arguments: [szItem] -- Ansi string for the new item
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL_(void) CDdeObject::ChangeItem
+ (LPSTR szItem)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::ChangeItem(%x,szItem=%s)\n",this,szItem));
+ intrAssert(wIsValidAtom(m_aItem));
+ if (m_aItem)
+ GlobalDeleteAtom (m_aItem);
+ m_aItem = wGlobalAddAtomA (szItem);
+ intrAssert(wIsValidAtom(m_aItem));
+}
+
+
+
+
+INTERNAL CDdeObject::DeclareVisibility
+ (BOOL f,
+ BOOL fCallOnShowIfNec)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::DelcareVisibility(%x)\n",this));
+ if (f)
+ m_fWasEverVisible = TRUE;
+ if ((f && (!m_fVisible || !m_fCalledOnShow)) ||
+ (!f && m_fVisible))
+ {
+ if (m_pOleClientSite && fCallOnShowIfNec && m_clsid != CLSID_Package)
+ {
+ m_pOleClientSite->OnShowWindow (f);
+ m_fCalledOnShow = f;
+ }
+ m_fVisible = f;
+ }
+ return NOERROR;
+}
+
+
+
+INTERNAL CDdeObject::Update
+ (BOOL fRequirePresentation)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::Update(%x,fRequiredPresentation=%x)\n",
+ this,
+ fRequirePresentation));
+ // Get latest data
+ // OLE 1.0 spec says servers must supply metafile format.
+ HRESULT hresult = RequestData (m_cfPict ? m_cfPict : CF_METAFILEPICT);
+ if (fRequirePresentation && hresult!=NOERROR)
+ return hresult;
+ RetErr (RequestData (g_cfNative));
+ SendOnDataChange (ON_CHANGE);
+ return NOERROR;
+}
+
+
+
+INTERNAL CDdeObject::Save
+ (LPSTORAGE pstg)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::Save(%x)\n",this));
+ VDATEIFACE (pstg);
+#ifdef OLE1INTEROP
+ RetErr (StSave10NativeData (pstg, m_hNative, m_fOle1interop));
+#else
+ RetErr (StSave10NativeData (pstg, m_hNative, FALSE));
+#endif
+ if (m_aItem)
+ {
+ intrAssert(wIsValidAtom(m_aItem));
+ RetErr (StSave10ItemName (pstg, wAtomNameA (m_aItem)));
+ }
+ RetErr (wWriteFmtUserType (pstg, m_clsid));
+ return NOERROR;
+}
+
+/*
+ * IMPLEMENTATION of CUnknownImpl
+ *
+ */
+
+
+
+STDMETHODIMP_(ULONG) NC(CDdeObject,CUnknownImpl)::AddRef()
+{
+ ChkD(m_pDdeObject);
+
+ return InterlockedAddRef(&(m_pDdeObject->m_refs));
+}
+
+
+STDMETHODIMP_(ULONG) NC(CDdeObject,CUnknownImpl)::Release()
+{
+ ChkD(m_pDdeObject);
+ Assert (m_pDdeObject->m_refs != 0);
+ ULONG ul;
+
+ if ((ul=InterlockedRelease(&(m_pDdeObject->m_refs))) == 0) {
+ m_pDdeObject->m_ProxyMgr.Disconnect();
+
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ // the object can not be delete if guarded
+ // which is the case if DelayDelete state is 'DelayIt'
+ //
+ if (m_pDdeObject->_DelayDelete == DelayIt)
+ {
+ // set the state to ReadyToDelete and
+ // the object will be deleted at the
+ // UnGuard call
+ m_pDdeObject->_DelayDelete = ReadyToDelete;
+ intrDebugOut((DEB_IWARN ,"Can not release CDdeObject\n"));
+ return 1;
+ }
+#endif //_CHICAGO_
+ delete m_pDdeObject;
+ return 0;
+ }
+ return ul;
+}
+
+
+
+
+STDMETHODIMP NC(CDdeObject,CUnknownImpl)::QueryInterface(REFIID iid, LPLPVOID ppv)
+{
+ ChkD(m_pDdeObject);
+ if (iid == IID_IUnknown) {
+ *ppv = (void FAR *)&m_pDdeObject->m_Unknown;
+ AddRef();
+ return NOERROR;
+ }
+ else if (iid == IID_IOleObject)
+ *ppv = (void FAR *) &(m_pDdeObject->m_Ole);
+ else if (iid == IID_IDataObject)
+ *ppv = (void FAR *) &(m_pDdeObject->m_Data);
+ else if (iid == IID_IPersist || iid == IID_IPersistStorage)
+ *ppv = (void FAR *) &(m_pDdeObject->m_PersistStg);
+ else if (iid == IID_IProxyManager)
+ *ppv = (void FAR *) &(m_pDdeObject->m_ProxyMgr);
+ else if (iid == IID_IOleItemContainer
+ || iid == IID_IOleContainer
+ || iid == IID_IParseDisplayName)
+ *ppv = (void FAR *) &(m_pDdeObject->m_OleItemContainer);
+ else {
+ Puts ("INTERFACE NOT FOUND \r\n");
+ *ppv = NULL;
+ return ReportResult(0, E_NOINTERFACE, 0, 0);
+ }
+
+ m_pDdeObject->m_pUnkOuter->AddRef();
+ return NOERROR;
+}
+
diff --git a/private/ole32/com/remote/dde/client/ddeproxy.h b/private/ole32/com/remote/dde/client/ddeproxy.h
new file mode 100644
index 000000000..8f55b6dd2
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/ddeproxy.h
@@ -0,0 +1,608 @@
+/* ddeproxy.h
+
+ Used by ddeproxy.cpp ddeDO.cpp ddeOO.cpp
+
+ Author: Jason Fuller jasonful 24-July-1992
+
+*/
+#ifndef fDdeProxy_h
+#define fDdeProxy_h
+
+//
+// One of the oleint.h routines redefines GlobalAlloc and friends
+// to perform some memory tracking functions.
+//
+// This doesn't work in these files, since the tracking functions
+// add tail checking, and size to the data structures. GlobalSize
+// is a common function to use to determine how much data to
+// serialize, plus it turns out that the other side of a DDE
+// connection will often be the caller to free the memory.
+//
+// Therefore, OLE_DDE_NO_GLOBAL_TRACKING is used to disable this in the
+// global header file ih\memapi.hxx. Check to insure this
+// flag is set on the compile line
+//
+#if !defined(OLE_DDE_NO_GLOBAL_TRACKING)
+error OLE_DDE_OLE_DDE_NO_GLOBAL_TRACKING must be defined to build this directory
+#endif
+
+
+#include <ole2int.h>
+#include <callcont.hxx>
+#include <ddeint.h>
+#include <dde.h>
+#include <olerem.h>
+#include <ole1cls.h>
+#include <limits.h>
+// For fDdeCodeInOle2Dll flag
+#include <ddeatoms.h>
+#include <ddepack.h>
+#include <ddedebug.h>
+
+#ifdef OLE_DEBUG_EXT
+#include <ntsdexts.h>
+#endif OLE_DEBUG_EXT
+
+#include "ddechc.hxx"
+#define LPCALLINFO LPVOID
+#include "ddeerr.h"
+#include "cnct_tbl.h"
+
+#define MAX_STR 256
+
+// number of .01 mm per inch
+#define HIMETRIC_PER_INCH 2540
+
+//#define fDebugOutput
+
+// callback notifications
+#define ON_CHANGE 0
+#define ON_SAVE 1
+#define ON_CLOSE 2
+#define ON_RENAME 3
+
+// AwaitAck values
+#define AA_NONE 0
+#define AA_REQUEST 1
+#define AA_ADVISE 2
+#define AA_POKE 3
+#define AA_EXECUTE 4
+#define AA_UNADVISE 5
+#define AA_INITIATE 6
+#define AA_TERMINATE 7
+// A DDE_REQUEST to see if a format is available, not to keep the data.
+#define AA_REQUESTAVAILABLE 8
+
+// Bits for Positive WM_DDE_ACK
+//#define POSITIVE_ACK 0x8000
+//#define NEGATIVE_ACK 0x0000
+
+
+
+typedef DWORD CHK;
+const DWORD chkDdeObj = 0xab01; // magic cookie
+
+
+typedef struct tagDDE_CHANNEL : public CPrivAlloc {
+ ULONG AddReference()
+ {
+ return ++m_cRefs;
+ }
+ ULONG ReleaseReference()
+ {
+ if (--m_cRefs == 0)
+ {
+ delete this;
+ return(0);
+ }
+ return(m_cRefs);
+ }
+ ULONG m_cRefs;
+ HWND hwndCli;
+ HWND hwndSvr;
+ BOOL bTerminating;
+ int iExtraTerms;
+ WORD wTimer;
+ DWORD dwStartTickCount;
+ WORD msgFirst;
+ WORD msgLast;
+ HWND msghwnd; //
+ BOOL fRejected; // because fBusy flag set in DDE_ACK
+ WORD wMsg;
+ LONG lParam;
+ int iAwaitAck;
+ HRESULT hres;
+ HANDLE hopt; // Memory blocks I may have to free for DDE_ADVISE
+ HANDLE hDdePoke; // for DDE_POKE
+ HANDLE hCommands; // for DDE_EXECUTE
+ WORD wChannelDeleted;
+ PCALLDATA pCD;
+ PCALLCONTROL pCallCont;
+ CDdeChannelControl *pChanCont;
+} DDE_CHANNEL;
+
+
+#define Channel_InModalloop 1
+#define Channel_DeleteNow 2
+
+
+typedef DDE_CHANNEL * LPDDE_CHANNEL;
+extern BOOL bWndClassesRegistered;
+
+#define hinstSO g_hmodOLE2
+extern HMODULE g_hmodOLE2;
+
+extern INTERNAL_(BOOL) wRegisterClasses (void);
+
+#ifndef _MAC
+extern CLIPFORMAT g_cfNative;
+extern CLIPFORMAT g_cfBinary;
+#endif
+
+#ifdef _CHICAGO_
+//Note:POSTPPC
+//
+// DelayDelete is used to delay deleting the CDdeObject
+// Guard will set it to DelayIt
+// UnGuard will reset it to NoDelay or delete the object
+// if state is ReadyToDelete
+//
+typedef enum
+{
+ NoDelay = 0, // normal state
+ DelayIt = 1, // object is protected and deleting will be delayed
+ ReadyToDelete = 2 // object was is DelayIt state and can be deleted
+} DelayDelete;
+
+#endif // _CHICAGO_
+
+/*
+ * Definition of CDdeObject
+ *
+ */
+class CMsgFilterInfo;
+class CDdeObject;
+
+class CDdeObject : public CPrivAlloc
+{
+public:
+
+ static INTERNAL_(LPUNKNOWN) Create (IUnknown * pUnkOuter,
+ REFCLSID clsidClass,
+ ULONG ulObjType = OT_EMBEDDED,
+ ATOM aTopic = NULL,
+ LPOLESTR szItem = NULL,
+ CDdeObject * * ppdde = NULL,
+ BOOL fAllowNullClsid = FALSE);
+
+ INTERNAL_(void) OnInitAck (LPDDE_CHANNEL pChannel, HWND hwndSvr);
+ INTERNAL_(BOOL) OnAck (LPDDE_CHANNEL pChannel, LONG lParam);
+ INTERNAL_(void) OnTimer (LPDDE_CHANNEL pChannel);
+ INTERNAL OnData (LPDDE_CHANNEL pChannel, HANDLE hData,ATOM aItem);
+ INTERNAL OnDataAvailable (LPDDE_CHANNEL pChannel, HANDLE hData,ATOM aItem);
+ INTERNAL OnTerminate (LPDDE_CHANNEL pChannel, HWND hwndPost);
+
+ INTERNAL_(LPDDE_CHANNEL) GetSysChannel(void)
+ { return m_pSysChannel; }
+
+ INTERNAL_(LPDDE_CHANNEL) GetDocChannel(void)
+ { return m_pDocChannel; }
+
+ INTERNAL_(BOOL) AllocDdeChannel(LPDDE_CHANNEL * lpChannel, LPSTR lpszWndClass);
+ INTERNAL_(BOOL) InitSysConv (void);
+ INTERNAL_(void) SetTopic (ATOM aTopic);
+
+ INTERNAL SendOnDataChange (int iAdvOpt);
+ INTERNAL OleCallBack (int iAdvOpt,LPDDE_CHANNEL pChannel);
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ INTERNAL_(void) Guard()
+ {
+ intrDebugOut((DEB_IWARN ,"CDdeObject: %x DelayDelete is set to 'DelayIt'\n", this));
+ _DelayDelete = DelayIt;
+ }
+ INTERNAL_(BOOL) UnGuard()
+ {
+ if (_DelayDelete == ReadyToDelete)
+ {
+ intrDebugOut((DEB_IWARN ,"CDdeObject: %x DelayDelete it set 'ReadyToDelete'\n", this));
+ delete this;
+ intrDebugOut((DEB_IWARN ,"CDdeObject: %x was deleted\n", this));
+ return TRUE;
+ }
+ else
+ {
+ intrDebugOut((DEB_IWARN ,"CDdeObject: %x DelayDelete set to 'NoDelay'\n", this));
+ _DelayDelete = NoDelay;
+ }
+
+ return FALSE;
+ }
+#endif // _CHICAGO_
+
+ BOOL m_fDoingSendOnDataChange;
+ ULONG m_cRefCount;
+
+private:
+
+ CDdeObject (IUnknown * pUnkOuter);
+ ~CDdeObject (void);
+ INTERNAL TermConv (LPDDE_CHANNEL pChannel, BOOL fWait=TRUE);
+ INTERNAL_(void) DeleteChannel (LPDDE_CHANNEL pChannel);
+ INTERNAL_(BOOL) LaunchApp (void);
+ INTERNAL MaybeUnlaunchApp (void);
+ INTERNAL UnlaunchApp (void);
+ INTERNAL Execute (LPDDE_CHANNEL pChannel,
+ HANDLE hdata,
+ BOOL fStdCloseDoc=FALSE,
+ BOOL fWait=TRUE,
+ BOOL fDetectTerminate = TRUE);
+ INTERNAL Advise(void);
+ INTERNAL AdviseOn (CLIPFORMAT cfFormat, int iAdvOn);
+ INTERNAL UnAdviseOn (CLIPFORMAT cfFormat, int iAdvOn);
+ INTERNAL Poke (ATOM aItem, HANDLE hDdePoke);
+ INTERNAL PostSysCommand (LPDDE_CHANNEL pChannel,
+ LPCSTR szCmd,
+ BOOL bStdNew=FALSE,
+ BOOL fWait=TRUE);
+
+#ifdef _CHICAGO_
+ //POSTPPC
+ INTERNAL_(BOOL) CanMakeOutCall(LPDDE_CHANNEL pChannel);
+#endif
+
+ INTERNAL WaitForReply (LPDDE_CHANNEL pChannel,
+ int iAwaitAck,
+ BOOL fStdCloseDoc = FALSE,
+ BOOL fDetectTerminate = TRUE);
+ INTERNAL KeepData (LPDDE_CHANNEL pChannel, HANDLE hDdeData);
+ INTERNAL ChangeTopic (LPSTR lpszTopic);
+ INTERNAL_(void) ChangeItem (LPSTR lpszItem);
+ INTERNAL IsFormatAvailable (LPFORMATETC);
+ INTERNAL_(BOOL) CanCallBack(LPINT);
+ INTERNAL RequestData (CLIPFORMAT);
+ INTERNAL SetTargetDevice (const DVTARGETDEVICE *);
+ INTERNAL DocumentLevelConnect (LPBINDCTX pbc);
+ INTERNAL SendOnClose (void);
+ INTERNAL UpdateAdviseCounts (CLIPFORMAT cf,
+ int iAdvOn,
+ signed int cDelta);
+ INTERNAL DeclareVisibility (BOOL fVisible,
+ BOOL fCallOnShowIfNec=TRUE);
+ INTERNAL Save (LPSTORAGE);
+ INTERNAL Update (BOOL fRequirePresentation);
+
+implementations:
+
+ STDUNKDECL(CDdeObject,DdeObject)
+ STDDEBDECL(CDdeObject,DdeObject)
+
+
+ implement COleObjectImpl : IOleObject
+ {
+ public:
+ COleObjectImpl (CDdeObject * pDdeObject)
+ { m_pDdeObject = pDdeObject; }
+
+ // *** IUnknown methods ***
+ STDMETHOD(QueryInterface) ( REFIID riid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) ();
+ STDMETHOD_(ULONG,Release) ();
+
+ // *** IOleObject methods ***
+ STDMETHOD(SetClientSite) ( LPOLECLIENTSITE pClientSite);
+ STDMETHOD(GetClientSite) ( LPOLECLIENTSITE * ppClientSite);
+ STDMETHOD(SetHostNames) ( LPCOLESTR szContainerApp, LPCOLESTR szContainerObj);
+ STDMETHOD(Close) ( DWORD reserved);
+ STDMETHOD(SetMoniker) ( DWORD dwWhichMoniker, LPMONIKER pmk);
+ STDMETHOD(GetMoniker) ( DWORD dwAssign, DWORD dwWhichMoniker,LPMONIKER * ppmk);
+ STDMETHOD(InitFromData) ( LPDATAOBJECT pDataObject,BOOL fCreation,DWORD dwReserved);
+ STDMETHOD(GetClipboardData) ( DWORD dwReserved,LPDATAOBJECT * ppDataObject);
+
+ STDMETHOD(DoVerb) ( LONG iVerb,
+ LPMSG lpmsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lindex,
+ HWND hwndParent,
+ const RECT * lprcPosRect);
+
+ STDMETHOD(EnumVerbs) ( IEnumOLEVERB * * ppenumOleVerb);
+ STDMETHOD(Update) ();
+ STDMETHOD(IsUpToDate) ();
+ STDMETHOD(GetUserClassID) ( CLSID * pClsid);
+ STDMETHOD(GetUserType) ( DWORD dwFormOfType, LPOLESTR * pszUserType);
+ STDMETHOD(SetExtent) ( DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHOD(GetExtent) ( DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHOD(Advise)( IAdviseSink * pAdvSink, DWORD * pdwConnection) ;
+ STDMETHOD(Unadvise) ( DWORD dwConnection);
+ STDMETHOD(EnumAdvise) ( LPENUMSTATDATA * ppenumAdvise);
+ STDMETHOD(GetMiscStatus) ( DWORD dwAspect, DWORD * pdwStatus);
+ STDMETHOD(SetColorScheme) ( LPLOGPALETTE lpLogpal);
+
+ private:
+ CDdeObject * m_pDdeObject;
+ };
+
+
+ implement CDataObjectImpl : IDataObject
+ {
+ public:
+ CDataObjectImpl (CDdeObject * pDdeObject)
+ { m_pDdeObject = pDdeObject; }
+ // *** IUnknown methods ***
+ STDMETHOD(QueryInterface) ( REFIID riid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) () ;
+ STDMETHOD_(ULONG,Release) ();
+
+ STDMETHOD(GetData) ( LPFORMATETC pformatetcIn,LPSTGMEDIUM pmedium );
+ STDMETHOD(GetDataHere) ( LPFORMATETC pformatetc,LPSTGMEDIUM pmedium );
+ STDMETHOD(QueryGetData) ( LPFORMATETC pformatetc );
+ STDMETHOD(GetCanonicalFormatEtc) ( LPFORMATETC pformatetc,LPFORMATETC pformatetcOut);
+ STDMETHOD(SetData) ( LPFORMATETC pformatetc, STGMEDIUM * pmedium, BOOL fRelease);
+ STDMETHOD(EnumFormatEtc) ( DWORD dwDirection, LPENUMFORMATETC * ppenumFormatEtc);
+ STDMETHOD(DAdvise) ( FORMATETC * pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD * pdwConnection) ;
+ STDMETHOD(DUnadvise) ( DWORD dwConnection) ;
+ STDMETHOD(EnumDAdvise) ( LPENUMSTATDATA * ppenumAdvise) ;
+
+ private:
+ CDdeObject * m_pDdeObject;
+ };
+
+
+ implement CPersistStgImpl : IPersistStorage
+ {
+ public:
+ CPersistStgImpl (CDdeObject * pDdeObject)
+ { m_pDdeObject = pDdeObject; }
+
+ STDMETHOD(QueryInterface) ( REFIID iid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) ();
+ STDMETHOD_(ULONG,Release) ();
+ STDMETHOD(GetClassID) ( LPCLSID pClassID);
+ STDMETHOD(IsDirty) (void);
+ STDMETHOD(InitNew) ( LPSTORAGE pstg);
+ STDMETHOD(Load) ( LPSTORAGE pstg);
+ STDMETHOD(Save) ( LPSTORAGE pstgSave, BOOL fSameAsLoad);
+ STDMETHOD(SaveCompleted) ( LPSTORAGE pstgNew);
+ STDMETHOD(HandsOffStorage) (void);
+
+ private:
+ CDdeObject * m_pDdeObject;
+ };
+
+
+ implement CProxyManagerImpl : IProxyManager
+ {
+ public:
+ CProxyManagerImpl (CDdeObject * pDdeObject)
+ { m_pDdeObject = pDdeObject; }
+
+ STDMETHOD(QueryInterface) ( REFIID iid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) ();
+ STDMETHOD_(ULONG,Release) ();
+
+ STDMETHOD(CreateServer)(REFCLSID rclsid, DWORD clsctx, void *pv);
+ STDMETHOD_(BOOL, IsConnected)(void);
+ STDMETHOD(LockConnection)(BOOL fLock, BOOL fLastUnlockReleases);
+ STDMETHOD_(void, Disconnect)();
+
+
+ STDMETHOD(Connect)(OID oid, REFCLSID rclsid);
+ STDMETHOD(EstablishIID)(REFIID iid, LPVOID FAR* ppv);
+
+ STDMETHOD(CreateServerWithHandler)(REFCLSID rclsid, DWORD clsctx, void *pv,
+ REFCLSID rclsidHandler, IID iidSrv, void **ppv,
+ IID iidClnt, void *pClientSiteInterface);
+
+ private:
+ CDdeObject * m_pDdeObject;
+ };
+
+
+ implement COleItemContainerImpl : IOleItemContainer
+ {
+ public:
+ COleItemContainerImpl (CDdeObject * pDdeObject)
+ { m_pDdeObject = pDdeObject; }
+
+ STDMETHOD(QueryInterface) ( REFIID iid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) ();
+ STDMETHOD_(ULONG,Release) ();
+
+ // IParseDisplayName method
+ STDMETHOD(ParseDisplayName) ( LPBC pbc,
+ LPOLESTR lpszDisplayName,
+ ULONG * pchEaten,
+ LPMONIKER * ppmkOut) ;
+
+ // IOleContainer methods
+ STDMETHOD(EnumObjects) ( DWORD grfFlags,LPENUMUNKNOWN * ppenumUnk);
+
+ STDMETHOD(LockContainer) (BOOL fLock);
+
+ // IOleItemContainer methods
+ STDMETHOD(GetObject) ( LPOLESTR lpszItem,
+ DWORD dwSpeedNeeded,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID * ppvObject) ;
+ STDMETHOD(GetObjectStorage) ( LPOLESTR lpszItem,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID * ppvStorage) ;
+
+ STDMETHOD(IsRunning) ( LPOLESTR lpszItem) ;
+
+ private:
+ CDdeObject * m_pDdeObject;
+ };
+
+
+
+ DECLARE_NC(CDdeObject, COleObjectImpl)
+ DECLARE_NC(CDdeObject, CDataObjectImpl)
+ DECLARE_NC(CDdeObject, CPersistStgImpl)
+ DECLARE_NC(CDdeObject, CProxyManagerImpl)
+ DECLARE_NC(CDdeObject, COleItemContainerImpl)
+
+ COleObjectImpl m_Ole;
+ CDataObjectImpl m_Data;
+ CPersistStgImpl m_PersistStg;
+ CProxyManagerImpl m_ProxyMgr;
+ COleItemContainerImpl m_OleItemContainer;
+
+shared_state:
+ ULONG m_refs;
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ DelayDelete _DelayDelete;
+#endif // _CHICAGO_
+ ULONG m_ulObjType;
+ CLSID m_clsid;
+ ATOM m_aClass;
+ ATOM m_aExeName;
+ ATOM m_aTopic;
+ ATOM m_aItem;
+ BOOL m_bRunning;
+ IUnknown * m_pUnkOuter;
+ IOleClientSite * m_pOleClientSite;
+ LPSTORAGE m_pstg;
+ BOOL m_bInitNew;
+ BOOL m_bOldSvr;
+ HANDLE m_hNative;
+ HANDLE m_hPict;
+ HANDLE m_hExtra;
+ CLIPFORMAT m_cfPict;
+ CLIPFORMAT m_cfExtra;
+
+ BOOL m_fDidSendOnClose;
+ BOOL m_fNoStdCloseDoc;
+ BOOL m_fDidStdCloseDoc;
+ BOOL m_fDidStdOpenDoc;
+ BOOL m_fDidGetObject;
+ BOOL m_fDidLaunchApp;
+ BOOL m_fUpdateOnSave;
+ BOOL m_fGotCloseData;
+
+#ifdef OLE1INTEROP
+ BOOL m_fOle1interop;
+#endif
+
+ // Invisible update stuff
+ ULONG m_cLocks; // PM::LockConnection lock count (init 1)
+ BOOL m_fVisible; // is server visible (as best we know)?
+ BOOL m_fWasEverVisible;
+ BOOL m_fCalledOnShow; // Did we call IOleClientSite::OnShow
+
+ CHK m_chk;
+ DVTARGETDEVICE * m_ptd;
+
+ // m_iAdvClose and m_iAdvSave are counts (1 or 2) of the number of formats
+ // that have advise connections of a given type (Save or Close)
+ int m_iAdvClose;
+ int m_iAdvSave;
+ int m_iAdvChange;
+
+ BOOL m_fDidAdvNative;
+
+ // Extent info
+#ifdef OLD
+ long m_cxContentExtent;
+ long m_cyContentExtent;
+#endif
+
+ // terminate info - only used to detect a premature WM_DDE_TERMINATE
+ WORD m_wTerminate;
+
+ IDataAdviseHolder * m_pDataAdvHolder;
+ IOleAdviseHolder * m_pOleAdvHolder;
+ CDdeConnectionTable m_ConnectionTable;
+
+
+ // DDE window related stuff
+ LPDDE_CHANNEL m_pSysChannel;
+ LPDDE_CHANNEL m_pDocChannel;
+
+ friend INTERNAL DdeBindToObject
+ (LPCOLESTR szFile,
+ REFCLSID clsid,
+ BOOL fPackageLink,
+ REFIID iid,
+ LPLPVOID ppv);
+
+ friend INTERNAL DdeIsRunning
+ (CLSID clsid,
+ LPCOLESTR szFile,
+ LPBC pbc,
+ LPMONIKER pmkToLeft,
+ LPMONIKER pmkNewlyRunning);
+#ifdef OLE_DEBUG_EXT
+
+#endif OLE_DEBUG_EXT
+};
+//
+// Note: WM_DDE_TERMINATE
+// A state machine is used to delay the executing of a premature WM_DDE_TERMINTE
+// message, which is send by some apps instead of WM_DDE_ACK (or alike).
+// The code is in WaitForReply() and in OnTerminate()
+typedef enum {
+ Terminate_None = 0, // default state - terminate code is executed
+ Terminate_Detect = 1, // window proc will NOT execute terminate code
+ Terminate_Received = 2 // wait loop does not need to run, execute terminate code now
+} TERMINATE_DOCUMENT;
+
+
+
+INTERNAL_(BOOL) wPostMessageToServer(LPDDE_CHANNEL pChannel,
+ WORD wMsg,
+ LONG lParam,
+ BOOL fFreeOnError);
+
+INTERNAL_(ATOM) wAtomFromCLSID(REFCLSID rclsid);
+INTERNAL_(ATOM) wGetExeNameAtom (REFCLSID rclsid);
+INTERNAL_(BOOL) wIsWindowValid (HWND hwnd);
+INTERNAL_(void) wFreeData (HANDLE hData, CLIPFORMAT cfFormat,
+ BOOL fFreeNonGdiHandle=TRUE);
+INTERNAL_(BOOL) wInitiate (LPDDE_CHANNEL pChannel, ATOM aLow, ATOM aHigh);
+INTERNAL wScanItemOptions (ATOM aItem, int * lpoptions);
+INTERNAL_(BOOL) wClearWaitState (LPDDE_CHANNEL pChannel);
+INTERNAL_(HANDLE) wStdCloseDocumentHandle (void);
+INTERNAL_(ATOM) wExtendAtom (ATOM aIitem, int iAdvOn);
+INTERNAL_(int) wAtomLen (ATOM atom);
+INTERNAL_(int) wAtomLenA (ATOM atom);
+INTERNAL_(LPDDE_CHANNEL) wAllocDdeChannel(void);
+INTERNAL_(HANDLE) wHandleFromDdeData(HANDLE hDdeData);
+INTERNAL_(BOOL) wIsOldServer (ATOM aClass);
+INTERNAL_(LPSTR) wAllocDdePokeBlock (DWORD dwSize, CLIPFORMAT cfFormat,LPHANDLE phDdePoke);
+INTERNAL_(void) wFreePokeData (LPDDE_CHANNEL pChannel, BOOL fMSDrawBug);
+INTERNAL_(HANDLE) wPreparePokeBlock (HANDLE hData, CLIPFORMAT cfFormat,
+ ATOM aClass, BOOL bOldSvr);
+INTERNAL_(HANDLE) wNewHandle (LPSTR lpstr, DWORD cb);
+INTERNAL wDupData (LPHANDLE ph, HANDLE h, CLIPFORMAT cf);
+INTERNAL wHandleCopy (HANDLE hDst, HANDLE hSrc);
+INTERNAL wGetRequestResponse (LPDDE_CHANNEL pChannel, CLIPFORMAT cf, ATOM aItem);
+INTERNAL wGetItemFromClipboard (ATOM * paItem);
+INTERNAL GetDefaultIcon (REFCLSID clsidIn, LPCOLESTR szFile, HANDLE * phmfp);
+INTERNAL_(BOOL) wTerminateIsComing (LPDDE_CHANNEL);
+INTERNAL wTimedGetMessage (LPMSG pmsg, HWND hwnd, WORD wFirst, WORD wLast);
+
+INTERNAL_(ATOM) wGlobalAddAtom(LPCOLESTR sz);
+INTERNAL_(ATOM) wGlobalAddAtomA(LPCSTR sz);
+
+INTERNAL wVerifyFormatEtc (LPFORMATETC pformatetc);
+INTERNAL wNormalize (LPFORMATETC pfetc, LPFORMATETC pfetcOut);
+INTERNAL wTransferHandle (LPHANDLE phDst, LPHANDLE phSrc, CLIPFORMAT cf);
+INTERNAL wClassesMatch (REFCLSID clsidIn, LPOLESTR szFile);
+
+#if DBG == 1
+INTERNAL_(BOOL) wIsValidHandle (HANDLE h, CLIPFORMAT cf);
+INTERNAL_(BOOL) wIsValidAtom (ATOM a);
+#endif
+
+const char achStdCloseDocument[]="[StdCloseDocument]";
+const char achStdOpenDocument[]="StdOpenDocument";
+const char achStdExit[]="StdExit";
+const char achStdNewDocument[]="StdNewDocument";
+const char achStdEditDocument[]="StdEditDocument";
+
+#endif // ddeproxy.h
diff --git a/private/ole32/com/remote/dde/client/ddestg.cxx b/private/ole32/com/remote/dde/client/ddestg.cxx
new file mode 100644
index 000000000..657b9c2fe
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/ddestg.cxx
@@ -0,0 +1,535 @@
+/*
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddeStg.cpp
+
+Abstract:
+
+ This module contains the DdeObject::PersistStg and
+ DdeObject::ProxyManager methods
+
+Author:
+
+ Srini Koppolu (srinik) 22-June-1992
+ Jason Fuller (jasonful) 24-July-1992
+
+*/
+
+#include "ddeproxy.h"
+ASSERTDATA
+
+
+/*
+ * IMPLEMENTATION of CPersistStgImpl methods
+ *
+ */
+
+
+STDUNKIMPL_FORDERIVED(DdeObject, PersistStgImpl)
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_GetClassID)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::GetClassID (CLSID FAR* pClassID)
+{
+ *pClassID = m_pDdeObject->m_clsid;
+ return NOERROR;
+}
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_IsDirty)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::IsDirty ()
+{
+ return NOERROR;
+}
+
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_InitNew)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::InitNew
+ (IStorage FAR* pstg)
+{
+ HRESULT hres;
+ intrDebugOut((DEB_ITRACE,
+ "DdeObejct::InitNew(%x,pstg=%x)\n",
+ this,
+ pstg));
+
+ if (hres = m_pDdeObject->PostSysCommand (m_pDdeObject->m_pSysChannel,
+ (LPSTR)&achStdNewDocument,
+ TRUE))
+ return hres;
+
+ if (hres = m_pDdeObject->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL))
+ return hres;
+
+ RetErr (m_pDdeObject->TermConv (m_pDdeObject->m_pSysChannel));
+ if (m_pDdeObject->m_pstg)
+ {
+ m_pDdeObject->m_pstg->Release();
+ }
+ m_pDdeObject->m_pstg = pstg;
+ pstg->AddRef();
+ return hres;
+}
+
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_Load)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::Load (IStorage FAR* pstg)
+{
+ LPSTR lpBuf=NULL;
+ HANDLE hDdePoke = NULL;
+ DWORD dwSize;
+ CStmBufRead StmRead;
+ CStmBufRead StmReadItem;
+ HRESULT hresult;
+
+ intrDebugOut((DEB_ITRACE,"CDdeObject::Load(%x,pstg=%x)\n",this,pstg));
+
+ {
+
+ if (hresult = StmRead.OpenStream(pstg, OLE10_NATIVE_STREAM))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) OpenStream failed(%x)\n",
+ this,
+ hresult));
+ return hresult;
+ }
+
+
+ if (hresult = StmRead.Read(&dwSize, sizeof(DWORD)))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) StRead failed(%x)\n",
+ this,
+ hresult));
+
+ goto errRtn;
+ }
+
+
+ lpBuf = wAllocDdePokeBlock (dwSize, g_cfNative, &hDdePoke);
+
+ if (lpBuf == NULL)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) wAllocDdePokeBlock failed(%x)\n",
+ this,
+ hresult));
+
+ hresult = E_OUTOFMEMORY;
+ goto errRtn;
+ }
+
+ if (hresult = StmRead.Read(lpBuf, dwSize))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) StRead of cfNative failed(%x)\n",
+ this,
+ hresult));
+ goto errRtn;
+ }
+
+ if (m_pDdeObject->m_hNative)
+ {
+ GlobalFree (m_pDdeObject->m_hNative);
+ }
+ m_pDdeObject->m_hNative = wNewHandle (lpBuf, dwSize);
+
+ if (m_pDdeObject->m_hNative == NULL)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) m_hNative NULL\n",
+ this));
+ }
+ }
+
+ GlobalUnlock (hDdePoke); // done with lpBuf
+
+ if (hresult = m_pDdeObject->PostSysCommand (m_pDdeObject->m_pSysChannel,
+ (LPSTR)&achStdEditDocument,
+ FALSE))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) PostSysCommand %s failed (%x)\n",
+ this,
+ &achStdEditDocument,
+ hresult));
+ goto errRtn;
+ }
+
+
+ // Read Item Name, if there is one
+ if (NOERROR == StmReadItem.OpenStream(pstg, OLE10_ITEMNAME_STREAM))
+ {
+ LPSTR szItemName = NULL;
+
+ ErrRtnH (ReadStringStreamA (StmReadItem, &szItemName));
+ m_pDdeObject->ChangeItem (szItemName);
+ PubMemFree(szItemName);
+ }
+
+ if (hresult = m_pDdeObject->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) ProxyMgr.Connect failed(%x)\n",
+ this,
+ hresult));
+ goto errRtn;
+ }
+
+
+ if ((hresult = m_pDdeObject->Poke(m_pDdeObject->m_aItem, hDdePoke))
+ != NOERROR)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) Poke failed(%x)\n",
+ this,
+ hresult));
+
+ // the Poke calls frees the Poke data even in case of failure.
+#ifdef LATER
+
+ if (hresult = m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel,
+ wNewHandle ((LPSTR)achStdCloseDocument,sizeof(achStdCloseDocument)));
+ goto errDoc;
+#elseif
+ goto errDoc;
+#endif
+ }
+
+ hresult = m_pDdeObject->TermConv (m_pDdeObject->m_pSysChannel);
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) TermConv on SysChannel failed(%x)\n",
+ this,
+ hresult));
+ goto errRtn;
+ }
+
+
+ if (m_pDdeObject->m_pstg)
+ {
+ m_pDdeObject->m_pstg->Release();
+ }
+
+ m_pDdeObject->m_pstg = pstg;
+ pstg->AddRef();
+ goto LExit;
+
+errRtn:
+ if (hDdePoke)
+ GlobalFree (hDdePoke);
+ if (m_pDdeObject->m_pDocChannel)
+ m_pDdeObject->TermConv (m_pDdeObject->m_pDocChannel);
+LExit:
+ StmReadItem.Release();
+ StmRead.Release();
+
+ intrDebugOut((DEB_ITRACE,"::Load(%x) returning (%x)\n",this,hresult));
+ return hresult;
+}
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_Save)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::Save
+ (IStorage FAR* pstgSave, BOOL fSameAsLoad)
+{
+ intrDebugOut((DEB_ITRACE,
+ "DdeObject::Save(%x,pstgSave=%x)\n",
+ this,
+ pstgSave));
+
+
+ HRESULT hresult=NOERROR;
+
+ if (m_pDdeObject->m_fUpdateOnSave
+ && (m_pDdeObject->m_clsid != CLSID_Package
+ || m_pDdeObject->m_hNative == NULL))
+ {
+ // Get latest data from server, if it is not shutting down
+ // or telling us to Save, in which case it just gave us data.
+ // (If it is shutting down, it probably won't respond.
+ // Draw does respond, but gives bad data.)
+ // Packager gives truncated native data (header info with no
+ // actual embedded file) if you DDE_REQUEST it. Bug 3103
+ m_pDdeObject->Update (FALSE);
+ }
+
+ if (m_pDdeObject->m_hNative == NULL)
+ {
+ // we still have nothing to save
+ return ResultFromScode (E_BLANK);
+ }
+
+ hresult = m_pDdeObject->Save (pstgSave);
+
+ Puts ("PersistStg::Save done\n");
+ return hresult;
+}
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_SaveCompleted)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::SaveCompleted
+ (IStorage FAR* pstgNew)
+{
+ intrDebugOut((DEB_ITRACE,
+ "DdeObejct::SaveCompleted(%x,pstgNew=%x)\n",
+ this,
+ pstgNew));
+
+ RetZ (m_pDdeObject->m_pOleAdvHolder);
+ m_pDdeObject->m_pOleAdvHolder->SendOnSave();
+ if (pstgNew)
+ {
+ if (m_pDdeObject->m_pstg)
+ m_pDdeObject->m_pstg->Release();
+ m_pDdeObject->m_pstg = pstgNew;
+ pstgNew->AddRef();
+ }
+ return NOERROR;
+}
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_HandsOffStorage)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::HandsOffStorage(void)
+{
+ intrDebugOut((DEB_ITRACE,"DdeObejct::HandsOffStorage(%x)\n",this));
+ if (m_pDdeObject->m_pstg)
+ {
+ m_pDdeObject->m_pstg->Release();
+ m_pDdeObject->m_pstg = NULL;
+ }
+ return NOERROR;
+}
+
+
+/*
+ * IMPLEMENTATION of CProxyManagerImpl methods
+ *
+ */
+
+
+STDUNKIMPL_FORDERIVED(DdeObject, ProxyManagerImpl)
+
+
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_CreateServer)
+STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::CreateServer(REFCLSID rclsid,
+ DWORD clsctx,
+ void *pv)
+{
+ intrDebugOut((DEB_ITRACE,"DdeObejct::CreateServer(%x)\n",this));
+ HRESULT hresult = NOERROR;
+
+ if (m_pDdeObject->m_pSysChannel)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::CreateServer(%x)m_pSysChannel exists\n",
+ this));
+ return NOERROR;
+ }
+
+ if (m_pDdeObject->m_aExeName == NULL)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::CreateServer(%x) Class Not Registered\n",
+ this));
+ return(REGDB_E_CLASSNOTREG);
+ }
+
+
+ if (!m_pDdeObject->AllocDdeChannel(&m_pDdeObject->m_pSysChannel,SYS_CLASSA))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::CreateServer(%x)AllocDdeChannel is failing\n",
+ this));
+ return ReportResult(0, E_OUTOFMEMORY,0,0);
+ }
+
+ if (!m_pDdeObject->InitSysConv())
+ {
+ if (!(m_pDdeObject->LaunchApp()))
+ {
+ intrDebugOut((DEB_IERROR,"::CreateServer Could not launch app\n"));
+ hresult = ResultFromScode (CO_E_APPNOTFOUND);
+ goto errRtn;
+ }
+
+ if (!m_pDdeObject->InitSysConv())
+ {
+ intrDebugOut((DEB_IERROR,"::CreateServer Second init failed\n"));
+ hresult = ResultFromScode (CO_E_APPDIDNTREG);
+ goto errRtn;
+ }
+ }
+
+ return NOERROR;
+
+errRtn:
+ intrDebugOut((DEB_ITRACE,"DdeObejct::CreateServer(%x) is failing(%x)\n",this,hresult));
+ m_pDdeObject->DeleteChannel (m_pDdeObject->m_pSysChannel);
+ Assert (hresult != NOERROR); // This is an error path
+ return hresult;
+
+}
+
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_Connect)
+STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::Connect(OID oid, REFCLSID rclsid)
+{
+ intrDebugOut((DEB_ITRACE,"DdeObject::Connect(%x)\n",this));
+
+ if (m_pDdeObject->m_pDocChannel)
+ return NOERROR;
+
+ if (!m_pDdeObject->AllocDdeChannel (&m_pDdeObject->m_pDocChannel,CLIENT_CLASSA))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Connect(%x) AllocDdeChannel failed, return E_OUTOFMEMORY\n",
+ this));
+ return ReportResult(0, E_OUTOFMEMORY,0,0);
+ }
+
+ // Bug 3701
+ m_pDdeObject->m_fDidSendOnClose = FALSE;
+ if (wInitiate (m_pDdeObject->m_pDocChannel, m_pDdeObject->m_aClass,
+ m_pDdeObject->m_aTopic))
+ {
+ return NOERROR;
+ }
+
+ intrDebugOut((DEB_ITRACE,"::Connect(%x) wInitiate failed\n",this));
+ m_pDdeObject->DeleteChannel (m_pDdeObject->m_pDocChannel);
+ return ResultFromScode (E_FAIL);
+}
+
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_LockConnection)
+STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::LockConnection(BOOL fLock, BOOL fLastUnlockReleases)
+{
+ intrDebugOut((DEB_ITRACE,
+ "DdeObject::LockConnection(%x,fLock=%x,fLastUnlockReleases=%x)\n",
+ this,
+ fLock,
+ fLastUnlockReleases));
+
+ if (fLock)
+ m_pDdeObject->m_cLocks++;
+ else
+ {
+ if (m_pDdeObject->m_cLocks!=0 && 0 == --m_pDdeObject->m_cLocks &&
+ fLastUnlockReleases && !m_pDdeObject->m_fVisible)
+ (void)m_pDdeObject->m_Ole.Close (OLECLOSE_SAVEIFDIRTY);
+ }
+ return NOERROR;
+}
+
+
+#ifdef NOTNEEDED
+#pragma SEG(CDdeObject_CProxyManagerImpl_GetClassID)
+STDMETHODIMP_(void) NC(CDdeObject, CProxyManagerImpl)::GetClassID(CLSID FAR* pClsid)
+{
+ *pClsid = m_pDdeObject->m_clsid;
+}
+
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_GetOID)
+STDMETHODIMP_(OID) NC(CDdeObject, CProxyManagerImpl)::GetOID()
+{
+ if (m_pDdeObject->m_pSysChannel)
+ return (OID) m_pDdeObject->m_pSysChannel;
+
+ if (m_pDdeObject->m_pDocChannel)
+ return (OID) m_pDdeObject->m_pDocChannel;
+
+ return NULL;
+}
+#endif
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_IsConnected)
+STDMETHODIMP_(BOOL) NC(CDdeObject, CProxyManagerImpl)::IsConnected(void)
+{
+ return m_pDdeObject->m_pDocChannel != NULL;
+}
+
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_EstablishIID)
+STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::EstablishIID(REFIID iid, LPVOID FAR* ppv)
+{
+ // REVIEW: this is correct, but can we be smarter like in the real PM?
+ return QueryInterface(iid, ppv);
+}
+
+
+#pragma SEG(wTerminateIsComing)
+INTERNAL_(BOOL) wTerminateIsComing (LPDDE_CHANNEL pChannel)
+{
+ MSG msg;
+ return SSPeekMessage (&msg, pChannel->hwndCli, 0, 0, PM_NOREMOVE)
+ && msg.message == WM_DDE_TERMINATE
+ && (HWND)msg.wParam==pChannel->hwndSvr;
+}
+
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_Disconnect)
+STDMETHODIMP_(void) NC(CDdeObject, CProxyManagerImpl)::Disconnect()
+{
+ intrDebugOut((DEB_ITRACE,"DdeObject::Disonnect(%x)\n",this));
+ #define p m_pDdeObject
+ if (m_pDdeObject->m_pDocChannel)
+ {
+ BOOL fTermComing = wTerminateIsComing (m_pDdeObject->m_pDocChannel);
+ if ((!m_pDdeObject->m_fNoStdCloseDoc
+ || (!m_pDdeObject->m_fWasEverVisible // invisible update or
+ && !m_pDdeObject->m_fDidGetObject // link from file case.
+ && m_pDdeObject->m_fDidStdOpenDoc)) // only do StdClose if did StdOpen
+ && !m_pDdeObject->m_fDidStdCloseDoc
+ && !fTermComing)
+ {
+ m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel,
+ wNewHandle ((LPSTR)&achStdCloseDocument,sizeof(achStdCloseDocument)),
+ /*fStdClose*/TRUE,
+ /*fWait*/TRUE,
+ /*fDetectTerminate*/TRUE);
+
+ m_pDdeObject->m_fDidStdCloseDoc = TRUE;
+ }
+ if (!m_pDdeObject->m_fDidSendOnClose /*|| fTermComing*/)
+ {
+ // if we did not call SendOnClose() then Disconnect() was called
+ // by a Release method, not by SendOnClose().
+ // This happens when user deletes object in container.
+ BOOL fVisible = m_pDdeObject->m_fWasEverVisible; // TermConv clears this flag
+ m_pDdeObject->TermConv (m_pDdeObject->m_pDocChannel);
+ if (!fVisible)
+ m_pDdeObject->MaybeUnlaunchApp();
+ }
+ }
+
+ if (m_pDdeObject->m_pSysChannel)
+ {
+ intrDebugOut((DEB_IWARN,"Terminating system conversation in Disconnect()\n"));
+ // This should never happen, I think.
+ m_pDdeObject->TermConv (m_pDdeObject->m_pSysChannel);
+ }
+ #undef p
+}
+
+//
+// There is no ServerHandler with DDE servers. Therefore, this function returns E_NOTIMPL
+// back to the handler.
+//
+STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::CreateServerWithHandler (REFCLSID rclsid, DWORD clsctx, void *pv,
+ REFCLSID rclsidHandler, IID iidSrv, void **ppv,
+ IID iidClnt, void *pClientSiteInterface)
+{
+ return E_NOTIMPL;
+}
+
+
diff --git a/private/ole32/com/remote/dde/client/ddewnd.cxx b/private/ole32/com/remote/dde/client/ddewnd.cxx
new file mode 100644
index 000000000..a3a6725a0
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/ddewnd.cxx
@@ -0,0 +1,363 @@
+/*++
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddewnd.cpp
+
+Abstract:
+
+ This module contains the code for the dde window procs
+
+Author:
+
+ Srini Koppolu (srinik) 20-June-1992
+
+Revision History:
+
+--*/
+#include "ddeproxy.h"
+
+
+
+#define SYS_MSG 0
+#define DOC_MSG 1
+
+// SysWndProc: Window Procedure for System Topic DDE conversations
+// wndproc for system topic
+
+
+STDAPI_(LRESULT) SysWndProc (
+ HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+)
+{
+ StackAssert(SSOnSmallStack());
+ CDdeObject FAR* pDdeObj = NULL;
+ LPDDE_CHANNEL pChannel = NULL;
+
+ if (message>=WM_DDE_FIRST && message <= WM_DDE_LAST)
+ {
+ if (pDdeObj = (CDdeObject FAR*) GetWindowLong (hwnd, 0))
+ {
+ pChannel = pDdeObj->GetSysChannel();
+ }
+
+ if (pChannel == NULL)
+ {
+ intrAssert(pChannel != NULL);
+ return SSDefWindowProc (hwnd, message, wParam, lParam);
+ }
+ }
+ if ( pChannel
+ && ( pChannel->iAwaitAck == AA_EXECUTE
+ || pChannel->iAwaitAck == AA_INITIATE) )
+ {
+ MSG msg;
+ BOOL fDisp = FALSE;
+ while (SSPeekMessage(&msg, hwnd, WM_DDE_ACK, WM_DDE_ACK, PM_REMOVE | PM_NOYIELD) )
+ {
+ intrDebugOut((DEB_WARN, "DDE SysWndProc: dispatching WM_DDE_ACK message (%x)\n",pChannel));
+ SSDispatchMessage(&msg);
+ fDisp = TRUE;
+ }
+ if (fDisp && (pDdeObj = (CDdeObject FAR*) GetWindowLong (hwnd, 0)))
+ {
+ pChannel = pDdeObj->GetSysChannel();
+ }
+
+ if (pChannel == NULL)
+ {
+ intrAssert(pChannel != NULL);
+ return SSDefWindowProc (hwnd, message, wParam, lParam);
+ }
+ }
+
+ switch (message){
+ case WM_DDE_ACK:
+ intrDebugOut((DEB_ITRACE,
+ "SWP: WM_DDE_ACK pChannel(%x)\n",pChannel));
+ if (pChannel->bTerminating)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "SWP: pChannel->bTerminating: no action\n"));
+
+ break;
+ }
+
+ switch (pChannel->iAwaitAck) {
+ case AA_INITIATE:
+ pDdeObj->OnInitAck (pChannel, (HWND)wParam);
+ if (LOWORD(lParam))
+ GlobalDeleteAtom (LOWORD(lParam));
+ if (HIWORD(lParam))
+ GlobalDeleteAtom (HIWORD(lParam));
+ break;
+
+ case AA_EXECUTE:
+ pDdeObj->OnAck (pChannel, lParam);
+ break;
+
+ default:
+ intrDebugOut((DEB_ITRACE,
+ "SWP: WM_DDE_ACK UnhandledpChannel(%x)\n",pChannel));
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ pDdeObj->OnTimer (pChannel);
+ break;
+
+ case WM_DDE_TERMINATE:
+ intrDebugOut((DEB_ITRACE,
+ "SWP: WM_DDE_TERMINATE pChannel(%x)\n",pChannel));
+ pDdeObj->OnTerminate (pChannel, (HWND)wParam);
+ break;
+
+ default:
+ return SSDefWindowProc (hwnd, message, wParam, lParam);
+ }
+
+ return 0L;
+}
+
+
+// ClientDocWndProc: Window procedure used to document DDE conversations
+STDAPI_(LRESULT) ClientDocWndProc (
+ HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+)
+{
+ StackAssert(SSOnSmallStack());
+ CDdeObject FAR* pDdeObj = NULL;
+ LPDDE_CHANNEL pChannel = NULL;
+ HANDLE hData;
+ ATOM aItem;
+
+ if (message>=WM_DDE_FIRST && message <= WM_DDE_LAST)
+ {
+
+ if (pDdeObj = (CDdeObject FAR*) GetWindowLong (hwnd, 0))
+ pChannel = pDdeObj->GetDocChannel();
+
+ if (pChannel == NULL)
+ {
+ //
+ // pChannel == NULL. Something is very wrong! But, lets
+ // not fault on it.
+ //
+ //intrAssert(pChannel != NULL);
+ return SSDefWindowProc (hwnd, message, wParam, lParam);
+ }
+
+ }
+ if ( pChannel
+ && ( pChannel->iAwaitAck == AA_EXECUTE
+ || pChannel->iAwaitAck == AA_INITIATE
+ || pChannel->iAwaitAck == AA_REQUESTAVAILABLE
+ || pChannel->iAwaitAck == AA_REQUEST
+ || pChannel->iAwaitAck == AA_UNADVISE
+ || pChannel->iAwaitAck == AA_EXECUTE
+ || pChannel->iAwaitAck == AA_ADVISE
+ || pChannel->iAwaitAck == AA_POKE) )
+ {
+ MSG msg;
+ BOOL fDisp = FALSE;
+ while (SSPeekMessage(&msg, hwnd, WM_DDE_ACK, WM_DDE_ACK, PM_REMOVE | PM_NOYIELD) )
+ {
+ intrDebugOut((DEB_WARN, "DDE DocWndProc: dispatching WM_DDE_ACK message (%x)\n",pChannel));
+ SSDispatchMessage(&msg);
+ fDisp = TRUE;
+ }
+
+ if (fDisp && (pDdeObj = (CDdeObject FAR*) GetWindowLong (hwnd, 0)))
+ {
+ pChannel = pDdeObj->GetDocChannel();
+ }
+
+ if (pChannel == NULL)
+ {
+ intrAssert(pChannel != NULL);
+ return SSDefWindowProc (hwnd, message, wParam, lParam);
+ }
+ }
+
+ switch (message)
+ {
+ case WM_DDE_ACK:
+
+ intrDebugOut((DEB_ITRACE,
+ "ClientWndProc: WM_DDE_ACK pChannel(%x)\n",
+ pChannel));
+ if (pChannel->bTerminating){
+ // ### this error recovery may not be correct.
+ DEBUG_OUT ("No action due to termination process",0)
+ break;
+ }
+
+ switch(pChannel->iAwaitAck){
+ case AA_INITIATE:
+ pDdeObj->OnInitAck (pChannel, (HWND)wParam);
+ if (LOWORD(lParam))
+ GlobalDeleteAtom (LOWORD(lParam));
+ if (HIWORD(lParam))
+ GlobalDeleteAtom (HIWORD(lParam));
+ break;
+
+ case AA_REQUESTAVAILABLE:
+ case AA_REQUEST:
+ case AA_UNADVISE:
+ case AA_EXECUTE:
+ case AA_ADVISE:
+ pDdeObj->OnAck (pChannel, lParam);
+ break;
+
+ case AA_POKE:
+ // freeing pokedata is done in handleack
+ pDdeObj->OnAck (pChannel, lParam);
+ break;
+
+ default:
+ intrDebugOut((DEB_IERROR,
+ "ClientWndProc: WM_DDE_ACK unhandled\n"));
+ break;
+
+ } // end of switch
+ break;
+
+ case WM_DDE_DATA:
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ pDdeObj->Guard();
+#endif // _CHICAGO_
+ hData = GET_WM_DDE_DATA_HDATA(wParam,lParam);
+ aItem = GET_WM_DDE_DATA_ITEM(wParam,lParam);
+ intrDebugOut((DEB_ITRACE,
+ "CWP: WM_DDE_DATA pChannel(%x) hData(%x) aItem(%x)\n",
+ pChannel,hData,aItem));
+ pDdeObj->OnData (pChannel, hData, aItem);
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ if (pDdeObj->UnGuard())
+ {
+ SetWindowLong(hwnd, 0, (LONG)0);
+ intrDebugOut((DEB_IWARN, "DDE ClientDocWndProc Release on pUnkOuter == 0 (this:%x, hwnd:%x\n",pDdeObj, hwnd ));
+ }
+#endif // _CHICAGO_
+
+ break;
+
+ case WM_DDE_TERMINATE:
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ pDdeObj->Guard();
+#endif // _CHICAGO_
+ intrDebugOut((DEB_ITRACE,
+ "CWP: WM_DDE_TERMINATE pChannel(%x)\n",pChannel));
+
+
+ if (pDdeObj->m_fDoingSendOnDataChange)
+ {
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ BOOL fPostMsg = TRUE;
+#endif
+ //
+ // Cheese alert! This protocol is very bad. The original
+ // 16 bit code something even more worse, so we are stuck
+ // to do something roughly compatible.
+ //
+ // If fDoingSendOnDataChange, the client may be asking for
+ // additional information from the server. The way the code
+ // is structured, it doesn't handle OnTerminate gracefully
+ // in this case.
+ //
+ // To fix this, we first tell the call control that
+ // the server has died. Then we repost the terminate
+ // message so we can handle it later.
+ //
+ // The old code did a
+ // pDdeObj->QueueMsg (hwnd, message, wParam, lParam);
+ //
+ // and the old SendOnDataChange removed the message.
+ // This probably didn't work either, but was never
+ // actually encountered.
+ //
+
+ intrDebugOut((DEB_ITRACE,
+ "CWP: term doing SendOnDataChange \n"));
+ //
+ // If we got here, there should be a CallData assigned
+ // to the channel.
+ //
+ if ((pChannel->pCD) && (pChannel->pCallCont))
+ {
+ intrDebugOut((DEB_ITRACE,"CWP: Setting call state\n"));
+
+ pChannel->pCallCont->SetCallState(pChannel->pCD,
+ SERVERCALLEX_ISHANDLED,
+ RPC_E_SERVER_DIED);
+
+ }
+ else
+ {
+ //
+ // If there is no call data, then we aren't waiting in
+ // the channel. Terminate the conversation.
+ //
+
+ intrDebugOut((DEB_ERROR,"CWP: No call state exists\n"));
+ pDdeObj->OnTerminate (pChannel, (HWND)wParam);
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ fPostMsg = FALSE;
+#else
+ break;
+#endif //
+ }
+
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ if (fPostMsg)
+ {
+#endif
+ //
+ // Repost the message and try again.
+ //
+ intrDebugOut((DEB_ITRACE,"CWP: Reposting WM_DDE_TERMINATE\n"));
+ PostMessage(hwnd,message,wParam,lParam);
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ }
+#else
+ break;
+#endif
+
+ }
+ else
+ {
+ pDdeObj->OnTerminate (pChannel, (HWND)wParam);
+ }
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ if (pDdeObj->UnGuard())
+ {
+ SetWindowLong(hwnd, 0, (LONG)0);
+ intrDebugOut((DEB_IWARN, "DDE ClientDocWndProc Release on pUnkOuter == 0 (this:%x, hwnd:%x\n",pDdeObj, hwnd ));
+ }
+#endif // _CHICAGO_
+ break;
+
+ default:
+ return SSDefWindowProc (hwnd, message, wParam, lParam);
+
+ }
+
+ return 0L;
+}
diff --git a/private/ole32/com/remote/dde/client/ddeworkr.cxx b/private/ole32/com/remote/dde/client/ddeworkr.cxx
new file mode 100644
index 000000000..9d117db18
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/ddeworkr.cxx
@@ -0,0 +1,1331 @@
+/*++
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddeworkr.cpp
+
+Abstract:
+
+ This module contains the code for the worker routines
+
+Author:
+
+ Srini Koppolu (srinik) 22-June-1992
+ Jason Fuller (jasonful) 24-July-1992
+
+Revision History:
+ Kevin Ross (KevinRo) 10-May-1994
+ Mostly added comments, and attempted to clean
+ it up.
+
+--*/
+#include "ddeproxy.h"
+
+ASSERTDATA
+
+/*
+ * WORKER ROUTINES
+ *
+ */
+
+
+INTERNAL_(BOOL) wPostMessageToServer(LPDDE_CHANNEL pChannel,
+ WORD wMsg,
+ LONG lParam,
+ BOOL fFreeOnError)
+{
+ int c=0;
+ intrDebugOut((DEB_ITRACE,
+ "wPostMessageToServer(pChannel=%x,wMsg=%x,lParam=%x,fFreeOnError=%x\n",
+ pChannel,
+ wMsg,
+ lParam,
+ fFreeOnError));
+ if (NULL==pChannel)
+ {
+ AssertSz (0, "Channel missing");
+ return FALSE;
+ }
+ pChannel->wMsg = wMsg;
+ pChannel->lParam = lParam;
+ pChannel->hres = NOERROR;
+
+ while (TRUE && c<10 )
+ {
+ if (!IsWindow (pChannel->hwndSvr))
+ {
+ intrDebugOut((DEB_IWARN,
+ "wPostMessageToServer: invalid window %x\n",
+ pChannel->hwndSvr));
+ goto errRet;
+ }
+ if (wTerminateIsComing (pChannel)
+ && wMsg != WM_DDE_ACK
+ && wMsg != WM_DDE_TERMINATE)
+ {
+ intrDebugOut((DEB_IWARN,"Server sent terminate, cannot post\n"));
+ goto errRet;
+ }
+ if (!PostMessage (pChannel->hwndSvr, wMsg, (WPARAM) pChannel->hwndCli, lParam))
+ {
+ intrDebugOut((DEB_IWARN,
+ "wPostMessageToServer: PostMessageFailed, yielding\n"));
+ Yield ();
+ c++;
+ }
+ else
+ return TRUE;
+ }
+ AssertSz (0, "PostMessage failed");
+
+errRet:
+ intrDebugOut((DEB_IWARN,"wPostMessageToServer returns FALSE\n"));
+ if (fFreeOnError)
+ {
+ DDEFREE(wMsg,lParam);
+ }
+
+ return FALSE;
+}
+
+
+// call Ole1ClassFromCLSID then global add atom; returns NULL if error.
+INTERNAL_(ATOM) wAtomFromCLSID(REFCLSID rclsid)
+{
+ WCHAR szClass[MAX_STR];
+ ATOM aCls;
+
+ if (Ole1ClassFromCLSID2(rclsid, szClass, sizeof(szClass)) == 0)
+ return NULL;
+ aCls = wGlobalAddAtom(szClass);
+ intrAssert(wIsValidAtom(aCls));
+ return aCls;
+}
+
+INTERNAL_(ATOM) wGlobalAddAtom(LPCOLESTR sz)
+{
+ if (sz==NULL || sz[0] == '\0')
+ {
+ return NULL;
+ }
+
+ ATOM a = GlobalAddAtom(sz);
+ intrAssert(wIsValidAtom(a));
+ return a;
+}
+
+INTERNAL_(ATOM) wGlobalAddAtomA(LPCSTR sz)
+{
+ if (sz==NULL || sz[0] == '\0')
+ return NULL;
+ ATOM a = GlobalAddAtomA(sz);
+ intrAssert(wIsValidAtom(a));
+ return a;
+}
+
+
+INTERNAL_(ATOM) wGetExeNameAtom (REFCLSID rclsid)
+{
+ LONG cb = MAX_STR;
+ WCHAR key[MAX_STR];
+ ATOM a;
+
+ if (Ole1ClassFromCLSID2(rclsid, key, sizeof(key)) == 0)
+ return NULL;
+
+ lstrcatW (key, OLESTR("\\protocol\\StdFileEditing\\server"));
+
+ if (RegQueryValue (HKEY_CLASSES_ROOT, key, key, &cb))
+ {
+ Puts ("ERROR: wGetExeNameAtom failed\n");
+ return NULL;
+ }
+ a = wGlobalAddAtom (key);
+ intrAssert(wIsValidAtom(a));
+ return a;
+}
+
+INTERNAL_(void) wFreeData (HANDLE hData, CLIPFORMAT cfFormat,
+ BOOL fFreeNonGdiHandle)
+{
+ intrDebugOut((DEB_ITRACE,
+ "wFreeData(hData=%x,cfFormat=%x,FreeNonGDIHandle=%x\n",
+ hData,
+ (USHORT)cfFormat,
+ fFreeNonGdiHandle));
+
+ AssertSz (hData != NULL, "Trying to free NULL handle");
+ AssertSz (hData != (HANDLE) 0xcccccccc, "Trying to free handle from a deleted object");
+
+ switch (cfFormat) {
+ case CF_METAFILEPICT:
+ LPMETAFILEPICT lpMfp;
+
+ if (lpMfp = (LPMETAFILEPICT) GlobalLock (hData))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "wFreeData freeing metafile %x\n",
+ lpMfp->hMF));
+
+ OleDdeDeleteMetaFile(lpMfp->hMF);
+ GlobalUnlock (hData);
+ }
+ GlobalFree (hData);
+ break;
+
+ case CF_BITMAP:
+ case CF_PALETTE:
+ Verify(DeleteObject (hData));
+ break;
+
+ case CF_DIB:
+ GlobalFree (hData);
+ break;
+
+ default:
+ if (fFreeNonGdiHandle)
+ GlobalFree (hData);
+ break;
+ }
+}
+
+
+
+INTERNAL_(BOOL) wInitiate (LPDDE_CHANNEL pChannel, ATOM aLow, ATOM aHigh)
+{
+ intrDebugOut((DEB_ITRACE,"wInitiate(pChannel=%x,aLow=%x,aHigh=%x)\n",
+ pChannel, aLow, aHigh));
+
+ intrAssert(wIsValidAtom(aLow));
+ if (aLow == (ATOM)0)
+ {
+ intrDebugOut((DEB_IERROR,"wInitiate Failed, aLow == 0\n"));
+ return FALSE;
+ }
+
+ pChannel->iAwaitAck = AA_INITIATE;
+
+ SSSendMessage ((HWND)-1, WM_DDE_INITIATE, (WPARAM) pChannel->hwndCli,
+ MAKE_DDE_LPARAM (WM_DDE_INITIATE, aLow, aHigh));
+
+ pChannel->iAwaitAck = NULL;
+
+ intrDebugOut((DEB_ITRACE,
+ "wInitiate pChannel->hwndSrvr = %x\n",
+ pChannel->hwndSvr));
+
+ return (pChannel->hwndSvr != NULL);
+}
+
+
+
+INTERNAL_(HRESULT) wScanItemOptions (ATOM aItem, int FAR* lpoptions)
+{
+ ATOM aModifier;
+ LPOLESTR lpbuf;
+ WCHAR buf[MAX_STR];
+
+ *lpoptions = ON_CHANGE; // default
+
+ if (!aItem) {
+ // NULL item with no modifier means ON_CHANGE for NULL item
+ return NOERROR;
+ }
+
+ intrAssert(wIsValidAtom(aItem));
+ GlobalGetAtomName (aItem, buf, MAX_STR);
+ lpbuf = buf;
+
+ while ( *lpbuf && *lpbuf != '/')
+ IncLpch (lpbuf);
+
+ // no modifier same as /change
+
+ if (*lpbuf == NULL)
+ return NOERROR;
+
+ *lpbuf++ = NULL; // seperate out the item string
+ // We are using this in the caller.
+
+ if (!(aModifier = GlobalFindAtom (lpbuf)))
+ {
+ Puts ("ERROR: wScanItemOptions found non-atom modifier\n");
+ return ReportResult(0, RPC_E_DDE_SYNTAX_ITEM, 0, 0);
+ }
+
+ intrAssert(wIsValidAtom(aModifier));
+
+ if (aModifier == aChange)
+ return NOERROR;
+
+ // Is it a save?
+ if (aModifier == aSave){
+ *lpoptions = ON_SAVE;
+ return NOERROR;
+ }
+ // Is it a Close?
+ if (aModifier == aClose){
+ *lpoptions = ON_CLOSE;
+ return NOERROR;
+ }
+
+ // unknown modifier
+ Puts ("ERROR: wScanItemOptions found bad modifier\n");
+ return ReportResult(0, RPC_E_DDE_SYNTAX_ITEM, 0, 0);
+}
+
+
+INTERNAL_(BOOL) wClearWaitState (LPDDE_CHANNEL pChannel)
+{
+ Assert (pChannel);
+ // kill if any timer active.
+ if (pChannel->wTimer) {
+ KillTimer (pChannel->hwndCli, 1);
+ pChannel->wTimer = 0;
+
+ if (pChannel->hDdePoke) {
+ GlobalFree (pChannel->hDdePoke);
+ pChannel->hDdePoke = NULL;
+ }
+
+ if (pChannel->hopt) {
+ GlobalFree (pChannel->hopt);
+ pChannel->hopt = NULL;
+ }
+
+ //
+ // If the channel is waiting on an Ack, and there is an
+ // lParam, then we may need to cleanup the data.
+
+ if (pChannel->iAwaitAck && (pChannel->lParam)) {
+ if (pChannel->iAwaitAck == AA_EXECUTE)
+ {
+ //
+ // KevinRo: Found the following comment in the code.
+ // ; // BUGBUG32 - get hData from GET_WM_DDE_EXECUTE_HADATA ??
+ // It appears, by looking at what the 16-bit code does,
+ // that the goal is to free the handle that was passed as
+ // part of the EXECUTE message. Judging by what the 16-bit
+ // code did, I have determined that this is correct.
+ //
+ // The macro used below wanted two parameters. The first was
+ // the WPARAM, the second the LPARAM. We don't have the WPARAM.
+ // However, it isn't actually used by the macro, so I have
+ // cheated and provided 0 as a default
+ //
+ GlobalFree(GET_WM_DDE_EXECUTE_HDATA(0,pChannel->lParam));
+
+#ifdef KEVINRO_HERE_IS_THE_16_BIT_CODE
+ GlobalFree (HIWORD (pChannel->lParam));
+#endif
+ }
+ else
+ {
+ //
+ // All of the other DDE messages pass an Atom in the high word.
+ // Therefore, we should delete the atom.
+ //
+ //
+ ATOM aTmp;
+
+ aTmp = MGetDDElParamHi(pChannel->wMsg,pChannel->lParam);
+
+ intrAssert(wIsValidAtom(aTmp));
+ if (aTmp)
+ {
+ GlobalDeleteAtom (aTmp);
+ }
+ }
+ DDEFREE(pChannel->wMsg,pChannel->lParam);
+
+ // we want to wipe out the lParam
+ pChannel->lParam = 0x0;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+// wNewHandle (LPSTR, DWORD)
+//
+// Copy cb bytes from lpstr into a new memory block and return a handle to it.
+// If lpstr is an ASCIIZ string, cb must include 1 for the null terminator.
+//
+
+INTERNAL_(HANDLE) wNewHandle (LPSTR lpstr, DWORD cb)
+{
+
+ HANDLE hdata = NULL;
+ LPSTR lpdata = NULL;
+
+ hdata = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, cb);
+ if (hdata == NULL || (lpdata = (LPSTR) GlobalLock (hdata)) == NULL)
+ goto errRtn;
+
+ memcpy (lpdata, lpstr, cb);
+ GlobalUnlock (hdata);
+ return hdata;
+
+errRtn:
+ Puts ("ERROR: wNewHandle\n");
+ Assert (0);
+ if (lpdata)
+ GlobalUnlock (hdata);
+
+ if (hdata)
+ GlobalFree (hdata);
+ return NULL;
+}
+
+
+
+// wDupData
+//
+// Copy data from handle h into a new handle which is returned as *ph.
+//
+
+INTERNAL wDupData (LPHANDLE ph, HANDLE h, CLIPFORMAT cf)
+{
+ Assert (ph);
+ RetZ (wIsValidHandle(h, cf));
+ *ph = OleDuplicateData (h, cf, GMEM_DDESHARE | GMEM_MOVEABLE);
+ RetZ (wIsValidHandle (*ph, cf));
+ return NOERROR;
+}
+
+
+// wTransferHandle
+//
+//
+INTERNAL wTransferHandle
+ (LPHANDLE phDst,
+ LPHANDLE phSrc,
+ CLIPFORMAT cf)
+{
+ RetErr (wDupData (phDst, *phSrc, cf));
+ wFreeData (*phSrc, cf, TRUE);
+ *phSrc = (HANDLE)0;
+ return NOERROR;
+}
+
+
+// wHandleCopy
+//
+// copy data from hSrc to hDst.
+// Both handles must already have memory allocated to them.
+//
+
+INTERNAL wHandleCopy (HANDLE hDst, HANDLE hSrc)
+{
+ LPSTR lpDst, lpSrc;
+ DWORD dwSrc;
+
+ if (NULL==hDst || NULL==hSrc)
+ return ResultFromScode (E_INVALIDARG);
+ if (GlobalSize(hDst) < (dwSrc=GlobalSize(hSrc)))
+ {
+ HANDLE hDstNew = GlobalReAlloc (hDst, dwSrc, GMEM_DDESHARE | GMEM_MOVEABLE);
+ if (hDstNew != hDst)
+ return ResultFromScode (E_OUTOFMEMORY);
+ }
+ if (!(lpDst = (LPSTR) GlobalLock(hDst)))
+ {
+ intrAssert(!"ERROR: wHandleCopy hDst");
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+ if (!(lpSrc = (LPSTR) GlobalLock(hSrc)))
+ {
+ GlobalUnlock(hDst);
+ intrAssert (!"ERROR: wHandleCopy hSrc");
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+ memcpy (lpDst, lpSrc, dwSrc);
+ GlobalUnlock(hDst);
+ GlobalUnlock(hSrc);
+ return NOERROR;
+}
+
+
+// ExtendAtom: Create a new atom, which is the old one plus extension
+
+INTERNAL_(ATOM) wExtendAtom (ATOM aItem, int iAdvOn)
+{
+ WCHAR buffer[MAX_STR+1];
+ LPOLESTR lpext;
+
+ buffer[0] = 0;
+ // aItem==NULL for embedded objects.
+ // If so, there is no item name before the slash.
+ if (aItem)
+ GlobalGetAtomName (aItem, buffer, MAX_STR);
+
+ switch (iAdvOn) {
+ case ON_CHANGE:
+ lpext = OLESTR("");
+ break;
+
+ case ON_SAVE:
+ lpext = OLESTR("/Save");
+ break;
+
+ case ON_CLOSE:
+ lpext = OLESTR("/Close");
+ break;
+
+ default:
+ AssertSz (FALSE, "Unknown Advise option");
+ break;
+
+ }
+
+ lstrcatW (buffer, lpext);
+ if (buffer[0])
+ return wGlobalAddAtom (buffer);
+ else
+ return NULL;
+ // not an error. For embedded object on-change, aItem==NULL
+}
+
+
+
+
+INTERNAL_(ATOM) wDupAtom (ATOM a)
+{
+ WCHAR sz[MAX_STR];
+
+ if (!a)
+ return NULL;
+
+ Assert (wIsValidAtom (a));
+ GlobalGetAtomName (a, sz, MAX_STR);
+ return wGlobalAddAtom (sz);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: wAtomLen
+//
+// Synopsis: Return the length, in characters, of the atom name.
+// The length includes the NULL. This function returns the
+// length of the UNICODE version of the atom.
+//
+// Effects:
+//
+// Arguments: [atom] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL_(int) wAtomLen (ATOM atom)
+{
+ WCHAR buf[MAX_STR];
+
+ if (!atom)
+ return NULL;
+
+ return (GlobalGetAtomName (atom, buf, MAX_STR));
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: wAtomLenA
+//
+// Synopsis: Return the length, in characters, of the atom name.
+// The length includes the NULL This function returns the
+// length of the ANSI version of the atom,
+//
+// Effects:
+//
+// Arguments: [atom] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL_(int) wAtomLenA (ATOM atom)
+{
+ char buf[MAX_STR];
+
+ if (!atom)
+ return NULL;
+
+ return (GlobalGetAtomNameA (atom, (LPSTR)buf, MAX_STR));
+}
+
+
+
+// NOTE: returns address of static buffer. Use return value immediately.
+//
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: wAtomName
+//
+// Synopsis: Returns a STATIC BUFFER that holds the string name of the
+// atom.
+//
+// Effects:
+//
+// Arguments: [atom] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Commented
+//
+// Notes:
+//
+// WARNING: This uses a static buffer, so don't depend on the pointer for
+// very long.
+//
+//----------------------------------------------------------------------------
+INTERNAL_(LPOLESTR) wAtomName (ATOM atom)
+{
+ static WCHAR buf[MAX_STR];
+
+ if (!atom)
+ return NULL;
+
+ if (0==GlobalGetAtomName (atom, buf, MAX_STR))
+ return NULL;
+
+ return buf;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: wAtomName
+//
+// Synopsis: Returns a STATIC BUFFER that holds the string name of the
+// atom.
+//
+// Effects:
+//
+// Arguments: [atom] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Commented
+//
+// Notes:
+//
+// WARNING: This uses a static buffer, so don't depend on the pointer for
+// very long.
+//
+//----------------------------------------------------------------------------
+INTERNAL_(LPSTR) wAtomNameA (ATOM atom)
+{
+ static char buf[MAX_STR];
+
+ if (!atom)
+ return NULL;
+
+ if (0==GlobalGetAtomNameA (atom, (LPSTR)buf, MAX_STR))
+ return NULL;
+
+ return buf;
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: wHandleFromDdeData
+//
+// Synopsis: Return a handle from the DDEDATA passed in.
+//
+// Effects: This function will return the correct data from the
+// DDEDATA that is referenced by the handle passed in.
+//
+// DDEDATA is a small structure that is used in DDE to
+// specify the data type of the buffer, its release
+// semantics, and the actual data.
+//
+// In the case of a known format, the handle to the
+// data is extracted from the DDEDATA structure, and
+// the hDdeData is released.
+//
+// If its a Native format, the data is either moved
+// within the memory block allocated, or is copied to
+// another block, depending on the fRelease flag in
+// the hDdeData.
+//
+// Arguments: [hDdeData] -- Handle to DDEDATA
+//
+// Requires:
+//
+// Returns: A handle to the data. hDdeData will be invalidated
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-13-94 kevinro Commented
+//
+// Notes:
+//
+// hDdeData is invalid after calling this function
+//
+//----------------------------------------------------------------------------
+
+
+INTERNAL_(HANDLE) wHandleFromDdeData
+ (HANDLE hDdeData)
+{
+ intrDebugOut((DEB_ITRACE,"wHandleFromDdeData(%x)\n",hDdeData));
+ BOOL fRelease;
+ HGLOBAL h = NULL; // return value
+
+ DDEDATA FAR* lpDdeData = (DDEDATA FAR *) GlobalLock (hDdeData);
+
+ //
+ // If the handle is invalid, then the lpDdeData will be NULL
+ //
+ if (!lpDdeData)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "\twHandleFromDdeData(%x) invalid handle\n",
+ hDdeData));
+ return NULL;
+ }
+
+
+ //
+ // The header section of a DDEDATA consists of 2 shorts.
+ // That makes it 4 bytes. Due to the new packing values,
+ // it turns out that doing a sizeof(DDEDATA) won't work,
+ // because the size gets rounded up to a multple of 2
+ //
+ // We will just hard code the 4 here, since it cannot change
+ // for all time anyway.
+ //
+ #define cbHeader 4
+ Assert (cbHeader==4);
+
+ //
+ // If the cfFormat is BITMAP or METAFILEPICT, then the
+ // handle will be retrieved from the first DWORD of the
+ // buffer
+ //
+ if (lpDdeData->cfFormat == CF_BITMAP ||
+ lpDdeData->cfFormat == CF_METAFILEPICT)
+ {
+ //
+ // The alignment here should be fine, since the Value
+ // field is DWORD aligned. So, we trust this cast
+ //
+ h = *(LPHANDLE)lpDdeData->Value;
+ Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE);
+ fRelease = lpDdeData->fRelease;
+ GlobalUnlock (hDdeData);
+ if (fRelease)
+ {
+ GlobalFree (hDdeData);
+ }
+
+ return h;
+ }
+ else if (lpDdeData->cfFormat == CF_DIB)
+ {
+ //
+ // The alignment here should be fine, since the Value
+ // field is DWORD aligned.
+ //
+ // This changes the memory from fixed to moveable.
+ //
+ h = GlobalReAlloc (*(LPHANDLE)lpDdeData->Value, 0L,
+ GMEM_MODIFY|GMEM_MOVEABLE);
+ Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE);
+ fRelease = lpDdeData->fRelease;
+ GlobalUnlock (hDdeData);
+ if (fRelease)
+ GlobalFree (hDdeData);
+ return h;
+ }
+
+
+ // Native and other data case
+ // dwSize = size of Value array, ie, size of the data itself
+ const DWORD dwSize = GlobalSize (hDdeData) - cbHeader;
+
+ if (lpDdeData->fRelease)
+ {
+ // Move the Value data up over the DDE_DATA header flags.
+ memcpy ((LPSTR)lpDdeData, ((LPSTR)lpDdeData)+cbHeader, dwSize);
+ GlobalUnlock (hDdeData);
+ h = GlobalReAlloc (hDdeData, dwSize, GMEM_MOVEABLE);
+ Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE);
+ return h;
+ }
+ else
+ {
+ // Duplicate the data because the server will free the original.
+ h = wNewHandle (((LPSTR)lpDdeData)+cbHeader, dwSize);
+ Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE);
+ GlobalUnlock (hDdeData);
+ return h;
+ }
+}
+
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::CanCallBack
+//
+// Synopsis: This routine apparently was supposed to determine if a
+// call back could be made. However, the PeekMessage stuff
+// was commented out.
+//
+// So, it returns TRUE if 0 or 1, FALSE but increments lpCount
+// if 2, returns true but decrements lpCount if > 3. Why?
+// Dunno. Need to ask JasonFul
+//
+// Effects:
+//
+// Arguments: [lpCount] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-16-94 kevinro Commented, confused, and disgusted
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL_(BOOL) CDdeObject::CanCallBack (LPINT lpCount)
+{
+ switch (*lpCount) {
+ case 0:
+ case 1:
+ return TRUE;
+
+ case 2:
+ {
+// MSG msg;
+ if (0)
+ //!PeekMessage (&msg, m_pDocChannel->hwndCli,0,0, PM_NOREMOVE) ||
+ // msg.message != WM_DDE_DATA)
+ {
+ Puts ("Server only sent one format (hopefully presentation)\n");
+ return TRUE;
+ }
+ else
+ {
+ ++(*lpCount);
+ return FALSE;
+ }
+ }
+
+ case 3:
+ --(*lpCount);
+ return TRUE;
+
+ default:
+ AssertSz (FALSE, "012345" + *lpCount);
+ return FALSE;
+ }
+}
+
+
+INTERNAL_(BOOL) wIsOldServer (ATOM aClass)
+{
+ LONG cb = MAX_STR;
+ WCHAR key[MAX_STR];
+ int len;
+
+ if (aClass==(ATOM)0)
+ return FALSE;
+
+ if (!GlobalGetAtomName (aClass, key, sizeof(key)))
+ return TRUE;
+
+ lstrcatW (key, OLESTR("\\protocol\\StdFileEditing\\verb\\"));
+ len = lstrlenW (key);
+ key [len++] = (char) ('0');
+ key [len++] = 0;
+
+ if (RegQueryValue (HKEY_CLASSES_ROOT, key, key, &cb))
+ return TRUE; // no verbs registered
+
+ return FALSE;
+}
+
+
+
+
+INTERNAL_(void) wFreePokeData
+ (LPDDE_CHANNEL pChannel,
+ BOOL fMSDrawBug)
+{
+ DDEPOKE FAR * lpdde;
+
+ if (!pChannel )
+ return;
+
+ if (!pChannel->hDdePoke)
+ return;
+
+ if (lpdde = (DDEPOKE FAR *) GlobalLock (pChannel->hDdePoke)) {
+
+ // The old version of MSDraw expects the _contents_ of METAFILEPICT
+ // structure, rather than the handle to it, to be part of DDEPOKE.
+
+ if (fMSDrawBug && lpdde->cfFormat==CF_METAFILEPICT) {
+ intrDebugOut((DEB_ITRACE,
+ "wFreePokeData is accomodating MSDraw bug\n"));
+ //
+ // This meta file was created in 32-bits, and was not passed
+ // into us by DDE. Therefore, this metafile should not need to
+ // call WOW to be free'd.
+ //
+ DeleteMetaFile (((LPMETAFILEPICT) ((LPVOID) &lpdde->Value))->hMF);
+ }
+ // If there is a normal metafile handle in the Value field,
+ // it will be freed (if necessary) by the ReleaseStgMedium()
+ // in DO::SetData
+ GlobalUnlock (pChannel->hDdePoke);
+ }
+ GlobalFree (pChannel->hDdePoke);
+ pChannel->hDdePoke = NULL;
+}
+
+
+
+
+INTERNAL_(HANDLE) wPreparePokeBlock
+ (HANDLE hData, CLIPFORMAT cfFormat, ATOM aClass, BOOL bOldSvr)
+{
+ HANDLE hDdePoke;
+ LPSTR lpBuf;
+
+ if (!hData)
+ return NULL;
+
+ // The old version of MSDraw expects the contents of METAFILEPICT
+ // structure to be part of DDEPOKE, rather than the handle to it.
+ if ((cfFormat==CF_METAFILEPICT && !(aClass==aMSDraw && bOldSvr))
+ || (cfFormat == CF_DIB)
+ || (cfFormat == CF_BITMAP)) {
+
+ Verify (lpBuf = wAllocDdePokeBlock (4, cfFormat, &hDdePoke));
+ *((HANDLE FAR*)lpBuf) = hData;
+
+ }
+ else {
+ // Handle the non-metafile case and the MS-Draw bug
+ DWORD dwSize = GlobalSize (hData);
+
+ if ((aClass == aMSDraw) && bOldSvr)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "wPreparePokeBlock is accomodating MSDraw bug\n"));
+ }
+
+ if (lpBuf = wAllocDdePokeBlock (dwSize, cfFormat, &hDdePoke)) {
+ memcpy (lpBuf, GlobalLock(hData), dwSize);
+ GlobalUnlock (hData);
+ }
+ }
+ GlobalUnlock (hDdePoke);
+ return hDdePoke;
+}
+
+
+// wAllocDdePokeBlock
+// The caller must unlock *phDdePoke when it is done using the return value
+// of this function but before a DDe message is sent using *phDdePoke.
+//
+
+INTERNAL_(LPSTR) wAllocDdePokeBlock
+ (DWORD dwSize, CLIPFORMAT cfFormat, LPHANDLE phDdePoke)
+{
+ HANDLE hdde = NULL;
+ DDEPOKE FAR * lpdde = NULL;
+
+ if (!(hdde = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT,
+ (dwSize + sizeof(DDEPOKE) - sizeof(BYTE) ))))
+ return NULL;
+
+ if (!(lpdde = (DDEPOKE FAR*)GlobalLock (hdde))) {
+ GlobalFree (hdde);
+ return NULL;
+ }
+ // hdde will be UnLock'ed in wPreparePokeBlock and Free'd in wFreePokeData
+ lpdde->fRelease = FALSE;
+ lpdde->cfFormat = cfFormat;
+ *phDdePoke = hdde;
+ return (LPSTR) &(lpdde->Value);
+}
+
+
+#ifdef OLD
+INTERNAL_(ULONG) wPixelsToHiMetric
+ (ULONG cPixels,
+ ULONG cPixelsPerInch)
+{
+ return cPixels * HIMETRIC_PER_INCH / cPixelsPerInch;
+}
+#endif
+
+// Can ask for icon based on either CLSID or filename
+//
+
+INTERNAL GetDefaultIcon (REFCLSID clsidIn, LPCOLESTR szFile, HANDLE FAR* phmfp)
+{
+ if (!(*phmfp = OleGetIconOfClass(clsidIn, NULL, TRUE)))
+ return ResultFromScode(E_OUTOFMEMORY);
+
+ return NOERROR;
+}
+
+#ifdef OLD
+ VDATEPTROUT (phmfp, HICON);
+ VDATEPTRIN (szFile, char);
+ WCHAR szExe[MAX_STR];
+ HICON hicon;
+ HDC hdc;
+ METAFILEPICT FAR* pmfp=NULL;
+ HRESULT hresult;
+ static int cxIcon = 0;
+ static int cyIcon = 0;
+ static int cxIconHiMetric = 0;
+ static int cyIconHiMetric = 0;
+
+ *phmfp = NULL;
+ CLSID clsid;
+ if (clsidIn != CLSID_NULL)
+ {
+ clsid = clsidIn;
+ }
+ else
+ {
+ RetErr (GetClassFile (szFile, &clsid));
+ }
+ ATOM aExe = wGetExeNameAtom (clsid);
+ if (0==GlobalGetAtomName (aExe, szExe, MAX_STR))
+ {
+ Assert (0);
+ return ReportResult(0, E_UNEXPECTED, 0, 0);
+ }
+ hicon = ExtractIcon (hmodOLE2, szExe, 0/*first icon*/);
+ if (((HICON) 1)==hicon || NULL==hicon)
+ {
+ // ExtractIcon failed, so we can't support DVASPECT_ICON
+ return ResultFromScode (DV_E_DVASPECT);
+ }
+ *phmfp = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(METAFILEPICT));
+ ErrZS (*phmfp, E_OUTOFMEMORY);
+ pmfp = (METAFILEPICT FAR*) GlobalLock (*phmfp);
+ ErrZS (pmfp, E_OUTOFMEMORY);
+ if (0==cxIcon)
+ {
+ // In units of pixels
+ Verify (cxIcon = GetSystemMetrics (SM_CXICON));
+ Verify (cyIcon = GetSystemMetrics (SM_CYICON));
+ // In units of .01 millimeter
+ cxIconHiMetric = (int)(long)wPixelsToHiMetric (cxIcon, giPpliX) ;
+ cyIconHiMetric = (int)(long)wPixelsToHiMetric (cyIcon, giPpliY) ;
+ }
+ pmfp->mm = MM_ANISOTROPIC;
+ pmfp->xExt = cxIconHiMetric;
+ pmfp->yExt = cyIconHiMetric;
+ hdc = CreateMetaFile (NULL);
+ SetWindowOrg (hdc, 0, 0);
+ SetWindowExt (hdc, cxIcon, cyIcon);
+ DrawIcon (hdc, 0, 0, hicon);
+ pmfp->hMF = CloseMetaFile (hdc);
+ ErrZ (pmfp->hMF);
+ Assert (wIsValidHandle (pmfp->hMF, NULL));
+ GlobalUnlock (*phmfp);
+ Assert (wIsValidHandle (*phmfp, CF_METAFILEPICT));
+ return NOERROR;
+
+ errRtn:
+ if (pmfp)
+ GlobalUnlock (*phmfp);
+ if (*phmfp)
+ GlobalFree (*phmfp);
+ return hresult;
+}
+#endif
+
+#define DWTIMEOUT 1000L
+
+INTERNAL wTimedGetMessage
+ (LPMSG pmsg,
+ HWND hwnd,
+ WORD wFirst,
+ WORD wLast)
+{
+ DWORD dwStartTickCount = GetTickCount();
+ while (!SSPeekMessage (pmsg, hwnd, wFirst, wLast, PM_REMOVE))
+ {
+ if (GetTickCount() - dwStartTickCount > DWTIMEOUT)
+ {
+ if (!IsWindow (hwnd))
+ return ResultFromScode (RPC_E_CONNECTION_LOST);
+ else
+ return ResultFromScode (RPC_E_SERVER_DIED);
+ }
+ }
+ return NOERROR;
+}
+
+
+INTERNAL wNormalize
+ (LPFORMATETC pformatetcIn,
+ LPFORMATETC pformatetcOut)
+{
+ if (pformatetcIn->cfFormat == 0
+ && pformatetcIn->ptd == NULL // Is WildCard
+ && pformatetcIn->dwAspect == -1L
+ && pformatetcIn->lindex == -1L
+ && pformatetcIn->tymed == -1L)
+ {
+ pformatetcOut->cfFormat = CF_METAFILEPICT;
+ pformatetcOut->ptd = NULL;
+ pformatetcOut->dwAspect = DVASPECT_CONTENT;
+ pformatetcOut->lindex = DEF_LINDEX;
+ pformatetcOut->tymed = TYMED_MFPICT;
+ }
+ else
+ {
+ memcpy (pformatetcOut, pformatetcIn, sizeof(FORMATETC));
+ }
+ return NOERROR;
+}
+
+
+
+INTERNAL wVerifyFormatEtc
+ (LPFORMATETC pformatetc)
+{
+ intrDebugOut((DEB_ITRACE,
+ "wVerifyFormatEtc(pformatetc=%x)\n",
+ pformatetc));
+
+ VDATEPTRIN (pformatetc, FORMATETC);
+ if (!HasValidLINDEX(pformatetc))
+ {
+ intrDebugOut((DEB_IERROR, "\t!HasValidLINDEX(pformatetc)\n"));
+ return(DV_E_LINDEX);
+ }
+
+ if (0==(pformatetc->tymed & (TYMED_HGLOBAL | TYMED_MFPICT | TYMED_GDI)))
+ {
+ intrDebugOut((DEB_IERROR,
+ "\t0==(pformatetc->tymed & (TYMED_HGLOBAL | TYMED_MFPICT | TYMED_GDI))\n"));
+ return ResultFromScode (DV_E_TYMED);
+ }
+ if (0==(UtFormatToTymed (pformatetc->cfFormat) & pformatetc->tymed))
+ {
+ intrDebugOut((DEB_IERROR,
+ "\t0==(UtFormatToTymed (pformatetc->cfFormat) & pformatetc->tymed)\n"));
+ return ResultFromScode (DV_E_TYMED);
+ }
+ if (0==(pformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON)))
+ {
+ intrDebugOut((DEB_IERROR,
+ "\t0==(pformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON))\n"));
+
+ return ResultFromScode (DV_E_DVASPECT);
+ }
+ if (pformatetc->dwAspect & DVASPECT_ICON)
+ {
+ if (CF_METAFILEPICT != pformatetc->cfFormat)
+ {
+ intrDebugOut((DEB_IERROR,
+ "\tCF_METAFILEPICT != pformatetc->cfFormat\n"));
+ return ResultFromScode (DV_E_CLIPFORMAT);
+ }
+
+ if (0==(pformatetc->tymed & TYMED_MFPICT))
+ {
+ intrDebugOut((DEB_IERROR,
+ "\t0==(pformatetc->tymed & TYMED_MFPICT)\n"));
+ return ResultFromScode (DV_E_TYMED);
+ }
+ }
+ if (pformatetc->ptd)
+ {
+ if (IsBadReadPtr (pformatetc->ptd, sizeof (DWORD))
+ || IsBadReadPtr (pformatetc->ptd, (size_t)pformatetc->ptd->tdSize))
+ {
+ intrDebugOut((DEB_IERROR,"\tDV_E_DVTARGETDEVICE\n"));
+
+ return ResultFromScode (DV_E_DVTARGETDEVICE);
+ }
+ }
+ return NOERROR;
+}
+
+
+
+INTERNAL wClassesMatch
+ (REFCLSID clsidIn,
+ LPOLESTR szFile)
+{
+ CLSID clsid;
+ if (NOERROR==GetClassFile (szFile, &clsid))
+ {
+ return clsid==clsidIn ? NOERROR : ResultFromScode (S_FALSE);
+ }
+ else
+ {
+ // If we can't determine the class of the file (because it's
+ // not a real file) then OK. Bug 3937.
+ return NOERROR;
+ }
+}
+
+
+
+#ifdef KEVINRO_DUPLICATECODE
+
+This routine also appears in ole1.lib in the OLE232\OLE1 directory
+
+INTERNAL wWriteFmtUserType
+ (LPSTORAGE pstg,
+ REFCLSID clsid)
+{
+ HRESULT hresult = NOERROR;
+ LPOLESTR szProgID = NULL;
+ LPOLESTR szUserType = NULL;
+
+ ErrRtnH (ProgIDFromCLSID (clsid, &szProgID));
+ ErrRtnH (OleRegGetUserType (clsid, USERCLASSTYPE_FULL, &szUserType));
+ ErrRtnH (WriteFmtUserTypeStg (pstg, RegisterClipboardFormat (szProgID),
+ szUserType));
+ errRtn:
+ delete szProgID;
+ delete szUserType;
+ return hresult;
+}
+#endif
+
+#if DBG == 1
+
+INTERNAL_(BOOL) wIsValidHandle
+ (HANDLE h,
+ CLIPFORMAT cf) // cf==NULL means normal memory
+{
+ LPVOID p;
+ if (CF_BITMAP == cf)
+ {
+ BITMAP bm;
+ return (0 != GetObject (h, sizeof(BITMAP), (LPVOID) &bm));
+ }
+ if (CF_PALETTE == cf)
+ {
+ WORD w;
+ return (0 != GetObject (h, sizeof(w), (LPVOID) &w));
+ }
+ if (!(p=GlobalLock(h)))
+ {
+ Puts ("Invalid handle");
+ Puth (h);
+ Putn();
+ return FALSE;
+ }
+ if (IsBadReadPtr (p, (WPARAM) min (UINT_MAX, GlobalSize(h))))
+ {
+ GlobalUnlock (h);
+ return FALSE;
+ }
+ GlobalUnlock (h);
+ return TRUE;
+}
+INTERNAL_(BOOL) wIsValidAtom (ATOM a)
+{
+ WCHAR sz[MAX_STR];
+ if (a==0)
+ return TRUE;
+ if (a < 0xC000)
+ return FALSE;
+ if (0==GlobalGetAtomName (a, sz, MAX_STR))
+ return FALSE;
+ if ('\0'==sz[0])
+ return FALSE;
+ return TRUE;
+}
+
+
+// A "gentle" assert used in reterr.h
+//
+
+
+INTERNAL_(void) wWarn
+ (LPSTR sz,
+ LPSTR szFile,
+ int iLine)
+{
+ intrDebugOut((DEB_WARN,
+ "Warning: %s:%u %s\n",
+ szFile,iLine,sz));
+}
+
+#endif // DBG
+
+
diff --git a/private/ole32/com/remote/dde/client/dirs b/private/ole32/com/remote/dde/client/dirs
new file mode 100644
index 000000000..94c45c76c
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/dirs
@@ -0,0 +1,37 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+#
+# This is a list of all subdirectories that build required components.
+# Each subdirectory name should appear on a line by itself. The build
+# follows the order in which the subdirectories are specified.
+#
+
+DIRS=
+
+#
+# This is a list of all subdirectories that build optional components.
+# Each subdirectory name should appear on a line by itself. The build
+# follows the order in which the subdirectories are specified.
+#
+
+OPTIONAL_DIRS= \
+
+
diff --git a/private/ole32/com/remote/dde/client/modallp.cxx b/private/ole32/com/remote/dde/client/modallp.cxx
new file mode 100644
index 000000000..d6d79a806
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/modallp.cxx
@@ -0,0 +1,201 @@
+/*
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ modallp.cpp
+
+Abstract:
+
+ This module contains the code to wait for reply on a remote call.
+
+Author:
+ Johann Posch (johannp) 01-March-1993 modified to use CoRunModalLoop
+
+*/
+
+#include "ddeproxy.h"
+
+
+#define DebWarn(x)
+#define DebError(x)
+#define DebAction(x)
+#if DBG==1
+static unsigned iCounter=0;
+#endif
+//
+// Called after posting a message (call) to a server
+//
+#pragma SEG(CDdeObject_WaitForReply)
+
+
+
+#ifdef _CHICAGO_
+ //POSTPPC
+INTERNAL_(BOOL) CDdeObject::CanMakeOutCall(LPDDE_CHANNEL pChannel)
+{
+ intrDebugOut((DEB_ITRACE,"::CanMakeOutCall (%x) returns %d \n",pChannel,
+ (pChannel->pCD && (pChannel->pCD->id != CALLDATAID_UNUSED)) ? FALSE : TRUE));
+ return (pChannel->pCD && (pChannel->pCD->id != CALLDATAID_UNUSED)) ? FALSE : TRUE;
+}
+#endif
+
+
+INTERNAL CDdeObject::WaitForReply
+ (LPDDE_CHANNEL pChannel, int iAwaitAck, BOOL fStdCloseDoc, BOOL fDetectTerminate)
+{
+#ifdef _MAC
+#else
+ CALLDATA CD;
+ IID iid = CLSID_NULL;
+ DDECALLDATA DdeCD;
+ MSG PrevMsg;
+ BOOL fPending;
+ HRESULT hres;
+
+
+
+#if DBG == 1
+ unsigned iAutoCounter;
+ intrDebugOut((INTR_DDE,
+ "DdeObject::WaitForReply(%x) Call#(%x) awaiting %x\n",
+ this,
+ iAutoCounter=++iCounter,
+ iAwaitAck));
+#endif
+
+ if (pChannel->pCD && (pChannel->pCD->id != CALLDATAID_UNUSED)) {
+ // this callinfo is in use
+ intrDebugOut((DEB_ERROR,
+ "DdeObject::WaitForReply(%x)ERROR: DDE: callinfo is used\n", this));
+ return ResultFromScode (E_UNEXPECTED);
+ }
+
+
+ // Note: this is to detect a premature DDE_TERMINATE
+ // here we care about if we receive a WM_DDE_TERMINATE instead ACK
+ // the next call to WaitForReply will detect this state and return
+ // since the terminate was send prematurly (Excel is one of this sucker)
+ //
+ if ( fDetectTerminate ) {
+ Assert(m_wTerminate == Terminate_None);
+ // if this flag is on terminate should not execute the default code
+ // in the window procedure
+ m_wTerminate = Terminate_Detect;
+ }
+
+ pChannel->iAwaitAck = iAwaitAck;
+ pChannel->dwStartTickCount = GetTickCount();
+
+ // start looking only for dde messages first
+ pChannel->msgFirst = WM_DDE_FIRST;
+ pChannel->msgLast = WM_DDE_LAST;
+ pChannel->msghwnd = pChannel->hwndCli;
+ PrevMsg.message = 0;
+ PrevMsg.time = 0;
+
+ pChannel->fRejected = FALSE;
+ // see if there is a thread window for lrpc communication
+ // if so we have to dispatch this messages as well
+ fPending = FALSE;
+
+ intrDebugOut((DEB_ITRACE,
+ "+++ Waiting for reply: server: %x, client %x Call#(%x) +++\n",
+ pChannel->hwndSvr,
+ pChannel->hwndCli,
+ iAutoCounter));
+
+ // prepare and enter the modal loop
+ DdeCD.hwndSvr = pChannel->hwndSvr;
+ DdeCD.hwndCli = pChannel->hwndCli;
+ DdeCD.wMsg = pChannel->wMsg;
+ DdeCD.wParam = (WPARAM) pChannel->hwndCli,
+ DdeCD.lParam = pChannel->lParam;
+ DdeCD.fInitialSend = TRUE;
+
+ CD.id = CALLDATAID_UNUSED;
+ CD.lid = iid;
+ CD.TIDCallee = 0;
+ CD.pRpcMsg = (LPVOID) &DdeCD;
+ CD.CallCat = CALLCAT_SYNCHRONOUS;
+ CD.Event = 0;
+
+ pChannel->pCD = &CD;
+
+ //
+ // Setting this value tells DeleteChannel NOT to delete itself.
+ // If the value changes to Channel_DeleteNow while we are in
+ // the modal loop, this routine will delete the channel
+ //
+ pChannel->wChannelDeleted = Channel_InModalloop;
+
+ //
+ // hres will be the return code from the message
+ // handlers, or from the channel itself. The return
+ // code comes from calls to SetCallState. Most of the
+ // time, it will be things like RPC_E_DDE_NACK. However,
+ // it may also return OUTOFMEMORY, or other ModalLoop
+ // problems.
+ //
+
+ hres = pChannel->pCallCont->CallRunModalLoop(&CD);
+
+ if (hres != NOERROR)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "**************** CallRunModalLoop returns %x ***\n",
+ hres));
+ }
+
+ if (m_wTerminate == Terminate_Received) {
+ intrAssert(fDetectTerminate);
+ //
+ // There really wasn't an error, its just that the server decided
+ // to terminate. If we return an error here, the app may decide
+ // that things have gone awry. Excel, for example, will decide
+ // that the object could not be activated, even though it has
+ // already updated its cache information.
+ //
+ hres = NOERROR;
+ intrDebugOut((DEB_ITRACE,
+ "::WaitForReply setting hres=%x\n",
+ hres));
+ intrDebugOut((DEB_ITRACE,
+ "::WaitForReply posting TERMINATE to self hwnd=%x\n",
+ DdeCD.hwndCli));
+ // set state to normal and repost message
+ Verify (PostMessage (DdeCD.hwndCli, WM_DDE_TERMINATE,
+ (WPARAM)DdeCD.hwndSvr, (LPARAM)0));
+ }
+ m_wTerminate = Terminate_None;
+
+ //
+ // If the channel is to be deleted, then do it now. This flag would
+ // have been set in the DeleteChannel routine.
+ //
+ if (pChannel->wChannelDeleted == Channel_DeleteNow)
+ {
+ intrDebugOut((INTR_DDE,
+ "::WaitForReply(%x) Channel_DeleteNow pChannel(%x)\n",
+ pChannel));
+
+ pChannel->ReleaseReference();
+
+ // Excel will send TERMINATE before sending an ACK to StdCloseDoc
+ return ResultFromScode (fStdCloseDoc ? S_OK : RPC_E_DDE_POST);
+ }
+ pChannel->wChannelDeleted = 0;
+
+ pChannel->iAwaitAck = 0;
+ pChannel->pCD = NULL;
+
+ intrDebugOut((DEB_ITRACE,
+ "### Waiting for reply done: server: %x, client %x hres(%x)###\n",
+ pChannel->hwndSvr,
+ pChannel->hwndCli,
+ hres));
+
+ return hres;
+#endif _MAC
+}
diff --git a/private/ole32/com/remote/dde/client/packmnkr.cxx b/private/ole32/com/remote/dde/client/packmnkr.cxx
new file mode 100644
index 000000000..b4642bb8c
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/packmnkr.cxx
@@ -0,0 +1,273 @@
+/*
+ PackMnkr.cpp
+ PackageMoniker
+
+ This module implements the CPackagerMoniker class and
+ CreatePackagerMoniker()
+
+ Author:
+ Jason Fuller jasonful Nov-2-1992
+
+ Copyright (c) 1992 Microsoft Corporation
+*/
+
+#include <ole2int.h>
+#include "packmnkr.h"
+#include "..\server\ddedebug.h"
+#include <ole1cls.h>
+
+ASSERTDATA
+
+
+STDMETHODIMP CPackagerMoniker::QueryInterface
+ (REFIID riid, LPVOID * ppvObj)
+{
+ M_PROLOG(this);
+ VDATEIID (riid);
+ VDATEPTROUT (ppvObj, LPVOID);
+
+ if ((riid == IID_IMoniker) || (riid == IID_IUnknown) ||
+ (riid == IID_IPersistStream) || (riid == IID_IInternalMoniker))
+ {
+ *ppvObj = this;
+ ++m_refs;
+ return NOERROR;
+ }
+ AssertSz (0, "Could not find interface\r\n");
+ *ppvObj = NULL;
+ return ReportResult(0, E_NOINTERFACE, 0, 0);
+}
+
+
+
+STDMETHODIMP_(ULONG) CPackagerMoniker::AddRef()
+{
+ M_PROLOG(this);
+ return ++m_refs;
+}
+
+
+
+STDMETHODIMP_(ULONG) CPackagerMoniker::Release()
+{
+ M_PROLOG(this);
+ Assert (m_refs > 0);
+ if (0 == --m_refs)
+ {
+ m_pmk->Release();
+ delete m_szFile;
+ delete this;
+ return 0;
+ }
+ return m_refs;
+}
+
+
+
+STDMETHODIMP CPackagerMoniker::GetClassID (THIS_ LPCLSID lpClassID)
+{
+ M_PROLOG(this);
+ *lpClassID = CLSID_PackagerMoniker;
+ return NOERROR;
+}
+
+
+
+STDMETHODIMP CPackagerMoniker::BindToObject (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
+ REFIID riidResult, LPVOID * ppvResult)
+{
+ M_PROLOG(this);
+ WIN32_FIND_DATA fd;
+ HRESULT hr;
+
+ // The following code ensures that the file exists before we try to bind it.
+ HANDLE hFind = FindFirstFile(m_szFile, &fd);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ hr = DdeBindToObject (m_szFile, CLSID_Package, m_fLink, riidResult, ppvResult);
+ FindClose(hFind);
+ }
+ else
+ hr = MK_E_CANTOPENFILE;
+ return hr;
+}
+
+STDMETHODIMP CPackagerMoniker::IsRunning (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
+ LPMONIKER pmkNewlyRunning)
+{
+ M_PROLOG(this);
+ VDATEIFACE (pbc);
+
+ if (pmkToLeft)
+ VDATEIFACE (pmkToLeft);
+ if (pmkNewlyRunning)
+ VDATEIFACE (pmkNewlyRunning);
+
+ // There is no way to tell if a packaged object is running
+ return ReportResult (0, S_FALSE, 0, 0);
+}
+
+
+STDAPI CreatePackagerMoniker(LPOLESTR szFile, LPMONIKER * ppmk, BOOL fLink )
+{
+ return CPackagerMoniker::Create (szFile, ppmk, fLink);
+}
+
+HRESULT CPackagerMoniker::Create(LPOLESTR szFile,LPMONIKER * ppmk, BOOL fLink )
+{
+ HRESULT hresult;
+ VDATEPTROUT (ppmk, LPMONIKER);
+ *ppmk = NULL;
+
+ CPackagerMoniker * pmkPack = new CPackagerMoniker;
+ if (NULL==pmkPack)
+ return ReportResult (0, E_OUTOFMEMORY, 0, 0);
+ ErrRtnH (CreateFileMoniker (szFile, &(pmkPack->m_pmk)));
+
+ pmkPack->m_szFile = new WCHAR [lstrlenW(szFile)+1];
+ lstrcpyW (pmkPack->m_szFile, szFile);
+
+ pmkPack->m_fLink = fLink;
+ pmkPack->m_refs = 1;
+
+ *ppmk = pmkPack;
+ return NOERROR;
+
+errRtn:
+ Assert (0);
+ delete pmkPack;
+ return hresult;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////
+// The rest of these methods just delegate to m_pmk
+// or return some error code.
+
+
+STDMETHODIMP CPackagerMoniker::IsDirty (THIS)
+{
+ M_PROLOG(this);
+ return ReportResult(0, S_FALSE, 0, 0);
+ // monikers are immutable so they are either always dirty or never dirty.
+ //
+}
+
+STDMETHODIMP CPackagerMoniker::Load (THIS_ LPSTREAM pStm)
+{
+ M_PROLOG(this);
+ return m_pmk->Load(pStm);
+}
+
+
+STDMETHODIMP CPackagerMoniker::Save (THIS_ LPSTREAM pStm,
+ BOOL fClearDirty)
+{
+ M_PROLOG(this);
+ return m_pmk->Save(pStm, fClearDirty);
+}
+
+
+STDMETHODIMP CPackagerMoniker::GetSizeMax (THIS_ ULARGE_INTEGER * pcbSize)
+{
+ M_PROLOG(this);
+ return m_pmk->GetSizeMax (pcbSize);
+}
+
+ // *** IMoniker methods ***
+STDMETHODIMP CPackagerMoniker::BindToStorage (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
+ REFIID riid, LPVOID * ppvObj)
+{
+ M_PROLOG(this);
+ *ppvObj = NULL;
+ return ReportResult(0, E_NOTIMPL, 0, 0);
+}
+
+STDMETHODIMP CPackagerMoniker::Reduce (THIS_ LPBC pbc, DWORD dwReduceHowFar, LPMONIKER *
+ ppmkToLeft, LPMONIKER * ppmkReduced)
+{
+ M_PROLOG(this);
+ return m_pmk->Reduce (pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
+}
+
+STDMETHODIMP CPackagerMoniker::ComposeWith (THIS_ LPMONIKER pmkRight, BOOL fOnlyIfNotGeneric,
+ LPMONIKER * ppmkComposite)
+{
+ M_PROLOG(this);
+ return m_pmk->ComposeWith (pmkRight, fOnlyIfNotGeneric, ppmkComposite);
+}
+
+STDMETHODIMP CPackagerMoniker::Enum (THIS_ BOOL fForward, LPENUMMONIKER * ppenumMoniker)
+{
+ M_PROLOG(this);
+ return m_pmk->Enum (fForward, ppenumMoniker);
+}
+
+STDMETHODIMP CPackagerMoniker::IsEqual (THIS_ LPMONIKER pmkOtherMoniker)
+{
+ M_PROLOG(this);
+ return m_pmk->IsEqual (pmkOtherMoniker);
+}
+
+STDMETHODIMP CPackagerMoniker::Hash (THIS_ LPDWORD pdwHash)
+{
+ M_PROLOG(this);
+ return m_pmk->Hash (pdwHash);
+}
+
+STDMETHODIMP CPackagerMoniker::GetTimeOfLastChange (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
+ FILETIME * pfiletime)
+{
+ M_PROLOG(this);
+ return m_pmk->GetTimeOfLastChange (pbc, pmkToLeft, pfiletime);
+}
+
+STDMETHODIMP CPackagerMoniker::Inverse (THIS_ LPMONIKER * ppmk)
+{
+ M_PROLOG(this);
+ return m_pmk->Inverse (ppmk);
+}
+
+STDMETHODIMP CPackagerMoniker::CommonPrefixWith (LPMONIKER pmkOther, LPMONIKER *
+ ppmkPrefix)
+{
+ M_PROLOG(this);
+ return m_pmk->CommonPrefixWith (pmkOther, ppmkPrefix);
+}
+
+STDMETHODIMP CPackagerMoniker::RelativePathTo (THIS_ LPMONIKER pmkOther, LPMONIKER *
+ ppmkRelPath)
+{
+ M_PROLOG(this);
+ return m_pmk->RelativePathTo (pmkOther, ppmkRelPath);
+}
+
+STDMETHODIMP CPackagerMoniker::GetDisplayName (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
+ LPOLESTR * lplpszDisplayName)
+{
+ M_PROLOG(this);
+ return m_pmk->GetDisplayName (pbc, pmkToLeft, lplpszDisplayName);
+}
+
+STDMETHODIMP CPackagerMoniker::ParseDisplayName (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
+ LPOLESTR lpszDisplayName, ULONG * pchEaten,
+ LPMONIKER * ppmkOut)
+{
+ M_PROLOG(this);
+ return m_pmk->ParseDisplayName (pbc, pmkToLeft, lpszDisplayName, pchEaten,
+ ppmkOut);
+}
+
+
+STDMETHODIMP CPackagerMoniker::IsSystemMoniker (THIS_ LPDWORD pdwMksys)
+{
+ M_PROLOG(this);
+ VDATEPTROUT (pdwMksys, DWORD);
+
+ *pdwMksys = MKSYS_NONE;
+ return NOERROR;
+}
+
+
+
diff --git a/private/ole32/com/remote/dde/client/packmnkr.h b/private/ole32/com/remote/dde/client/packmnkr.h
new file mode 100644
index 000000000..bc312bfab
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/packmnkr.h
@@ -0,0 +1,63 @@
+/*
+ packmnkr.h
+*/
+
+class CPackagerMoniker : public IMoniker
+{
+ public:
+ // *** IUnknown methods ***
+ STDMETHOD(QueryInterface) ( REFIID riid, LPVOID * ppvObj) ;
+ STDMETHOD_(ULONG,AddRef) () ;
+ STDMETHOD_(ULONG,Release) () ;
+
+ // *** IPersist methods ***
+ STDMETHOD(GetClassID) ( LPCLSID lpClassID) ;
+
+ // *** IPersistStream methods ***
+ STDMETHOD(IsDirty) () ;
+ STDMETHOD(Load) ( LPSTREAM pStm) ;
+ STDMETHOD(Save) ( LPSTREAM pStm,
+ BOOL fClearDirty) ;
+ STDMETHOD(GetSizeMax) ( ULARGE_INTEGER * pcbSize) ;
+
+ // *** IMoniker methods ***
+ STDMETHOD(BindToObject) ( LPBC pbc, LPMONIKER pmkToLeft,
+ REFIID riidResult, LPVOID * ppvResult) ;
+ STDMETHOD(BindToStorage) ( LPBC pbc, LPMONIKER pmkToLeft,
+ REFIID riid, LPVOID * ppvObj) ;
+ STDMETHOD(Reduce) ( LPBC pbc, DWORD dwReduceHowFar, LPMONIKER *
+ ppmkToLeft, LPMONIKER * ppmkReduced) ;
+ STDMETHOD(ComposeWith) ( LPMONIKER pmkRight, BOOL fOnlyIfNotGeneric,
+ LPMONIKER * ppmkComposite) ;
+ STDMETHOD(Enum) ( BOOL fForward, LPENUMMONIKER * ppenumMoniker)
+ ;
+ STDMETHOD(IsEqual) ( LPMONIKER pmkOtherMoniker) ;
+ STDMETHOD(Hash) ( LPDWORD pdwHash) ;
+ STDMETHOD(IsRunning) ( LPBC pbc, LPMONIKER pmkToLeft, LPMONIKER
+ pmkNewlyRunning) ;
+ STDMETHOD(GetTimeOfLastChange) ( LPBC pbc, LPMONIKER pmkToLeft,
+ FILETIME * pfiletime) ;
+ STDMETHOD(Inverse) ( LPMONIKER * ppmk) ;
+ STDMETHOD(CommonPrefixWith) ( LPMONIKER pmkOther, LPMONIKER *
+ ppmkPrefix) ;
+ STDMETHOD(RelativePathTo) ( LPMONIKER pmkOther, LPMONIKER *
+ ppmkRelPath) ;
+ STDMETHOD(GetDisplayName) ( LPBC pbc, LPMONIKER pmkToLeft,
+ LPOLESTR * lplpszDisplayName) ;
+ STDMETHOD(ParseDisplayName) ( LPBC pbc, LPMONIKER pmkToLeft,
+ LPOLESTR lpszDisplayName, ULONG * pchEaten,
+ LPMONIKER * ppmkOut) ;
+ STDMETHOD(IsSystemMoniker) ( LPDWORD pdwMksys) ;
+
+ static HRESULT Create ( LPOLESTR szFile, LPMONIKER * ppmk, BOOL fLink) ;
+
+ private:
+
+ ULONG m_refs;
+ LPOLESTR m_szFile;
+ LPMONIKER m_pmk;
+ BOOL m_fLink;
+
+
+};
+
diff --git a/private/ole32/com/remote/dde/client/trgt_dev.h b/private/ole32/com/remote/dde/client/trgt_dev.h
new file mode 100644
index 000000000..a2de2d4b3
--- /dev/null
+++ b/private/ole32/com/remote/dde/client/trgt_dev.h
@@ -0,0 +1,19 @@
+// trgt_dev.h
+
+// OLE 1.0 Target Device
+
+typedef struct _OLETARGETDEVICE
+{
+ USHORT otdDeviceNameOffset;
+ USHORT otdDriverNameOffset;
+ USHORT otdPortNameOffset;
+ USHORT otdExtDevmodeOffset;
+ USHORT otdExtDevmodeSize;
+ USHORT otdEnvironmentOffset;
+ USHORT otdEnvironmentSize;
+ BYTE otdData[1];
+} OLETARGETDEVICE;
+
+typedef OLETARGETDEVICE const FAR* LPCOLETARGETDEVICE;
+typedef OLETARGETDEVICE FAR* LPOLETARGETDEVICE;
+
diff --git a/private/ole32/com/remote/dde/dirs b/private/ole32/com/remote/dde/dirs
new file mode 100644
index 000000000..8d723ece9
--- /dev/null
+++ b/private/ole32/com/remote/dde/dirs
@@ -0,0 +1,36 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+#
+# This is a list of all subdirectories that build required components.
+# Each subdirectory name should appear on a line by itself. The build
+# follows the order in which the subdirectories are specified.
+#
+
+DIRS= client server
+
+#
+# This is a list of all subdirectories that build optional components.
+# Each subdirectory name should appear on a line by itself. The build
+# follows the order in which the subdirectories are specified.
+#
+
+OPTIONAL_DIRS=
+
diff --git a/private/ole32/com/remote/dde/server/daytona/makefile b/private/ole32/com/remote/dde/server/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/ole32/com/remote/dde/server/daytona/sources b/private/ole32/com/remote/dde/server/daytona/sources
new file mode 100644
index 000000000..f557ef159
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/daytona/sources
@@ -0,0 +1,83 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# This is the name of the target built from the source files specified
+# below. The name should include neither the path nor the file extension.
+#
+
+TARGETNAME= ddesvr
+
+#
+# This specifies where the target is to be built. A private target of
+# type LIBRARY or DYNLINK should go to obj, whereas a public target of
+# type LIBRARY or DYNLINK should go to $(BASEDIR)\public\sdk\lib.
+#
+
+TARGETPATH= obj
+
+#
+# This specifies the type of the target, such as PROGRAM, DYNLINK, LIBRARY,
+# etc.
+#
+
+TARGETTYPE= LIBRARY
+
+INCLUDES = ..\.;..\..\client;..\..\..\..\..\common\daytona;..\..\..\..\..\ih;..\..\..;..\..\..\..\inc;..\..\..\..\idl\daytona;..\..\..\..\class;..\..\..\..\objact;..\..\..\..\..\ole232\inc
+
+!include ..\..\..\..\..\daytona.inc
+
+C_DEFINES= -DOLE_DDE_NO_GLOBAL_TRACKING=1\
+ $(C_DEFINES) \
+
+
+SOURCES= \
+ ..\ddeadv.cxx \
+ ..\ddesink.cxx \
+ ..\ddesite.cxx \
+ ..\ddesrvr.cxx \
+ ..\ddeutils.cxx \
+ ..\doc.cxx \
+ ..\item.cxx \
+ ..\item2.cxx \
+ ..\itemutil.cxx \
+ ..\srvr.cxx \
+ ..\srvrmain.cxx
+
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+# PRECOMPILED_INCLUDE= ..\headers.cxx
+
+
diff --git a/private/ole32/com/remote/dde/server/ddeadv.cxx b/private/ole32/com/remote/dde/server/ddeadv.cxx
new file mode 100644
index 000000000..0d03789ed
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/ddeadv.cxx
@@ -0,0 +1,132 @@
+// ddeadv.cpp
+//
+// Mapping from DDE advise to/from OLE 2.0 advises
+//
+// Author:
+// Jason Fuller jasonful 8-16-92
+//
+// Copyright (c) 1992 Microsoft Corporation
+
+#include "ole2int.h"
+#include "srvr.h"
+#include "ddedebug.h"
+ASSERTDATA
+
+
+INTERNAL CDefClient::DoOle20Advise
+ (OLE_NOTIFICATION options,
+ CLIPFORMAT cf)
+{
+ HRESULT hresult = NOERROR;
+ FORMATETC formatetc;
+ formatetc.cfFormat = cf;
+ formatetc.ptd = m_ptd;
+ formatetc.lindex = DEF_LINDEX;
+ formatetc.dwAspect = DVASPECT_CONTENT;
+ // only types 1.0 client wants
+ formatetc.tymed = TYMED_HGLOBAL | TYMED_MFPICT | TYMED_GDI;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::DoOle20Advise(options=%x,cf=%x)\n",
+ this,
+ options,
+ (ULONG)cf));
+ ChkC(this);
+ switch (options)
+ {
+ case OLE_CHANGED:
+#ifdef UPDATE
+ case OLE_SAVED:
+#endif
+ if (0 == m_dwConnectionDataObj)
+ {
+ Assert (m_lpdataObj);
+ RetErr (m_lpdataObj->DAdvise (&formatetc,0/* ADVF_PRIMEFIRST*/,
+ &m_AdviseSink,
+ &m_dwConnectionDataObj));
+ Assert (m_dwConnectionDataObj != 0);
+ }
+ // Fall through:
+ // Even for OLE_CHANGED do an Ole Advise so we get OnClose
+ // notifications for linked objects.
+
+#ifndef UPDATE
+ case OLE_SAVED:
+#endif
+ case OLE_RENAMED: // Link case
+ case OLE_CLOSED:
+ Assert (m_lpoleObj);
+ // Only do one OleObject::Advise even if 1.0 client asks
+ // for two advises for two different formats and two events,
+ // i.e., native and metafile, save and close.
+ if (m_lpoleObj && 0==m_dwConnectionOleObj)
+ {
+ Puts ("Calling OleObject::Advise\r\n");
+ Assert (m_dwConnectionOleObj == 0L);
+ hresult = m_lpoleObj->Advise (&m_AdviseSink, &m_dwConnectionOleObj);
+ if (hresult != NOERROR)
+ {
+ goto errRtn;
+ }
+ }
+ Assert (m_dwConnectionOleObj != 0);
+ break;
+
+ default:
+ Assert(0);
+ break;
+ }
+
+errRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::DoOle20Advise hresult=%x\n",
+ this,hresult));
+
+
+ return NOERROR;
+}
+
+
+
+
+INTERNAL CDefClient::DoOle20UnAdviseAll
+ (void)
+{
+ HRESULT hr;
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::DoOle20UnAdviseAll\n",
+ this));
+
+ ChkC(this);
+ if (m_dwConnectionOleObj != 0L)
+ {
+ if (m_lpoleObj)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "%x ::DoOle20UnAdviseAll unadvise OLE obj\n",
+ this));
+ Puts ("Unadvising ole obj\r\n");
+ hr = m_lpoleObj->Unadvise (m_dwConnectionOleObj);
+ intrAssert(hr == NOERROR);
+ m_dwConnectionOleObj = 0L;
+ }
+ }
+ if (m_dwConnectionDataObj != 0L)
+ {
+ if (m_lpdataObj)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "%x ::DoOle20UnAdviseAll unadvise DATA obj\n",
+ this));
+ Puts ("Unadvising data obj\r\n");
+ hr = m_lpdataObj->DUnadvise (m_dwConnectionDataObj);
+ intrAssert(hr == NOERROR);
+ m_dwConnectionDataObj = 0L;
+ }
+ }
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::DoOle20UnAdviseAll\n",
+ this));
+
+ return NOERROR;
+}
diff --git a/private/ole32/com/remote/dde/server/ddeatoms.h b/private/ole32/com/remote/dde/server/ddeatoms.h
new file mode 100644
index 000000000..ba105ba17
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/ddeatoms.h
@@ -0,0 +1,42 @@
+/* ddeatoms.h */
+
+//This is here because the file is #included by both client and server files
+#define fDdeCodeInOle2Dll 1
+
+// These atoms are defined in srvrmain.cpp
+extern ATOM aEditItems;
+extern ATOM aFormats;
+extern ATOM aOLE;
+extern ATOM aProtocols;
+extern ATOM aStatus;
+extern ATOM aStdClose;
+extern ATOM aStdCreate;
+extern ATOM aStdCreateFromTemplate;
+extern ATOM aStdEdit;
+extern ATOM aStdExit;
+extern ATOM aStdOpen;
+extern ATOM aStdShowItem;
+extern ATOM aSysTopic;
+extern ATOM aTopics;
+
+// defined in ddewnd.cpp
+extern ATOM aChange;
+extern ATOM aClose;
+extern ATOM aMSDraw;
+extern ATOM aNullArg;
+extern ATOM aOle;
+extern ATOM aSave;
+extern ATOM aStdColorScheme;
+extern ATOM aStdDocDimensions;
+extern ATOM aStdDocName;
+extern ATOM aStdHostNames;
+extern ATOM aStdTargetDevice ;
+extern ATOM aSystem;
+
+// defined in ddewnd.cpp
+extern CLIPFORMAT cfBinary; // "Binary format"
+extern CLIPFORMAT cfNative; // "NativeFormat"
+
+// defined in srvrmain.cpp
+extern CLIPFORMAT cfLink; // "ObjectLink"
+extern CLIPFORMAT cfOwnerLink; // "Ownerlink"
diff --git a/private/ole32/com/remote/dde/server/ddedebug.h b/private/ole32/com/remote/dde/server/ddedebug.h
new file mode 100644
index 000000000..dfb7401e6
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/ddedebug.h
@@ -0,0 +1,99 @@
+// ddeDebug.h
+//
+// Generic debug routines
+//
+// Author:
+// Jason Fuller jasonful 8-16-92
+//
+
+#ifndef fDdedebug_h
+#define fDdedebug_h
+
+#define INTR_DDE 0x00010000
+#define INTR_CHNL 0x00020000
+#define INTR_PARAM 0x00040000
+
+//#define fDebugOutput
+#define WIDECHECK(x) (x?x:L"<NULL>")
+#define ANSICHECK(x) (x?x:"<NULL>")
+
+#if DBG == 1
+#define DEBUG_GUIDSTR(name,guid) WCHAR name [48]; StringFromGUID2( *guid , name , sizeof( name ));
+#else
+#define DEBUG_GUIDSTR(name,guid)
+#endif
+#ifdef _DEBUG
+
+ // defined in clientddeworkr.cpp
+ BOOL wIsValidHandle (HANDLE, CLIPFORMAT);
+ BOOL wIsValidAtom (ATOM);
+
+ #define DebugOnly(x) x
+ #define ChkC(p) Assert (p && p->m_chk==chkDefClient)
+ #define ChkS(p) Assert (p && p->m_chk==chkDdeSrvr)
+ #define ChkD(p) Assert ((p) && (p)->m_chk==chkDdeObj)
+ #define AssertIsDoc(p) Assert ((p) && (p)->m_pdoc==(p) && (p)->m_bContainer)
+
+ #define ChkCR(p) RetZ (p && p->m_chk==chkDefClient)
+ #define ChkSR(p) RetZ (p && p->m_chk==chkDdeSrvr)
+ #define ChkDR(p) RetZ ((p) && (p)->m_chk==chkDdeObj)
+ #define AssertIsDocR(p) RetZ ((p) && (p)->m_pdoc==(p) && (p)->m_bContainer)
+
+ #ifdef fDebugOutput
+
+ #define Puti(i) do {char sz[50]; wsprintf(sz, " %lu ", (unsigned long) (i)); Puts(sz);} while(0)
+ #define Puth(i) do {char sz[50]; wsprintf(sz, " 0x%lx ", (unsigned long) (i)); Puts(sz);} while(0)
+ #define Puta(a) do {char sz[50]="NULL"; if (a) GlobalGetAtomName(a,sz,50); \
+ Puth(a); Puts("\""); Puts(sz); Puts("\" "); } while(0)
+ #define Putsi(i) do { Puts(#i " = "); Puti(i); Puts("\n");} while (0)
+ #define Putn() Puts("\r\n")
+
+ #else
+
+ #undef Puts
+ #define Puts(i) ((void)0)
+ #define Puti(i) ((void)0)
+ #define Puth(i) ((void)0)
+ #define Puta(a) ((void)0)
+ #define Putsi(i) ((void)0)
+ #define Putn() ((void)0)
+
+ #endif // fDebugOutput
+ #define DEBUG_OUT(a,b) OutputDebugStringA(a);
+#else
+ #define DEBUG_OUT(a,b)
+ #define Puti(i) ((void)0)
+ #define Puth(i) ((void)0)
+ #define Puta(a) ((void)0)
+ #define Putsi(i) ((void)0)
+ #define Putn() ((void)0)
+ #define wIsValidHandle(h,cf) (TRUE)
+ #define wIsValidAtom(a) (TRUE)
+ #define DebugOnly(x)
+ #define ChkC(p)
+ #define ChkS(p)
+ #define ChkD(p)
+ #define AssertIsDoc(p)
+ #define ChkCR(p)
+ #define ChkSR(p)
+ #define ChkDR(p)
+ #define AssertIsDocR(p)
+
+#endif // _DEBUG
+
+
+// Stuff common to both client and server directories
+
+#define POSITIVE_ACK (0x8000)
+#define NEGATIVE_ACK (0x0000)
+
+#include <reterr.h>
+
+INTERNAL_(LPOLESTR) wAtomName (ATOM atom);
+INTERNAL_(LPSTR) wAtomNameA (ATOM atom);
+INTERNAL_(ATOM) wDupAtom (ATOM aSrc);
+
+INTERNAL wClassesMatch (REFCLSID clsid, LPOLESTR szFile);
+INTERNAL wWriteFmtUserType (LPSTORAGE, REFCLSID);
+
+#endif // fDdedebug_h
diff --git a/private/ole32/com/remote/dde/server/ddeerr.h b/private/ole32/com/remote/dde/server/ddeerr.h
new file mode 100644
index 000000000..f35a88b63
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/ddeerr.h
@@ -0,0 +1,78 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: ddeerr.h
+//
+// Contents: Error codes from the previous release
+//
+// Classes:
+//
+// Functions:
+//
+// History: 4-26-94 kevinro Commented/cleaned
+//
+// This is actually the contents from ole2anac.h, with some parts removed.
+// Specifically, including ole2anac.h renamed DAdvise and friends, which
+// is bad.
+//----------------------------------------------------------------------------
+#if !defined( _OLE2ANAC_H_ )
+#define _OLE2ANAC_H_
+
+typedef enum tagSTGSTATE
+{
+ STGSTATE_DOC = 1,
+ STGSTATE_CONVERT = 2,
+ STGSTATE_FILESTGSAME = 4
+} STGSTATE;
+
+
+#define MK_E_EXCEEDED_DEADLINE MK_E_EXCEEDEDDEADLINE
+#define MK_E_NEED_GENERIC MK_E_NEEDGENERIC
+#define MK_E_INVALID_EXTENSION MK_E_INVALIDEXTENSION
+#define MK_E_INTERMEDIATE_INTERFACE_NOT_SUPPORTED \
+ MK_E_INTERMEDIATEINTERFACENONOT_SUPPORTED
+#define MK_E_NOT_BINDABLE MK_E_NOTBINDABLE
+#define S_TRUE S_OK
+
+#define E_BLANK OLE_E_BLANK
+#define E_STATIC OLE_E_STATIC
+#define E_NOTRUNNING OLE_E_NOTRUNNING
+#define E_FORMAT DV_E_CLIPFORMAT
+#define OLE_E_CLSID REGDB_E_CLASSNOTREG
+#define OLE_E_NOTSUPPORTED E_NOTIMPL
+#define OLE_E_REGDB_KEY REGDB_E_KEYMISSING
+#define OLE_E_REGDB_FMT REGDB_E_INVALIDVALUE
+
+
+#define OLEVERB_PRIMARY OLEIVERB_PRIMARY
+#define OLEVERB_SHOW OLEIVERB_SHOW
+
+// these DDE error codes are not returned anymore; these definitions are
+// here just to make existing code compile without changes.
+#define RPC_E_FIRST MAKE_SCODE(SEVERITY_ERROR, FACILITY_RPC, 0x000)
+#define RPC_E_DDE_FIRST MAKE_SCODE(SEVERITY_ERROR, FACILITY_RPC, 0x100)
+
+#define RPC_E_DDE_BUSY (RPC_E_DDE_FIRST + 0x0)
+#define RPC_E_DDE_CANT_UPDATE (RPC_E_DDE_FIRST + 0x1)
+#define RPC_E_DDE_INIT (RPC_E_DDE_FIRST + 0x2)
+#define RPC_E_DDE_NACK E_FAIL
+#define RPC_E_DDE_LAUNCH CO_E_APPNOTFOUND
+#define RPC_E_DDE_POST RPC_E_SERVER_DIED
+#define RPC_E_DDE_PROTOCOL (RPC_E_DDE_FIRST + 0x6)
+#define RPC_E_DDE_REVOKE (RPC_E_DDE_FIRST + 0x7)
+#define RPC_E_DDE_SYNTAX_EXECUTE RPC_E_INVALID_PARAMETER
+#define RPC_E_DDE_SYNTAX_ITEM RPC_E_INVALID_PARAMETER
+#define RPC_E_DDE_UNEXP_MSG (RPC_E_DDE_FIRST + 0xa)
+#define RPC_E_DDE_DATA RPC_E_INVALID_PARAMETER
+
+
+#define RPC_E_CONNECTION_LOST (RPC_E_FIRST + 0x6)
+#define RPC_E_BUSY (RPC_E_FIRST + 0x0)
+#define RPC_E_MSG_REJECTED (RPC_E_FIRST + 0x1)
+#define RPC_E_CANCELLED (RPC_E_FIRST + 0x2)
+#define RPC_E_DISPATCH_ASYNCCALL (RPC_E_FIRST + 0x4)
+
+
+#endif // _OLE2ANAC_H_
diff --git a/private/ole32/com/remote/dde/server/ddeint.h b/private/ole32/com/remote/dde/server/ddeint.h
new file mode 100644
index 000000000..d99fb29f3
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/ddeint.h
@@ -0,0 +1,179 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: ddeint.h
+//
+// Contents: This file contains shared macros/state between the server
+// and client directories
+// Classes:
+//
+// Functions:
+//
+// History: 5-04-94 kevinro Commented/cleaned
+//
+//----------------------------------------------------------------------------
+
+//
+// BUGBUG: (KevinRo) The new definition of DVTARGETDEVICE uses an unsized array
+// of bytes at the end. Therefore, the sizeof operator no longer works. So, I
+// have calculated the size of the cbHeader by accounting for each member of
+// the structure independently. I am not too proud of this at the moment,
+// but need to move on.
+//
+
+#define DEB_DDE_INIT (DEB_ITRACE|DEB_USER1)
+
+// names of the DDE window classes
+#ifdef _CHICAGO_
+// Note: we have to create a unique string so that get
+// register a unique class for each 16 bit app.
+// The class space is global on chicago.
+//
+extern LPSTR szSYS_CLASSA;
+extern LPSTR szCLIENT_CLASSA;
+extern LPSTR szSRVR_CLASSA;
+extern LPSTR szDOC_CLASSA;
+extern LPSTR szITEM_CLASSA;
+extern LPSTR szCOMMONCLASSA;
+
+#define DOC_CLASSA szDOC_CLASSA
+#define SYS_CLASSA szSYS_CLASSA
+#define CLIENT_CLASSA szCLIENT_CLASSA
+
+#define SYS_CLASS szSYS_CLASSA
+#define CLIENT_CLASS szCLIENT_CLASSA
+#define SRVR_CLASS szSRVR_CLASSA
+#define SRVR_CLASS szSRVR_CLASSA
+#define DOC_CLASS szDOC_CLASSA
+#define ITEM_CLASS szITEM_CLASSA
+#define COMMONCLASS szCOMMONCLASSA
+
+
+#define DDEWNDCLASS WNDCLASSA
+#define DdeRegisterClass RegisterClassA
+#define DdeUnregisterClass UnregisterClassA
+#define DdeCreateWindowEx SSCreateWindowExA
+
+#else
+
+#define SYS_CLASS L"Ole2SysWndClass"
+#define SYS_CLASSA "Ole2SysWndClass"
+
+#define CLIENT_CLASS L"Ole2ClientWndClass"
+#define CLIENT_CLASSA "Ole2ClientWndClass"
+
+#define SRVR_CLASS (OLESTR("SrvrWndClass"))
+#define SRVR_CLASSA ("SrvrWndClass")
+
+#define DOC_CLASS (OLESTR("ViewObjWndClass"))
+#define DOC_CLASSA ("ViewObjWndClass")
+
+#define ITEM_CLASS (OLESTR("ItemWndClass"))
+
+#define DDEWNDCLASS WNDCLASS
+#define DdeRegisterClass RegisterClass
+#define DdeUnregisterClass UnregisterClass
+#define DdeCreateWindowEx CreateWindowEx
+
+#endif // !_CHICAGO_
+
+STDAPI_(LRESULT) DocWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+STDAPI_(LRESULT) SrvrWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+STDAPI_(LRESULT) SysWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+STDAPI_(LRESULT) ClientDocWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+BOOL SendMsgToChildren (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+
+#define SIZEOF_DVTARGETDEVICE_HEADER (sizeof(DWORD) + (sizeof(WORD) * 4))
+
+// forward declarations
+class CDefClient;
+typedef CDefClient FAR *LPCLIENT;
+
+class CDDEServer;
+typedef CDDEServer FAR *LPSRVR;
+typedef CDDEServer FAR *HDDE; // used by ClassFactory table
+
+
+PCALLCONTROL GetDdeCallControlInterface();
+void ReleaseDdeCallControlInterface();
+
+//
+// The wire representation of STDDOCDIMENSIONS is a 16-bit
+// format. This means instead of 4 longs, there are
+// 4 shorts. This structure is used below to pick the data
+// from the wire representation. Amazingly stupid, but
+// backward compatible is the name of the game.
+//
+typedef struct tagRECT16
+{
+ SHORT left;
+ SHORT top;
+ SHORT right;
+ SHORT bottom;
+
+} RECT16, *LPRECT16;
+
+//+---------------------------------------------------------------------------
+//
+// Function: ConvertToFullHWND
+//
+// Synopsis: This function is used to convert a 16-bit HWND into a 32-bit
+// hwnd
+//
+// Effects: When running in a VDM, depending on who dispatches the message
+// we can end up with either a 16 or 32 bit window message. This
+// routine is used to make sure we always deal with a 32bit
+// HWND. Otherwise, some of our comparisions are incorrect.
+//
+// Arguments: [hwnd] -- HWND to convert. 16 or 32 bit is fine
+//
+// Returns: Always returns a 32 bit HWND
+//
+// History: 8-03-94 kevinro Created
+//
+// Notes:
+// This routine calls a private function given to use by OLETHK32
+//
+//----------------------------------------------------------------------------
+inline
+HWND ConvertToFullHWND(HWND hwnd)
+{
+ if (IsWOWThreadCallable() &&
+ ((((ULONG)hwnd & 0xFFFF0000) == 0) ||
+ (((ULONG)hwnd & 0xFFFF0000) == 0xFFFF0000)))
+ {
+ return(g_pOleThunkWOW->ConvertHwndToFullHwnd(hwnd));
+ }
+ return(hwnd);
+}
+
+inline
+void OleDdeDeleteMetaFile(HANDLE hmf)
+{
+ intrDebugOut((DEB_ITRACE,
+ "OleDdeDeleteMetaFile(%x)\n",
+ hmf));
+ if (IsWOWThreadCallable())
+ {
+ intrDebugOut((DEB_ITRACE,
+ "InWow: calling WOWFreeMetafile(%x)\n",
+ hmf));
+
+ if (!g_pOleThunkWOW->FreeMetaFile(hmf))
+ {
+ return;
+ }
+ intrDebugOut((DEB_ITRACE,
+ "WOWFreeMetafile(%x) FAILED\n",
+ hmf));
+ }
+ intrDebugOut((DEB_ITRACE,
+ "Calling DeleteMetaFile(%x)\n",
+ hmf));
+
+ DeleteMetaFile((HMETAFILE)hmf);
+}
diff --git a/private/ole32/com/remote/dde/server/ddepack.h b/private/ole32/com/remote/dde/server/ddepack.h
new file mode 100644
index 000000000..ef250cafb
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/ddepack.h
@@ -0,0 +1,20 @@
+
+#ifdef WIN32
+extern "C"
+{
+#include <port1632.h>
+}
+
+#define MAKE_DDE_LPARAM(msg,lo,hi) PackDDElParam(msg,(UINT)lo,(UINT)hi)
+
+#else
+
+#define GET_WM_DDE_EXECUTE_HDATA(wParam,lParam) ((HANDLE) HIWORD(lParam))
+#define GET_WM_DDE_DATA_HDATA(wParam,lParam) ((HANDLE) LOWORD(lParam))
+#define GET_WM_DDE_REQUEST_ITEM(wParam,lParam) ((ATOM) HIWORD(lParam))
+#define GET_WM_DDE_DATA_ITEM(wParam,lParam) ((ATOM) HIWORD(lParam))
+#define MAKE_DDE_LPARAM(msg,lo,hi) MAKELONG(lo,hi)
+#define DDEFREE(msg,lParam)
+
+#endif
+
diff --git a/private/ole32/com/remote/dde/server/ddesink.cxx b/private/ole32/com/remote/dde/server/ddesink.cxx
new file mode 100644
index 000000000..302db683e
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/ddesink.cxx
@@ -0,0 +1,251 @@
+// ddesink.cpp
+//
+// Methods for CDefClient::CAdviseSinkImpl
+//
+// Author:
+// Jason Fuller jasonful 8-16-92
+//
+// Copyright (c) 1990, 1991 Microsoft Corporation
+
+
+#include <ole2int.h>
+#include "srvr.h"
+#include "ddedebug.h"
+
+
+ASSERTDATA
+
+STDUNKIMPL_FORDERIVED (DefClient, AdviseSinkImpl)
+
+ BOOL PeekOneMessage
+ (MSG FAR* pmsg,
+ HWND hwnd,
+ UINT message)
+{
+ // We have to verify pmsg->message because PeekMessage will return
+ // WM_QUIT even if you didn't ask for it.
+
+ if (SSPeekMessage (pmsg, hwnd, message, message, PM_REMOVE))
+ {
+ if (pmsg->message==message)
+ return TRUE;
+ else
+ {
+ AssertSz (pmsg->message == WM_QUIT, "Unexpected message");
+ if (WM_QUIT==pmsg->message)
+ {
+ // Put message back
+ PostQuitMessage (pmsg->wParam);
+ }
+ return FALSE;
+ }
+ }
+ else
+ return FALSE;
+}
+
+
+
+
+
+
+STDMETHODIMP_(void) NC(CDefClient,CAdviseSinkImpl)::OnClose
+ (void)
+{
+ MSG msg;
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::OnClose\n",
+ this));
+
+ ChkC(m_pDefClient);
+
+ m_pDefClient->m_fInOnClose = TRUE;
+ // AddRef/Release safety bracket. Do not remove.
+ m_pDefClient->m_pUnkOuter->AddRef();
+
+ #ifdef _DEBUG
+ if (m_pDefClient->m_bContainer)
+ {
+ if (NOERROR != m_pDefClient->NoItemConnections())
+ Warn ("OnClose called on document before item");
+ }
+ #endif
+
+ if (m_pDefClient->m_ExecuteAck.f)
+ {
+ // in case the server closes in the middle of a DoVerb, send the ACK
+ // for the EXECUTE now to keep the messages in order.
+ m_pDefClient->SendExecuteAck (NOERROR);
+ }
+
+ if (!m_pDefClient->m_fGotStdCloseDoc)
+ {
+ // if client sent us StdCloseDocument, then he certainly
+ // is not in a state to receive callbacks
+ m_pDefClient->ItemCallBack (OLE_CLOSED);
+ }
+
+ // We have to check the message field because PeekMessage will return
+ // WM_QUIT even if you didn't ask for it.
+ if (PeekOneMessage (&msg, m_pDefClient->m_hwnd, WM_DDE_EXECUTE))
+ {
+ LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,POSITIVE_ACK,
+ GET_WM_DDE_EXECUTE_HDATA(msg.wParam,msg.lParam));
+
+ intrDebugOut((DEB_ITRACE,
+ "%x ::OnClose found StdCloseDocument in queue\n",
+ this));
+
+ if(!PostMessageToClient ((HWND)msg.wParam,
+ WM_DDE_ACK,
+ (UINT) m_pDefClient->m_hwnd,
+ lp))
+ {
+ DDEFREE(WM_DDE_ACK,lp);
+ }
+
+ }
+
+
+ ChkC (m_pDefClient);
+
+ if (m_pDefClient->m_bContainer)
+ {
+ // If the document (container) is closing, then we
+ // should send a TERMINATE to the client windows.
+ // We don't do this for items because a client window
+ // may still be connected to another item.
+ // Items within one document share one window.
+
+ m_pDefClient->SendTerminateMsg ();
+ ChkC (m_pDefClient);
+ AssertIsDoc (m_pDefClient);
+ m_pDefClient->ReleaseAllItems();
+ }
+ else
+ {
+ m_pDefClient->RemoveItemFromItemList ();
+ }
+
+ // If item was deleted in client app, m_lpoleObj could be NULL
+ m_pDefClient->ReleaseObjPtrs ();
+
+ // If "this" is an item, get the doc that contains this item
+ LPCLIENT pdoc = m_pDefClient->m_pdoc;
+ Assert (pdoc);
+
+ Assert (pdoc->m_chk==chkDefClient);
+ if (pdoc->m_chk==chkDefClient && pdoc->m_fRunningInSDI)
+ if (pdoc->m_fRunningInSDI)
+ {
+ Puts ("Running in SDI\r\n");
+ // The server app never registered a class factory, so no
+ // RevokeClassFactory will trigger the destruction of the
+ // CDdeServer, so we do it here if there are no other clients
+ // connected to that CDdeServer
+ if (pdoc->m_psrvrParent->QueryRevokeClassFactory())
+ {
+ // Assert (No sibling documents)
+ Verify (NOERROR==pdoc->m_psrvrParent->Revoke());
+ pdoc->m_psrvrParent = NULL;
+ }
+ }
+ m_pDefClient->m_fInOnClose = FALSE;
+
+ // AddRef/Release safety bracket. Do not remove.
+ // Do not use m_pDefClient after this Release.
+ m_pDefClient->m_pUnkOuter->Release();
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::OnClose\n",
+ this));
+}
+
+
+
+
+STDMETHODIMP_(void) NC(CDefClient,CAdviseSinkImpl)::OnSave
+ (THIS)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::OnSave\n",
+ this));
+
+ ChkC(m_pDefClient);
+ if (!m_pDefClient->m_fInOleSave)
+ {
+ // If we called OleSave to get the native data, then of course
+ // we will get an OnSave notification.
+ m_pDefClient->ItemCallBack (OLE_SAVED);
+ }
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::OnSave\n",
+ this));
+}
+
+
+
+STDMETHODIMP_(void) NC(CDefClient,CAdviseSinkImpl)::OnDataChange
+ (THIS_ FORMATETC FAR* pFormatetc,
+ STGMEDIUM FAR* pStgmed)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::OnDataChange pFormatetc=%x\n",
+ this,
+ pFormatetc));
+ // note we are ignoring both the pformatetc and the pStgMed.
+ // ItemCallBack will ask (using GetData) for the data the client wants.
+ // We are treating a call to this function as a simple Ping.
+
+ ChkC(m_pDefClient);
+ m_pDefClient->ItemCallBack (OLE_CHANGED);
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::OnDataChange\n",
+ this));
+}
+
+
+
+STDMETHODIMP_(void) NC(CDefClient,CAdviseSinkImpl)::OnRename
+ (THIS_ LPMONIKER pmk)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::OnRename pmk=%x\n",
+ this,pmk));
+
+ LPOLESTR szFile=NULL;
+
+ ChkC(m_pDefClient);
+ if (Ole10_ParseMoniker (pmk, &szFile, NULL) != NOERROR)
+ {
+ // Wrong type of moniker
+ intrDebugOut((DEB_IERROR,
+ "%x ::OnRename pmk=%x wrong moniker\n",
+ this,pmk));
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE,
+ "%x ::OnRename pmk=%x pmk.Name=(%ws)\n",
+ this,
+ pmk,
+ WIDECHECK(szFile)));
+ // Notify client
+ m_pDefClient->ItemCallBack (OLE_RENAMED, szFile);
+ CoTaskMemFree(szFile);
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::OnRename\n",
+ this));
+}
+
+
+
+STDMETHODIMP_(void) NC(CDefClient,CAdviseSinkImpl)::OnViewChange
+ (THIS_ DWORD aspects, LONG lindex)
+{
+ // Response to IViewObjectAdvise::Advise, which we do not do
+}
+
+
diff --git a/private/ole32/com/remote/dde/server/ddesite.cxx b/private/ole32/com/remote/dde/server/ddesite.cxx
new file mode 100644
index 000000000..6f1a4e503
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/ddesite.cxx
@@ -0,0 +1,89 @@
+// ddesite.cpp
+//
+// Methods for CDefClient::COleClientSiteImpl
+//
+// Author:
+// Jason Fuller jasonful 8-16-92
+//
+// Copyright (c) 1990, 1991 Microsoft Corporation
+
+
+#include <ole2int.h>
+#include "srvr.h"
+#include "ddedebug.h"
+
+ASSERTDATA
+
+STDUNKIMPL_FORDERIVED (DefClient, OleClientSiteImpl)
+
+
+STDMETHODIMP NC(CDefClient,COleClientSiteImpl)::SaveObject
+ (void)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::SaveObject\n",
+ this));
+
+ ChkC(m_pDefClient);
+
+ if (!m_pDefClient->m_fGotStdCloseDoc)
+ m_pDefClient->ItemCallBack (OLE_SAVED);
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::SaveObject\n",
+ this));
+ return NOERROR;
+}
+
+
+
+STDMETHODIMP NC(CDefClient,COleClientSiteImpl)::GetContainer
+ (LPOLECONTAINER FAR * lplpContainer)
+{
+ VDATEPTROUT( lplpContainer, LPOLECONTAINER);
+ *lplpContainer = NULL;
+
+ ChkC(m_pDefClient);
+ return ResultFromScode (E_NOTIMPL);
+}
+
+
+
+STDMETHODIMP NC(CDefClient,COleClientSiteImpl)::GetMoniker
+ (DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk)
+{
+ VDATEPTROUT( ppmk, LPMONIKER);
+ *ppmk = NULL;
+
+ ChkC(m_pDefClient);
+ // OLE 1.0 does not support linking to embeddings
+ return ReportResult(0, E_NOTIMPL, 0, 0);
+}
+
+STDMETHODIMP NC(CDefClient,COleClientSiteImpl)::ShowObject
+ (void)
+{
+ ChkC(m_pDefClient);
+ Puts ("OleClientSite::ShowObject\r\n");
+ // REVIEW: what are we supposed do?
+ return ResultFromScode (E_NOTIMPL);
+}
+
+STDMETHODIMP NC(CDefClient,COleClientSiteImpl)::OnShowWindow
+ (BOOL fShow)
+{
+ ChkC(m_pDefClient);
+ Puts ("OleClientSite::OnShowWindow\r\n");
+ // REVIEW: what are we supposed do?
+ return NOERROR;
+}
+
+STDMETHODIMP NC(CDefClient,COleClientSiteImpl)::RequestNewObjectLayout(void)
+{
+ ChkC(m_pDefClient);
+ Puts ("OleClientSite::RequestNewObjectLayout\r\n");
+ return ReportResult(0, S_FALSE, 0, 0);
+}
+
+
+
diff --git a/private/ole32/com/remote/dde/server/ddesrvr.cxx b/private/ole32/com/remote/dde/server/ddesrvr.cxx
new file mode 100644
index 000000000..aa9c4f2fd
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/ddesrvr.cxx
@@ -0,0 +1,839 @@
+/*
+ ddesrvr.cpp
+
+ Author:
+ Jason Fuller jasonful 8-11-92
+*/
+
+#include <ole2int.h>
+#include <dde.h>
+#include <olerem.h>
+#include "srvr.h"
+#include "ddeatoms.h"
+#include "ddesrvr.h"
+#include "ddedebug.h"
+#include "map_up.h"
+
+#include "map_dwp.h"
+
+ASSERTDATA
+
+// Dde Common Window stuff
+
+UINT cCommonWindows = 0;
+
+#ifdef _CHICAGO_
+// Note: we have to create a unique string so that get
+// register a unique class for each 16 bit app.
+// The class space is global on chicago.
+//
+LPSTR szSYS_CLASSA = "Ole2SysWndClass 0x######## ";
+LPSTR szCLIENT_CLASSA = "Ole2ClientWndClass 0x######## ";
+LPSTR szSRVR_CLASSA = "SrvrWndClass 0x######## ";
+LPSTR szDOC_CLASSA = "ViewObjWndClass 0x######## ";
+LPSTR szITEM_CLASSA = "ItemWndClass 0x######## ";
+LPSTR szCOMMONCLASSA = "DdeCommonWindowClass 0x######## ";
+
+LPSTR szDdeServerWindow = "DDE Server Window";
+#define szDdeCommonWindowClass szCOMMONCLASSA
+#else
+const LPOLESTR szDdeServerWindow = OLESTR("DDE Server Window");
+const LPOLESTR szDdeCommonWindowClass = OLESTR("DdeCommonWindowClass");
+#endif
+
+//+---------------------------------------------------------------------------
+//
+// Function: CreateDdeSrvrWindow
+//
+// Synopsis: When CoRegisterClassObject is called, this function
+// is called to create a DDE window to listen for DDE messages
+// from a 1.0 client.
+//
+// Effects:
+//
+// Arguments: [clsid] --
+// [aClass] --
+// [phwnd] --
+// [fIsRunning] --
+// [aOriginalClass] --
+// [cnvtyp] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-27-94 kevinro Commented/cleaned
+// 13-Jul-94 BruceMa Make register/unregister dde window class
+// thread safe
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL CreateDdeSrvrWindow
+ (REFCLSID clsid,
+ ATOM aClass,
+ HWND FAR* phwnd, // optional out parm: created window
+ BOOL fIsRunning, // Is the item atom a file in the ROT?
+ ATOM aOriginalClass, // for TreatAs/ConvertTo case
+ CNVTYP cnvtyp)
+{
+ intrDebugOut((DEB_DDE_INIT,"0 _IN CreateDdeSrvrWindow\n"));
+
+ VDATEHEAP();
+ HWND hwnd = NULL;
+
+ HRESULT hresult = NOERROR;
+
+ DdeClassInfo ddeClassInfo;
+
+ ddeClassInfo.dwContextMask = CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER;
+ ddeClassInfo.fClaimFactory = FALSE;
+
+ // Null out parameter in case of error
+ if (phwnd)
+ {
+ *phwnd = NULL;
+ }
+
+ intrAssert (wIsValidAtom (aClass));
+
+ //
+ // See if this process is registered as a class server for
+ // the requested class. If it isn't, then check for a running
+ // object.
+ //
+ if (GetClassInformationForDde(clsid,&ddeClassInfo) == FALSE)
+ {
+ intrDebugOut((DEB_DDE_INIT,
+ "CreateDdeSrvrWindow No class information available\n"));
+
+ //
+ // The ClassObject was not found in the table.
+ //
+
+ if (fIsRunning)
+ {
+ // Link case.
+ // An SDI app was launched by the user (without "-Embedding").
+ // It did not register its class factory. (It never does.)
+ // Meanwhile, a DDE_INIT with a filename as an item atom was
+ // broadcasted.
+ // We are in the task of the SDI app that loaded that filename,
+ // so this function was called.
+ // So we need to create the window even though no class factory
+ // was registered.
+ // Call CDDEServer::Create with a lot of NULLs.
+ // Once the DDE_INIT is passed along to the server window, it
+ // should immediately cause a doc window to be created.
+ // Must be SDI or we wouldn't have this problem.
+ //
+ // This works because we are going to attempt to 'bind' to the
+ // object which is the subject of the link. If the link object
+ // was registered as running, we will find it. Otherwise, the
+ // attempt to create via the class factory will fail, since the
+ // class factory doesn't exist.
+ //
+
+ intrDebugOut((DEB_DDE_INIT,
+ "::CreateDdeServerWindow fIsRunning - override dwFlags\n"));
+
+ //
+ // NULL out the entire structure, then set only the flags
+ //
+ memset(&ddeClassInfo,0,sizeof(ddeClassInfo));
+ ddeClassInfo.dwFlags = REGCLS_SINGLEUSE;
+
+
+ }
+ else
+ {
+ intrDebugOut((DEB_DDE_INIT,
+ "CreateDdeServerWindow Returning FALSE\n"));
+
+ hresult = S_FALSE;
+ goto errRtn;
+ }
+ }
+ intrDebugOut((DEB_DDE_INIT,
+ "::CreateDdeServerWindow found class\n"));
+ // Create() does the real work: creates a CDDEServer and the window.
+ WCHAR szClass[MAX_STR];
+ lstrcpyW (szClass, wAtomName (aClass));
+ Assert (szClass[0]);
+
+ hresult = CDDEServer::Create(szClass,
+ clsid,
+ &ddeClassInfo,
+ &hwnd,
+ aOriginalClass,
+ cnvtyp);
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,
+ "CreateDdeServerWindow CDDEServer::Create returns %x\n",
+ hresult));
+ goto errRtn;
+ }
+
+ Assert (IsWindowValid(hwnd));
+
+ // Fill in out parameter
+ if (phwnd)
+ {
+ *phwnd = hwnd;
+ }
+
+
+errRtn:
+ VDATEHEAP();
+ intrDebugOut((DEB_DDE_INIT,
+ "0 _OUT CreateDdeSrvrWindow %x\n",
+ hresult));
+ return hresult;
+
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DestroyDdeSrvrWindow
+//
+// Synopsis: Destroy a DDE server window
+//
+// Effects:
+//
+// Arguments: [hwnd] -- Window to destroy
+// [aClass] -- Class for server
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-24-94 kevinro Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL DestroyDdeSrvrWindow
+ (HWND hwnd,
+ ATOM aClass)
+{
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN DestroyDdeSrvrWindow\n"));
+ VDATEHEAP();
+ Assert (IsAtom (aClass));
+
+ // Make sure it is a server window
+ RetZ (IsWindowValid (hwnd));
+ RetZ (GetWindowWord (hwnd, WW_LE) == WC_LE);
+
+
+ // Get the Common window for this task.
+
+ HWND hwndCommonServer = (HWND)TLSGetDdeServer();
+
+ if (hwndCommonServer == NULL)
+ {
+ intrDebugOut((DEB_IERROR,"hwndCommonServer != NULL\n"));
+ return(E_UNEXPECTED);
+ }
+ if (!IsWindow(hwndCommonServer))
+ {
+ intrAssert(IsWindow(hwndCommonServer));
+ return(E_UNEXPECTED);
+ }
+
+ // Get the map from the common window
+ CMapUintPtr FAR *pmapClassToHwnd;
+ Assert (sizeof (CMapUintPtr FAR *)==sizeof(LONG));
+ pmapClassToHwnd = (CMapUintPtr FAR *) GetWindowLong (hwndCommonServer, 0);
+ Assert (pmapClassToHwnd);
+
+ // Make sure the window we're deleting is the server window for this class
+ void *hwndSrvr;
+ RetZ (pmapClassToHwnd->Lookup (aClass,hwndSrvr) && hwndSrvr == hwnd);
+
+ RetZ (SSDestroyWindow (hwnd));
+
+ // Remove this window from the map
+ pmapClassToHwnd->RemoveKey (aClass);
+
+ VDATEHEAP();
+ intrDebugOut((DEB_ITRACE,
+ "0 _OUT DestroyDdeSrvrWindow\n"));
+
+ return NOERROR;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: DdeCommonWndProc
+//
+// Synopsis: Window proc for the common dde server window that
+// listens for all WM_DDE_INITIATEs
+//
+// Effects: When a DDE_INITIATE comes in, this routine will determine
+// the class of the object being requested. If the class is
+// served by this thread, then it will create a window to
+// converse with the server.
+//
+// Arguments: [hWnd] -- hWnd of Common DDE
+// [wMsg] -- msg
+// [wParam] -- Return Window to converse with
+// [lParam] -- HIWORD(aItem) LOWORD(aClass)
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-27-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)
+DdeCommonWndProc(HWND hwndIn, UINT wMsg, WPARAM wParam, LPARAM lParam)
+{
+
+ switch (wMsg)
+ {
+ case WM_DDE_INITIATE:
+ {
+ VDATEHEAP();
+ ATOM aClass = LOWORD(lParam);
+ ATOM aItem = HIWORD(lParam);
+ HWND hwnd;
+
+ CNVTYP cnvtyp = cnvtypNone;
+
+ BOOL fIsFile= FALSE; // Must initialize
+ BOOL fIsRunning= FALSE; // Must initialize
+ BOOL fUnsavedDoc = FALSE; // Is the "file" really an unsaved doc
+ HWND hwndServer;
+ HRESULT hresult;
+
+
+ //
+ // From this point forward, we need to insure we are using a
+ // FULL hwnd.
+ //
+ hwnd = ConvertToFullHWND(hwndIn);
+
+ //
+ // The following should already be initialized
+ //
+ intrAssert (aOLE != NULL);
+ intrAssert (aSysTopic != NULL);
+
+ if (aItem==aOLE || aItem==aSysTopic
+ || (fIsFile=IsFile (aItem, &fUnsavedDoc)))
+ {
+
+
+ intrDebugOut((DEB_DDE_INIT,
+ "DdeCommonWndProc:hWnd(%x) DDE_INITIATE cls(%ws)\n",
+ hwnd,
+ wAtomName(aClass)));
+
+ //
+ // Get the ClassToHwnd map for this thread
+ //
+ CMapUintPtr FAR *pmapClassToHwnd;
+ Assert (sizeof (CMapUintPtr FAR *)==sizeof(LONG));
+ pmapClassToHwnd = (CMapUintPtr FAR *) GetWindowLong (hwnd, 0);
+ Assert (pmapClassToHwnd);
+
+
+ // Convert atom to CLSID, taking into account
+ // TreatAs and AutoConvert.
+ CLSID clsid;
+ ATOM aOriginalClass = aClass;
+
+ if (CLSIDFromAtomWithTreatAs (&aClass, &clsid, &cnvtyp) != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,"Could not get clsid for this class\n"));
+ return 0L;
+ }
+
+ void *pServerTmp;
+ if (TRUE == pmapClassToHwnd->Lookup (aClass, pServerTmp))
+ {
+ //
+ // Since a server window for this class already exists, but is a child window
+ // of ours, we will send it this message directly.
+ //
+
+ intrDebugOut((DEB_DDE_INIT,
+ "DdeCommonWndProc Server cls exists. Forwarding to %x\n",
+ pServerTmp));
+
+ return SSSendMessage ((HWND)pServerTmp, WM_DDE_INITIATE, wParam,lParam);
+
+ }
+
+ if (CoIsOle1Class (clsid))
+ {
+ // We have no business intercepting Initiates sent
+ // to 1.0 servers
+ intrDebugOut((DEB_DDE_INIT,
+ "DdeCommonWndProc: Its a OLE 1.0 class\n"));
+ return 0L;
+ }
+
+ if (fIsFile)
+ {
+ // Link case
+ WCHAR szFile[MAX_STR];
+
+ WORD cb=GlobalGetAtomName (aItem, szFile, MAX_STR);
+ Assert (cb>0 && cb < MAX_STR-1);
+ intrDebugOut((DEB_DDE_INIT,
+ "Looking for file %ws\n",szFile));
+
+ IsRunningInThisTask (szFile, &fIsRunning);
+ }
+
+ // If it's not a file, it can't be running, obviously.
+ intrAssert (fIsFile || !fIsRunning);
+
+ if (NOERROR == (hresult=(CreateDdeSrvrWindow (clsid,
+ aClass,
+ &hwndServer,
+ fIsRunning,
+ aOriginalClass,
+ cnvtyp))))
+ {
+
+ // Indicate that we have created a server window
+ // for this class. We could have used any value in
+ // place of hwndServer_. It's just a flag.
+ // REVIEW jasonful: how to handle OOM?
+
+ pmapClassToHwnd->SetAt (wDupAtom(aClass), hwndServer);
+
+#if DBG == 1
+ // Verify the SetAt we just did.
+ void FAR* pv;
+ Verify (pmapClassToHwnd->Lookup(aClass, pv));
+ Assert (pv == hwndServer);
+#endif
+ // Pass the INITIATE along to the real,
+ // newly-created server window and forge
+ // the sender's hwnd to be whoever called
+ // the common server window.
+ // SendMessage should return 1L is doc is running,
+ // indicating an ACK was sent.
+ Assert (IsWindowValid (hwndServer));
+ SSSendMessage (hwndServer, WM_DDE_INITIATE, wParam,lParam);
+ intrDebugOut((DEB_DDE_INIT,
+ "DdeCommonWndProc:hWnd(%x) DDE_INITIATE complete(%ws)\n",
+ hwnd,
+ wAtomName(aClass)));
+ VDATEHEAP();
+ }
+ else
+ {
+ if (S_FALSE!=GetScode(hresult))
+ {
+ intrDebugOut((DEB_IERROR,
+ "DCWP: CreateDdeSrvrWindow failed %x\n",
+ hresult));
+ }
+ }
+ }
+ else
+ {
+ //
+ // We have a DDE_INITIATE message that needs to be forwarded to our
+ // child window.
+ //
+ return SendMsgToChildren(hwnd,wMsg,wParam,lParam);
+ }
+ return 0L;
+ }
+ break;
+
+ case WM_DESTROY:
+ {
+ //
+ // When this window is destroyed, we cleanup the
+ // windows attached data.
+ //
+
+ CMapUintPtr FAR *pmapClassToHwnd;
+ pmapClassToHwnd = (CMapUintPtr FAR *) GetWindowLong (hwndIn, 0);
+
+ //
+ // Make sure there are no server windows
+ // created by this common window still extant. If there are, print out
+ // a message on a debug build. Otherwise, there really isn't much we
+ // can do about it. We are already closing down. The DDE emulation layer
+ // will send appropriate terminate messages.
+ //
+
+ #if DBG == 1
+ if (pmapClassToHwnd && !pmapClassToHwnd->IsEmpty())
+ {
+ intrDebugOut((DEB_ERROR,
+ "DCDW Leaking active OLE 1.0 clients\n"));
+ intrDebugOut((DEB_ERROR,
+ "There were active OLE 1.0 connections at shutdown\n"));
+ }
+ #endif
+ delete pmapClassToHwnd;
+ return(0);
+ }
+
+
+
+ default:
+ return SSDefWindowProc (hwndIn, wMsg, wParam, lParam);
+ }
+}
+
+
+
+
+ COleStaticMutexSem commonDdeMutex;
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: CreateCommonDdeWindow
+//
+// Synopsis: Creates a DDE window for initiating conversations with this
+// threads objects.
+//
+// Effects: Creates a window that responds to DDE_INITIATE messages, and
+// determines if it needs to respond to the INITIATE. This
+// routine is called by OleInitializeEx()
+//
+// The handle to the created window is placed in the TLS
+// structure.
+//
+// Arguments: [void] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-27-94 kevinro Converted to OLE32
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL CreateCommonDdeWindow
+ (void)
+{
+ intrDebugOut((DEB_ITRACE,"%p _IN CreateCommonDdeWindow\n",0));
+
+ HRESULT hr = NOERROR;
+ HWND hwndDdeServer;
+ //
+ // If a DdeServer window already exists, then return NOERROR.
+ // If Com has been initialized but Ole has not, then we dont
+ // create a window, we just return NOERROR. This way, COM-only
+ // servers dont start serving OLE1 clients.
+ //
+
+ COleTls tls;
+ hwndDdeServer = tls->hwndDdeServer;
+ if ( hwndDdeServer != NULL || tls->cOleInits == 0)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "CreateCommonDocWindow: HWND(%x) cOleInits(%x)\n",
+ hwndDdeServer,
+ tls->cOleInits));
+ goto exitRtn;
+ }
+
+ //
+ // Only need to register the window class once per
+ // process so we protect it via a critical section
+ //
+ {
+ COleStaticLock lck(commonDdeMutex);
+
+ if (0 == cCommonWindows)
+ {
+ // Register "DDE Common window" class
+ //
+ DDEWNDCLASS wc;
+ wc.style = 0;
+ wc.lpfnWndProc = DdeCommonWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = sizeof (CMapUintPtr FAR*);
+ Assert (g_hmodOLE2);
+ wc.hInstance = g_hmodOLE2;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = szDdeCommonWindowClass;
+
+ if (!DdeRegisterClass(&wc) )
+ {
+ //
+ // It is possible that the register has failed because
+ // the class was previously registered, but failed to
+ // unregister. We are ignoring it, because if the
+ // class really couldn't register, then the CreateWindow
+ // will fail, which is what we really care about anyway.
+ //
+ intrDebugOut((DEB_IERROR,
+ "RegisterClass() %s has failed %x\n", szDdeCommonWindowClass,
+ GetLastError()));
+ intrAssert(!"CreateCommonDdeWindow register failed.");
+
+ }
+ }
+
+ cCommonWindows++;
+ }
+
+ if (!(hwndDdeServer = DdeCreateWindowEx(0, szDdeCommonWindowClass,
+ szDdeServerWindow,
+ WS_POPUP,0,0,0,0,
+ NULL,NULL,
+ g_hmodOLE2, NULL)))
+ {
+ intrDebugOut((DEB_IERROR,
+ "CreateCommonDocWindow() has failed %x\n",
+ GetLastError()));
+
+ hr = E_OUTOFMEMORY;
+ goto exitRtn;
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "CreateCommonDocWindow() hwndDdeServer=%x\n",
+ hwndDdeServer));
+
+ // Give the common window a map from classes to server windows
+
+ CMapUintPtr FAR *pmapClassToHwnd;
+
+ Assert (sizeof(LONG)==sizeof (CMapUintPtr FAR*));
+
+ if ((pmapClassToHwnd = new CMapUintPtr) == NULL)
+ {
+ intrDebugOut((DEB_ERROR,"pmapClassToHwnd != NULL\n"));
+ hr = E_OUTOFMEMORY;
+ goto errRtn;
+ }
+
+ SetWindowLong (hwndDdeServer, 0, (LONG)pmapClassToHwnd);
+ //
+ // Set the pointer to the server in the TLS data
+ //
+ tls->hwndDdeServer = hwndDdeServer;
+
+ hr = NOERROR;
+
+exitRtn:
+
+ intrDebugOut((DEB_ITRACE,"%p _OUT CreateCommonDocWindow (%x)\n",0,hr));
+
+ return(hr);
+
+ //
+ // In the error case, if the hwnDdeServer != NULL, then destroy it
+ //
+errRtn:
+ if (hwndDdeServer != NULL)
+ {
+ SSDestroyWindow(hwndDdeServer);
+ }
+
+ goto exitRtn;
+}
+
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DestroyCommonDdeWindow
+//
+// Synopsis: Destroys the common DDE Server window
+//
+// Effects:
+//
+// Arguments: [void] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-27-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL DestroyCommonDdeWindow
+ (void)
+{
+ intrDebugOut((DEB_ITRACE,"%p _IN DestroyCommonDdeWindow\n",0));
+
+ HRESULT hr = NOERROR;
+ HWND hwndDdeServer = (HWND)TLSGetDdeServer();
+
+ if (hwndDdeServer == NULL)
+ {
+ hr = E_UNEXPECTED;
+ goto errRtn;
+ }
+#if 0
+ // We do not need to validate this window since we created it!
+ if (!IsWindowValid(hwndDdeServer))
+ {
+ intrAssert(!"IsWindowValid");
+ hr = E_UNEXPECTED;
+ goto errRtn;
+ }
+#endif
+ //
+ // Get the map from the common window
+ //
+
+
+ //
+ // If destroying this window fails, there isn't much we can
+ // do about it.
+ //
+ if(!SSDestroyWindow (hwndDdeServer))
+ {
+ intrAssert(!"DestroyWindow");
+ hr = E_UNEXPECTED;
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE,
+ "DestroyCommonDocWindow() hwndDdeServer=%x\n",
+ hwndDdeServer));
+
+ // Must take a mutex around unregistering the class because another
+ // thread may be trying to register the window class at the same time
+ COleStaticLock lck(commonDdeMutex);
+
+ cCommonWindows--;
+
+ if (cCommonWindows == 0)
+ {
+ if(!DdeUnregisterClass (szDdeCommonWindowClass, g_hmodOLE2))
+ {
+ intrDebugOut((DEB_ERROR,
+ "DestroyCommonDocWindow(): UnregisterClass has failed error:>%x<\n",
+ GetLastError()));
+ intrAssert(!"DestroyCommonDdeWindow unregister failed.");
+ //
+ // If unregistering the class fails, there isn't a
+ // whole lot we can do about it. Its possible that
+ // there were still active client windows.
+ //
+ hr = E_UNEXPECTED;
+ }
+ }
+ }
+
+ if(!TLSSetDdeServer(NULL))
+ {
+ intrAssert(!"TLSSetDdeServer failed\n");
+ hr = E_UNEXPECTED;
+ }
+errRtn:
+ intrDebugOut((DEB_ITRACE,"%p _OUT DestroyCommonDdeWindow %x\n",0,hr));
+ return hr;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: IsRunningInThisTask
+//
+// Synopsis: Determine if the given file is running in the current task
+//
+// Effects: Calls a special function in the ROT to determine if the
+// file szFile is loaded as a moniker in the current task
+//
+// Arguments: [szFile] -- Filename
+// [pf] -- Points to a BOOL. Returned TRUE if running
+//
+// History: 6-29-94 kevinro Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL IsRunningInThisTask(LPOLESTR szFileIn,BOOL FAR* pf) // out parm
+{
+ HRESULT hresult;
+
+ intrDebugOut((DEB_DDE_INIT,
+ "IsRunninginThisTask szFileIn=%ws\n",
+ WIDECHECK(szFileIn)));
+
+ //
+ // The RunningObjectTable always stores LONG filenames, therefore we
+ // need to convert this name to the long name for the lookup.
+ //
+
+ WCHAR szFile[MAX_PATH];
+ if ((lstrlenW(szFileIn) == 0) || (GetLongPathNameW(szFileIn,szFile,MAX_PATH) == 0))
+ {
+ //
+ // Unable to determine a long path for this object. Use whatever we were
+ // handed.
+ //
+ intrDebugOut((DEB_DDE_INIT,"No conversion to long path. Copy szFileIn\n"));
+ lstrcpyW(szFile,szFileIn);
+ }
+
+ intrDebugOut((DEB_DDE_INIT,"Long file szFile(%ws)\n",szFile));
+
+ hresult = GetLocalRunningObjectForDde(szFile,NULL);
+
+ *pf = (hresult == S_OK);
+
+ intrDebugOut((DEB_DDE_INIT,
+ "IsRunninginThisTask szFile=%ws returns %s\n",
+ WIDECHECK(szFile),
+ *pf?"TRUE":"FALSE"));
+ return NOERROR;
+}
diff --git a/private/ole32/com/remote/dde/server/ddesrvr.h b/private/ole32/com/remote/dde/server/ddesrvr.h
new file mode 100644
index 000000000..291b2c389
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/ddesrvr.h
@@ -0,0 +1,26 @@
+/*
+ ddesrvr.h
+ Header file for ddesrvr.cpp
+
+ Author:
+ Jason Fuller jasonful 8-11-92
+*/
+
+#ifndef fDdesrvr_h
+#define fDdesrvr_h
+
+// Defined in cftable.cpp
+STDAPI RemGetInfoForCid
+ (REFCLSID clsid,
+ LPDWORD pgrf,
+ LPCLASSFACTORY FAR* ppCF,
+ LPHANDLE FAR* pphwndDde,
+ BOOL FAR* FAR* ppfAvail,
+ BOOL fEvenIfHidden=FALSE);
+
+INTERNAL DestroyDdeSrvrWindow (HWND hwnd, ATOM aClass);
+INTERNAL CreateCommonDdeWindow (void);
+INTERNAL DestroyCommonDdeWindow (void);
+
+INTERNAL IsRunningInThisTask (LPOLESTR szFile, BOOL FAR* pf);
+#endif
diff --git a/private/ole32/com/remote/dde/server/ddeutils.cxx b/private/ole32/com/remote/dde/server/ddeutils.cxx
new file mode 100644
index 000000000..272a6a2f1
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/ddeutils.cxx
@@ -0,0 +1,1015 @@
+/****************************** Module Header ******************************\
+* Module Name: ddeutils.c
+*
+* Purpose: Conatains all the utility routines
+*
+* Created: 1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor, Srinik (../../1990) Designed and coded
+*
+\***************************************************************************/
+#include <windows.h>
+#include "ole2int.h"
+//#include "cmacs.h"
+#include <dde.h>
+#include "srvr.h"
+#include "ddesrvr.h"
+#include "ddedebug.h"
+ASSERTDATA
+
+
+#define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
+#define WM_NCMOUSELAST WM_NCMBUTTONDBLCLK
+
+
+
+#define KB_64 65536
+
+extern ATOM aTrue;
+extern ATOM aFalse;
+
+extern ATOM aStdCreateFromTemplate;
+extern ATOM aStdCreate;
+extern ATOM aStdOpen;
+extern ATOM aStdEdit;
+extern ATOM aStdShowItem;
+extern ATOM aStdClose;
+extern ATOM aStdExit;
+extern ATOM aStdDoVerbItem;
+
+
+//ScanBoolArg: scans the argument which is not included in
+//the quotes. These args could be only TRUE or FALSE for
+//the time being. !!!The scanning routines should be
+//merged and it should be generalized.
+
+INTERNAL_(LPSTR) ScanBoolArg
+(
+LPSTR lpstr,
+BOOL FAR *lpflag
+)
+{
+
+
+ LPSTR lpbool;
+ ATOM aShow;
+ char ch;
+
+ lpbool = lpstr;
+
+ // !!! These routines does not take care of quoted quotes.
+
+ while((ch = *lpstr) && (!(ch == ')' || ch == ',')))
+ lpstr++;
+
+ if(ch == NULL)
+ return NULL;
+
+ *lpstr++ = NULL; // terminate the arg by null
+
+ // if terminated by paren, then check for end of command
+ // syntax.
+
+ // Check for the end of the command string.
+ if (ch == ')') {
+ if (*lpstr++ != ']')
+ return NULL;
+
+ if(*lpstr != NULL)
+ return NULL; //finally should be terminated by null.
+
+ }
+
+ aShow = GlobalFindAtomA (lpbool);
+ if (aShow == aTrue)
+ *lpflag = TRUE;
+
+ else {
+ if (aShow ==aFalse)
+ *lpflag = FALSE;
+ else
+ return NULL;;
+ }
+ return lpstr;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: CreateUnicodeFromAnsi
+//
+// Synopsis: Creates a UNICODE string from an ANSI string
+//
+// Effects: Makes a new UNICODE string from the given ANSI string.
+// The new UNICODE string is returned. Memory is allocated
+// using PrivMemAlloc
+//
+// Arguments: [lpAnsi] -- Ansi version of string
+//
+// Requires:
+//
+// Returns: NULL if cannot create new string.
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-07-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+LPOLESTR CreateUnicodeFromAnsi( LPCSTR lpAnsi)
+{
+ WCHAR buf[MAX_PATH];
+ ULONG ccbuf;
+ LPOLESTR lpWideStr;
+
+ if ((ccbuf=MultiByteToWideChar(CP_ACP,0,lpAnsi,-1,buf,MAX_PATH))
+ == FALSE)
+ {
+ intrAssert(!"Unable to convert characters");
+ return NULL;
+ }
+
+ lpWideStr = (LPOLESTR) PrivMemAlloc(ccbuf * sizeof(WCHAR));
+
+ if (lpWideStr != NULL)
+ {
+ memcpy(lpWideStr,buf,ccbuf*sizeof(WCHAR));
+ }
+ return(lpWideStr);
+}
+//+---------------------------------------------------------------------------
+//
+// Function: CreateAnsiFromUnicode
+//
+// Synopsis: Creates an Ansi string from a UNICODE string
+//
+// Effects: Makes a new ANSI string from the given UNICODE string.
+// The new string is returned. Memory is allocated
+// using PrivMemAlloc
+//
+// Arguments: [lpUnicode] -- Unicode version of string
+//
+// Requires:
+//
+// Returns: NULL if cannot create new string.
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-07-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+LPSTR CreateAnsiFromUnicode( LPCOLESTR lpUnicode)
+{
+ char buf[MAX_PATH];
+ ULONG ccbuf;
+ LPSTR lpAnsiStr;
+
+ ccbuf = WideCharToMultiByte(CP_ACP,
+ 0,
+ lpUnicode,
+ -1,
+ buf,
+ MAX_PATH,
+ NULL,
+ NULL);
+
+
+ if (ccbuf == FALSE)
+ {
+ intrAssert(!"Unable to convert characters");
+ return NULL;
+ }
+
+ lpAnsiStr = (LPSTR) PrivMemAlloc(ccbuf * sizeof(char));
+
+ if (lpAnsiStr != NULL)
+ {
+ memcpy(lpAnsiStr,buf,ccbuf);
+ }
+ return(lpAnsiStr);
+}
+
+//ScannumArg: Checks for the syntax of num arg in Execute and if
+//the arg is syntactically correct, returns the ptr to the
+//beginning of the next arg and also, returns the number
+//Does not take care of the last num arg in the list.
+
+INTERNAL_(LPSTR) ScanNumArg
+(
+LPSTR lpstr,
+LPINT lpnum
+)
+{
+
+ WORD val = 0;
+ char ch;
+
+ while((ch = *lpstr++) && (ch != ',')) {
+ if (ch < '0' || ch >'9')
+ return NULL;
+ val += val * 10 + (ch - '0');
+
+ }
+
+ if(!ch)
+ return NULL;
+
+ *lpnum = val;
+ return lpstr;
+}
+
+
+
+
+//ScanArg: Checks for the syntax of arg in Execute and if
+//the arg is syntactically correct, returns the ptr to the
+//beginning of the next arg or to the end of the excute string.
+
+INTERNAL_(LPSTR) ScanArg
+(
+LPSTR lpstr
+)
+{
+
+
+ // !!! These routines does not take care of quoted quotes.
+
+ // first char should be quote.
+
+ if (*(lpstr-1) != '\"')
+ return NULL;
+
+ while(*lpstr && *lpstr != '\"')
+ lpstr++;
+
+ if(*lpstr == NULL)
+ return NULL;
+
+ *lpstr++ = NULL; // terminate the arg by null
+
+ if(!(*lpstr == ',' || *lpstr == ')'))
+ return NULL;
+
+
+ if(*lpstr++ == ','){
+
+ if(*lpstr == '\"')
+ return ++lpstr;
+ // If it is not quote, leave the ptr on the first char
+ return lpstr;
+ }
+
+ // terminated by paren
+ // already skiped right paren
+
+ // Check for the end of the command string.
+ if (*lpstr++ != ']')
+ return NULL;
+
+ if(*lpstr != NULL)
+ return NULL; //finally should be terminated by null.
+
+ return lpstr;
+}
+
+// ScanCommand: scanns the command string for the syntax
+// correctness. If syntactically correct, returns the ptr
+// to the first arg or to the end of the string.
+
+INTERNAL_(WORD) ScanCommand
+(
+LPSTR lpstr,
+WORD wType,
+LPSTR FAR * lplpnextcmd,
+ATOM FAR * lpAtom
+)
+{
+ // !!! These routines does not take care of quoted quotes.
+ // and not taking care of blanks arround the operators
+
+ // !!! We are not allowing blanks after operators.
+ // Should be allright! since this is arestricted syntax.
+
+ char ch;
+ LPSTR lptemp = lpstr;
+
+
+ while(*lpstr && (!(*lpstr == '(' || *lpstr == ']')))
+ lpstr++;
+
+ if(*lpstr == NULL)
+ return NULL;
+
+ ch = *lpstr;
+ *lpstr++ = NULL; // set the end of command
+
+ *lpAtom = GlobalFindAtomA (lptemp);
+
+ if (!IsOleCommand (*lpAtom, wType))
+ return NON_OLE_COMMAND;
+
+ if (ch == '(') {
+ ch = *lpstr++;
+
+ if (ch == ')') {
+ if (*lpstr++ != ']')
+ return NULL;
+ }
+ else {
+ if (ch != '\"')
+ return NULL;
+ }
+
+ *lplpnextcmd = lpstr;
+ return OLE_COMMAND;
+ }
+
+ // terminated by ']'
+
+ if (*(*lplpnextcmd = lpstr)) // if no nul termination, then it is error.
+ return NULL;
+
+ return OLE_COMMAND;
+}
+
+
+//MakeDataAtom: Creates a data atom from the item string
+//and the item data otions.
+
+INTERNAL_(ATOM) MakeDataAtom
+(
+ATOM aItem,
+int options
+)
+{
+ WCHAR buf[MAX_STR];
+
+ if (options == OLE_CHANGED)
+ return DuplicateAtom (aItem);
+
+ if (!aItem)
+ buf[0] = NULL;
+ else
+ GlobalGetAtomName (aItem, buf, MAX_STR);
+
+ if (options == OLE_CLOSED)
+ lstrcatW (buf, OLESTR("/Close"));
+ else {
+ if (options == OLE_SAVED)
+ lstrcatW (buf, OLESTR("/Save"));
+ else
+ AssertSz (0, "Bad option\n");
+ }
+
+ Puts ("MakeDataAtom "); Puts(buf); Putn();
+ if (buf[0])
+ return wGlobalAddAtom (buf);
+ else
+ return NULL;
+}
+
+//DuplicateAtom: Duplicates an atom
+INTERNAL_(ATOM) DuplicateAtom
+(
+ATOM atom
+)
+{
+ WCHAR buf[MAX_STR];
+
+ if (!atom)
+ return NULL;
+
+ GlobalGetAtomName (atom, buf, MAX_STR);
+ return wGlobalAddAtom (buf);
+}
+
+// MakeGlobal: makes global out of strings.
+// works only for << 64k
+
+INTERNAL_(HANDLE) MakeGlobal
+(
+LPSTR lpstr
+)
+{
+
+ int len = 0;
+ HANDLE hdata = NULL;
+ LPSTR lpdata = NULL;
+
+ len = strlen (lpstr) + 1;
+
+ hdata = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, len);
+
+ if (hdata == NULL || (lpdata = (LPSTR) GlobalLock (hdata)) == NULL)
+ goto errRtn;
+
+
+ memcpy(lpdata, lpstr, (DWORD)len);
+ GlobalUnlock (hdata);
+ return hdata;
+
+errRtn:
+ Assert (0);
+ if (lpdata)
+ GlobalUnlock (hdata);
+
+
+ if (hdata)
+ GlobalFree (hdata);
+
+ return NULL;
+
+}
+
+
+INTERNAL_(BOOL) CLSIDFromAtom(ATOM aClass, LPCLSID lpclsid)
+{
+ WCHAR szProgID[MAX_STR];
+ if (!ISATOM (aClass))
+ return FALSE;
+ WORD cb=GlobalGetAtomName (aClass, szProgID, MAX_STR);
+ Assert (cb>0 && cb < (MAX_STR - 1));
+
+ return CLSIDFromProgID(szProgID, lpclsid) == S_OK;
+}
+
+// CLSIDFromAtomWithTreatAs
+//
+// Input: *paClass
+// Output: *pclsid == corresponding CLSID, taking into account TreatAs and
+// AutoConvert
+// *paClass == atom correpsonding to *pclsid
+//
+#pragma SEG(CLSIDFromAtomWithTreatAs)
+INTERNAL CLSIDFromAtomWithTreatAs
+ (ATOM FAR* paClass,
+ LPCLSID pclsid,
+ CNVTYP FAR* pcnvtyp)
+{
+ HRESULT hr;
+
+
+ intrDebugOut((DEB_ITRACE,
+ "%p _IN CLSIDFromAtomWithTreatAs(paClass=%x,"
+ "pclsid=%x,pcnvtyp=%x)\n",0,
+ paClass,pclsid,pcnvtyp));
+
+ LPOLESTR szProgID = NULL;
+ CLSID clsidNew;
+
+ if (!CLSIDFromAtom (*paClass, pclsid))
+ {
+ hr = S_FALSE;
+ goto exitRtn;
+ }
+
+ DEBUG_GUIDSTR(clsidStr,pclsid);
+
+ intrDebugOut((DEB_ITRACE,"Guid %ws",clsidStr));
+ if (CoGetTreatAsClass (*pclsid, &clsidNew) == NOERROR)
+ {
+ DEBUG_GUIDSTR(newStr,pclsid);
+
+ intrDebugOut((DEB_ITRACE," cnvtypTreatAs %ws\n",newStr));
+ if (pcnvtyp)
+ *pcnvtyp = cnvtypTreatAs;
+ }
+ else if (OleGetAutoConvert (*pclsid, &clsidNew) == NOERROR)
+ {
+ DEBUG_GUIDSTR(newStr,pclsid);
+ intrDebugOut((DEB_ITRACE," cnvtypConvertTo %ws\n",newStr));
+ if (pcnvtyp)
+ *pcnvtyp = cnvtypConvertTo;
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE," no conversion\n"));
+ if (pcnvtyp)
+ *pcnvtyp = cnvtypNone;
+ clsidNew = *pclsid; // no translation
+ }
+
+ hr = ProgIDFromCLSID(clsidNew, &szProgID);
+ if (FAILED(hr))
+ {
+ intrDebugOut((DEB_ITRACE," ProgIDFromCLSID failed\n"));
+ goto exitRtn;
+ }
+
+ intrDebugOut((DEB_ITRACE,"ProgIDFromCLSID returns %ws\n",szProgID));
+ *paClass = GlobalAddAtom (szProgID);
+ *pclsid = clsidNew;
+ CoTaskMemFree(szProgID);
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%p OUT CLSIDFromAtomWithTreatAs returns %x\n",
+ 0,hr));
+
+ return hr;
+}
+
+
+INTERNAL_(BOOL) PostMessageToClientWithReply
+(
+HWND hWnd,
+UINT wMsg,
+WPARAM wParam, // posting window
+LPARAM lParam,
+UINT wReplyMsg
+)
+{
+ MSG msg;
+
+ if (!IsWindowValid (hWnd))
+ {
+ AssertSz(FALSE, "Client's window is missing");
+ return FALSE;
+ }
+
+ if (!IsWindowValid ((HWND)wParam))
+ {
+ AssertSz (0, "Posting window is invalid");
+ return FALSE;
+ }
+
+ // Post message to client failed. Treat it as if we got the reply.
+ if (!PostMessageToClient (hWnd, wMsg, wParam, lParam))
+ return FALSE;
+
+ return NOERROR == wTimedGetMessage (&msg, (HWND)wParam, WM_DDE_TERMINATE,
+ WM_DDE_TERMINATE);
+}
+
+
+
+INTERNAL_(BOOL) PostMessageToClient
+(
+ HWND hWnd,
+ UINT wMsg,
+ WPARAM wParam,
+ LPARAM lParam
+)
+{
+ UINT c=0;
+
+ while (c < 10)
+ {
+ if (!IsWindowValid (hWnd)) {
+ Warn ("Client's window is missing");
+ return FALSE;
+ }
+ Puts ("Posting"); Puth(wMsg); Puts("to"); Puth(hWnd); Putn();
+ if (PostMessage (hWnd, wMsg, wParam, lParam))
+ return TRUE; // success
+ else
+ {
+ Yield();
+ c++; // try again
+ }
+ }
+ return FALSE;
+}
+
+
+INTERNAL_(BOOL) IsWindowValid
+ (HWND hwnd)
+{
+ HTASK htask;
+
+ if (!IsWindow (hwnd))
+ return FALSE;
+
+ htask = GetWindowThreadProcessId(hwnd, NULL);
+
+#ifndef WIN32
+ if (IsTask(htask))
+#endif
+ return TRUE;
+
+ return FALSE;
+}
+
+
+
+INTERNAL_(BOOL) UtilQueryProtocol
+(
+ATOM aClass,
+LPOLESTR lpprotocol
+)
+{
+ HKEY hKey;
+ WCHAR key[MAX_STR];
+ WCHAR cclass[MAX_STR];
+
+ if (!aClass)
+ return FALSE;
+
+ if (!GlobalGetAtomName (aClass, cclass, MAX_STR))
+ return FALSE;
+
+ lstrcpyW (key, cclass);
+ lstrcatW (key, OLESTR("\\protocol\\"));
+ lstrcatW (key, lpprotocol);
+ lstrcatW (key, OLESTR("\\server"));
+ if (RegOpenKey (HKEY_CLASSES_ROOT, key, &hKey) != ERROR_SUCCESS)
+ return FALSE;
+ RegCloseKey (hKey);
+ return TRUE;
+}
+
+
+
+INTERNAL_(BOOL) IsOleCommand
+(
+ATOM aCmd,
+WORD wType
+)
+{
+ if (wType == WT_SRVR) {
+ if ((aCmd == aStdCreateFromTemplate)
+ || (aCmd == aStdCreate)
+ || (aCmd == aStdOpen)
+ || (aCmd == aStdEdit)
+ || (aCmd == aStdShowItem)
+ || (aCmd == aStdClose)
+ || (aCmd == aStdExit))
+ return TRUE;
+ }
+ else {
+ if ((aCmd == aStdClose)
+ || (aCmd == aStdDoVerbItem)
+ || (aCmd == aStdShowItem))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+INTERNAL wFileBind
+ (LPOLESTR szFile,
+ LPUNKNOWN FAR* ppUnk)
+{
+ HRESULT hresult = NOERROR;
+ LPBC pbc = NULL;
+ LPMONIKER pmk = NULL;
+ *ppUnk = NULL;
+ ErrRtnH (CreateBindCtx (0, &pbc));
+ ErrRtnH (CreateFileMoniker (szFile, &pmk));
+ ErrRtnH (pmk->BindToObject (pbc, NULL, IID_IUnknown, (LPLPVOID) ppUnk));
+ errRtn:
+// AssertOutPtrIface(hresult, *ppUnk);
+ if (pbc)
+ pbc->Release();
+ if (pmk)
+ pmk->Release();
+ return hresult;
+}
+
+// SynchronousPostMessage
+//
+// Post a message and wait for the ack.
+// (jasonful)
+//
+INTERNAL SynchronousPostMessage
+ (HWND hWndTo, // also who you expect the reply from
+ UINT wMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+#ifdef _MAC
+#else
+
+ HRESULT hresult = NOERROR;
+
+ static unsigned iCounter;
+
+
+ HWND hWndFrom = (HWND) wParam;
+
+
+
+ RetZ (IsWindowValid(hWndFrom));
+ RetZ (IsWindowValid(hWndTo));
+
+ Assert (wMsg != WM_DDE_INITIATE); // can't check for positive ack.
+
+ RetZS (PostMessage (hWndTo, wMsg, wParam, lParam), RPC_E_SERVER_DIED);
+
+ MSG msg;
+ RetErr (wTimedGetMessage (&msg, hWndFrom, WM_DDE_ACK, WM_DDE_ACK));
+ Assert (msg.message == WM_DDE_ACK);
+ if (!( GET_WM_DDE_ACK_STATUS(msg.wParam,msg.lParam) & POSITIVE_ACK))
+ hresult = ResultFromScode (RPC_E_DDE_NACK);
+ if (msg.hwnd != hWndFrom)
+ hresult = ResultFromScode (RPC_E_DDE_UNEXP_MSG);
+
+
+
+ return hresult;
+#endif _MAC
+}
+
+
+INTERNAL wFileIsRunning
+ (LPOLESTR szFile)
+{
+ LPMONIKER pmk = NULL;
+ LPBINDCTX pbc=NULL;
+ HRESULT hresult;
+
+ RetErr (CreateBindCtx (0, &pbc));
+ ErrRtnH (CreateFileMoniker (szFile, &pmk));
+ hresult = pmk->IsRunning (pbc, NULL, NULL);
+ errRtn:
+ if (pbc)
+ pbc->Release();
+ if (pmk)
+ pmk->Release();
+ return hresult;
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: IsFile
+//
+// Synopsis: Given a handle to an atom, determine if it is a file
+//
+// Effects: Attempts to get the files attributes. If there are no
+// attributes, then the file doesn't exist.
+//
+// Arguments: [a] -- Atom for filename
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-03-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL_ (BOOL) IsFile
+ (ATOM a, BOOL FAR* pfUnsavedDoc)
+{
+ LPMONIKER pmk = NULL;
+ LPBC pbc = NULL;
+ LPRUNNINGOBJECTTABLE pROT=NULL;
+
+ WCHAR szFile [MAX_STR];
+ if (0==GlobalGetAtomName (a, szFile, MAX_STR))
+ return FALSE;
+
+ DWORD dwAttribs = GetFileAttributes(szFile);
+
+ /* flags prevent sharing violation*/
+ if (dwAttribs != 0xFFFFFFFF)
+ {
+ if (pfUnsavedDoc)
+ *pfUnsavedDoc = FALSE;
+ return TRUE;
+ }
+ // This will deal with unsaved documents in the ROT.
+ // We do NOT want to call pmk->IsRunning because if a 2.0 client called
+ // DdeIsRunning, we do not want call it here, because then we get stuck
+ // in an infinite loop. We only care about true 2.0 running objects.
+
+
+ //
+ // BUGBUG: KevinRo There is a function (GetPathFromRot) that could replace
+ // the following code sequence.
+ //
+
+ BOOL f= NOERROR==CreateBindCtx (0, &pbc) &&
+ NOERROR==CreateFileMoniker (szFile, &pmk) &&
+ NOERROR==pbc->GetRunningObjectTable (&pROT) &&
+ NOERROR==pROT->IsRunning (pmk) ;
+ if (pROT)
+ pROT->Release();
+ if (pmk)
+ pmk->Release();
+ if (pbc)
+ pbc->Release();
+ if (pfUnsavedDoc)
+ *pfUnsavedDoc = TRUE;
+ return f;
+
+
+}
+
+// wCompatibleClasses
+//
+// Determine if class "aClient" is Auto-Converted to class "aSrvr" or
+// Treated-As class "aSrvr".
+// (Does not check if aClient==aSrvr)
+//
+#pragma SEG(wCompatibleClasses)
+INTERNAL wCompatibleClasses
+ (ATOM aClient,
+ ATOM aSrvr)
+{
+ CLSID clsidClient, clsidSrvr, clsidTo;
+ HRESULT hresult;
+ RetZS (CLSIDFromAtom (aClient, &clsidClient), S_FALSE);
+ RetZS (CLSIDFromAtom (aSrvr, &clsidSrvr ), S_FALSE);
+ if (NOERROR==OleGetAutoConvert (clsidClient, &clsidTo)
+ && clsidTo == clsidSrvr)
+ {
+ // aClient is Auto-Converted to aSrvr
+ return NOERROR;
+ }
+ hresult = CoGetTreatAsClass(clsidClient, &clsidTo);
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,
+ "wCompatibleClasses CoGetTreatAs returns %x\n",
+ hresult));
+ return(hresult);
+ }
+
+ if (clsidTo == clsidSrvr)
+ {
+ // aClient is Treated-As aSrvr
+ return NOERROR;
+ }
+ return ResultFromScode (S_FALSE); // not compatible
+}
+
+
+
+// wCreateStgAroundNative
+//
+// Build an OLE2 storage around 1.0 native data by putting it in
+// stream "\1Ole10Native" and creating valid CompObj and OLE streams.
+// Return the IStorage and the ILockBytes it is built on.
+//
+INTERNAL wCreateStgAroundNative
+ (HANDLE hNative,
+ ATOM aClassOld,
+ ATOM aClassNew,
+ CNVTYP cnvtyp,
+ ATOM aItem,
+ LPSTORAGE FAR* ppstg,
+ LPLOCKBYTES FAR* pplkbyt)
+{
+ HRESULT hresult;
+ LPSTORAGE pstg = NULL;
+ LPLOCKBYTES plkbyt = NULL;
+ LPOLESTR szUserType = NULL;
+ WCHAR szClassOld [256];
+ CLSID clsid;
+ ATOM aClass;
+ *ppstg = NULL;
+
+ intrDebugOut((DEB_ITRACE,
+ "%p wCreateStgAroundNative(hNative=%x,aClassOld=%x"
+ ",aClassNew=%x cnvtyp=%x,aItem=%x)\n",
+ 0,hNative,aClassOld,aClassNew,cnvtyp,aItem));
+
+ // Create temporary docfile on our ILockBytes
+ ErrRtnH (CreateILockBytesOnHGlobal (NULL,/*fDeleteOnRelease*/TRUE,&plkbyt));
+
+ Assert (plkbyt);
+
+ ErrRtnH (StgCreateDocfileOnILockBytes (plkbyt, grfCreateStg, 0, &pstg));
+
+ RetZ (pstg);
+ Assert (NOERROR==StgIsStorageILockBytes(plkbyt));
+
+ aClass = (cnvtyp == cnvtypConvertTo)?aClassNew:aClassOld;
+
+ if (CLSIDFromAtom (aClass,(LPCLSID)&clsid) == FALSE)
+ {
+ hresult = REGDB_E_CLASSNOTREG;
+ goto errRtn;
+ }
+
+ ErrRtnH (WriteClassStg (pstg, clsid));
+
+ // The UserType always corresponds to the clsid.
+ ErrRtnH (OleRegGetUserType (clsid, USERCLASSTYPE_FULL, &szUserType));
+
+ // The format is always the 1.0 format (classname/progid)
+ ErrZS (GlobalGetAtomName (aClassOld, szClassOld, 256), E_UNEXPECTED);
+
+ ErrRtnH (WriteFmtUserTypeStg (pstg, RegisterClipboardFormat(szClassOld),
+ szUserType));
+
+
+ if (cnvtyp == cnvtypConvertTo)
+ {
+ // SetConvertStg also writes a complete default Ole Stream
+ ErrRtnH (SetConvertStg (pstg, TRUE));
+ }
+ else
+ {
+ ErrRtnH (WriteOleStg (pstg, NULL, (CLIPFORMAT)0, NULL));
+ }
+ ErrRtnH (StSave10NativeData (pstg, hNative, FALSE));
+ if (aItem)
+ {
+ ErrRtnH (StSave10ItemName (pstg, wAtomNameA (aItem)));
+ }
+ *ppstg = pstg;
+ *pplkbyt = plkbyt;
+ return NOERROR;
+
+ errRtn:
+ if (pstg)
+ pstg->Release();
+ if (plkbyt)
+ plkbyt->Release();
+ CoTaskMemFree(szUserType);
+ return hresult;
+}
+
+
+#ifdef _DEBUG
+
+
+INTERNAL_ (BOOL) IsAtom (ATOM a)
+{
+ WCHAR sz[256]= {0};
+ if (a < 0xc000)
+ return FALSE;
+ WORD cb=GlobalGetAtomName (a, sz, 256);
+ Assert (lstrlenW(sz) == (int) cb);
+ return cb>0 && cb < MAX_STR;
+}
+
+
+#include <limits.h>
+#undef GlobalFree
+
+
+
+
+INTERNAL_(HANDLE) wGlobalFree (HANDLE h)
+{
+ LPVOID p;
+ Assert ((GlobalFlags(h) & GMEM_LOCKCOUNT)==0);
+ if (!(p=GlobalLock(h)))
+ {
+ Puts ("Cannot free handle");
+ Puth (h);
+ Putn();
+ AssertSz(0, "Invalid Handle\r\n");
+ }
+ Assert (!IsBadReadPtr (p, (UINT) min (UINT_MAX, GlobalSize(h))));
+ Assert (GlobalUnlock(h)==0);
+ Verify (!GlobalFree (h));
+ Puts ("FREEING ");
+ Puth (h);
+ Putn ();
+ return NULL; // success
+}
+
+
+
+#undef GlobalDeleteAtom
+
+INTERNAL_(ATOM) wGlobalDeleteAtom (ATOM a)
+{
+ WCHAR sz[256];
+ Assert (0 != GlobalGetAtomName (a, sz, 256));
+ Assert (0==GlobalDeleteAtom (a));
+ return (ATOM)0;
+}
+
+INTERNAL_(int) wCountChildren
+ (HWND h)
+{
+ int c = 0;
+ HWND hwndChild = GetWindow (h, GW_CHILD);
+ while (hwndChild)
+ {
+ c++;
+ hwndChild = GetWindow (hwndChild, GW_HWNDNEXT);
+ }
+ return c;
+}
+
+
+#endif // _DEBUG
diff --git a/private/ole32/com/remote/dde/server/dirs b/private/ole32/com/remote/dde/server/dirs
new file mode 100644
index 000000000..94c45c76c
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/dirs
@@ -0,0 +1,37 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+#
+# This is a list of all subdirectories that build required components.
+# Each subdirectory name should appear on a line by itself. The build
+# follows the order in which the subdirectories are specified.
+#
+
+DIRS=
+
+#
+# This is a list of all subdirectories that build optional components.
+# Each subdirectory name should appear on a line by itself. The build
+# follows the order in which the subdirectories are specified.
+#
+
+OPTIONAL_DIRS= \
+
+
diff --git a/private/ole32/com/remote/dde/server/doc.cxx b/private/ole32/com/remote/dde/server/doc.cxx
new file mode 100644
index 000000000..3975d4d3e
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/doc.cxx
@@ -0,0 +1,1680 @@
+/***************************************************************************\
+* 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 HINSTANCE hdllInst;
+extern HANDLE hddeRename;
+extern HWND hwndRename;
+
+
+// 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);;
+
+ lpclient->m_pCallControl = GetDdeCallControlInterface();
+
+ intrAssert(lpclient->m_pCallControl != NULL);
+
+ if (lpclient->m_pCallControl == NULL)
+ {
+ intrDebugOut((DEB_IWARN,
+ "CDefClient::Create(%ws) CallControlGet failed\n",
+ WIDECHECK(lpdocName)));
+
+ goto errRtn;
+ }
+
+
+ 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 = SSCreateWindowExA(0, DOC_CLASSA,"DDE ViewObj",
+ WS_CHILD,0,0,0,0,lpsrvr->m_hwnd,NULL, hdllInst, NULL)))
+ {
+ intrDebugOut((DEB_ITRACE,"CDefClient::Create() couldn't create window\n"));
+ goto errRtn;
+ }
+
+
+ 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_pCallControl)
+ ReleaseDdeCallControlInterface();
+
+ 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;
+ INTERFACEINFO32 ifInfo;
+
+ IID iid; // Currently, we have a random iid, based on whatever is on
+ // the stack. These calls do not nest, so this isn't supposed
+ // to matter.
+
+
+ intrAssert(pDocData != NULL);
+
+ ICallControl *lpCallCont = pDocData->lpclient->m_pCallControl;
+
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN DocHandleIncomingCall lpclient=%x pDocData=%x\n",
+ pDocData->lpclient,
+ pDocData));
+
+ //
+ // It would be very bad if this didn't exist.
+ //
+ intrAssert(lpCallCont);
+
+ //
+ // There is no information to provide here
+ // By setting pUnk to NULL, the CallControl will pass the
+ // message filter a NULL ifInfo.
+ //
+
+ ifInfo.pUnk = NULL;
+ ifInfo.wMethod=0;
+
+ //
+ // TERMINATE messages must always be handled ASYNC, and cannot
+ // be rejected.
+ //
+ if (pDocData->msg == WM_DDE_TERMINATE)
+ {
+ ifInfo.callcat = CALLCAT_ASYNC;
+ }
+ else
+ {
+ ifInfo.callcat = CALLCAT_SYNCHRONOUS;
+ }
+
+ dispatchdata.pData = (LPVOID) pDocData;
+ pDocData->wDispFunc = DDE_DISP_DOCWNDPROC;
+
+ hresult = lpCallCont->HandleDispatchCall((DWORD)GetWindowTask(pDocData->hwnd),
+ iid,
+ &ifInfo,
+ &dispatchdata);
+
+ 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_pCallData)
+ {
+ 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_pCallData)
+ {
+ if (lpclient->m_pCallData)
+ {
+ // 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_pCallData, 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_pCallData)
+ {
+ intrAssert(lpclient->m_pCallControl != NULL);
+ if (lpclient->m_pCallControl != NULL)
+ {
+ lpclient->m_pCallControl->SetCallState(lpclient->m_pCallData,
+ SERVERCALLEX_ISHANDLED,
+ NOERROR);
+ }
+ 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_pCallData)
+ {
+ // 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_pCallData)
+ {
+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_pCallData)
+ {
+ 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_pCallData)
+ {
+ 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;
+}
diff --git a/private/ole32/com/remote/dde/server/item.cxx b/private/ole32/com/remote/dde/server/item.cxx
new file mode 100644
index 000000000..f268cdbcc
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/item.cxx
@@ -0,0 +1,1210 @@
+/****************************** Module Header ******************************\
+* Module Name: Item.c Object(item) main module
+*
+* Purpose: Includes All the object releated routiens.
+*
+* Created: Oct 1990.
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor (../10/1990) Designed, coded
+*
+*
+\***************************************************************************/
+
+
+#include "ole2int.h"
+//#include "cmacs.h"
+#include <dde.h>
+#include "ddeatoms.h"
+#include "ddedebug.h"
+#include "srvr.h"
+#include "itemutil.h"
+
+ASSERTDATA
+
+
+// !!!change child enumeration.
+// !!!No consistency in errors (Sometimes Bools and sometimes HRESULT).
+
+
+//SearchItem: Searches for a given item in a document tree.
+//If found, returns the corresponding client ptr.
+
+INTERNAL_(LPCLIENT) CDefClient::SearchItem
+(
+LPOLESTR lpitemname
+)
+
+{
+ ATOM aItem;
+ LPCLIENT lpclient;
+
+ ChkC(this);
+ Assert (m_pdoc==this);
+ Assert (m_bContainer);
+
+ Puts ("DefClient::SearchItem\r\n");
+ // If the item passed is an atom, get its name.
+ if (!HIWORD(lpitemname))
+ aItem = (ATOM) (LOWORD((DWORD)lpitemname));
+ else if (!lpitemname[0])
+ aItem = NULL;
+ else
+ aItem = GlobalFindAtom (lpitemname);
+
+ // walk thru the items list and mtach for the itemname.
+ lpclient = this;
+
+ while (lpclient) {
+ ChkC(lpclient);
+ if (lpclient->m_aItem == aItem)
+ return lpclient;
+ // The NULL item is the client that is a container (the whole doc).
+ // REVIEW: jasonful
+ if (lpclient->m_bContainer && aItem==NULL)
+ return lpclient;
+ lpclient = lpclient->m_lpNextItem;
+ }
+
+ Puts ("SearchItem failed\r\n");
+ return NULL;
+
+}
+
+
+
+// FindItem: Given the itemname and the doc obj ptr,
+// searches for the the item (object) in the document tree.
+// Items are lonked to the doc obj.
+
+INTERNAL_(HRESULT) CDefClient::FindItem
+(
+LPOLESTR lpitemname,
+LPCLIENT FAR * lplpclient
+)
+{
+ LPCLIENT lpclient;
+ WCHAR buf[MAX_STR];
+
+ Puts ("DefClient::FindItem "); Puts (lpitemname); Putn();
+ ChkC(this);
+
+ if (lpclient = SearchItem (lpitemname)) {
+ // we found the item window
+
+ ChkC(lpclient);
+ *lplpclient = lpclient;
+ return NOERROR;
+
+ }
+
+ if (!HIWORD(lpitemname)){
+ if (LOWORD(lpitemname))
+ GlobalGetAtomName ((ATOM)LOWORD((DWORD)lpitemname),
+ buf, MAX_STR);
+ else
+ buf[0] = NULL;
+
+ lpitemname = buf;
+ }
+
+ // Item (object)window is not created yet. Let us create one.
+ return RegisterItem (lpitemname, lplpclient, TRUE);
+}
+
+
+
+//RegisterItem: Given the document handle and the item string
+//creates item with the given name in the doc obj list..
+
+INTERNAL CDefClient::RegisterItem
+ (LPOLESTR lpitemname,
+ LPCLIENT FAR * lplpclient,
+ BOOL bSrvr)
+{
+ LPCLIENT pitemNew = NULL;
+ HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0);
+ LPOLEOBJECT lpoleObj = NULL;
+ LPOLEITEMCONTAINER lpcontainer;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::RegisterItem(%ws)\n",
+ this,WIDECHECK(lpitemname)));
+ ChkC(this);
+ AssertIsDoc(this);
+ *lplpclient = NULL;
+
+ ErrZS (pitemNew = new CDefClient(NULL), E_OUTOFMEMORY);
+
+ pitemNew->m_bTerminate = FALSE;
+ pitemNew->m_bContainer = FALSE; // not a container, i.e.,document
+
+
+ // Set containing document
+ pitemNew->m_pdoc = this;
+ m_pUnkOuter->AddRef(); // item keeps its document alive
+ // Corresponding Release is in CDefClient::~CDefClient
+
+ if (!HIWORD(lpitemname)) {
+ AssertSz (!bSrvr, "invalid lpitemname in RegisterItem\r\n");
+ pitemNew->m_aItem = LOWORD((DWORD)lpitemname);
+ }
+ else if (!lpitemname[0])
+ pitemNew->m_aItem = NULL;
+ else
+ pitemNew->m_aItem = wGlobalAddAtom (lpitemname);
+
+ lpoleObj = m_lpoleObj;
+
+ // Call the server if the item is not one of the standard items.
+ if (bSrvr) {
+
+ // Call the server app for container interface
+ hresult = lpoleObj->QueryInterface (IID_IOleItemContainer, (LPVOID FAR *)&lpcontainer);
+
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,
+ "%x ::RegisterItem(%ws) No IOleContainer intr\n",
+ this,WIDECHECK(lpitemname)));
+ goto errRtn;
+ }
+
+ hresult = lpcontainer->GetObject(lpitemname, BINDSPEED_INDEFINITE, 0,
+ IID_IOleObject, (LPLPVOID)&pitemNew->m_lpoleObj);
+
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_ERROR,
+ "IOleItemContainer::GetObject(%ws,...) failed (hr=%x)\n",
+ lpitemname,
+ hresult));
+ }
+
+ lpcontainer->Release ();
+ if (hresult != NOERROR)
+ goto errRtn;
+
+ hresult = pitemNew->m_lpoleObj->QueryInterface (IID_IDataObject, (LPLPVOID)
+ &pitemNew->m_lpdataObj);
+
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_ERROR,
+ "::QueryInterface(IID_IDataObject) failed (hr=%x)\n",
+ hresult));
+ pitemNew->m_lpoleObj->Release();
+ goto errRtn;
+ }
+
+
+ // 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.
+ pitemNew->DoOle20Advise (OLE_CLOSED, (CLIPFORMAT)0);
+ }
+
+
+
+ // This keeps the CDefClient alive until _we_ are done with it
+ // The corresponding Release is in CDefClient::Revoke
+ pitemNew->m_pUnkOuter->AddRef();
+
+ pitemNew->m_lpNextItem = m_lpNextItem;
+ pitemNew->m_hwnd = m_hwnd; // set the window handle to
+ // same as the doc level window
+
+ m_lpNextItem = pitemNew;
+ *lplpclient = pitemNew;
+
+ hresult = NOERROR;
+ goto exitRtn;
+
+errRtn:
+ if (pitemNew) {
+ delete pitemNew;
+ }
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x CDefClient::RegisterItem(%ws) hresult=%x\n",
+ this,WIDECHECK(lpitemname),hresult));
+
+
+ return(hresult);
+}
+
+
+
+// Return NOERROR if "this" document has no items which have connections
+// (client windows).
+//
+INTERNAL CDefClient::NoItemConnections (void)
+{
+ PCLINFO pclinfo = NULL;
+ HANDLE hcliPrev = NULL;
+ HANDLE hcli;
+ PCLILIST pcli;
+ HANDLE *phandle;
+
+ ChkCR (this);
+ AssertIsDoc (this);
+ LPCLIENT pitem;
+ for (pitem = m_lpNextItem;
+ pitem;
+ pitem = pitem->m_lpNextItem)
+ {
+ ChkCR (pitem);
+ if (pitem->m_aItem == aStdDocName)
+ continue;
+ hcli = pitem->m_hcliInfo;
+ while (hcli)
+ {
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ return ResultFromScode (S_FALSE);
+
+ phandle = (HANDLE *) (pcli->info);
+ while (phandle < (HANDLE *)(pcli + 1))
+ {
+ if (*phandle)
+ {
+ LocalUnlock (hcli);
+ return ResultFromScode (S_FALSE);
+ }
+ else
+ {
+ phandle++;
+ phandle++;
+ }
+ }
+
+ hcliPrev = hcli;
+ hcli = pcli->hcliNext;
+ LocalUnlock (hcliPrev);
+ }
+ }
+ return NOERROR;
+}
+
+
+
+INTERNAL_(void) CDefClient::DeleteAdviseInfo (void)
+{
+
+
+ PCLINFO pclinfo = NULL;
+ HANDLE hcliPrev = NULL;
+ PCLILIST pcli;
+ HANDLE *phandle;
+ HANDLE hcli;
+ HANDLE hcliInfo;
+
+ Puts ("DefClient::DeleteAdviseInfo\r\n");
+ ChkC(this);
+ hcli = m_hcliInfo;
+ while (hcli) {
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ return;
+
+ phandle = (HANDLE *) (pcli->info);
+ while (phandle < (HANDLE *)(pcli + 1)) {
+ if (*phandle) {
+ *phandle++ = 0;
+
+ // delete the printer dev info block
+ if(pclinfo = (PCLINFO)LocalLock ((hcliInfo = *phandle++))){
+ if(pclinfo->hdevInfo)
+ GlobalFree (pclinfo->hdevInfo);
+
+ LocalUnlock (hcliInfo);
+ // no free if lock failed
+ LocalFree (hcliInfo);
+ }
+ } else {
+ phandle++;
+ phandle++;
+
+ }
+ }
+
+ hcliPrev = hcli;
+ hcli = pcli->hcliNext;
+ LocalUnlock (hcliPrev);
+ LocalFree (hcliPrev); // free the block;
+ }
+ m_hcliInfo = NULL;
+}
+
+
+
+//DeleteFromItemsList: Deletes a client from the object lists of
+//all the objects of a given document. Thie client possibly
+//is terminating the conversation with our doc window.
+//
+INTERNAL_(void) CDefClient::DeleteFromItemsList
+ (HWND hwndClient)
+{
+ HANDLE hclinfo;
+ PCLINFO pclinfo;
+ LPCLIENT lpclient;
+ LPCLIENT FAR* ppitemLast = NULL;
+ BOOL fRevokedDoc = FALSE;
+ static int staticcounter;
+ int counter = ++staticcounter;
+
+ Puts ("DefClient::DeleteFromItemsList "); Puti(counter); Putn();
+ AssertIsDoc(this);
+ lpclient = this;
+ ppitemLast = &m_lpNextItem;
+ while (lpclient)
+ {
+ ChkC(lpclient);
+ BOOL fDoc = (lpclient==this);
+ if (fDoc)
+ {
+ AssertIsDoc (lpclient);
+ // Remove window from doc's master list
+ HWND hwnd = (HWND) FindClient (lpclient->m_hcli, hwndClient, /*fDelete*/TRUE);
+ Assert (hwnd==hwndClient);
+ }
+
+ hclinfo = FindClient (lpclient->m_hcliInfo, hwndClient, /*fDelete*/TRUE);
+ LPCLIENT pitemNext = lpclient->m_lpNextItem;
+
+ // We must make sure no other client is connected (linked)
+ // to this item before deleting.
+ if (!fDoc && AreNoClients (lpclient->m_hcliInfo))
+ {
+ Assert (ppitemLast);
+ if (ppitemLast && !fDoc)
+ {
+ // Remove from linked list
+ *ppitemLast = lpclient->m_lpNextItem;
+ }
+ fRevokedDoc |= fDoc;
+ lpclient->Revoke ();
+ }
+ else
+ {
+ ppitemLast = &(lpclient->m_lpNextItem);
+ }
+ if (hclinfo)
+ {
+ if(pclinfo = (PCLINFO)LocalLock (hclinfo))
+ {
+ if(pclinfo->hdevInfo)
+ GlobalFree (pclinfo->hdevInfo);
+ LocalUnlock (hclinfo);
+ }
+ LocalFree (hclinfo);
+ }
+ lpclient = pitemNext;
+ }
+
+ // Handle invisible update
+ if (!fRevokedDoc && !m_fEmbed //&& !m_fGotDdeAdvise
+ && NOERROR ==NoItemConnections()
+ && AreNoClients (m_hcliInfo)
+ && AreNoClients (m_hcli) )
+ {
+ ChkC (this);
+ Assert (m_lpoleObj);
+ Assert (m_lpdataObj);
+ ReleaseObjPtrs();
+ }
+
+ Puts ("DefClient::DeleteFromItemsList Done "); Puti(counter); Putn();
+}
+
+
+INTERNAL_(void) CDefClient::RemoveItemFromItemList
+ (void)
+{
+ // Make sure it's an item
+ Assert (m_pdoc != this && !m_bContainer);
+
+ LPCLIENT lpclient = m_pdoc;
+ ChkC (lpclient);
+ LPCLIENT FAR* ppitemLast = &(m_pdoc->m_lpNextItem);
+
+ while (lpclient)
+ {
+ ChkC(lpclient);
+ if (lpclient==this)
+ {
+ // Remove from linked list
+ *ppitemLast = lpclient->m_lpNextItem;
+ break;
+ }
+ ppitemLast = &(lpclient->m_lpNextItem);
+ lpclient = lpclient->m_lpNextItem;
+ }
+ Revoke();
+}
+
+
+
+
+INTERNAL_(void) CDefClient::ReleaseAllItems ()
+{
+ LPCLIENT lpclient;
+
+ Puts ("DefClient::ReleaseAllItems\r\n");
+ AssertIsDoc(this);
+
+ // leave the doc level object.
+ lpclient = m_lpNextItem;
+
+ while (lpclient)
+ {
+ ChkC(this);
+ LPCLIENT pitemNext = lpclient->m_lpNextItem;
+ lpclient->Revoke();
+ lpclient = pitemNext;
+ }
+ // After revoking all the items, we can't keep any refernces to them.
+ m_lpNextItem = NULL;
+}
+
+
+
+INTERNAL_(void) CDefClient::DeleteAllItems ()
+{
+ LPCLIENT lpclient;
+
+ Puts ("DefClient::DeleteAllItems\r\n");
+ AssertIsDoc(this);
+
+ // leave the doc level object.
+ lpclient = m_lpNextItem;
+
+ while (lpclient)
+ {
+ ChkC(lpclient);
+ if (ISATOM(lpclient->m_aItem))
+ GlobalDeleteAtom (lpclient->m_aItem);
+ // Delete client advise info
+ lpclient->DeleteAdviseInfo ();
+
+ lpclient = lpclient->m_lpNextItem;
+ }
+}
+
+
+
+
+// PokeData: Prepares and gives the data to the server app thru
+// the SetData object method.
+
+INTERNAL CDefClient::PokeData(HWND hwndClient,ATOM aItem,HANDLE hPoke)
+{
+ HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0);
+ DDEPOKE FAR * lpPoke = NULL;
+ int format;
+ BOOL fRelease = FALSE;
+ LPPERSISTSTORAGE pPersistStg=NULL;
+ FORMATETC formatetc;
+ STGMEDIUM medium;
+
+ // Due to a C7 bug, do not use a structure initialization for STGMEDIUM
+ medium.tymed = TYMED_HGLOBAL;
+ medium.hGlobal = NULL; // invalid
+ medium.pUnkForRelease= NULL;
+
+ intrDebugOut((DEB_ITRACE,
+ "%p CDefClient::PokeData(hwndClient=%x,aItem=%x,hPoke=%x)\n",
+ this,hwndClient,aItem,hPoke));
+
+ ChkC(this);
+ AssertIsDoc (this);
+
+
+ // Until now, m_aItem had been the client-generated (ugly) document name.
+ // Now it becomes the actual item name, which will almost always be NULL.
+ // Only in the TreatAs/ConvertTo case will it be non-NULL.
+ m_aItem = aItem;
+
+ formatetc.cfFormat = 0; /* invalid */
+ formatetc.ptd = m_ptd;
+ formatetc.lindex = DEF_LINDEX;
+ formatetc.dwAspect = DVASPECT_CONTENT;
+ formatetc.tymed = TYMED_HGLOBAL;
+
+ ErrZS (hPoke && (lpPoke = (DDEPOKE FAR *) GlobalLock (hPoke)),
+ E_OUTOFMEMORY);
+
+ format = formatetc.cfFormat = (UINT)(unsigned short)lpPoke->cfFormat;
+ Assert (format);
+ fRelease = lpPoke->fRelease;
+
+ // We found the item. Now prepare the data to be given to the object
+ // MakeItemData returns a newly allocated handle.
+ if (!(medium.hGlobal = MakeItemData (lpPoke, hPoke, format)))
+ goto errRtn;
+
+ // Change type acording to format (not that default has been set above)
+ if (format == CF_METAFILEPICT)
+ formatetc.tymed = medium.tymed = TYMED_MFPICT;
+ else
+ if (format == CF_BITMAP)
+ formatetc.tymed = medium.tymed = TYMED_GDI;
+
+ // Now send the data to the object
+
+
+ if (formatetc.cfFormat==g_cfNative)
+ {
+ m_fGotEditNoPokeNativeYet = FALSE;
+
+ // Cannot do SetData. Must do PersisStg::Load on an IStorage
+ // made from the native data, i.e., medium.hGlobal.
+
+ Assert (m_plkbytNative==NULL);
+ ErrRtnH (CreateILockBytesOnHGlobal (medium.hGlobal,
+ /*fDeleteOnRelease*/TRUE,
+ &m_plkbytNative));
+
+ Assert (m_pstgNative==NULL);
+
+ if (NOERROR==StgIsStorageILockBytes(m_plkbytNative))
+ {
+ // This is a flattened 2.0 storage
+ ErrRtnH (StgOpenStorageOnILockBytes (m_plkbytNative,
+ (LPSTORAGE)NULL,
+ STGM_READWRITE| STGM_SHARE_EXCLUSIVE| STGM_DIRECT,
+ (SNB)NULL,
+ 0,
+ &m_pstgNative));
+ }
+ else
+ {
+ // It is a raw 1.0 Native handle.
+ // This is the TreatAs/ ConvertTo case.
+ LPLOCKBYTES plkbyt = NULL;
+ Assert (m_psrvrParent->m_aOriginalClass);
+
+ ErrRtnH (wCreateStgAroundNative (medium.hGlobal,
+ m_psrvrParent->m_aOriginalClass,
+ m_psrvrParent->m_aClass,
+ m_psrvrParent->m_cnvtyp,
+ m_aItem,
+ &m_pstgNative,
+ &plkbyt));
+
+
+ Assert (m_plkbytNative);
+ if (m_plkbytNative)
+ {
+ // This should free the original native hGlobal also.
+ m_plkbytNative->Release();
+ medium.hGlobal = NULL;
+ }
+ m_plkbytNative = plkbyt;
+
+ }
+
+ RetZ (m_pstgNative);
+ Assert (m_lpoleObj);
+ ErrRtnH (m_lpoleObj->QueryInterface (IID_IPersistStorage,
+ (LPLPVOID) &pPersistStg));
+ hresult = pPersistStg->Load (m_pstgNative);
+ pPersistStg->Release();
+ pPersistStg=NULL;
+ ErrRtnH (hresult);
+
+ // Now that we have initialized the object, we can call SetClientSite
+ 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.
+ ErrRtnH (DoOle20Advise (OLE_CLOSED, (CLIPFORMAT)0));
+ }
+ else
+ {
+ if (m_fGotEditNoPokeNativeYet)
+ {
+ // We got StdEdit, but instead of getting Poke for native data,
+ // we got poke for someother format. So we want to generate
+ // InitNew() call for the object.
+
+ ErrRtnH (DoInitNew()); // the function clears the flag
+ }
+
+ // Not native format, do SetData
+ // Callee frees medium, i.e., the hglobal returned by MakeItemData
+ Assert (m_lpdataObj);
+ hresult = m_lpdataObj->SetData (&formatetc, &medium, TRUE);
+#ifdef _DEBUG
+ if (hresult != NOERROR)
+ {
+ Puts ("****WARNING: SetData failed. cfFormat==");
+ WCHAR sz[100];
+ GetClipboardFormatName (formatetc.cfFormat, sz, 100);
+ Puts (sz);
+ Putn();
+ }
+#endif
+ // We free the data if server deos not return NOERROR.
+ // Otherwise server must've deleted it.
+ if (hresult == NOERROR)
+ medium.hGlobal = NULL;
+ }
+
+
+errRtn:
+ GlobalUnlock (hPoke);
+
+ if (fRelease && hPoke)
+ GlobalFree (hPoke);
+
+// Do NOT free medium.hGlobal, because it becomes the hGlobal on which
+// m_plkbytNative (and therefore m_pstgNative) is based.
+// It will be freed when m_plkbytNative is Release().
+// if (medium.hGlobal)
+// ReleaseStgMedium(&medium);
+
+ if (pPersistStg)
+ pPersistStg->Release();
+
+ return hresult;
+}
+
+
+
+INTERNAL_(HRESULT) CDefClient::UnAdviseData
+ (HWND hwndClient,
+ ATOM aItem)
+{
+ WCHAR buf[MAX_STR];
+ int options;
+ LPCLIENT lpclient;
+ HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0);
+ HANDLE hclinfo = NULL;
+ PCLINFO pclinfo = NULL;
+
+ Puts ("DefClient::UnadviseData\r\n");
+ ChkC(this);
+
+ if (aItem == NULL)
+ {
+ buf[0] = NULL;
+ }
+ else
+ {
+ GlobalGetAtomName (aItem, buf, MAX_STR);
+ }
+
+ // Scan for the advise options like "Close", "Save" etc
+ // at the end of the item.
+
+ ErrRtnH (ScanItemOptions (buf, (int far *)&options));
+
+ // Now get the corresponding object.
+ ErrRtnH (FindItem (buf, (LPCLIENT FAR *)&lpclient));
+
+ // Find the client structure to be attached to the object.
+ if ((hclinfo = FindClient (lpclient->m_hcliInfo, hwndClient, FALSE)) == NULL ||
+ (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL )
+ {
+ hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ goto errRtn;
+ }
+
+ pclinfo->options &= (~(0x0001 << options));
+
+errRtn:
+ if (pclinfo)
+ LocalUnlock (hclinfo);
+ return hresult;
+
+}
+
+
+
+// AdviseStdItems: This routine takes care of the DDEADVISE for a
+//particular object in given document. Creates a client strutcure
+//and attaches to the property list of the object window.
+
+INTERNAL_(HRESULT) CDefClient::AdviseStdItems
+(
+
+HWND hwndClient,
+ATOM aItem,
+HANDLE hopt,
+BOOL FAR * lpfack
+)
+{
+
+ DDEADVISE FAR *lpopt;
+ HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0);
+
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::AdviseStdItems(hwndClient=%x,aItem=%x(%ws),hopt=%x)\n",
+ this,
+ hwndClient,
+ aItem,
+ wAtomName(aItem),
+ hopt));
+
+ ChkC(this);
+ ErrZS (lpopt = (DDEADVISE FAR *) GlobalLock (hopt), E_OUTOFMEMORY);
+
+ AssertSz (aItem == aStdDocName, "AdviseStdItem is not Documentname");
+
+ *lpfack = lpopt->fAckReq;
+ hresult = (HRESULT)SetStdInfo (hwndClient, OLESTR("StdDocumentName"), NULL);
+
+
+ if (lpopt)
+ GlobalUnlock (hopt);
+
+errRtn:
+
+ if (hresult == NOERROR)
+ {
+ // Rules say to free handle if ACK will be positive
+ GlobalFree (hopt);
+ }
+ Assert (hresult==NOERROR);
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::AdviseStdItems hresult=%x\n",
+ this,
+ hresult));
+
+ return hresult;
+}
+
+
+
+//AdviseData: This routine takes care of the DDE_ADVISE for a
+//particular object in given document. Creates a client strutcure
+//and attaches to the property list of the object window.
+
+INTERNAL CDefClient::AdviseData
+(
+HWND hwndClient,
+ATOM aItem,
+HANDLE hopt,
+BOOL FAR * lpfack
+)
+{
+ DDEADVISE FAR *lpopt = NULL;
+ int format = NULL;
+ WCHAR buf[MAX_STR];
+ OLE_NOTIFICATION options;
+ LPCLIENT lpclient;
+ HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0);
+ HANDLE hclinfo = NULL;
+ PCLINFO pclinfo = NULL;
+ BOOL fAllocatedClInfo = FALSE;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::AdviseData(hwndClient=%x,aItem=%x(%ws),hopt=%x)\n",
+ this,
+ hwndClient,
+ aItem,
+ wAtomName(aItem),
+ hopt));
+ ChkC(this);
+ if (m_fGotEditNoPokeNativeYet) {
+ // We got StdEdit, but instead of getting Poke for native data,
+ // we got advise. So we want to generate InitNew() call for
+ // the object.
+
+ DoInitNew(); // the function clears the flag
+ }
+
+ m_fGotDdeAdvise = TRUE;
+
+ ErrZS (lpopt = (DDEADVISE FAR *) GlobalLock (hopt), E_OUTOFMEMORY);
+
+ if (!aItem)
+ buf[0] = NULL;
+ else
+ GlobalGetAtomName (aItem, buf, MAX_STR);
+
+ // Scan for the advise options like "Close", "Save" etc
+ // at the end of the item.
+
+ // ack flag should be set before the error return. Otherwise the
+ // the atom is getting deleted.
+
+ *lpfack = lpopt->fAckReq;
+ ErrRtnH (ScanItemOptions (buf, (int far *)&options));
+
+ // Now get the corresponding item.
+ ErrRtnH (FindItem (buf, (LPCLIENT FAR *)&lpclient));
+
+ if (!IsFormatAvailable ((CLIPFORMAT)(unsigned short)lpopt->cfFormat)){
+ hresult = ReportResult(0, DV_E_CLIPFORMAT, 0, 0); // this format is not supported;
+ goto errRtn;
+ }
+
+ lpclient->DoOle20Advise (options, (CLIPFORMAT)(unsigned short)lpopt->cfFormat);
+
+
+ // Create the client structure to be attcahed to the object.
+ if (!(hclinfo = FindClient (lpclient->m_hcliInfo, hwndClient, FALSE)))
+ {
+ hclinfo = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (CLINFO));
+ fAllocatedClInfo = TRUE;
+ }
+
+
+ if (hclinfo == NULL || (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL){
+ hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ goto errRtn;
+ }
+
+ // Remember the client window (Needed for sending DATA later on
+ // when the data change message comes from the server)
+
+ pclinfo->hwnd = hwndClient;
+ if ((CLIPFORMAT)(unsigned short)lpopt->cfFormat == g_cfNative)
+ pclinfo->bnative = TRUE;
+ else
+ pclinfo->format = (CLIPFORMAT)(unsigned short)lpopt->cfFormat;
+
+ // Remeber the data transfer options
+ pclinfo->options |= (1 << options) ;
+
+ pclinfo->bdata = !lpopt->fDeferUpd;
+ LocalUnlock (hclinfo);
+ pclinfo = NULL;
+
+ // if the entry exists already, delete it.
+ FindClient (lpclient->m_hcliInfo, hwndClient, /*fDelete*/TRUE);
+
+ // Now add this client to item client list
+ // !!! This error recovery is not correct.
+ if(!AddClient ((LPHANDLE)&lpclient->m_hcliInfo, hwndClient, hclinfo))
+ goto errRtn;
+
+
+errRtn:
+ if (lpopt)
+ GlobalUnlock (hopt);
+
+ if (pclinfo)
+ LocalUnlock (hclinfo);
+
+ if (hresult==NOERROR)
+ {
+ // hresult==NOERROR iff we will send a postive ACK, so we must
+ // free the hOptions handle.
+ GlobalFree (hopt);
+ }
+ else
+ {
+ intrDebugOut((DEB_IERROR,
+ "%x ::AdviseData() failing.\n",this));
+ // We free hclinfo because it was not stored in the item's
+ // client list via the AddClient just before the errRtn label.
+ if (hclinfo && fAllocatedClInfo)
+ LocalFree (hclinfo);
+
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::AdviseData() returns hresult = %x\n",
+ this, hresult));
+
+ return hresult;
+
+}
+
+
+
+
+
+INTERNAL_(BOOL) CDefClient::IsFormatAvailable
+ (CLIPFORMAT cfFormat)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::IsFormatAvailable(cfFormat=%x)\n",
+ this, cfFormat));
+
+ ChkC(this);
+
+ BOOL f = ((cfFormat==g_cfNative) || UtIsFormatSupported (m_lpdataObj, DATADIR_GET, cfFormat));
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::IsFormatAvailable(cfFormat=%x) returning %x\n",
+ this, cfFormat,f));
+
+ return f;
+}
+
+
+//RequestData: Sends data in response to a DDE Request message.
+// for agiven doc and an object.
+
+INTERNAL_(HRESULT) CDefClient::RequestData
+(
+HWND hwndClient,
+ATOM aItem,
+USHORT cfFormat,
+LPHANDLE lphdde
+)
+{
+
+ HRESULT hresult = NOERROR;
+ LPCLIENT lpclient;
+ FORMATETC formatetc;
+ STGMEDIUM medium;
+ // Due to a C7 bug, do not use a structure initialization for STGMEDIUM
+ medium.tymed = TYMED_NULL;
+ medium.hGlobal = 0;
+ medium.pUnkForRelease= NULL;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::RequestData(hwndClient=%x,aItem=%x(%ws),cfFormat=%x,lphdde=%x)\n",
+ this,
+ hwndClient,
+ aItem,
+ wAtomName(aItem),
+ cfFormat,
+ lphdde));
+ ChkC(this);
+
+ // If edit environment Send data if we can
+ if (aItem == aEditItems)
+ {
+ hresult = RequestDataStd (aItem, lphdde);
+ goto exitRtn;
+ }
+
+ hresult = FindItem ((LPOLESTR) MAKEINTATOM(aItem),(LPCLIENT FAR *)&lpclient);
+ if (hresult != NOERROR)
+ {
+ goto errRtn;
+ }
+
+ ChkC (lpclient);
+
+ formatetc.cfFormat = cfFormat;
+ formatetc.ptd = lpclient->m_ptd;
+ formatetc.lindex = DEF_LINDEX;
+ formatetc.dwAspect = DVASPECT_CONTENT;
+ formatetc.tymed = TYMED_HGLOBAL;
+
+
+ hresult = ReportResult(0, DV_E_FORMATETC, 0, 0);
+ if (!lpclient->IsFormatAvailable (formatetc.cfFormat))
+ {
+ goto errRtn;
+ }
+
+
+ // Now ask the item for the given format data
+
+ SendDevInfo (hwndClient);
+
+ wSetTymed (&formatetc);
+ hresult = lpclient->GetData (&formatetc, &medium);
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,
+ "GetData returns hresult=%x\n",
+ hresult));
+ goto errRtn;
+ }
+ if (medium.tymed & ~(TYMED_HGLOBAL | TYMED_MFPICT | TYMED_GDI))
+ {
+ AssertSz (0, "Got a storage medium of type other than hGlobal");
+ goto errRtn;
+ }
+ if (cfFormat == CF_METAFILEPICT)
+ {
+ ChangeOwner (medium.hGlobal);
+ }
+
+
+ // Duplicate the DDE data
+ // medium.hGlobal is freed by MakeDdeData or by the client once the
+ // DDE_DATA is posted with *lphdde.
+ if (MakeDDEData (medium.hGlobal, cfFormat, lphdde, TRUE)){
+ // !!! Why do we have to duplicate the atom
+ DuplicateAtom (aItem);
+ hresult = NOERROR;
+ }
+ else
+ hresult = E_OUTOFMEMORY;
+
+errRtn:
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::RequestData() returning %x\n",
+ this, hresult));
+
+ return hresult;
+}
+
+
+
+// REVIEW: needs review. Item callvback has to be split
+
+// ItemCallback: Calback routine for the server to inform the
+// data changes. When the change message is received, DDE data
+// message is sent to each of the clients depending on the
+// options.
+
+INTERNAL_(HRESULT) CDefClient::ItemCallBack
+(
+ int msg, // notification message
+ LPOLESTR szNewName // for OLE_RENAMED notification
+)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::ItemCallBack(msg=%x,szNewName=%x)\n",
+ this,
+ szNewName));
+
+ HRESULT hresult = NOERROR;
+ BOOL bSaved;
+ LPCLIENT lpclientRename;
+ LPCLIENT lpclient;
+
+ ChkC(this);
+
+ if (msg == OLE_RENAMED) {
+
+ Assert (szNewName);
+ intrDebugOut((DEB_ITRACE,
+ "%x ::ItemCallBack(szNewName=(%ws))\n",
+ WIDECHECK(szNewName)));
+
+
+ if (!m_bContainer)
+ {
+ lpclient = (LPCLIENT)GetWindowLong (m_hwnd, 0);
+ Assert (lpclient==m_pdoc);
+ }
+ else
+ lpclient = this;
+
+ Assert (lpclient->m_chk==chkDefClient);
+
+ // Replace the internally-stored name
+ if (lpclient->m_aItem)
+ {
+ GlobalDeleteAtom (lpclient->m_aItem);
+ lpclient->m_aItem = wGlobalAddAtom (szNewName);
+ }
+
+
+ // find if any StdDocName item is present at all
+ if (lpclientRename =
+ lpclient->SearchItem ((LPOLESTR) MAKEINTATOM(aStdDocName)))
+ {
+ HANDLE hDdeData=NULL;
+
+ //
+ // We have a new name in UNICODE. Need to create a new
+ // name in ANSI.
+ //
+ LPSTR lpName = CreateAnsiFromUnicode(szNewName);
+
+ HANDLE hNewName = wNewHandle (lpName, strlen(lpName) + 1);
+
+ PrivMemFree(lpName);
+
+ // hNewName is freed by MakeDDEData
+
+ if (!MakeDDEData (hNewName, (int)g_cfBinary, &hDdeData, FALSE))
+ {
+ hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ goto errrtn;
+ }
+
+ Assert (hDdeData);
+ lpclientRename->SendRenameMsgs (hDdeData);
+ GlobalFree (hDdeData);
+
+ // Post termination for each of the doc clients that did not
+ // advise on rename
+ lpclient->TerminateNonRenameClients (lpclientRename);
+ }
+
+
+ Assert (FALSE == lpclient->m_fEmbed);
+
+ // REVIEW: what is this?
+ //lpclient->m_fEmbed = FALSE;
+
+ hresult = NOERROR;
+
+ errrtn:
+ Assert (hresult == NOERROR);
+ goto exitRtn;
+
+ } else {
+
+ // Enumerate all the clients and send DDE_DATA if necessary.
+ bSaved = SendDataMsg (msg);
+
+ // REVIEW: Hack from 1.0 for old pre-OLE-library apps
+ if ((msg == OLE_SAVED) && m_fEmbed && !bSaved)
+ return ReportResult(0, RPC_E_DDE_CANT_UPDATE, 0, 0);
+
+ hresult = NOERROR;
+ }
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::ItemCallBack() returning hresult=%x\n",
+ this,hresult));
+
+ return(hresult);
+}
+
+
+// This func should definitely be replaced by use of MFC map. (IsEmpty)
+INTERNAL_(BOOL) AreNoClients (HANDLE hcli)
+{
+ HANDLE hcliPrev = NULL;
+ PCLILIST pcli;
+ HANDLE *phandle;
+
+ while (hcli) {
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ {
+ Puth (hcli);
+ Putn();
+ Assert(0);
+ return TRUE;
+ }
+
+ phandle = (HANDLE *) pcli->info;
+ while (phandle < (HANDLE *)(pcli + 1))
+ {
+ if (*phandle)
+ {
+ LocalUnlock (hcli);
+ return FALSE;
+ }
+ phandle++;
+ phandle++;
+ }
+ hcliPrev = hcli;
+ hcli = pcli->hcliNext;
+ LocalUnlock (hcliPrev);
+ }
+ return TRUE;
+}
+
+
+#ifdef _DEBUG
+// For use in CodeView
+// NOTE: Returns a static string
+INTERNAL_(LPOLESTR) a2s (ATOM a)
+{
+ static WCHAR sz[256];
+ GlobalGetAtomName (a, sz, 256);
+ return sz;
+}
+#endif
diff --git a/private/ole32/com/remote/dde/server/item2.cxx b/private/ole32/com/remote/dde/server/item2.cxx
new file mode 100644
index 000000000..20def4815
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/item2.cxx
@@ -0,0 +1,1400 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: item2.cxx
+//
+// Contents:
+//
+// Classes:
+//
+// Functions:
+//
+// History: 6-07-94 kevinro Converted to NT and commented
+//
+//----------------------------------------------------------------------------
+
+#include "ole2int.h"
+#include <dde.h>
+#include "ddeatoms.h"
+#include "ddedebug.h"
+#include "srvr.h"
+#include "itemutil.h"
+#include "trgt_dev.h"
+#include <stddef.h>
+#ifndef WIN32
+// #include <print.h>
+#endif
+
+ASSERTDATA
+
+
+INTERNAL_(void) CDefClient::TerminateNonRenameClients
+(
+LPCLIENT lprenameClient
+)
+{
+
+ HANDLE hcliPrev = NULL;
+ PCLILIST pcli;
+ HANDLE *phandle;
+ HANDLE hcli;
+ HWND hwndClient;
+ LPCLIENT lpdocClient;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::TerminateNonRenameClients(lprenClient=%x)\n",
+ this,
+ lprenameClient));
+
+ // items also keep the parents window handle.
+ hwndClient = m_hwnd;
+ lpdocClient = (LPCLIENT)GetWindowLong (m_hwnd, 0);
+
+
+ hcli = m_hcliInfo;
+ while (hcli)
+ {
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ {
+ break;
+ }
+
+ phandle = (HANDLE *) (pcli->info);
+ while (phandle < (HANDLE *)(pcli + 1))
+ {
+ if (*phandle)
+ {
+ // This client is in the rename list. So, no termination
+ if(!FindClient (lprenameClient->m_hcliInfo, *phandle, FALSE))
+ {
+
+#ifdef KEVINRO_I_CHANGED_THIS
+//
+// BUGBUG: (KevinRo) I don't understand why this didn't just call Terminate() instead.
+// There may be the potential for problems on this PostMessageToClient, since it doesn't
+// do the ModalLoop stuff. It is going to busy wait by doing Peeks
+//
+// I have changed this to call Terminate
+//
+ PostMessageToClientWithReply ((HWND)*phandle,
+ WM_DDE_TERMINATE,
+ (UINT) hwndClient, NULL,
+ WM_DDE_TERMINATE);
+#endif
+ //
+ // Terminate will send a WM_DDE_TERMINATE at the client
+ //
+ Terminate((HWND)*phandle,hwndClient);
+
+ // delete this client from all the items lists.
+ lpdocClient->DeleteFromItemsList ((HWND)*phandle);
+ }
+ }
+ phandle++;
+ phandle++;
+ }
+
+ hcliPrev = hcli;
+ hcli = pcli->hcliNext;
+ LocalUnlock (hcliPrev);
+ }
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::TerminateNonRenameClients\n",
+ this));
+
+}
+
+
+
+INTERNAL CDefClient::Terminate
+ (HWND hwndTo,
+ HWND hwndFrom)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::Terminate hwndTo=%x hwndFrom=%x\n",
+ this,
+ hwndTo,
+ hwndFrom));
+
+ CALLDATA CD;
+ IID iid = CLSID_NULL;
+ DDECALLDATA DdeCD;
+ HRESULT hresult;
+
+ DdeCD.hwndSvr = hwndTo;
+ DdeCD.hwndCli = hwndFrom;
+ DdeCD.wMsg = WM_DDE_TERMINATE;
+ DdeCD.wParam = (WPARAM)hwndFrom,
+ DdeCD.lParam = 0;
+ DdeCD.fInitialSend = FALSE;
+
+ CD.id = CALLDATAID_UNUSED;
+ CD.lid = iid;
+ CD.TIDCallee = 0;
+ CD.pRpcMsg = (LPVOID) &DdeCD;
+ CD.CallCat = CALLCAT_SYNCHRONOUS;
+ CD.Event = 0;
+
+ //
+ // Setting the pCallData variable effects the way that the
+ // DocWndProc handles WM_DDE_TERMINATE. If it is set, then this
+ // object initiated the terminate, and will not reply to the
+ // TERMINATE. It will allow us to leave the CallRunModalLoop
+ //
+ m_pCallData = &CD;
+
+ hresult = m_pCallControl->CallRunModalLoop(&CD);
+
+ m_pCallData = NULL;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::Terminate hresult = %x\n",
+ this,hresult));
+
+ return(hresult);
+}
+
+
+INTERNAL_(void) CDefClient::SendTerminateMsg ()
+{
+
+ HANDLE hcliPrev = NULL;
+ PCLILIST pcli;
+ HANDLE *phandle;
+ HANDLE hcli;
+ HWND hwnd;
+ LPCLIENT lpdocClient;
+ static int staticcounter;
+ int counter = ++staticcounter;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::SendTerminateMsg\n",
+ this));
+
+ // items also keep the document's window handle
+
+ Assert (IsWindow (m_hwnd));
+
+ if (!IsWindow (m_hwnd))
+ {
+ goto exitRtn;
+ }
+
+ hwnd = m_hwnd;
+
+ lpdocClient = (LPCLIENT)GetWindowLong (m_hwnd, 0);
+
+ Assert (lpdocClient);
+
+ if (NULL==lpdocClient)
+ {
+ goto exitRtn;
+ }
+
+ Assert (lpdocClient==m_pdoc);
+ AssertIsDoc (lpdocClient);
+ // If "this" is a document (container) then iterate through
+ // and terminate all its client windows. If "this" is an item
+ // just terminate that item's client windows.
+ hcli = m_bContainer ? lpdocClient->m_hcli : m_hcliInfo;
+ while (hcli)
+ {
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ {
+ goto exitRtn;
+ }
+ phandle = (HANDLE *) (pcli->info);
+ while (phandle < (HANDLE *)(pcli + 1))
+ {
+ if ((HWND)*phandle)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "%x ::SendTerminateMsg on hwnd=%x\n",
+ this,
+ (HWND)*phandle));
+
+ Terminate ((HWND)*phandle, hwnd);
+
+ Assert (lpdocClient->m_cClients > 0);
+
+ lpdocClient->m_cClients--;
+
+ HWND hwndClient = *(HWND *)phandle;
+ // This window is no longer a client.
+
+ // Remove window from document's master list
+ // and its item's list.
+ lpdocClient->DeleteFromItemsList (hwndClient);
+ }
+ //
+ // (KevinRo): Don't understand why the phandle is
+ // incremented twice. This is the same as the original
+ // code. Leaving it for now, since I don't have enough
+ // information.
+ //
+ phandle++;
+ phandle++;
+ }
+
+ hcliPrev = hcli;
+ hcli = pcli->hcliNext;
+ LocalUnlock (hcliPrev);
+ }
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::SendTerminateMsg\n",
+ this));
+
+}
+
+
+
+// SendRenameMsg: enumerates the clients for the rename item
+// and sends rename message for all the clients.
+
+INTERNAL_(void) CDefClient::SendRenameMsgs
+(
+HANDLE hddeRename
+)
+{
+ ATOM aData = NULL;
+ HANDLE hdde = NULL;
+ PCLINFO pclinfo = NULL;
+ HWND hwndClient;
+
+ HANDLE hcliPrev = NULL;
+ PCLILIST pcli;
+ HANDLE *phandle;
+ HANDLE hcli;
+ HANDLE hcliInfo;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::SendRenameMsgs(hddeRename=%x)\n",
+ this,
+ hddeRename));
+
+ hcli = m_hcliInfo;
+ LPARAM lp;
+ while (hcli)
+ {
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ {
+ goto exitRtn;
+ }
+
+
+ phandle = (HANDLE *) (pcli->info);
+ while (phandle < (HANDLE *)(pcli + 1))
+ {
+ if (*phandle++)
+ {
+ hdde = NULL;
+ aData = NULL;
+
+ if (!(pclinfo = (PCLINFO) LocalLock (hcliInfo = *phandle++)))
+ {
+ goto exitRtn;
+ }
+
+
+ // Make the item atom with the options.
+ aData = DuplicateAtom (aStdDocName);
+ hdde = UtDupGlobal (hddeRename,GMEM_MOVEABLE);
+
+ hwndClient = pclinfo->hwnd;
+ LocalUnlock (hcliInfo);
+
+ // Post the message
+
+ lp = MAKE_DDE_LPARAM(WM_DDE_DATA,hdde,aData);
+
+ if (!PostMessageToClient (hwndClient,
+ WM_DDE_DATA,
+ (UINT) m_hwnd,
+ lp))
+ {
+ DDEFREE(WM_DDE_DATA,lp);
+ if (hdde)
+ GlobalFree (hdde);
+ if (aData)
+ GlobalDeleteAtom (aData);
+ }
+ }
+ else
+ {
+ phandle++;
+ }
+
+ }
+
+ hcliPrev = hcli;
+ hcli = pcli->hcliNext;
+ LocalUnlock (hcliPrev);
+ }
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::SendRenameMsgs void return\n",
+ this));
+
+}
+
+
+
+INTERNAL_(BOOL) CDefClient::SendDataMsg
+(
+WORD msg // notification message
+)
+{
+
+ HANDLE hcliPrev = NULL;
+ PCLILIST pcli;
+ HANDLE *phandle;
+ HANDLE hcli;
+ BOOL bSaved = FALSE;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::SendDataMsg(msg=%x)\n",
+ this,
+ msg));
+
+ hcli = m_hcliInfo;
+ while (hcli)
+ {
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ {
+ break;
+ }
+ phandle = (HANDLE *) (pcli->info);
+ while (phandle < (HANDLE *)(pcli + 1)) {
+ if (*phandle++)
+ bSaved = SendDataMsg1 (*phandle++, msg);
+ else
+ phandle++;
+ }
+
+ hcliPrev = hcli;
+ hcli = pcli->hcliNext;
+ LocalUnlock (hcliPrev);
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::SendDataMsg() returns %x)\n",
+ this,bSaved));
+
+ return bSaved;
+}
+
+
+
+//SendDataMsg: Send data to the clients, if the data change options
+//match the data advise options.
+
+INTERNAL_(BOOL) CDefClient::SendDataMsg1
+(
+HANDLE hclinfo, // handle of the client info
+WORD msg // notification message
+)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::SendDataMsg1(hclinfo=%x,msg=%x)\n",
+ this,
+ hclinfo,
+ msg));
+
+ PCLINFO pclinfo = NULL;
+ HANDLE hdde = NULL;
+ ATOM aData = NULL;
+ HRESULT retval;
+ BOOL bSaved = FALSE;
+
+
+ ChkC (this);
+ if (m_lpdataObj == NULL) goto errRtn;
+
+ // LATER: Allow server to give us other tymed's beside HGLOBAL and do
+ // the conversion ourselves, e.g., IStorageToHGlobal()
+
+ FORMATETC formatetc;// = {0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ STGMEDIUM medium;// = {TYMED_NULL, NULL, NULL};
+ formatetc.ptd = m_ptd;
+ formatetc.dwAspect = DVASPECT_CONTENT;
+ formatetc.lindex = DEF_LINDEX;
+ formatetc.tymed = TYMED_HGLOBAL;
+ medium.tymed = TYMED_NULL;
+ medium.hGlobal=0; // not really necessary
+ medium.pUnkForRelease = NULL;
+
+ if (!(pclinfo = (PCLINFO) LocalLock (hclinfo)))
+ {
+ goto errRtn;
+ }
+
+ // if the client dead, then no message
+ if (!IsWindowValid(pclinfo->hwnd))
+ {
+ goto errRtn;
+ }
+
+
+ //
+ // (KevinRo) UPDATE was not defined in the OLE 2.01 code base
+ //
+#ifdef UPDATE
+ // OLE_SAVED is what 1.0 clients expect to get for embedded objects.
+ if (msg==OLE_CHANGED && m_fEmbed)
+ msg=OLE_SAVED;
+#endif
+
+ if (pclinfo->options & (0x0001 << msg))
+ {
+ bSaved = TRUE;
+ SendDevInfo (pclinfo->hwnd);
+
+ // send message if the client needs data for every change or
+ // only for the selective ones he wants.
+
+ // now look for the data option.
+ if (pclinfo->bnative){
+ // prepare native data
+ if (pclinfo->bdata){
+
+ // Wants the data with DDE_DATA message
+ // Get native data from the server.
+
+ // GetData
+ formatetc.cfFormat = g_cfNative;
+ wSetTymed (&formatetc);
+ retval = GetData (&formatetc, &medium);
+
+ if (retval != NOERROR)
+ {
+ Assert(0);
+ goto errRtn;
+ }
+ Assert (medium.tymed==TYMED_HGLOBAL);
+ Assert (medium.hGlobal);
+
+ // Prepare the DDE data block.
+ // REVIEW: MakeDDEData frees medium.hGlobal manually, but should
+ // really call ReleaseStgMedium.
+ if(!MakeDDEData (medium.hGlobal, (int)g_cfNative, (LPHANDLE)&hdde, FALSE))
+ {
+ goto errRtn;
+ }
+ }
+
+
+ // Make the item atom with the options.
+ aData = MakeDataAtom (m_aItem, msg);
+
+ intrDebugOut((DEB_ITRACE,
+ "%x ::SendDataMsg1 send NativeData to hwnd=%x"
+ "format %x\n",
+ this,
+ pclinfo->hwnd,
+ pclinfo->format));
+
+ LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_DATA,hdde,aData);
+ if (!PostMessageToClient(pclinfo->hwnd,
+ WM_DDE_DATA,
+ (UINT) m_hwnd,
+ lp))
+
+
+ {
+ DDEFREE(WM_DDE_DATA,lp);
+ //
+ // The two data items will be free'd on exit
+ //
+ goto errRtn;
+ }
+ hdde = NULL;
+ aData = NULL;
+ }
+
+
+ // Now post the data for the display format
+
+ if (pclinfo->format)
+ {
+ if (pclinfo->bdata)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "%x ::SendDataMsg1 GetData on cf = %x\n",
+ pclinfo->format));
+ // Must reset because previous call to GetData set it.
+ medium.tymed = TYMED_NULL;
+
+ // GetData
+ formatetc.cfFormat = pclinfo->format;
+ wSetTymed (&formatetc);
+ Assert (IsValidInterface (m_lpdataObj));
+ retval = m_lpdataObj->GetData (&formatetc, &medium);
+
+ if (retval != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,
+ "m_lpdataObj->GetData returns %x\n",
+ retval));
+ goto errRtn;
+ }
+
+
+ if (pclinfo->format == CF_METAFILEPICT)
+ ChangeOwner (medium.hGlobal);
+
+ if(!MakeDDEData (medium.hGlobal, pclinfo->format, (LPHANDLE)&hdde, FALSE))
+ goto errRtn;
+
+ }
+
+ // atom is deleted. So, we need to duplicate for every post
+ aData = MakeDataAtom (m_aItem, msg);
+ // now post the message to the client;
+ intrDebugOut((DEB_ITRACE,
+ "%x ::SendDataMsg1 send PresentationData to hwnd=%x"
+ " cf=%x\n",
+ this,
+ pclinfo->hwnd,
+ pclinfo->format));
+
+ LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_DATA,hdde,aData);
+
+ if (!PostMessageToClient(pclinfo->hwnd,
+ WM_DDE_DATA,
+ (UINT) m_hwnd,
+ lp))
+ {
+ DDEFREE(WM_DDE_DATA,lp);
+ goto errRtn;
+ }
+
+ hdde = NULL;
+ aData = NULL;
+ }
+
+ }
+
+
+errRtn:
+ if (pclinfo)
+ LocalUnlock (hclinfo);
+
+ if (hdde)
+ GlobalFree (hdde);
+
+ if (aData)
+ GlobalDeleteAtom (aData);
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::SendDataMsg1() returns %x\n",
+ this,bSaved));
+
+
+ return bSaved;
+
+}
+
+
+
+// FixWriteBug
+//
+// `Write' gives a target device that is missing a NULL between
+// the device name and the driver name. This function creates
+// a fixed 1.0 target device.
+//
+// REVIEW: There is another Write bug we should work around.
+// Write does not send the "extra bytes" that are supposed to follow
+// the DEVMODE. It puts the Environment immediately after the DEVMODE.
+// So the driver will read the Environment thinking it is the extra bytes.
+// To fix this, FixWriteBug() should zero out the Environment bytes; the
+// 2.0 target device does not use them anyway.
+//
+ INTERNAL FixWriteBug
+ (HANDLE hTD,
+ LPHANDLE ph)
+{
+ HRESULT hresult;
+ LPBYTE pChunk2;
+ LPBYTE pNewChunk2;
+ const LPCOLETARGETDEVICE ptd1 = (LPCOLETARGETDEVICE) GlobalLock (hTD);
+ RetZS (ptd1, E_OUTOFMEMORY);
+
+ HANDLE hNew = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE,
+ GlobalSize (hTD) + 1);
+ RetZS (hNew, E_OUTOFMEMORY);
+ const LPBYTE pNew = (LPBYTE) GlobalLock (hNew);
+ RetZS (pNew, E_OUTOFMEMORY);
+ ULONG cbChunk1 = 7 * sizeof(UINT) + ptd1->otdDriverNameOffset;
+ ULONG cbChunk2 = GlobalSize (hTD) - cbChunk1;
+ ErrZS (!IsBadWritePtr (pNew, (UINT)cbChunk1), E_OUTOFMEMORY);
+ memcpy (pNew, ptd1, cbChunk1);
+ pNew[cbChunk1] = '\0'; // insert the missing NULL
+
+ pNewChunk2 = pNew + cbChunk1 + 1;
+ pChunk2 = (LPBYTE)ptd1 + cbChunk1;
+ ErrZS (!IsBadWritePtr (pNewChunk2, (UINT)cbChunk2), E_OUTOFMEMORY);
+ Assert (!IsBadReadPtr (pChunk2, (UINT)cbChunk2));
+ memcpy (pNewChunk2, pChunk2, cbChunk2);
+
+ // Fix up the offsets to accomodate the added NULL
+ #define macro(x) if (ptd1->otd##x##Offset > ptd1->otdDeviceNameOffset)\
+ ((LPOLETARGETDEVICE)pNew)->otd##x##Offset++;
+ macro (DriverName)
+ macro (PortName)
+ macro (ExtDevmode)
+ macro (Environment)
+ #undef macro
+
+ GlobalUnlock (hNew);
+ GlobalUnlock (hTD);
+ *ph = hNew;
+ return NOERROR;
+
+ errRtn:
+ if (pNew)
+ GlobalUnlock (hNew);
+ if (ptd1)
+ GlobalUnlock (hTD);
+ return hresult;
+}
+
+
+
+
+
+
+// Convert10TargetDevice
+//
+INTERNAL Convert10TargetDevice
+ (HANDLE hTD, // 1.0 Target Device
+ DVTARGETDEVICE FAR* FAR* pptd2) // Out parm, corresponding 2.0 TD
+{
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN Convert10TargetDevice hTD=%x\n",hTD));
+
+ ULONG cbData1, cbData2;
+
+ if (NULL==hTD)
+ {
+ Assert(0);
+ return ReportResult(0, E_INVALIDARG, 0, 0);
+ }
+
+ if (*pptd2)
+ {
+ // delete old target device
+ PrivMemFree(*pptd2);
+ *pptd2 = NULL;
+ }
+
+ LPOLETARGETDEVICE ptd1 = (LPOLETARGETDEVICE) GlobalLock (hTD);
+
+ RetZS (ptd1, E_OUTOFMEMORY);
+
+ if ((ptd1->otdDeviceNameOffset < ptd1->otdDriverNameOffset)
+ && (ptd1->otdDeviceNameOffset
+ + strlen (LPSTR(((BYTE *)ptd1->otdData) +
+ ptd1->otdDeviceNameOffset)) + 1 > ptd1->otdDriverNameOffset))
+ {
+ // No NULL between device and driver name
+ HANDLE hNew;
+ GlobalUnlock (hTD);
+ RetErr (FixWriteBug (hTD, &hNew));
+ HRESULT hresult = Convert10TargetDevice (hNew, pptd2);
+ Verify (0==GlobalFree (hNew));
+ return hresult;
+ }
+ // Word Bug
+ DEVMODEA UNALIGNED *pdevmode = (DEVMODEA UNALIGNED *)
+ (((BYTE *)ptd1->otdData)+ ptd1->otdExtDevmodeOffset);
+
+ if ( HIBYTE(pdevmode->dmSpecVersion) < 3
+ || HIBYTE(pdevmode->dmSpecVersion) > 6
+ || pdevmode->dmDriverExtra > 0x1000)
+ {
+ if (0==ptd1->otdEnvironmentSize)
+ {
+ // Sometimes Word does not give an environment.
+ ptd1->otdExtDevmodeOffset = 0;
+ ptd1->otdExtDevmodeSize = 0;
+ }
+ else
+ {
+ // DevMode is garbage, use environment instead.
+ ptd1->otdExtDevmodeOffset = ptd1->otdEnvironmentOffset;
+ ptd1->otdExtDevmodeSize = ptd1->otdEnvironmentSize;
+ }
+ }
+
+ // These next assert does not HAVE to be true,
+ // but it's a sanity check.
+ Assert (ptd1->otdDeviceNameOffset
+ + strlen (LPSTR(((BYTE *)ptd1->otdData) +
+ ptd1->otdDeviceNameOffset)) + 1
+ == ptd1->otdDriverNameOffset);
+
+
+ // Excel has zeroes for DevMode and Environment offsets and sizes
+
+ // Calculate size of Data block. Many 1.0 clients don't make their
+ // target device data block big enough for the DEVMODE.dmDriverExtra
+ // bytes (and they don't copy those bytes either). We can't reconstruct
+ // the bytes out of thin air, but we can at least make sure there's not
+ // a GP fault when the printer driver tries to access those bytes in
+ // a call to CreateDC. Any extra bytes are zeroed.
+ cbData2 = ptd1->otdExtDevmodeOffset + ptd1->otdExtDevmodeSize;
+
+ if (ptd1->otdExtDevmodeOffset != 0)
+ {
+ cbData2 += ((DEVMODEA UNALIGNED *)((LPBYTE)ptd1->otdData +
+ ptd1->otdExtDevmodeOffset))->dmDriverExtra;
+ }
+
+ cbData2 = max (cbData2,
+ ptd1->otdPortNameOffset + strlen (LPCSTR(
+ ((BYTE *)ptd1->otdData) + ptd1->otdPortNameOffset)) + 1);
+
+ // Calculate size of OLE2 Target Device
+ //
+ // Its the size of the DVTARGETDEVICE header, plus the cbData2
+ // The definition of DVTARGETDEVICE currently uses an unsized array
+ // of bytes at the end, therefore we can not just do a sizeof().
+ //
+
+ ULONG cbTD2 = SIZEOF_DVTARGETDEVICE_HEADER + cbData2;
+
+ // Allocate OLE2 Target Device
+ *pptd2 = (DVTARGETDEVICE FAR*) PrivMemAlloc(cbTD2);
+ if (IsBadWritePtr (*pptd2, cbTD2)
+ || IsBadWritePtr ((*pptd2)->tdData, cbData2))
+ {
+ AssertSz (0, "out of memory");
+ GlobalUnlock (hTD);
+ return ResultFromScode (E_OUTOFMEMORY);
+ }
+ _fmemset (*pptd2, '\0', cbTD2);
+
+ // OLE2 offsets are from the beginning of the DVTARGETDEVICE
+ const ULONG cbOffset = offsetof (DVTARGETDEVICE, tdData);
+
+ // Fill in new Target Device
+
+ (*pptd2)->tdSize = cbTD2;
+
+ #define Convert(a) \
+ ((*pptd2)->td##a##Offset = (USHORT)(ptd1->otd##a##Offset + cbOffset))
+
+ Convert (DeviceName);
+ Convert (DriverName);
+ Convert (PortName);
+ if (ptd1->otdExtDevmodeOffset != 0)
+ Convert (ExtDevmode);
+ else // Excel uses 0
+ (*pptd2)->tdExtDevmodeOffset = 0;
+
+ // Calculate size of 1.0 data block in case the 1.0 target
+ // device is incorrectly not big enough.
+ cbData1 = (size_t) GlobalSize(hTD) - offsetof (OLETARGETDEVICE, otdData);
+
+ #undef Convert
+ _fmemcpy ((*pptd2)->tdData, ptd1->otdData, min(cbData1, cbData2));
+
+ GlobalUnlock (hTD);
+
+ //
+ // At this point, pptd2 holds an ANSI version of a DVTARGET device
+ //
+ // Now, we need to convert it to a UNICODE version. There are routines
+ // for doing this in the UTILS.H file.
+ //
+
+ DVTDINFO dvtdInfo;
+ DVTARGETDEVICE * pdvtd32 = NULL;
+ HRESULT hr;
+
+ hr = UtGetDvtd16Info(*pptd2, &dvtdInfo);
+ if (hr != NOERROR)
+ {
+ goto errRtn;
+ }
+
+ pdvtd32 = (DVTARGETDEVICE *) PrivMemAlloc(dvtdInfo.cbConvertSize);
+
+ if (pdvtd32 == NULL)
+ {
+ goto errRtn;
+ }
+
+ hr = UtConvertDvtd16toDvtd32(*pptd2, &dvtdInfo, pdvtd32);
+
+ if (hr != NOERROR)
+ {
+ PrivMemFree(pdvtd32);
+ pdvtd32=NULL;
+ }
+
+errRtn:
+
+ PrivMemFree(*pptd2);
+ *pptd2 = pdvtd32;
+
+ return hr;
+}
+//+---------------------------------------------------------------------------
+//
+// Method: CDefClient::PokeStdItems
+//
+// Synopsis: Pokes the data for the standard items.
+//
+// Effects:
+//
+// For StdHostnames, StdDocDimensions and SetColorScheme the data is
+// sent immediately and for the the StdTargetDeviceinfo the
+// data is set in each client block and the data is sent just
+// before the GetData call for rendering the right data.
+//
+// Arguments: [hwndClient] --
+// [aItem] --
+// [hdata] --
+// [index] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 6-07-94 kevinro Commented
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL CDefClient::PokeStdItems(HWND hwndClient,
+ ATOM aItem,
+ HANDLE hdata,
+ int index)
+{
+ DDEDATA FAR * lpdata = NULL;
+ HANDLE hnew = NULL;
+ LPHOSTNAMES lphostnames;
+ HRESULT retval = E_OUTOFMEMORY;
+ WORD format;
+ BOOL fRelease;
+
+ intrDebugOut((DEB_ITRACE,
+ "%p _IN CDefClient::PokeStdItems(hwndClient=%x,aItem=%x(%ws)hdata=%x,index=%x)\n",
+ this,
+ hwndClient,
+ aItem,
+ wAtomName(aItem),
+ hdata,
+ index));
+
+ if (m_fGotEditNoPokeNativeYet)
+ {
+ // We got StdEdit, but instead of getting Poke for native data,
+ // we got poke for some std items. So we want to generate InitNew()
+ // call for the object.
+
+ DoInitNew(); // the function clears the flag
+ }
+
+ if(!(hdata && (lpdata = (DDEDATA FAR *)GlobalLock (hdata))))
+ {
+ goto errRtn;
+ }
+
+ format = lpdata->cfFormat;
+ fRelease = lpdata->fRelease;
+
+ AssertSz (format == (int)g_cfBinary, "Format is not binary");
+
+ // we have extracted the data successfully.
+ m_lpoleObj = m_lpoleObj;
+
+ if (index == STDHOSTNAMES)
+ {
+ lphostnames = (LPHOSTNAMES)lpdata->Value;
+ //
+ // The client should have sent the HOSTNAMES in ANSI. This
+ // means we need to convert them to UNICODE before we can
+ // use them.
+ //
+ LPOLESTR lpstrClient = CreateUnicodeFromAnsi((LPSTR)(lphostnames->data) + lphostnames->clientNameOffset);
+ LPOLESTR lpstrDoc = CreateUnicodeFromAnsi((LPSTR)(lphostnames->data) + lphostnames->documentNameOffset);
+
+ intrDebugOut((DEB_ITRACE,
+ "%p ::PokeStdItems setting hostnames Client(%ws) Doc(%ws) \n",
+ this,
+ lpstrClient,
+ lpstrDoc));
+
+ retval = (HRESULT)m_lpoleObj->SetHostNames(lpstrClient,lpstrDoc);
+
+ if (retval==NOERROR)
+ {
+ m_fDidRealSetHostNames = TRUE;
+ }
+
+ PrivMemFree(lpstrClient);
+ PrivMemFree(lpstrDoc);
+
+ goto end;
+ }
+
+
+ if (index == STDDOCDIMENSIONS)
+ {
+
+ SIZEL size;
+ size.cy = ((LPRECT16)(lpdata->Value))->top;
+ size.cx = ((LPRECT16)(lpdata->Value))->left;
+ intrDebugOut((DEB_ITRACE,
+ "%p ::PokeStdItems STDDOCDIMENSIONS cy=%x cx=%x\n",
+ this,
+ size.cy,
+ size.cx));
+ retval = m_lpoleObj->SetExtent (DVASPECT_CONTENT, &size);
+
+ goto end;
+
+ }
+
+
+ if (index == STDCOLORSCHEME) {
+ intrDebugOut((DEB_ITRACE,
+ "%p ::PokeStdItems setting STDCOLORSCHEME\n",this));
+
+ retval = m_lpoleObj->SetColorScheme((LPLOGPALETTE)(lpdata->Value));
+
+ goto end;
+ }
+
+ // Target Device
+ if (index == STDTARGETDEVICE)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "%p ::PokeStdItems setting STDTARGETDEVICE\n",this));
+
+ if (!(hnew = MakeItemData ((DDEPOKE FAR *)lpdata, hdata, format)))
+ goto errRtn;
+
+ retval = Convert10TargetDevice (hnew, &m_ptd);
+ goto end;
+
+ }
+ retval = E_UNEXPECTED;
+
+ intrAssert(!"::PokeStdItems - Unknown index\n");
+
+ //
+ // (KevinRo) Found the following line already commented out.
+ //
+ //(HRESULT)SetStdInfo (hwndClient, (LPOLESTR) (MAKELONG(STDTARGETDEVICE,0)),hnew);
+
+end:
+errRtn:
+ if (hnew)
+ // can only be global memory block
+ GlobalFree (hnew);
+
+ if (lpdata) {
+ GlobalUnlock (hdata);
+ if (retval == NOERROR && fRelease)
+ GlobalFree (hdata);
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "%p _OUT CDefClient::PokeStdItems() hresult = %x\n",
+ this,
+ retval));
+
+ return retval;
+}
+
+
+
+
+
+
+// SetStdInfo: Sets the targetdevice info. Creates a client
+// for "StdTargetDevice". This item is created only within the
+// lib and it is never visible in server app. When the change
+// message comes from the server app, before we ask for
+// the data, we send the targetdevice info if there is
+// info for the client whom we are trying to send the data
+// on advise.
+
+
+INTERNAL_(HRESULT) CDefClient::SetStdInfo
+(
+HWND hwndClient,
+LPOLESTR lpitemname,
+HANDLE hdata
+)
+{
+ HANDLE hclinfo = NULL;
+ PCLINFO pclinfo = NULL;
+ LPCLIENT lpclient;
+ HRESULT retval = NOERROR;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::SetStdInfo(hwndClient=%x,ItemName=(%ws),hdata=%x)\n",
+ this,
+ hwndClient,
+ lpitemname,
+ hdata));
+ //
+ // first create/find the StdTargetDeviceItem.
+ //
+
+ if ((lpclient = SearchItem (lpitemname)) == NULL)
+ {
+ retval = (HRESULT)RegisterItem (lpitemname,(LPCLIENT FAR *)&lpclient, FALSE);
+ if (retval != NOERROR)
+ {
+ goto errRtn;
+ }
+ }
+
+ if(hclinfo = FindClient (lpclient->m_hcliInfo, hwndClient, FALSE))
+ {
+ if (pclinfo = (PCLINFO) LocalLock (hclinfo))
+ {
+ if (pclinfo->hdevInfo)
+ GlobalFree (pclinfo->hdevInfo);
+ pclinfo->bnewDevInfo = TRUE;
+ if (hdata)
+ pclinfo->hdevInfo = UtDupGlobal (hdata,GMEM_MOVEABLE);
+ else
+ pclinfo->hdevInfo = NULL;
+ pclinfo->hwnd = hwndClient;
+ LocalUnlock (hclinfo);
+
+ // We do not have to reset the client because we did not
+ // change the handle it self.
+ }
+ }
+ else
+ {
+ // Create the client structure to be attcahed to the object.
+ hclinfo = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (CLINFO));
+ if (hclinfo == NULL || (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL)
+ goto errRtn;
+
+ pclinfo->bnewDevInfo = TRUE;
+ if (hdata)
+ pclinfo->hdevInfo = UtDupGlobal (hdata,GMEM_MOVEABLE);
+ else
+ pclinfo->hdevInfo = NULL;
+
+ pclinfo->hwnd = hwndClient;
+ LocalUnlock (hclinfo);
+
+
+ // Now add this client to item client list
+ // !!! This error recovery is not correct.
+ if (!AddClient ((LPHANDLE)&lpclient->m_hcliInfo, hwndClient, hclinfo))
+ goto errRtn;
+ }
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::SetStdInfo() hresult=%x\n",
+ this,retval));
+
+ return retval;
+errRtn:
+ Assert(0);
+ if (pclinfo)
+ LocalUnlock (hclinfo);
+
+ if (hclinfo)
+ LocalFree (hclinfo);
+
+ retval = E_OUTOFMEMORY;
+ goto exitRtn;
+}
+
+
+// SendDevInfo: Sends targetdevice info to the the object.
+// Caches the last targetdevice info sent to the object.
+// If the targetdevice block is same as the one in the
+// cache, then no targetdevice info is sent.
+// (!!! There might be some problem here getting back
+// the same global handle).
+
+INTERNAL_(void) CDefClient::SendDevInfo
+(
+HWND hWndCli
+)
+{
+
+ HANDLE hclinfo = NULL;
+ PCLINFO pclinfo = NULL;
+ HANDLE hdata;
+ LPCLIENT lpdocClient;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::SendDevInfo(hwndCli=%x)\n",
+ this,
+ hWndCli));
+#if 0
+ if (!m_bContainer)
+ lpdocClient = (LPCLIENT)GetWindowLong (m_hwnd, 0);
+ else
+ lpdocClient = this;
+#endif
+
+ // find if any StdTargetDeviceInfo item is present at all
+ AssertIsDoc(m_pdoc);
+ lpdocClient = m_pdoc->SearchItem ((LPOLESTR) (MAKELONG(STDTARGETDEVICE, 0)));
+ if (lpdocClient == NULL)
+ {
+ goto exitRtn;
+ }
+
+ hclinfo = FindClient (lpdocClient->m_hcliInfo, hWndCli, FALSE);
+
+ // This client has not set any target device info. no need to send
+ // any stdtargetdevice info
+ if (hclinfo != NULL) {
+ if (!(pclinfo = (PCLINFO)LocalLock (hclinfo)))
+ goto end;
+
+ // if we cached it, do not send it again.
+ if ((!pclinfo->bnewDevInfo) && pclinfo->hdevInfo == m_hdevInfo)
+ goto end;
+
+ pclinfo->bnewDevInfo = FALSE;
+ if(!(hdata = UtDupGlobal (pclinfo->hdevInfo,GMEM_MOVEABLE)))
+ goto end;
+ } else {
+
+ // already screen
+ if (!m_hdevInfo)
+ goto end;
+
+ //for screen send NULL.
+ hdata = NULL;
+ }
+
+
+
+ if (pclinfo)
+ {
+ m_hdevInfo = pclinfo->hdevInfo;
+ }
+ else
+ {
+ m_hdevInfo = NULL;
+ }
+
+
+
+ // !!! error case who frees the data?'
+
+end:
+ if (pclinfo)
+ LocalUnlock (hclinfo);
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::SendDevInfo(hwndCli=%x)\n",
+ this,
+ hWndCli));
+ return;
+}
+
+
+
+
+// Constructor
+CDefClient::CDefClient (LPUNKNOWN pUnkOuter): m_Unknown (this),
+ m_OleClientSite (this),
+ m_AdviseSink (this)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::CDefClient(pUnkOuter=%x)\n",
+ this,
+ pUnkOuter));
+
+ m_pUnkOuter = pUnkOuter ? pUnkOuter : &m_Unknown;
+ m_bContainer = TRUE;
+ m_lpoleObj = NULL;
+ m_lpdataObj = NULL;
+ m_bCreateInst = FALSE;
+ m_bTerminate = FALSE;
+ m_termNo = 0;
+ m_hcli = NULL;
+ m_lpNextItem = NULL;
+ m_cRef = 0;
+ m_hwnd = (HWND)0;
+ m_hdevInfo = NULL;
+ m_hcliInfo = NULL;
+ m_fDidRealSetHostNames= FALSE;
+ m_fDidSetClientSite = FALSE;
+ m_fGotDdeAdvise = FALSE;
+ m_fCreatedNotConnected = FALSE;
+ m_fInOnClose = FALSE;
+ m_fInOleSave = FALSE;
+ m_dwConnectionOleObj = 0L;
+ m_dwConnectionDataObj = 0L;
+ m_fGotStdCloseDoc = FALSE;
+ m_fEmbed = FALSE;
+ m_cClients = 0;
+ m_plkbytNative = NULL;
+ m_pstgNative = NULL;
+ m_fRunningInSDI = FALSE;
+ m_psrvrParent = NULL;
+ m_ptd = NULL;
+ m_pdoc = NULL;
+ m_chk = chkDefClient;
+ m_ExecuteAck.f = FALSE;
+ m_fGotEditNoPokeNativeYet = FALSE;
+ m_fLocked = FALSE;
+ m_pCallData = NULL;
+ m_pCallControl = NULL;
+ // CDefClient::Create does all the real work.
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::CDefClient(pUnkOuter=%x)\n",
+ this,
+ pUnkOuter));
+
+}
+
+
+CDefClient::~CDefClient (void)
+{
+ // This should be more object-oriented.
+ // But right now, this BOOL tells us what kind of obj
+ // (doc or item) "this" is
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::~CDefClient\n",
+ this));
+
+ Puts ("~CDefClient "); Puta(m_aItem); Putn();
+ BOOL fDoc = (m_pdoc==this);
+
+ Assert (m_chk==chkDefClient);
+
+ ReleaseObjPtrs ();
+
+ if (m_pdoc && !fDoc)
+ {
+ Assert (m_pdoc->m_chk==chkDefClient);
+ m_pdoc->m_pUnkOuter->Release();
+ }
+ if (fDoc)
+ {
+ // delete all the items(objects) for this doc
+ DeleteAllItems ();
+ if (m_fRunningInSDI && m_psrvrParent
+ && m_psrvrParent->QueryRevokeClassFactory())
+ {
+ m_psrvrParent->Revoke();
+ }
+
+ }
+
+ if (ISATOM(m_aItem))
+ GlobalDeleteAtom (m_aItem);
+ if (m_plkbytNative)
+ {
+ m_plkbytNative->Release();
+ Assert (m_pstgNative);
+ // They always go together
+ }
+ if (m_pstgNative)
+ m_pstgNative->Release();
+ if (m_ptd)
+ PrivMemFree(m_ptd);
+
+ // Delete client advise info
+ DeleteAdviseInfo ();
+ if (fDoc && IsWindow(m_hwnd))
+ {
+ SSDestroyWindow (m_hwnd);
+ }
+ if (m_pCallControl)
+ {
+ ReleaseDdeCallControlInterface();
+ }
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDefClient::~CDefClient\n",
+ this));
+
+}
+
+
+//
+// Unknown Implementation
+//
+
+STDMETHODIMP NC(CDefClient,CUnknownImpl)::QueryInterface
+ (REFIID iid,
+ LPVOID FAR* ppv)
+{
+ intrDebugOut((DEB_ITRACE,"%p CDefClient::QueryInterface()\n",this));
+
+ if (iid == IID_IUnknown)
+ {
+ *ppv = (LPVOID) &m_pDefClient->m_Unknown;
+ AddRef();
+ return NOERROR;
+ }
+ else if (iid==IID_IAdviseSink)
+ *ppv = (LPVOID) &m_pDefClient->m_AdviseSink;
+ else if (iid==IID_IOleClientSite)
+ *ppv = (LPVOID) &m_pDefClient->m_OleClientSite;
+ else
+ {
+ *ppv = NULL;
+ return ReportResult(0, E_NOINTERFACE, 0, 0);
+ }
+ m_pDefClient->m_pUnkOuter->AddRef();
+
+ return NOERROR;
+}
+
+
+STDMETHODIMP_(ULONG) NC(CDefClient,CUnknownImpl)::AddRef()
+{
+ intrDebugOut((DEB_ITRACE,
+ "%p CDefClient::AddRef() returns %x\n",
+ this,
+ m_pDefClient->m_cRef+1));
+
+ return ++m_pDefClient->m_cRef;
+}
+
+
+STDMETHODIMP_(ULONG) NC(CDefClient,CUnknownImpl)::Release()
+{
+ AssertSz (m_pDefClient->m_cRef, "Release is being called on ref count of zero");
+ if (--m_pDefClient->m_cRef == 0)
+ {
+ delete m_pDefClient;
+ intrDebugOut((DEB_ITRACE,
+ "%p CDefClient::Release() returns 0\n",
+ this));
+ return 0;
+ }
+ intrDebugOut((DEB_ITRACE,
+ "%p CDefClient::Release() returns %x\n",
+ this,
+ m_pDefClient->m_cRef));
+
+ return m_pDefClient->m_cRef;
+}
diff --git a/private/ole32/com/remote/dde/server/itemutil.cxx b/private/ole32/com/remote/dde/server/itemutil.cxx
new file mode 100644
index 000000000..c0ba1b0f0
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/itemutil.cxx
@@ -0,0 +1,516 @@
+// itemutil.h//
+// routines used by item.cpp
+// They used to be in item.cpp but it got too big.
+
+
+#include "ole2int.h"
+#include "srvr.h"
+#include "itemutil.h"
+#include "ddedebug.h"
+
+ASSERTDATA
+
+
+//ScanItemOptions: Scan for the item options like Close/Save etc.
+
+INTERNAL_(HRESULT) ScanItemOptions
+(
+LPOLESTR lpbuf,
+int far *lpoptions
+)
+{
+
+ ATOM aModifier;
+
+ *lpoptions = OLE_CHANGED;
+ while ( *lpbuf && *lpbuf != '/') lpbuf++;
+
+ // no modifier same as /change
+
+ if (*lpbuf == NULL)
+ return NOERROR;
+
+ *lpbuf++ = NULL; // seperate out the item string
+ // We are using this in the caller.
+
+ if (!(aModifier = GlobalFindAtom (lpbuf)))
+ return ReportResult(0, RPC_E_DDE_SYNTAX_ITEM, 0, 0);
+
+ if (aModifier == aChange)
+ return NOERROR;
+
+ // Is it a save?
+ if (aModifier == aSave){
+ *lpoptions = OLE_SAVED;
+ return NOERROR;
+ }
+ // Is it a Close?
+ if (aModifier == aClose){
+ *lpoptions = OLE_CLOSED;
+ return NOERROR;
+ }
+
+ // unknow modifier
+ return ReportResult(0, RPC_E_DDE_SYNTAX_ITEM, 0, 0);
+
+}
+
+
+
+
+//MakeDDEData: Create a Global DDE data handle from the server
+// app data handle.
+
+INTERNAL_(BOOL) MakeDDEData
+(
+HANDLE hdata,
+int format,
+LPHANDLE lph,
+BOOL fResponse
+)
+{
+ DWORD size;
+ HANDLE hdde = NULL;
+ DDEDATA FAR *lpdata= NULL;
+ BOOL bnative;
+ LPSTR lpdst;
+ LPSTR lpsrc;
+
+ Puts ("MakeDDEData\r\n");
+
+ if (!hdata) {
+ *lph = NULL;
+ return TRUE;
+ }
+
+
+ if (bnative = !(format == CF_METAFILEPICT
+ || format == CF_DIB
+ || format == CF_BITMAP))
+ {
+ // g_cfNative, CF_TEXT, g_cfBinary
+ size = GlobalSize (hdata) + sizeof (DDEDATA);
+ }
+ else
+ size = sizeof (LONG) + sizeof (DDEDATA);
+
+
+ hdde = (HANDLE) GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, size);
+ if (hdde == NULL || (lpdata = (DDEDATA FAR *) GlobalLock (hdde)) == NULL)
+ goto errRtn;
+
+ // set the data otions. Ask the client to delete
+ // it always.
+
+ lpdata->fAckReq = FALSE;
+ lpdata->fRelease = TRUE; // release the data
+ lpdata->cfFormat = format;
+ lpdata->fResponse = fResponse;
+
+ if (!bnative)
+ // If not native, stick in the handle what the server gave us.
+ *(LPHANDLE)lpdata->Value = hdata;
+
+ else {
+ // copy the native data junk here.
+ lpdst = (LPSTR)lpdata->Value;
+ if(!(lpsrc = (LPSTR)GlobalLock (hdata)))
+ goto errRtn;
+
+ size -= sizeof (DDEDATA);
+ memcpy (lpdst, lpsrc, size);
+ GlobalUnlock (hdata);
+ GlobalFree (hdata);
+
+ }
+
+ GlobalUnlock (hdde);
+ *lph = hdde;
+ return TRUE;
+
+errRtn:
+ if (lpdata)
+ GlobalUnlock (hdde);
+
+ if (hdde)
+ GlobalFree (hdde);
+
+ if (bnative)
+ GlobalFree (hdata);
+
+ return FALSE;
+}
+
+
+
+// IsAdviseStdItems: returns true if the item is one of the standard items
+// StdDocName;
+INTERNAL_(BOOL) IsAdviseStdItems (
+ATOM aItem
+)
+{
+
+ if ( aItem == aStdDocName)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+
+// GetStdItemIndex: returns index to Stditems in the "stdStrTable" if the item
+// is one of the standard items StdHostNames, StdTargetDevice,
+// StdDocDimensions, StdColorScheme
+WCHAR * stdStrTable[STDHOSTNAMES+1] = {NULL,
+ OLESTR("StdTargetDevice"),
+ OLESTR("StdDocDimensions"),
+ OLESTR("StdColorScheme"),
+ OLESTR("StdHostNames")};
+
+INTERNAL_(int) GetStdItemIndex (
+ATOM aItem
+)
+{
+
+ WCHAR str[MAX_STR];
+
+ if (!aItem)
+ return NULL;
+
+ if (!GlobalGetAtomName (aItem, str, MAX_STR))
+ return NULL;
+
+ if (!lstrcmpiW (str, stdStrTable[STDTARGETDEVICE]))
+ return STDTARGETDEVICE;
+ else if (!lstrcmpiW (str, stdStrTable[STDHOSTNAMES]))
+ return STDHOSTNAMES;
+ else if (!lstrcmpiW (str, stdStrTable[STDDOCDIMENSIONS]))
+ return STDDOCDIMENSIONS;
+ else if (!lstrcmpiW (str, stdStrTable[STDCOLORSCHEME]))
+ return STDCOLORSCHEME;
+
+ return NULL;
+}
+
+
+
+
+void ChangeOwner
+ (HANDLE hmfp)
+{
+
+#ifndef WIN32
+ LPMETAFILEPICT lpmfp;
+ if (lpmfp = (LPMETAFILEPICT) GlobalLock (hmfp))
+ {
+ SetMetaFileBitsBetter (lpmfp->hMF);
+ GlobalUnlock (hmfp);
+ }
+#endif
+}
+
+
+INTERNAL_(HANDLE) MakeItemData
+(
+DDEPOKE FAR * lpPoke,
+HANDLE hPoke,
+CLIPFORMAT cfFormat
+)
+{
+ HANDLE hnew;
+ LPBYTE lpnew;
+ DWORD dwSize;
+
+ Puts ("MakeItemData\r\n");
+
+ if (cfFormat == CF_METAFILEPICT)
+ return DuplicateMetaFile (*(LPHANDLE)lpPoke->Value);
+
+ if (cfFormat == CF_BITMAP)
+ return (HANDLE)DuplicateBitmap (*(HBITMAP *)lpPoke->Value);
+
+ if (cfFormat == CF_DIB)
+ return UtDupGlobal (*(LPHANDLE)lpPoke->Value,GMEM_MOVEABLE);
+
+ // Now we are dealing with normal case
+ if (!(dwSize = GlobalSize (hPoke)))
+ return NULL;
+
+ dwSize -= sizeof (DDEPOKE) - sizeof(BYTE);
+
+ // Use GMEM_ZEROINIT so there is no garbage after the data in field Value.
+ // This may be important when making an IStorage from native data,
+ // but I'm not sure.
+ // Note that the Value field itself could have garbage
+ // at the end if the hData of the DDE_POKE message is bigger than
+ // necessary, i.e.,
+ // GlobalSize(hData) > sizeof(DDEPOKE) - sizeof(Value) + realsize(Value)
+
+ // A DocFile is of size 512n
+ DebugOnly (
+ if (cfFormat==g_cfNative && dwSize%512 != 0)
+ {
+ Putsi(dwSize);
+ Puts ("DDE_POKE.Value not of size 512n\r\n");
+ }
+ )
+
+ if (hnew = GlobalAlloc (GMEM_MOVEABLE|GMEM_ZEROINIT, dwSize)) {
+ if (lpnew = (LPBYTE) GlobalLock (hnew)) {
+ memcpy (lpnew, lpPoke->Value, dwSize);
+ GlobalUnlock (hnew);
+ }
+ else {
+ GlobalFree (hnew);
+ hnew = NULL;
+ }
+ }
+
+ return hnew;
+}
+
+
+
+INTERNAL_(HANDLE) DuplicateMetaFile
+(
+HANDLE hSrcData
+)
+{
+ LPMETAFILEPICT lpSrcMfp;
+ LPMETAFILEPICT lpDstMfp = NULL;
+ HANDLE hMF = NULL;
+ HANDLE hDstMfp = NULL;
+
+ Puts ("DuplicateMetaFile\r\n");
+
+ if (!(lpSrcMfp = (LPMETAFILEPICT) GlobalLock(hSrcData)))
+ return NULL;
+
+ GlobalUnlock (hSrcData);
+
+ if (!(hMF = CopyMetaFile (lpSrcMfp->hMF, NULL)))
+ return NULL;
+
+ if (!(hDstMfp = GlobalAlloc (GMEM_MOVEABLE, sizeof(METAFILEPICT))))
+ goto errMfp;
+
+ if (!(lpDstMfp = (LPMETAFILEPICT) GlobalLock (hDstMfp)))
+ goto errMfp;
+
+ GlobalUnlock (hDstMfp);
+
+ *lpDstMfp = *lpSrcMfp;
+ lpDstMfp->hMF = (HMETAFILE)hMF;
+ return hDstMfp;
+errMfp:
+ //
+ // The following Metafile was created in this
+ // process. Therefore, the delete shouldn't need to
+ // call the DDE functions for deleting the DDE pair
+ //
+ if (hMF)
+ DeleteMetaFile ((HMETAFILE)hMF);
+
+ if (hDstMfp)
+ GlobalFree (hDstMfp);
+
+ return NULL;
+}
+
+
+
+INTERNAL_(HBITMAP) DuplicateBitmap
+(
+HBITMAP hold
+)
+{
+ HBITMAP hnew;
+ HANDLE hMem;
+ LPBYTE lpMem;
+ LONG retVal = TRUE;
+ DWORD dwSize;
+ BITMAP bm;
+
+ // !!! another way to duplicate the bitmap
+
+ Puts ("DuplicateBitmap\r\n");
+
+ GetObject (hold, sizeof(BITMAP), (LPSTR) &bm);
+ dwSize = ((DWORD) bm.bmHeight) * ((DWORD) bm.bmWidthBytes) *
+ ((DWORD) bm.bmPlanes) * ((DWORD) bm.bmBitsPixel);
+
+ if (!(hMem = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, dwSize)))
+ return NULL;
+
+ if (!(lpMem = (LPBYTE) GlobalLock (hMem))){
+ GlobalFree (hMem);
+ return NULL;
+ }
+
+ GetBitmapBits (hold, dwSize, lpMem);
+ if (hnew = CreateBitmap (bm.bmWidth, bm.bmHeight,
+ bm.bmPlanes, bm.bmBitsPixel, NULL))
+ retVal = SetBitmapBits (hnew, dwSize, lpMem);
+
+ GlobalUnlock (hMem);
+ GlobalFree (hMem);
+
+ if (hnew && (!retVal)) {
+ DeleteObject (hnew);
+ hnew = NULL;
+ }
+
+ return hnew;
+}
+
+
+
+
+// CDefClient::GetData
+//
+// Perform a normal GetData on m_lpdataObj, but if g_cfNative is requested,
+// do an OleSave onto our IStorage implemented
+// on top of an ILockBytes, then convert the ILockBytes to an hGlobal.
+// This flattened IStorage will be used as the native data.
+//
+INTERNAL CDefClient::GetData
+ (LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium)
+{
+ LPPERSISTSTORAGE pPersistStg=NULL;
+ HANDLE hNative =NULL;
+ HANDLE hNativeDup =NULL;
+ HRESULT hresult =NOERROR;
+ BOOL fFreeHNative = FALSE;
+ CLSID clsid;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDefClient::GetData(%x,%x)\n",
+ this,
+ pformatetc,
+ pmedium));
+
+ intrDebugOut((DEB_ITRACE,
+ " ::GetData format=%x\n",
+ pformatetc->cfFormat));
+
+ if (pformatetc->cfFormat==g_cfNative)
+ {
+ ErrRtnH (m_lpdataObj->QueryInterface (IID_IPersistStorage,
+ (LPLPVOID) &pPersistStg));
+ ErrZ (pPersistStg);
+ if (NULL==m_pstgNative)
+ {
+ // Embed from file case
+ Assert (NULL==m_plkbytNative);
+ ErrRtnH (CreateILockBytesOnHGlobal (NULL,
+ /*fDeleteOnRelease*/TRUE,
+ &m_plkbytNative));
+
+ Assert (m_plkbytNative);
+
+ ErrRtnH (StgCreateDocfileOnILockBytes (m_plkbytNative,
+ grfCreateStg, 0, &m_pstgNative));
+
+ ErrZ (m_pstgNative);
+ Assert (NOERROR==StgIsStorageILockBytes(m_plkbytNative));
+
+ m_fInOleSave = TRUE;
+ hresult = OleSave (pPersistStg, m_pstgNative, FALSE);
+ pPersistStg->SaveCompleted(NULL);
+ m_fInOleSave = FALSE;
+ ErrRtnH (hresult);
+ }
+ else
+ {
+ // Get the native data by calling OleSave
+ m_fInOleSave = TRUE;
+ hresult = OleSave (pPersistStg, m_pstgNative, TRUE);
+ pPersistStg->SaveCompleted(NULL);
+ m_fInOleSave = FALSE;
+ ErrRtnH (hresult);
+ }
+ ErrRtnH (ReadClassStg (m_pstgNative, &clsid));
+ if (CoIsOle1Class (clsid))
+ {
+ // TreatAs case:
+ // Get Native data from "\1Ole10Native" stream
+ fFreeHNative = TRUE;
+ ErrRtnH (StRead10NativeData (m_pstgNative, &hNative));
+ }
+ else
+ {
+
+ Assert (NOERROR==StgIsStorageILockBytes (m_plkbytNative));
+
+ ErrRtnH (GetHGlobalFromILockBytes (m_plkbytNative, &hNative));
+ }
+
+ ErrZ (wIsValidHandle (hNative, g_cfNative));
+
+ // Must duplicate because we let the client free the handle,
+ // so it can't be the one our ILockBytes depends on.
+ hNativeDup = UtDupGlobal (hNative, GMEM_DDESHARE | GMEM_MOVEABLE);
+ ErrZ (wIsValidHandle (hNativeDup, g_cfNative));
+
+ if (GlobalSize(hNativeDup) % 512 != 0)
+ {
+ Puts ("WARNING:\r\n\t");
+ Putsi (GlobalSize(hNativeDup));
+ }
+
+ pmedium->tymed = TYMED_HGLOBAL;
+ pmedium->hGlobal = hNativeDup;
+ pmedium->pUnkForRelease = NULL;
+
+ pPersistStg->Release();
+ hresult = NOERROR;
+ goto exitRtn;
+ }
+ else
+ {
+ // Anything but native
+ hresult = m_lpdataObj->GetData (pformatetc, pmedium);
+// AssertOutStgmedium(hresult, pmedium);
+ goto exitRtn;
+ }
+
+
+errRtn:
+ if (hNative && fFreeHNative)
+ GlobalFree (hNative);
+ if (pPersistStg)
+ pPersistStg->Release();
+
+ pmedium->tymed = TYMED_NULL;
+ pmedium->pUnkForRelease = NULL;
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x OUT CDefClient::GetData() return %x\n",
+ this,
+ hresult));
+ return hresult;
+}
+
+
+// Set pformatetc->tymed based on pformatetc->cfFormat
+//
+INTERNAL wSetTymed
+ (LPFORMATETC pformatetc)
+{
+ if (pformatetc->cfFormat == CF_METAFILEPICT)
+ {
+ pformatetc->tymed = TYMED_MFPICT;
+ }
+ else if (pformatetc->cfFormat == CF_PALETTE ||
+ pformatetc->cfFormat == CF_BITMAP)
+ {
+ pformatetc->tymed = TYMED_GDI;
+ }
+ else
+ {
+ pformatetc->tymed = TYMED_HGLOBAL;
+ }
+ return NOERROR;
+}
diff --git a/private/ole32/com/remote/dde/server/itemutil.h b/private/ole32/com/remote/dde/server/itemutil.h
new file mode 100644
index 000000000..e9af61df2
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/itemutil.h
@@ -0,0 +1,14 @@
+// itemutil.h
+//
+// Corresponds to itemutil.cpp
+
+void ChangeOwner (HANDLE hmfp);
+INTERNAL ScanItemOptions (LPSTR lpbuf, int far *lpoptions);
+INTERNAL_(BOOL) MakeDDEData (HANDLE hdata, int format, LPHANDLE lph, BOOL fResponse);
+INTERNAL_(BOOL) IsAdviseStdItems (ATOM aItem);
+INTERNAL_(int) GetStdItemIndex (ATOM aItem);
+void ChangeOwner (HANDLE hmfp);
+INTERNAL_(HANDLE) MakeItemData (DDEPOKE FAR *lpPoke, HANDLE hPoke, CLIPFORMAT cfFormat);
+INTERNAL_(HANDLE) DuplicateMetaFile (HANDLE hSrcData);
+INTERNAL_(HBITMAP) DuplicateBitmap (HBITMAP hold);
+INTERNAL wSetTymed (LPFORMATETC pformatetc);
diff --git a/private/ole32/com/remote/dde/server/srvr.cxx b/private/ole32/com/remote/dde/server/srvr.cxx
new file mode 100644
index 000000000..7027bf8df
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/srvr.cxx
@@ -0,0 +1,2369 @@
+
+/****************************** Module Header ******************************\
+* Module Name: Srvr.c Server Main module
+*
+* Purpose: Includes All the server communication related routines.
+*
+* Created: Oct 1990.
+*
+* Copyright (c) 1985, 1986, 1987, 1988, 1989 Microsoft Corporation
+*
+* History:
+* Raor: Wrote the original version.
+*
+*
+\***************************************************************************/
+
+#include "ole2int.h"
+//#include <shellapi.h>
+// #include "cmacs.h"
+#include <dde.h>
+
+// for RemDdeRevokeClassFactory and HDDESRVR
+#include <olerem.h>
+
+#include "srvr.h"
+#include "ddedebug.h"
+#include "ddesrvr.h"
+ASSERTDATA
+
+extern HINSTANCE hdllInst;
+
+#define WM_DONOTDESTROY WM_USER+1
+
+#ifdef FIREWALLS
+BOOL bShowed = FALSE;
+void ShowVersion (void);
+#endif
+
+#ifdef _CHICAGO_
+#define DdeCHAR CHAR
+#define Ddelstrcmp lstrcmpA
+#define DdeGetClassName GetClassNameA
+#define szCDDEServer "CDDEServer"
+#else
+#define DdeCHAR WCHAR
+#define Ddelstrcmp lstrcmpW
+#define DdeGetClassName GetClassName
+#define szCDDEServer OLESTR("CDDEServer")
+#endif
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDDEServer::Create
+//
+// Synopsis: Create a server window to service a particular class
+//
+// Effects: Using lpclass, and the information in lpDdeInfo, create
+// a server window that is ready to respond to initiate
+// messages from this class.
+//
+// Arguments: [lpclass] -- Class name
+// [rclsid] -- Class ID
+// [lpDdeInfo] -- Class Object information
+// [phwnd] -- Out pointer for new window
+// [aOriginalClass] -- For TreatAs/Convert to case
+// [cnvtyp] -- Conversion type
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-28-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL CDDEServer::Create
+ (LPOLESTR lpclass,
+ REFCLSID rclsid,
+ LPDDECLASSINFO lpDdeInfo,
+ HWND FAR * phwnd,
+ ATOM aOriginalClass,
+ CNVTYP cnvtyp)
+{
+ // REVIEW what happens if we have two MDI servers register the
+ // same class factory?.
+
+ LPSRVR lpDDEsrvr = NULL;
+ ATOM aExe = NULL;
+
+ intrDebugOut((DEB_DDE_INIT,
+ "0 _IN CDDEServer::Create(lpclass=%ws)\n",
+ lpclass));
+
+ // add the app atom to global list
+ if (!ValidateSrvrClass (lpclass, &aExe))
+ {
+ intrDebugOut((DEB_IWARN,
+ "CDDEServer::Create(%ws) Invalid Class\n",
+ lpclass));
+
+ return OLE_E_CLSID;
+ }
+
+ lpDDEsrvr = new CDDEServer;
+ RetZS (lpDDEsrvr, E_OUTOFMEMORY);
+
+
+ lpDDEsrvr->m_pCallControl = GetDdeCallControlInterface();
+
+ intrAssert(lpDDEsrvr->m_pCallControl != NULL);
+
+ if (lpDDEsrvr->m_pCallControl == NULL)
+ {
+ intrDebugOut((DEB_IWARN,
+ "CDDEServer::Create(%ws) CallControlGet failed\n",
+ lpclass));
+
+ goto errReturn;
+ }
+
+ // set the signature handle and the app atom.
+ lpDDEsrvr->m_chk = chkDdeSrvr;
+ lpDDEsrvr->m_aClass = wGlobalAddAtom (lpclass);
+ lpDDEsrvr->m_clsid = rclsid; // Class ID (already TreatAs'd)
+ lpDDEsrvr->m_aOriginalClass = wDupAtom (aOriginalClass);
+ lpDDEsrvr->m_pClassFactory = NULL;
+ lpDDEsrvr->m_dwClassFactoryKey = lpDdeInfo->dwRegistrationKey;
+ lpDDEsrvr->m_aExe = aExe;
+ lpDDEsrvr->m_cnvtyp = cnvtyp;
+ lpDDEsrvr->m_fcfFlags = lpDdeInfo->dwFlags;
+
+ lpDDEsrvr->m_bTerminate = FALSE; // Set if we are terminating.
+ lpDDEsrvr->m_hcli = NULL; // handle to the first block of clients list
+ lpDDEsrvr->m_termNo = 0; // termination count
+ lpDDEsrvr->m_cSrvrClients= 0; // no of clients;
+ lpDDEsrvr->m_fDoNotDestroyWindow= 0;
+
+
+
+
+
+#ifdef FIREWALLS
+ AssertSz(lpDdeInfo.dwFlags <= REGCLS_MULTI_SEPARATE, "invalid server options");
+#endif
+
+ // Create the server window and do not show it.
+ //
+ // We are explicitly calling CreateWindowA here.
+ // The DDE tracking layer will attempt to convert hCommands to UNICODE
+ // if the two windows in the conversation are both UNICODE.
+ // This window is created as a child of the common server window for this
+ // thread. When this thread dies, the common server window is destroyed if
+ // it exists, which will cause all of the child windows to be destroyed also.
+ //
+ //
+ if (!(lpDDEsrvr->m_hwnd = DdeCreateWindowEx (0, SRVR_CLASS,
+ szCDDEServer,
+ WS_OVERLAPPED | WS_CHILD,
+ 0,0,0,0,
+ (HWND)TLSGetDdeServer(),
+ NULL,
+ hdllInst, NULL)))
+ {
+ goto errReturn;
+
+ }
+
+ //
+ // The following will inform the class object in the class registration table
+ // that this window should be notified when the class object is revoked. This
+ // enables the window to shutdown properly.
+ //
+ // If there isn't a class factory, which happens for single instance servers
+ // which were launched with a filename, then m_dwClassFactory will be 0,
+ // in which case we don't make the set call.
+ //
+ if(lpDDEsrvr->m_dwClassFactoryKey != 0)
+ {
+ if(!SetDdeServerWindow(lpDDEsrvr->m_dwClassFactoryKey,lpDDEsrvr->m_hwnd))
+ {
+ intrDebugOut((DEB_IERROR,
+ "0 CDDEServer::Create unable to SetDdeServerWindow\n"));
+ goto errReturn;
+ }
+ }
+
+ intrDebugOut((DEB_DDE_INIT,
+ "DDE Server window for %ws created in task %x\n",
+ lpclass,GetCurrentThreadId()));
+
+ // save the ptr to the server struct in the window.
+ SetWindowLong (lpDDEsrvr->m_hwnd, 0, (LONG)lpDDEsrvr);
+
+ // Set the signature.
+ SetWindowWord (lpDDEsrvr->m_hwnd, WW_LE, WC_LE);
+
+ *phwnd = lpDDEsrvr->m_hwnd;
+
+
+ intrDebugOut((DEB_DDE_INIT,
+ "0 _OUT CDDEServer::Create returns %x\n",
+ NOERROR));
+ return NOERROR;
+
+errReturn:
+ AssertSz (0, "CDDEServer::Create errReturn");
+ if (lpDDEsrvr)
+ {
+ if (lpDDEsrvr->m_pCallControl)
+ ReleaseDdeCallControlInterface();
+
+ if (lpDDEsrvr->m_hwnd)
+ SSDestroyWindow (lpDDEsrvr->m_hwnd);
+
+ if (lpDDEsrvr->m_aClass)
+ GlobalDeleteAtom (lpDDEsrvr->m_aClass);
+
+ if (lpDDEsrvr->m_aExe)
+ GlobalDeleteAtom (lpDDEsrvr->m_aExe);
+ delete lpDDEsrvr;
+ }
+
+ intrDebugOut((DEB_IERROR,
+ "0 _OUT CDDEServer::Create returns %x\n",
+ E_OUTOFMEMORY));
+
+ return E_OUTOFMEMORY;
+}
+
+
+
+// ValidateSrvrClass checks whether the given server class is valid by
+// looking in the registration database.
+
+INTERNAL_(BOOL) ValidateSrvrClass (
+LPOLESTR lpclass,
+ATOM FAR * lpAtom
+)
+{
+ WCHAR buf[MAX_STR];
+ LONG cb = MAX_STR;
+ WCHAR key[MAX_STR];
+ LPOLESTR lptmp;
+ LPOLESTR lpbuf;
+ WCHAR ch;
+ CLSID clsid;
+
+ if (CLSIDFromProgID (lpclass, &clsid) != NOERROR)
+ {
+ // ProgId is not correctly registered in reg db
+ return FALSE;
+ }
+
+ lstrcpyW (key, lpclass);
+ lstrcatW (key, OLESTR("\\protocol\\StdFileEditing\\server"));
+
+ if (RegQueryValue (HKEY_CLASSES_ROOT, key, buf, &cb))
+ return TRUE;
+
+ if (!buf[0])
+ {
+ AssertSz (0, "ValidateSrvrClass failed.");
+ return FALSE;
+ }
+
+ // Get exe name without path and then get an atom for that
+ lptmp = lpbuf = buf;
+ while (ch = *lptmp)
+ {
+ lptmp++;
+ if (ch == '\\' || ch == ':')
+ lpbuf = lptmp;
+ }
+ *lpAtom = wGlobalAddAtom (lpbuf);
+
+ return TRUE;
+}
+
+
+
+INTERNAL RemDdeRevokeClassFactory
+ (LPSRVR lpsrvr)
+{
+ HRESULT hr;
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN RemDdeRevokeClassFactory(%x)\n",
+ lpsrvr));
+
+ ChkS(lpsrvr);
+ hr = lpsrvr->Revoke();
+ intrDebugOut((DEB_ITRACE,
+ "0 OUT RemDdeRevokeClassFactory(%x) %x\n",
+ lpsrvr,hr));
+ return(hr);
+}
+
+
+
+INTERNAL CDDEServer::Revoke ()
+{
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDDEServer::Revoke() m_cSrvrClients=%x\n",
+ this,
+ m_cSrvrClients));
+ HRESULT hr;
+
+ ChkS(this);
+
+ //
+ // Can't revoke if there are still clients. QueryRevokeCLassFactory
+ // determines if there are still clients attached.
+ //
+ if (!QueryRevokeClassFactory ())
+ {
+ intrDebugOut((DEB_IERROR,
+ "QueryRevokeClassFactory failed!"));
+ hr = RPC_E_DDE_REVOKE;
+ goto exitRtn;
+ }
+
+ if (m_cSrvrClients)
+ {
+ m_bTerminate = TRUE;
+ // if there are any clients connected to this classfactory,
+ // send terminates.
+ SendServerTerminateMsg ();
+ m_bTerminate = FALSE;
+ }
+
+ hr = FreeSrvrMem ();
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x OUT CDDEServer::Revoke(%x) hr = %x\n",
+ this, hr));
+ return hr;
+}
+
+INTERNAL_(void) CDDEServer::SendServerTerminateMsg ()
+{
+
+ HANDLE hcliPrev = NULL;
+ PCLILIST pcli;
+ HANDLE *phandle;
+ HANDLE hcli;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDDEServer::SendServerTerminateMsg\n",
+ this));
+
+ hcli = m_hcli;
+ while (hcli) {
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ {
+ Assert(0);
+ goto exitRtn;
+ }
+
+ phandle = (HANDLE *) (pcli->info);
+ while (phandle < (HANDLE *)(pcli + 1)) {
+ if (*phandle)
+ {
+ PostMessageToClientWithReply ((HWND)(*phandle), WM_DDE_TERMINATE,
+ (WPARAM) m_hwnd, NULL, WM_DDE_TERMINATE);
+ Assert (m_cSrvrClients);
+ m_cSrvrClients--;
+ }
+ phandle++;
+ phandle++;
+ }
+
+ hcliPrev = hcli;
+ hcli = pcli->hcliNext;
+ LocalUnlock (hcliPrev);
+ }
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x OUT CDDEServer::SendServerTerminateMsg\n",
+ this));
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDDEServer::FreeSrvrMem
+//
+// Synopsis: Free's up a CDDEServer.
+//
+// Effects:
+//
+// Arguments: [void] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 6-26-94 kevinro Commented
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL CDDEServer::FreeSrvrMem
+ (void)
+{
+ HRESULT hr;
+ // REVIEW: Not clear how this works in the synchronous mode
+ // Release for class factory is called only when everything is
+ // cleaned and srvr app can post WM_QUIT at this stage
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDDEServer::FreeSrvrMem\n",
+ this));
+
+ PCLILIST pcliPrev;
+ HANDLE hcli, hcliPrev;
+
+ if (m_bTerminate)
+ {
+ AssertSz (0, "terminate flag is not FALSE");
+ }
+
+
+ if (m_aExe)
+ {
+ GlobalDeleteAtom (m_aExe);
+ }
+
+
+ // We deliberately do not call this->Lock (FALSE)
+ // If the server has revoked his class object without
+ // waiting for his Lock count to go to zero, then
+ // presumably he doesn't need us to unlock him. In fact,
+ // doing such an unlock might confuse a server who then
+ // tries to call CoRevokeClassObject recursively.
+ if (m_pClassFactory)
+ {
+ m_pClassFactory->Release();
+ m_pClassFactory = NULL;
+ }
+
+ hcli = m_hcli;
+ while (hcli)
+ {
+ hcliPrev = hcli;
+ if (pcliPrev = (PCLILIST) LocalLock (hcliPrev))
+ {
+ hcli = pcliPrev->hcliNext;
+ }
+ else
+ {
+ AssertSz (0, "Corrupt internal data structure or out-of-memory");
+ hcli = NULL;
+ }
+ Verify (0==LocalUnlock (hcliPrev));
+ Verify (NULL==LocalFree (hcliPrev));
+ }
+
+ hr = DestroyDdeSrvrWindow(m_hwnd,m_aClass);
+ if (hr != NOERROR)
+ {
+ //
+ // Well now, if DestroyWindow fails, there isn't a whole heck of
+ // alot we can do about it. It could mean that the window was
+ // destroyed previously, or the parent window was destroyed during
+ // thread shutdown. We should still continue to cleanup
+ //
+ intrDebugOut((DEB_IERROR,
+ "%x CDDEServer::FreeSrvrMem DestroyDdeSrvrWindow failed %x\n",
+ this,
+ hr));
+ }
+
+ if (m_aClass)
+ {
+ GlobalDeleteAtom (m_aClass);
+ }
+
+ if (m_pCallControl)
+ {
+ ReleaseDdeCallControlInterface();
+ }
+
+ delete this;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDDEServer::FreeSrvrMem\n",
+ this));
+ return NOERROR;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: SrvrHandleIncomingCall
+//
+// Synopsis: Setup and call the CallControl to dispatch a call to the server
+//
+// 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 SrvrDispatchIncomingCall to actuall process the call.
+//
+// This routine should only be called by the SrvrWndProc
+//
+//
+// Arguments: [lpsrvr] -- Points to the server
+// [hwnd] -- hwnd of server
+// [hdata] -- Handle to data
+// [wParam] -- hwnd of client
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-05-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL SrvrHandleIncomingCall(LPSRVR lpsrvr,
+ HWND hwnd,
+ HANDLE hdata,
+ HWND wParam)
+{
+ VDATEHEAP();
+ HRESULT hresult = NOERROR;
+ IID iid;
+ SRVRDISPATCHDATA srvrdispdata;
+ DISPATCHDATA dispatchdata;
+ INTERFACEINFO32 ifInfo;
+ ICallControl *lpCallCont = lpsrvr->m_pCallControl;
+
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN SrvrHandleIncomingCall lpsrvr=%x hwnd=%x hdata=%x wParam=%x\n",
+ lpsrvr,
+ hwnd,
+ hdata,
+ wParam));
+
+ //
+ // It would be very bad if this didn't exist.
+ //
+ intrAssert(lpCallCont);
+
+ //
+ // There is no information to provide here
+ // By setting pUnk to NULL, the CallControl will pass the
+ // message filter a NULL ifInfo.
+ //
+
+ ifInfo.pUnk = NULL;
+ ifInfo.wMethod=0;
+ ifInfo.callcat = CALLCAT_SYNCHRONOUS;
+
+ dispatchdata.pData = (LPVOID) &srvrdispdata;
+
+ srvrdispdata.wDispFunc = DDE_DISP_SRVRWNDPROC;
+ srvrdispdata.hwnd = hwnd;
+ srvrdispdata.hData = hdata;
+ srvrdispdata.wParam = wParam;
+ srvrdispdata.lpsrvr = lpsrvr;
+
+ hresult = lpCallCont->HandleDispatchCall((DWORD)GetWindowTask(hwnd),
+ iid,
+ &ifInfo,
+ &dispatchdata);
+
+ intrDebugOut((DEB_ITRACE,
+ "0 _OUT SrvrHandleIncomingCall hresult=%x\n",
+ hresult));
+
+ return(hresult);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: SrvrDispatchIncomingCall
+//
+// Synopsis: Dispatch a call into the server.
+//
+// Effects: At the moment, the only incoming call that requires handling
+// by the server window is Execute. This routine dispatchs to it,
+// and returns.
+//
+// Arguments: [psdd] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-05-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL SrvrDispatchIncomingCall(PSRVRDISPATCHDATA psdd)
+{
+ VDATEHEAP();
+ HRESULT hr;
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN SrvrDispatchIncomingCall psdd(%x)\n",psdd));
+
+ hr = psdd->lpsrvr->SrvrExecute (psdd->hwnd,
+ psdd->hData,
+ (HWND)(psdd->wParam));
+
+ intrDebugOut((DEB_ITRACE,
+ "0 _OUT SrvrDispatchIncomingCall psdd(%x) hr =%x\n",
+ psdd,
+ hr));
+
+ return(hr);
+}
+
+
+// REVIEW: Revoking Class Factory will not be successful if
+// any clients are either connected to the classfactory
+// or to the object instances.
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SrvrWndProc
+//
+// Synopsis: This is the server window procedure.
+//
+// Effects:
+//
+// Arguments: [hwndIn] -- Window handle (may not be full. See note)
+// [msg] --
+// [wParam] --
+// [lParam] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 8-03-94 kevinro Created
+//
+// 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) SrvrWndProc (
+HWND hwndIn,
+UINT msg,
+WPARAM wParam,
+LPARAM lParam
+)
+{
+ BOOL fRevoke=FALSE;
+ LPSRVR lpsrvr;
+ WORD status = NULL;
+ HANDLE hdata;
+ ATOM aItem;
+ HRESULT retval;
+
+ //
+ // The following hwnd variable is used to determine the full HWND, in the
+ // event we were dispatched in a 16 bit process.
+ //
+ HWND hwnd;
+
+#ifdef FIREWALLS
+ HWND hwndClient;
+#endif
+
+
+ switch (msg){
+
+ case WM_DDE_INITIATE:
+ VDATEHEAP();
+#ifdef FIREWALLS
+ AssertSz (lpsrvr, "No server window handle in server window");
+#endif
+ hwnd = ConvertToFullHWND(hwndIn);
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0);
+ if (lpsrvr->m_bTerminate){
+ // we are terminating, no more connections
+ break;
+ }
+
+ // class is not matching, so it is not definitely for us.
+ // for apps sending the EXE for initiate, do not allow if the app
+ // is mutiple instance (Bug fix for winworks).
+
+ if (!(lpsrvr->m_aClass == (ATOM)(LOWORD(lParam)) ||
+ (NOERROR==wCompatibleClasses (LOWORD(lParam), lpsrvr->m_aClass)) ||
+ (lpsrvr->m_aExe == (ATOM)(LOWORD(lParam)) && IsSingleServerInstance() )))
+ {
+ break;
+ }
+
+ intrDebugOut((DEB_DDE_INIT,"::SrvrWndProc INITIATE\n"));
+
+
+ if (!lpsrvr->HandleInitMsg (lParam))
+ {
+ if (!(aSysTopic == (ATOM)(HIWORD(lParam))))
+ {
+ //
+ // If this isn't a sys topic, then it must be a request for
+ // a specific document. Send a message to the
+ // children windows, asking for the document. If one of them
+ // may send an ACK to the client.
+ //
+
+ // if the server window is not the right window for
+ // DDE conversation, then try with the doc windows.
+ BOOL fAckSent = SendInitMsgToChildren (hwnd, msg, wParam, lParam);
+
+#ifdef KEVINRO_OLDCODE
+ The following code was removed, because I don't belive it is required
+ any longer. I am not 100% sure yet, so I have left it in. If you find it,
+ you can probably remove it.
+ It appears to be trying to claim the SINGLE_USE class factory from the class
+ factory table. It does this when a child document window sends an ACK to the
+ client, claiming to support the document being asked for. It really doesn't
+ make too much sense here, since a single use server would have already removed
+ its class factory if there was an open document.
+
+ Anyway, the 16-bit version had a direct hack into the class factory table. We
+ don't have that anymore, so this code wouldn't work anyway.
+
+ if (lpsrvr->m_fcfFlags==REGCLS_SINGLEUSE)
+ {
+ if (lpsrvr->m_pfAvail)
+ {
+ // Hide the entry in the class factory table so that no 2.0
+ // client can connect to the same server.
+ Assert (!IsBadWritePtr (lpsrvr->m_pfAvail, sizeof(BOOL)));
+ *(lpsrvr->m_pfAvail) = FALSE;
+ }
+ }
+#endif // KEVINRO_OLDCODE
+ intrDebugOut((DEB_DDE_INIT,"SrvrWndProc Child Init\n"));
+ return fAckSent;
+ }
+ break;
+ }
+
+ // We can enterain this client. Put him in our client list
+ // and acknowledge the initiate.
+
+ if (!AddClient ((LPHANDLE)&lpsrvr->m_hcli, (HWND)wParam,(HWND)/*fLocked*/FALSE))
+ {
+ break;
+ }
+
+ //
+ // Now its time to grab up the class factory from the class
+ // factory table. When this window was created, the class factory
+ // was available. However, it is possible that it has already
+ // been claimed by someone else. So, we try grabbing it (which
+ // normally should succeed). If it fails, then delete the client
+ // and don't acknowledge.
+ //
+
+ if (lpsrvr->m_pClassFactory == NULL)
+ {
+ DdeClassInfo ddeInfo;
+ ddeInfo.dwContextMask = CLSCTX_LOCAL_SERVER |
+ CLSCTX_INPROC_SERVER;
+ intrDebugOut((DEB_DDE_INIT,"SrvrWndProc getting class factory\n"));
+ //
+ // The following asks for control of the class
+ // factory in the case of a single use class
+ //
+ ddeInfo.fClaimFactory = TRUE;
+ ddeInfo.dwRegistrationKey = lpsrvr->m_dwClassFactoryKey;
+
+ if (GetClassInformationFromKey(&ddeInfo) == FALSE)
+ {
+ intrDebugOut((DEB_IERROR,"SrvrWndProc failed to get class factory\n"));
+ //
+ // Whoops, we were not able to grab the class factory
+ // Cleanup and hop out
+ if (!FindClient ((LPHANDLE)lpsrvr->m_hcli,(HWND)wParam, TRUE))
+ {
+ intrAssert(!"FindClient failed\n");
+ }
+ return(0);
+ }
+ lpsrvr->m_pClassFactory = (IClassFactory *)ddeInfo.punk;
+ lpsrvr->m_fcfFlags = ddeInfo.dwFlags;
+ }
+
+ intrAssert(lpsrvr->m_pClassFactory != NULL);
+
+ lpsrvr->m_cSrvrClients++;
+
+ lpsrvr->Lock (TRUE, (HWND)wParam);
+
+ // Post acknowledge
+ DuplicateAtom (LOWORD(lParam));
+ DuplicateAtom (HIWORD(lParam));
+ SSSendMessage ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, lParam);
+
+
+ return 1L; // fAckSent==TRUE
+ VDATEHEAP();
+ break;
+
+
+ case WM_DDE_EXECUTE:
+ VDATEHEAP();
+ hwnd = ConvertToFullHWND(hwndIn);
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0);
+
+ hdata = GET_WM_DDE_EXECUTE_HDATA(wParam,lParam);
+
+#ifdef FIREWALLS
+ AssertSz (lpsrvr, "No server handle in server window");
+#endif
+
+ intrDebugOut((DEB_ITRACE,"SrvrWndProc WM_DDE_EXECUTE\n"));
+
+#ifdef FIREWALLS
+ // find the client in the client list.
+ hwndClient = FindClient (lpsrvr->m_hcli, (HWND)wParam, FALSE);
+ AssertSz (hwndClient, "Client is missing from the server")
+#endif
+ // Are we terminating
+ if (lpsrvr->m_bTerminate) {
+ intrDebugOut((DEB_ITRACE,
+ "SrvrWndProc WM_DDE_EXECUTE ignored for TERMINATE\n"));
+ // !!! are we supposed to free the data
+ GlobalFree (hdata);
+ break;
+ }
+
+ retval = SrvrHandleIncomingCall(lpsrvr,hwnd,hdata,(HWND)wParam);
+
+ if (NOERROR!=retval)
+ {
+ intrDebugOut((DEB_IERROR,
+ "SrvrWndProc SrvrHandleIncomingCall fail %x\n",
+ retval));
+ }
+ SET_MSG_STATUS (retval, status)
+
+ if (!lpsrvr->m_bTerminate)
+ {
+ // REVIEW: We are making an assumption that, we will not be posting
+ // any DDE messages because of calling the SrvrExecute.
+ // If we post any messages, before we post the acknowledge
+ // we will be in trouble.
+
+ lParam = MAKE_DDE_LPARAM(WM_DDE_ACK,status,(UINT) hdata);
+
+ intrDebugOut((DEB_ITRACE,
+ "SrvrWndProc WM_DDE_EXECUTE sending %x for ack\n",status));
+
+ // Post the acknowledge to the client
+ if (!PostMessageToClient ((HWND) wParam,
+ WM_DDE_ACK, (UINT) hwnd, lParam)) {
+ // if the window died or post failed, delete the atom.
+ GlobalFree (hdata);
+ DDEFREE(WM_DDE_ACK,lParam);
+ }
+ }
+ VDATEHEAP();
+ break;
+
+
+
+ case WM_DDE_TERMINATE:
+ intrDebugOut((DEB_ITRACE,
+ "SrvrWndProc WM_DDE_TERMINATE\n"));
+
+ hwnd = ConvertToFullHWND(hwndIn);
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0);
+
+#ifdef FIREWALLS
+ // find the client in the client list.
+ hwndClient = FindClient (lpsrvr->m_hcli, (HWND)wParam, FALSE);
+ AssertSz (hwndClient, "Client is missing from the server")
+#endif
+ Putsi (lpsrvr->m_bTerminate);
+ if (lpsrvr->m_bTerminate)
+ {
+ AssertSz (0, "Unexpected code path");
+ }
+ else
+ {
+ // If client initiated the terminate. post matching terminate
+ PostMessageToClient ((HWND)wParam,
+ WM_DDE_TERMINATE,
+ (UINT) hwnd,
+ NULL);
+ --lpsrvr->m_cSrvrClients;
+ if (0==lpsrvr->m_cSrvrClients
+ && lpsrvr->QueryRevokeClassFactory())
+ {
+#ifdef KEVINRO_OLD_CODE
+ if (lpsrvr->m_phwndDde)
+ {
+ // Remove from class factory table
+ *(lpsrvr->m_phwndDde) = (HWND)0;
+ }
+#endif // KEVINRO_OLD_CODE
+ fRevoke = TRUE;
+ }
+
+ lpsrvr->Lock (FALSE, (HWND)wParam); // Unlock server
+ FindClient (lpsrvr->m_hcli, (HWND)wParam, /*fDelete*/TRUE);
+
+ if (fRevoke)
+ {
+ lpsrvr->Revoke();
+ }
+ }
+ break;
+
+
+ case WM_DDE_REQUEST:
+ aItem = GET_WM_DDE_REQUEST_ITEM(wParam,lParam);
+
+ hwnd = ConvertToFullHWND(hwndIn);
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0);
+
+ intrDebugOut((DEB_ITRACE,
+ "SrvrWndProc WM_DDE_REQUEST(aItem=%x)\n",aItem));
+
+ if (lpsrvr->m_bTerminate || !IsWindowValid ((HWND) wParam))
+ {
+ goto RequestErr;
+ }
+
+ if(RequestDataStd (aItem, (HANDLE FAR *)&hdata) != NOERROR)
+ {
+
+ lParam = MAKE_DDE_LPARAM(WM_DDE_ACK,0x8000,aItem);
+
+ // if request failed, then acknowledge with error.
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK,
+ (UINT) hwnd, lParam))
+ {
+ DDEFREE(WM_DDE_ACK,lParam);
+RequestErr:
+ if (aItem)
+ {
+ GlobalDeleteAtom (aItem);
+ }
+
+ }
+ }
+ else
+ {
+ lParam = MAKE_DDE_LPARAM(WM_DDE_REQUEST,
+ (UINT) hdata,(UINT) aItem);
+
+ // post the data message and we are not asking for any
+ // acknowledge.
+
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_DATA,
+ (UINT) hwnd, lParam))
+ {
+ GlobalFree (hdata);
+ DDEFREE(WM_DDE_REQUEST,lParam);
+ goto RequestErr;
+ }
+ }
+ break;
+
+ case WM_DONOTDESTROY:
+ intrDebugOut((DEB_ITRACE,
+ "SrvrWndProc WM_DONOTDESTROY %x\n",
+ wParam));
+
+ //
+ // This message is only sent by 32-bit code that has been
+ // given our full handle
+ //
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwndIn, 0);
+
+ //
+ // The WM_DONOTDESTROY message tells the server how to
+ // handle the following WM_USER message. If wParam is set,
+ // then the m_fDoNotDestroyWindow flag will be set, which
+ // keeps us from destroying the server window. If cleared,
+ // it will enable the destruction. This message is sent
+ // from the MaybeCreateDocWindow routine
+ //
+
+ lpsrvr->m_fDoNotDestroyWindow = wParam;
+ return 0;
+ break;
+
+ case WM_USER:
+ intrDebugOut((DEB_ITRACE,
+ "SrvrWndProc WM_USER\n"));
+ //
+ // This message is only sent by 32-bit code that has been
+ // given our full handle
+ //
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwndIn, 0);
+
+ // cftable.cpp sends a WM_USER message to destory the DDE
+ // server window when a 2.0 client has connected to a
+ // SDI 2.0 server (and no 1.0 client should be allowed to also
+ // connect.
+ // cftable.cpp cannot call RemDdeRevokeClassFactory directly
+ // becuase they may be in different processes.
+ //
+ // The m_fDoNotDestroyWindow flag is used by
+ // MaybeCreateDocWindow in the case that the server is a
+ // single use server, and revokes its class factory when
+ // an object is created. MaybeCreateDocWindow will set this
+ // flag, telling us to ignore the message.
+ //
+ // returning 0 means we did destroy, 1 means we did not.
+
+ if (!lpsrvr->m_fDoNotDestroyWindow)
+ {
+ RemDdeRevokeClassFactory(lpsrvr);
+ return(0);
+ }
+ return 1;
+ break;
+
+ default:
+ return SSDefWindowProc (hwndIn, msg, wParam, lParam);
+ }
+
+ return 0L;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDDEServer::HandleInitMsg
+//
+// Synopsis: Determine if we are going to handle the INITIATE message.
+//
+// Effects:
+//
+// Arguments: [lParam] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-28-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL_(BOOL) CDDEServer::HandleInitMsg(LPARAM lParam)
+{
+
+ // If it is not system or Ole, this is not the server.
+ if (!((aSysTopic == (ATOM)(HIWORD(lParam))) || (aOLE == (ATOM)(HIWORD(lParam)))))
+ {
+ return FALSE;
+ }
+ Assert (m_fcfFlags<=REGCLS_MULTI_SEPARATE);
+
+ // single instance MDI accept
+ if (m_fcfFlags != REGCLS_SINGLEUSE)
+ {
+ return TRUE;
+ }
+
+ // this server is multiple instance. So, check for any clients or docs.
+ if (!GetWindow (m_hwnd, GW_CHILD) && 0==m_cSrvrClients)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+
+// AddClient: Adds a client entry to the list.
+// Each client entry is a pair of handles; key handle
+// and data handle. Ecah list entry contains space for
+// MAX_LIST of pairs of handles.
+
+INTERNAL_(BOOL) AddClient
+(
+LPHANDLE lphead, // ptr to loc which contains the head handle
+HANDLE hkey, // key
+HANDLE hdata // hdata
+)
+{
+
+ HANDLE hcli = NULL;
+ HANDLE hcliPrev = NULL;
+ PCLILIST pcli;
+ HANDLE *phandle;
+
+
+ hcli = *lphead;
+
+ // if the entry is already present, return error.
+ if (hcli && FindClient (hcli, hkey, FALSE))
+ return FALSE;
+
+ while (hcli) {
+ if (hcliPrev)
+ LocalUnlock (hcliPrev);
+
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ return FALSE;
+
+ phandle = (HANDLE *) pcli->info;
+ while (phandle < (HANDLE *)(pcli + 1)) {
+ if (*phandle == NULL) {
+ *phandle++ = hkey;
+ *phandle++ = hdata;
+ LocalUnlock (hcli);
+ return TRUE;
+ }
+ phandle++;
+ phandle++;
+ }
+ hcliPrev = hcli;
+ hcli = pcli->hcliNext;
+ lphead = (LPHANDLE)&pcli->hcliNext;
+ }
+
+ // not in the list.
+ hcli = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (CLILIST));
+ if (hcli == NULL)
+ goto errRtn;
+
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ goto errRtn;
+
+ // set the link to this handle in the previous entry
+ *lphead = hcli;
+ if (hcliPrev)
+ LocalUnlock (hcliPrev);
+
+ phandle = (HANDLE *) pcli->info;
+ *phandle++ = hkey;
+ *phandle++ = hdata;
+ LocalUnlock (hcli);
+ return TRUE;
+
+errRtn:
+
+ if (hcliPrev)
+ LocalUnlock (hcliPrev);
+
+ if (hcli)
+ LocalFree (hcli);
+
+ return FALSE;
+
+}
+
+
+// FindClient: finds a client and deletes the client if necessary.
+INTERNAL_(HANDLE) FindClient
+(
+HANDLE hcli,
+HANDLE hkey,
+BOOL bDelete
+)
+{
+ HANDLE hcliPrev = NULL;
+ PCLILIST pcli;
+ HANDLE *phandle;
+ HANDLE hdata;
+
+ while (hcli) {
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ return FALSE;
+
+ phandle = (HANDLE *) pcli->info;
+ while (phandle < (HANDLE *)(pcli + 1)) {
+ if (*phandle == hkey) {
+ if (bDelete)
+ *phandle = NULL;
+
+ hdata = *++phandle;
+ LocalUnlock (hcli);
+ return hdata;
+ }
+ phandle++;
+ phandle++;
+ }
+ hcliPrev = hcli;
+ hcli = pcli->hcliNext;
+ LocalUnlock (hcliPrev);
+
+ }
+ return NULL;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDDEServer::SrvrExecute
+//
+// Synopsis: takes care of the WM_DDE_EXECUTE for the server.
+//
+// Effects: Parses the EXECUTE string, and determines what it should be
+// done.
+//
+// Arguments: [hwnd] -- Server window
+// [hdata] -- Handle to EXECUTE string
+// [hwndClient] -- Client window
+//
+// Requires:
+// hdata is an ANSI string. It was passed to us by a DDE client.
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 6-05-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL CDDEServer::SrvrExecute
+(
+HWND hwnd,
+HANDLE hdata,
+HWND hwndClient
+)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDDESrvr::SrvrExecute(hwnd=%x,hdata=%x,hwndClient=%x)\n",
+ this,
+ hwnd,
+ hdata,
+ hwndClient));
+
+ ATOM aCmd;
+ BOOL fActivate;
+
+ LPSTR lpdata = NULL;
+ HANDLE hdup = NULL;
+ HRESULT hresult = E_UNEXPECTED;
+
+ LPSTR lpdocname;
+ LPSTR lptemplate;
+ LPCLIENT lpdocClient = NULL;
+ LPSTR lpnextarg;
+ LPSTR lpclassname;
+ LPSTR lpitemname;
+ LPSTR lpopt;
+ CLSID clsid;
+ WORD wCmdType;
+ BOOL bCreateInst = FALSE;
+ LPUNKNOWN pUnk = NULL;
+
+ LPPERSISTSTORAGE pPersistStg=NULL;
+
+ // REVIEW: if any methods called on the objects genarate DDE messages
+ // before we return from Execute, we will be in trouble.
+
+
+ // REVIEW: this code can be lot simplified if we do the argument scanning
+ // seperately and return the ptrs to the args. Rewrite later on.
+
+ ErrZS (hdup = UtDupGlobal (hdata,GMEM_MOVEABLE), E_OUTOFMEMORY);
+
+ ErrZS (lpdata = (LPSTR)GlobalLock (hdup), E_OUTOFMEMORY);
+
+ intrDebugOut((DEB_ITRACE,
+ "CDDESrvr::SrvrExecute(lpdata = %s)\n",lpdata));
+
+ if (*lpdata++ != '[') // commands start with the left sqaure bracket
+ {
+ hresult = ResultFromScode (RPC_E_DDE_SYNTAX_EXECUTE);
+ goto errRtn;
+ }
+
+ hresult = ReportResult(0, RPC_E_DDE_SYNTAX_EXECUTE, 0, 0);
+ // scan upto the first arg
+ if (!(wCmdType = ScanCommand (lpdata, WT_SRVR, &lpdocname, &aCmd)))
+ goto errRtn;
+
+ if (wCmdType == NON_OLE_COMMAND)
+ {
+ if (!UtilQueryProtocol (m_aClass, PROTOCOL_EXECUTE))
+ hresult = ReportResult(0, RPC_E_DDE_PROTOCOL, 0, 0);
+ else {
+ // REVIEW: StdExecute has to be mapped on to the StdCommandProtocol
+ // What command do we map on to?
+
+ AssertSz (0, "StdExecute is being called for server");
+ }
+
+ goto errRtn1;
+ }
+
+ if (aCmd == aStdExit)
+ {
+ if (*lpdocname)
+ goto errRtn1;
+
+ hresult = NOERROR;
+ // REVIEW: Do we have to initiate any terminations from the
+ // the servr side? Check how this works with excel.
+ goto end2;
+ }
+
+ // scan the next argument.
+ if (!(lpnextarg = ScanArg(lpdocname)))
+ goto errRtn;
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdShowItem("docname", "itemname"[, "true"])]
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+ if (aCmd == aStdShowItem) {
+
+ // first find the documnet. If the doc does not exist, then
+ // blow it off.
+
+ if (!(lpdocClient = FindDocObj (lpdocname)))
+ goto errRtn1;
+
+ lpitemname = lpnextarg;
+
+ if( !(lpopt = ScanArg(lpitemname)))
+ goto errRtn1;
+
+ // scan for the optional parameter
+ // Optional can be only TRUE or FALSE.
+
+ fActivate = FALSE;
+ if (*lpopt) {
+
+ if( !(lpnextarg = ScanBoolArg (lpopt, (BOOL FAR *)&fActivate)))
+ goto errRtn1;
+
+ if (*lpnextarg)
+ goto errRtn1;
+
+ }
+
+
+ // scan it. But, igonre the arg.
+ hresult = lpdocClient->DocShowItem (lpitemname, !fActivate);
+ goto end2;
+
+
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdCloseDocument ("docname")]
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+ if (aCmd == aStdClose) {
+ if (!(lpdocClient = FindDocObj (lpdocname)))
+ goto errRtn1;
+
+ if (*lpnextarg)
+ goto errRtn1;
+
+ // REVIEW: Do we have to do anything for shutting down the
+ // the app? Is the client going to initiate the terminate?.
+ // if we need to initiate the terminates, make sure we post
+ // the ACK first.
+
+ lpdocClient->Revoke();
+ goto end2;
+ }
+
+
+ if (aCmd == aStdOpen)
+ {
+ // find if any doc level object is already registerd.
+ // if the object is registerd, then no need to call srvr app.
+ if (FindDocObj (lpdocname))
+ {
+ // A client has already opened the document or user opened the
+ // doc. We should do an addref to the docobj
+
+#ifdef TRY
+ if (m_cSrvrClients == 0)
+ // Why are we doing this?
+ hresult = lpdocClient->m_lpoleObj->AddRef();
+ else
+#endif
+ hresult = NOERROR;
+ goto end1;
+ }
+ }
+
+ if (aCmd == aStdCreate || aCmd == aStdCreateFromTemplate) {
+ lpclassname = lpdocname;
+ lpdocname = lpnextarg;
+ if( !(lpnextarg = ScanArg(lpdocname)))
+ goto errRtn1;
+
+ }
+
+ // check whether we can create/open more than one doc.
+
+ if ((m_fcfFlags == REGCLS_SINGLEUSE) &&
+ GetWindow (m_hwnd, GW_CHILD))
+ goto errRtn;
+
+
+ ErrZ (CLSIDFromAtom(m_aClass, &clsid));
+
+
+ //
+ // Generate a wide version of the name
+ //
+
+ WCHAR awcWideDocName[MAX_STR];
+
+ if (MultiByteToWideChar(CP_ACP,0,lpdocname,-1,awcWideDocName,MAX_STR) == FALSE)
+ {
+ Assert(!"Unable to convert characters");
+ hresult = E_UNEXPECTED;
+ goto errRtn;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdOpenDocument ("docname")]
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+ // Document does not exist.
+ if (aCmd == aStdOpen)
+ {
+ ErrRtnH (wClassesMatch (clsid, awcWideDocName));
+ ErrRtnH (wFileBind (awcWideDocName, &pUnk));
+ }
+
+
+ ErrRtnH (CreateInstance (clsid, awcWideDocName, lpdocname, pUnk, &lpdocClient, hwndClient));
+ bCreateInst = TRUE;
+
+ if (aCmd == aStdOpen)
+ {
+ // Temporary flag to indicate someone will INITIATE on this doc.
+ // The flag is reset after the INITITATE.
+ // This is Yet-Another-Excel-Hack. See ::QueryRevokeClassFactory
+ lpdocClient->m_fCreatedNotConnected = TRUE;
+ }
+ else
+ {
+ lpdocClient->m_fEmbed = TRUE;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdNewDocument ("classname", "docname")]
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+ if (aCmd == aStdCreate)
+ {
+ hresult = lpdocClient->DoInitNew();
+ lpdocClient->m_fCreatedNotConnected = TRUE;
+ goto end;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdNewFormTemplate ("classname", "docname". "templatename)]
+ //
+ //////////////////////////////////////////////////////////////////////////
+ if (aCmd == aStdCreateFromTemplate)
+ {
+ ErrRtnH (lpdocClient->DoInitNew());
+ lpdocClient->m_fCreatedNotConnected = TRUE;
+ IPersistFile FAR * lpPF;
+ lptemplate = lpnextarg;
+
+ if(!(lpnextarg = ScanArg(lpnextarg)))
+ {
+ goto errRtn;
+ }
+
+
+ hresult = lpdocClient->m_lpoleObj->QueryInterface(IID_IPersistFile,(LPLPVOID)&lpPF);
+ if (hresult == NOERROR)
+ {
+ WCHAR awcWideTemplate[MAX_STR];
+
+ if (MultiByteToWideChar(CP_ACP,0,lpdocname,-1,awcWideTemplate,MAX_STR) != FALSE)
+ {
+ hresult = lpPF->Load(awcWideTemplate, 0);
+ }
+ else
+ {
+ Assert(!"Unable to convert characters");
+ lpPF->Release();
+ hresult = E_UNEXPECTED;
+ goto end;
+ }
+
+ lpPF->Release();
+ lpdocClient->m_fEmbed = TRUE;
+ }
+ else
+ {
+ goto end;
+ }
+ }
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdEditDocument ("docname")]
+ //
+ //////////////////////////////////////////////////////////////////////////
+ // REVIEW: Do we have to call InitNew for editing an embedded object
+
+ if (aCmd == aStdEdit)
+ {
+ lpdocClient->m_fEmbed = TRUE;
+ lpdocClient->m_fGotEditNoPokeNativeYet = TRUE;
+ lpdocClient->m_fCreatedNotConnected = TRUE;
+ goto end;
+ }
+
+ intrDebugOut((DEB_IERROR,
+ "%x CDDESrvr::SrvrExecute Unknown command\n",
+ this));
+
+end:
+
+ if (hresult != NOERROR)
+ goto errRtn;
+end1:
+ // make sure that the srg string is indeed terminated by
+ // NULL.
+ if (*lpnextarg)
+ {
+ hresult = RPC_E_DDE_SYNTAX_EXECUTE;
+ }
+errRtn:
+
+ if ( hresult != NOERROR)
+ {
+ if (bCreateInst && lpdocClient)
+ {
+ lpdocClient->DestroyInstance ();
+ lpdocClient = NULL; //DestroyInstance invalidates the pointer
+ }
+ }
+
+end2:
+errRtn1:
+
+ if (lpdata)
+ GlobalUnlock (hdup);
+
+ if (hdup)
+ GlobalFree (hdup);
+ if (pUnk)
+ pUnk->Release();
+
+ if (pPersistStg)
+ pPersistStg->Release();
+
+ Assert (GetScode(hresult) != E_UNEXPECTED);
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDDESrvr::SrvrExecute hresult=%x\n",
+ this,
+ hresult));
+
+ return hresult;
+}
+
+
+
+
+// Maybe CreateDocWindow
+//
+// Return NOERROR only if a doc window was created and it sent an ACK.
+//
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: MaybeCreateDocWindow
+//
+// Synopsis: Determine if a DocWindow should be created
+//
+// Effects: Given a class, and a filename atom, determine if this thread
+// should be the server for this request.
+//
+// Arguments: [aClass] -- Class of object (PROGID)
+// [aFile] -- Filename (ATOM)
+// [hwndDdeServer] -- HWND of CDDEServer
+// [hwndSender] -- HWND of new requesting client
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-29-94 kevinro Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+ INTERNAL MaybeCreateDocWindow
+ (ATOM aClass,
+ ATOM aFile,
+ HWND hwndDdeServer,
+ HWND hwndSender)
+{
+ CLSID clsid = CLSID_NULL;
+ LPUNKNOWN pUnk = NULL;
+ HWND hwndClient = NULL;
+ ULONG fAckSent = FALSE;
+ LPSRVR pDdeSrvr = NULL;
+ WCHAR szFile [MAX_STR];
+ BOOL fTrue = TRUE;
+ BOOL fRunningInSDI = FALSE;
+ HRESULT hresult = NOERROR;
+ IClassFactory *pcf = NULL;
+ IPersistFile *ppf = NULL;
+ DdeClassInfo ddeClassInfo;
+
+ intrDebugOut((DEB_DDE_INIT,
+ "MaybeCreateDocWindow(aClass=%x(%ws),aFile=%x,"
+ "hwndDdeServer=%x,hwndSender=%x\n",
+ aClass,wAtomName(aClass),aFile,hwndDdeServer,hwndSender));
+
+ //
+ // If the window isn't valid, it would be very bad.
+ //
+ if (!IsWindowValid(hwndDdeServer))
+ {
+ intrDebugOut((DEB_DDE_INIT,
+ "MaybeCreateDocWindow: hwndDdeServer is invalid\n"));
+ hresult = E_UNEXPECTED;
+ goto exitRtn;
+ }
+
+ //
+ // We need the filename, which is passed in an Atom
+ //
+ Assert (IsFile (aFile));
+ if (GlobalGetAtomName(aFile,szFile,MAX_STR) == 0)
+ {
+ //
+ // The filename was not valid
+ //
+ hresult = S_FALSE;
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow Invalid file atom\n"));
+ goto exitRtn;
+ }
+
+ intrDebugOut((DEB_DDE_INIT,
+ "MaybeCreateDocWindow File=(%ws)\n",
+ WIDECHECK(szFile)));
+
+ //
+ // Get the class of the object. The class was passed as an atom
+ // in the INITIATE message.
+ //
+ if (CLSIDFromAtomWithTreatAs (&aClass, &clsid, NULL))
+ {
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow CLSIDFromAtom failed\n"));
+
+ hresult = S_FALSE;
+ goto exitRtn;
+ }
+
+ if (CoIsOle1Class(clsid))
+ {
+ // we shouldn't even be looking at this INIT message
+ hresult = S_FALSE;
+ intrDebugOut((DEB_DDE_INIT,
+ "MaybeCreateDocWindow Its an OLE 1.0 class\n"));
+ goto exitRtn;
+ }
+
+ //
+ // First of three cases is to see if the object is running in our
+ // local apartment. If it is, then this is the object we need to create
+ // a DDEServer for.
+ //
+ // Otherwise, We are going to try and load this file.
+ // Therefore, we need the class factory from the CFT.
+ //
+ // GetClassInformationForDde won't find a match if the class factory was
+ // single use, and is now hidden or invalid.
+ //
+ // If there was no class information available, then we are going to
+ // check to see if the object is in the local ROT. If it is in the
+ // local ROT, then we will use it, since it is registered and
+ // available for use by others
+ //
+
+ ddeClassInfo.dwContextMask = CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER;
+ ddeClassInfo.fClaimFactory = TRUE;
+
+ if ( GetLocalRunningObjectForDde(szFile, &pUnk) == NOERROR)
+ {
+ intrDebugOut((DEB_DDE_INIT,
+ "Found %ws in ROT\n",WIDECHECK(szFile)));
+ //
+ // Elsewhere in the code, we need to know if this is an SDI server.
+ // The old code determined this by detecting that there is a running
+ // object, and there was no class factory registered.
+ // This is sick, and obscene. Compatibilities says we need to get the
+ // class info anyway. However, we don't want to claim it.
+ //
+
+ ddeClassInfo.fClaimFactory = FALSE;
+ fRunningInSDI = !GetClassInformationForDde(clsid,&ddeClassInfo);
+ }
+ else if (!GetClassInformationForDde(clsid,&ddeClassInfo))
+ {
+ intrDebugOut((DEB_IERROR,
+ "No class registered for %ws\n",WIDECHECK(szFile)));
+
+ hresult = S_FALSE;
+ goto exitRtn;
+ }
+ else
+ {
+ //
+ // Otherwise, we are registered as the server for this class. This
+ // means we can create this object.
+ //
+ // A 1.0 client will have launched the server with a command line
+ // like server.exe -Embedding filename The server ignored the filename
+ // so now we must make it load the file by binding the moniker.
+ //
+ // KevinRo: The old code did a bind moniker here, on the filename,
+ // which went through the ROT, didn't find the object, so went for
+ // a server. This isn't terribly safe, since we could end up binding
+ // out of process when we really didn't mean to. So, I have made this
+ // routine just use the ClassFactory we retrieve from the
+ // local class factory table.
+ //
+
+ intrDebugOut((DEB_DDE_INIT,
+ "Found classinfo: Loading %ws\n",WIDECHECK(szFile)));
+
+
+ //
+ // Need to insure that the server doesn't go away on us. The following
+ // tells the server not to destroy itself.
+ //
+ SSSendMessage(hwndDdeServer,WM_DONOTDESTROY,TRUE,0);
+
+ intrAssert(ddeClassInfo.punk != NULL);
+ pcf = (IClassFactory *) ddeClassInfo.punk;
+
+ hresult = pcf->CreateInstance(NULL,IID_IUnknown,(void **)&pUnk);
+
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow CreateInstancefailed File=(%ws)\n",
+ WIDECHECK(szFile)));
+ goto sndMsg;
+ }
+
+ //
+ // Get the IPersistFile interface, and ask the object to load
+ // itself.
+ //
+ hresult = pUnk->QueryInterface(IID_IPersistFile,(void **)&ppf);
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow QI IPF failed File=(%ws)\n",
+ WIDECHECK(szFile)));
+ goto sndMsg;
+ }
+ //
+ // Attempt to load the object. The flags STGM_READWRITE are the
+ // same default values used by a standard bind context.
+ //
+ hresult = ppf->Load(szFile,STGM_READWRITE);
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow ppf->Load(%ws) failed %x\n",
+ WIDECHECK(szFile),
+ hresult));
+ goto sndMsg;
+ }
+sndMsg:
+ SSSendMessage(hwndDdeServer,WM_DONOTDESTROY,FALSE,0);
+ if (hresult != NOERROR)
+ {
+ goto exitRtn;
+
+ }
+ intrDebugOut((DEB_DDE_INIT,
+ "Loading %ws complete\n",WIDECHECK(szFile)));
+
+ }
+
+
+ intrAssert(IsWindowValid(hwndDdeServer));
+ intrAssert (pUnk);
+
+ pDdeSrvr = (LPSRVR) GetWindowLong (hwndDdeServer, 0);
+ if (pDdeSrvr == NULL)
+ {
+ intrAssert(pDdeSrvr != NULL);
+ hresult = E_UNEXPECTED;
+ goto exitRtn;
+ }
+
+ // This actually creates the doc window as a child of the server window
+ // Do not set the client site becuase this is a link.
+ hresult = CDefClient::Create (pDdeSrvr,
+ pUnk,
+ szFile,
+ /*fSetClientSite*/FALSE,
+ /*fDoAdvise*/TRUE,
+ fRunningInSDI,
+ &hwndClient);
+
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow CDefClient::Create failed %x\n",
+ hresult));
+ goto exitRtn;
+ }
+
+ Assert (IsWindowValid (hwndClient));
+
+ //
+ // Pass along the original DDE_INIT to the newly created window.
+ // That window should respond by sending an ACK to the 1.0 client.
+ //
+ fAckSent = SSSendMessage (hwndClient,
+ WM_DDE_INITIATE,
+ (UINT) hwndSender,
+ MAKELONG(aClass, aFile));
+ if (!fAckSent)
+ {
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow !fAckSent\n"));
+ hresult = CO_E_APPDIDNTREG;
+ }
+
+exitRtn:
+
+ if (ppf)
+ {
+ ppf->Release();
+ }
+ if (pUnk)
+ {
+ pUnk->Release();
+ }
+ if (pcf)
+ {
+ pcf->Release();
+ }
+
+ intrDebugOut((DEB_DDE_INIT,
+ "MaybeCreateDocWindow returns %x\n",
+ hresult));
+ return hresult;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SendMsgToChildren
+//
+// Synopsis: This routine sends the msg to all child windows.
+//
+// Arguments: [hwnd] -- Hwnd of parent window
+// [msg] -- Message and parameters to send
+// [wParam] --
+// [lParam] --
+//
+// Notes: This routine will stop on the first non-zero return code.
+//
+//----------------------------------------------------------------------------
+BOOL SendMsgToChildren (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN SendMsgToChildren(hwnd=%x,msg=%x,wParam=%x,lParam=%x)\n",
+ hwnd,msg,wParam,lParam));
+
+ BOOL fAckSent = FALSE;
+
+ hwnd = GetWindow(hwnd, GW_CHILD);
+
+ //
+ // This routine is to be called only from one place, which is
+ // in the handling of WM_DDE_INITIATE. Because of that, we will terminate
+ // the loop on the first non-zero return code.
+ //
+ Assert (msg == WM_DDE_INITIATE);
+
+ while (hwnd)
+ {
+ intrDebugOut((DEB_ITRACE," SendMsgToChildren send to hwnd=%x\n",hwnd));
+
+ if (fAckSent = (1L==SSSendMessage (hwnd, msg, wParam, lParam)))
+ {
+ break;
+ }
+
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+
+ intrDebugOut((DEB_ITRACE,"0 OUT SendMsgToChildren returns %x\n",fAckSent));
+ return(fAckSent);
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SendInitMsgToChildren
+//
+// Synopsis: Sends an init message to all child windows of the hwnd
+//
+// Effects: This routine will send an init message to all children
+// of the given window. It is assuming that the lParam is
+// the atom that contains the topic (ie filename) of the
+// object being looked for.
+//
+// Arguments: [hwnd] -- hwnd of server window
+// [msg] -- MSG to send
+// [wParam] -- hwnd of client window
+// [lParam] -- HIWORD(lParam) is atom of filename
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-28-94 kevinro Commented
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+BOOL SendInitMsgToChildren (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ intrDebugOut((DEB_DDE_INIT,
+ "0 _IN SendInitMsgToChildren(hwnd=%x,msg=%x,wParam=%x,lParam=%x)\n",
+ hwnd,msg,wParam,lParam));
+
+ BOOL fAckSent = FALSE;
+
+ fAckSent = SendMsgToChildren(hwnd,msg,wParam,lParam);
+
+ //
+ // If no windows acknowledged, then we might need to create a doc window
+ //
+ if (!fAckSent)
+ {
+ ATOM aTopic = HIWORD(lParam);
+ Assert (IsAtom(aTopic));
+
+ // if someone's trying to initiate on a filename, i.e., for a link
+ // then create the doc window on demand because 2.0 servers do not
+ // register doc windows. They don't even accept "-Embedding filename"
+ // on the command line
+ if (aTopic != aOLE && aTopic != aSysTopic && IsFile (aTopic))
+ {
+ intrDebugOut((DEB_DDE_INIT," Initiate for link %ws\n",wAtomName(aTopic)));
+ HRESULT hresult = MaybeCreateDocWindow (LOWORD(lParam), aTopic,
+ hwnd, (HWND)wParam);
+
+ fAckSent = (NOERROR==hresult);
+ }
+ }
+ intrDebugOut((DEB_DDE_INIT,
+ "0 _OUT SendInitMsgToChildren fAckSent=%x\n",fAckSent));
+ return fAckSent;
+}
+
+
+
+INTERNAL_(HRESULT) RequestDataStd
+(
+ATOM aItem,
+LPHANDLE lphdde
+)
+{
+
+
+ HANDLE hnew = NULL;
+
+ if (!aItem)
+ goto errRtn;
+
+ if (aItem == aEditItems){
+ hnew = MakeGlobal ("StdHostNames\tStdDocDimensions\tStdTargetDevice");
+ goto PostData;
+
+ }
+
+ if (aItem == aProtocols) {
+ hnew = MakeGlobal ("Embedding\tStdFileEditing");
+ goto PostData;
+ }
+
+ if (aItem == aTopics) {
+ hnew = MakeGlobal ("Doc");
+ goto PostData;
+ }
+
+ if (aItem == aFormats) {
+ hnew = MakeGlobal ("Picture\tBitmap");
+ goto PostData;
+ }
+
+ if (aItem == aStatus) {
+ hnew = MakeGlobal ("Ready");
+ goto PostData;
+ }
+
+ // format we do not understand.
+ goto errRtn;
+
+PostData:
+
+ // Duplicate the DDE data
+ if (MakeDDEData (hnew, CF_TEXT, lphdde, TRUE)){
+ // !!! why are we duplicating the atom.
+ DuplicateAtom (aItem);
+ return NOERROR;
+ }
+errRtn:
+ return ReportResult(0, S_FALSE, 0, 0);
+}
+
+
+//IsSingleServerInstance: returns true if the app is single server app else
+//false.
+
+INTERNAL_(BOOL) IsSingleServerInstance ()
+{
+ HWND hwnd;
+ WORD cnt = 0;
+ HTASK hTask;
+ DdeCHAR buf[MAX_STR];
+
+ hwnd = GetWindow (GetDesktopWindow(), GW_CHILD);
+ hTask = GetCurrentThreadId();
+
+ while (hwnd) {
+ if (hTask == ((HTASK) GetWindowThreadProcessId (hwnd,NULL))) {
+ DdeGetClassName (hwnd, buf, MAX_STR);
+ if (Ddelstrcmp (buf, SRVR_CLASS) == 0)
+ cnt++;
+ }
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+#ifdef FIREWALLS
+ AssertSz (cnt > 0, "srvr window instance count is zero");
+#endif
+ if (cnt == 1)
+ return TRUE;
+ else
+ return FALSE;
+
+}
+
+
+// QueryRevokeClassFactory: returns FALSE if there are clients
+// connected tothis class factory;
+INTERNAL_(BOOL) CDDEServer::QueryRevokeClassFactory ()
+{
+
+ HWND hwnd;
+ LPCLIENT lpclient;
+
+ Assert (IsWindow (m_hwnd));
+ hwnd = GetWindow (m_hwnd, GW_CHILD);
+ while (hwnd)
+ {
+ Assert (IsWindow (hwnd));
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+ if (lpclient->m_cClients != 0 || lpclient->m_fCreatedNotConnected)
+ return FALSE;
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+ return TRUE;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDDEServer::CreateInstance
+//
+// Synopsis: Create an instance of a document
+//
+// Effects:
+//
+// Arguments: [lpclassName] --
+// [lpWidedocName] --
+// [lpdocName] --
+// [pUnk] --
+// [lplpdocClient] --
+// [hwndClient] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-30-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL CDDEServer::CreateInstance
+(
+REFCLSID lpclassName,
+LPOLESTR lpWidedocName,
+LPSTR lpdocName,
+LPUNKNOWN pUnk,
+LPCLIENT FAR* lplpdocClient,
+HWND hwndClient)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%p _IN CDDEServer::CreateInstance(lpWidedocName=%ws,hwndClient=%x)\n",
+ this,
+ WIDECHECK(lpWidedocName),
+ hwndClient));
+
+
+ LPUNKNOWN pUnk2=NULL;
+ LPOLEOBJECT lpoleObj= NULL; // unknown object
+ HRESULT hresult;
+
+ ChkS(this);
+
+ if (NULL==pUnk)
+ {
+ Assert (m_pClassFactory);
+ hresult = m_pClassFactory->CreateInstance (NULL, IID_IUnknown, (LPLPVOID)&pUnk2);
+
+ if (hresult != NOERROR)
+ {
+ return hresult;
+ }
+
+ // Now that we have *used* the DDE server window, we can unlock
+ // the server.
+ // The OLE1 OleLockServer API opens a dummy DDE system channel
+ // and just leaves it open until OleunlockServer is called.
+ // Since we have now used this channel, we know it was not created
+ // for the purpose of locking the server.
+ this->Lock (FALSE, hwndClient);
+
+ // if it is an SDI app, we must revoke the ClassFactory after using it
+ // it is only good for "one-shot" createinstance call.
+ if (m_fcfFlags == REGCLS_SINGLEUSE)
+ {
+ m_pClassFactory->Release(); // done with the ClassFactory
+ Puts ("NULLing m_pCF\r\n");
+ m_pClassFactory = NULL;
+ }
+ }
+ else
+ {
+ pUnk2 = pUnk;
+ pUnk->AddRef();
+ }
+
+ hresult = CDefClient::Create ((LPSRVR)this,
+ pUnk2,
+ lpWidedocName,
+ /*fSetClientSite*/FALSE,
+ /*fDoAdvise*/pUnk!=NULL);
+
+ intrAssert (pUnk2 != NULL);
+ if (pUnk2 != NULL)
+ {
+ pUnk2->Release();
+ }
+
+ pUnk2 = NULL;
+
+ // REVIEW: error recovery
+ if (!(*lplpdocClient = FindDocObj (lpdocName)))
+ {
+ intrAssert(!"Document created but not found");
+ }
+ else
+ {
+ // set the server instance flag so that WM_DDE_INITIATE will not icrement
+ // the ref count. (EXCEL BUG)
+ (*lplpdocClient)->m_bCreateInst = TRUE;
+ }
+ intrDebugOut((DEB_ITRACE,
+ "%p _OUT CDDEServer::CreateInstance hresult=%x\n",
+ this,hresult));
+ return hresult;
+}
+
+
+INTERNAL_(void) CDDEServer::Lock
+ (BOOL fLock, // lock or unlock?
+ HWND hwndClient) // on behalf of which window?
+{
+ intrDebugOut((DEB_ITRACE,
+ "%p _IN CDDEServer::Lock(fLock=%x,hwndCient=%x)\n",
+ this,
+ fLock,
+ hwndClient));
+
+ VDATEHEAP();
+ BOOL fIsLocked = (BOOL) FindClient (m_hcli, hwndClient, /*fDelete*/FALSE);
+
+ if (fLock && !fIsLocked)
+ {
+ if (m_pClassFactory)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "%p ::Locking %x\n",
+ this,
+ m_pClassFactory));
+
+ m_pClassFactory->LockServer (TRUE);
+ // Only way to change the data associated with a client window
+ // is to delete it and re-add it with the new data.
+ FindClient (m_hcli, hwndClient, /*fDelete*/ TRUE);
+ AddClient (&m_hcli, hwndClient, (HANDLE) TRUE); // mark as locked
+ }
+ }
+ else if (!fLock && fIsLocked)
+ {
+ if (m_pClassFactory)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "%p ::UnLocking %x\n",
+ this,
+ m_pClassFactory));
+ m_pClassFactory->LockServer (FALSE);
+ FindClient (m_hcli, hwndClient, /*fDelete*/ TRUE);
+ AddClient (&m_hcli, hwndClient, (HANDLE) FALSE); //mark as unlocked
+ }
+ }
+ VDATEHEAP();
+ intrDebugOut((DEB_ITRACE,
+ "%p _OUT CDDEServer::Lock(fLock=%x,hwndCient=%x)\n",
+ this,
+ fLock,
+ hwndClient));
+}
+
+
+
+
+
+INTERNAL CDefClient::DestroyInstance
+ (void)
+{
+ Puts ("DestroyInstance\r\n");
+ // We just created the instance. we ran into error.
+ // just call Release.
+ m_pUnkOuter->AddRef();
+ ReleaseObjPtrs();
+ Verify (0==m_pUnkOuter->Release());
+ // "this" should be deleted now
+ return NOERROR;
+}
+
+
+
+INTERNAL CDefClient::SetClientSite
+ (void)
+{
+ HRESULT hresult = m_lpoleObj->SetClientSite (&m_OleClientSite);
+ if (hresult==NOERROR)
+ {
+ m_fDidSetClientSite = TRUE;
+ }
+ else
+ {
+ Warn ("SetClientSite failed");
+ }
+ return hresult;
+}
+
+
+
diff --git a/private/ole32/com/remote/dde/server/srvr.h b/private/ole32/com/remote/dde/server/srvr.h
new file mode 100644
index 000000000..e599fb019
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/srvr.h
@@ -0,0 +1,522 @@
+/****************************** Module Header ******************************\
+* Module Name: srvr.h
+*
+* PURPOSE: Private definitions file for server code
+*
+* Created: 1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor (../../90,91) Original
+*
+\***************************************************************************/
+//
+// One of the oleint.h routines redefines GlobalAlloc and friends
+// to perform some memory tracking functions.
+//
+// This doesn't work in these files, since the tracking functions
+// add tail checking, and size to the data structures. GlobalSize
+// is a common function to use to determine how much data to
+// serialize, plus it turns out that the other side of a DDE
+// connection will often be the caller to free the memory.
+//
+// Therefore, OLE_DDE_NO_GLOBAL_TRACKING is used to disable this in the
+// global header file ih\memapi.hxx. Check to insure this
+// flag is set on the compile line
+//
+#if !defined(OLE_DDE_NO_GLOBAL_TRACKING)
+error OLE_DDE_OLE_DDE_NO_GLOBAL_TRACKING must be defined to build this directory
+#endif
+
+#include <dde.h>
+#include <ddeerr.h>
+#include "ddeatoms.h"
+#include "ddepack.h"
+#include <callcont.hxx>
+#include <ddeint.h>
+#include <ddechc.hxx>
+#include <longname.h>
+
+//#define UPDATE
+/*
+ if UPDATE is defined it means:
+ If a 1.0 client advises on save, also do a data advise.
+ This way the client will always
+ have an up-to-date picture (and native data) with respect to a
+ 2.0 server, like 2.0 clients do.
+ If a 1.0 client is prepared to accept data at save time
+ it should be able to handle data on each change: it is exactly
+ as if the user chose File.Update after each change.
+ In fact the item atom is appended with /Save, (see SendDataMsg1)
+ which is sort of a lie, but is what a 1.0 client expects for an
+ embedded object.
+ This is a UI issue.
+*/
+
+#define DEFSTD_ITEM_INDEX 0
+#define STDTARGETDEVICE 1
+#define STDDOCDIMENSIONS 2
+#define STDCOLORSCHEME 3
+#define STDHOSTNAMES 4
+
+
+#define PROTOCOL_EDIT (OLESTR("StdFileEditing"))
+#define PROTOCOL_EXECUTE (OLESTR("StdExecute"))
+
+#define ISATOM(a) ((a >= 0xC000) && (a <= 0xFFFF))
+
+// same limit as in OLE 1.0
+#define MAX_STR 124
+
+#define WW_LPTR 0 // ptr tosrvr/doc/item
+#define WW_HANDLE 4 // instance handle
+#define WW_LE 8 // signature
+
+
+#define WC_LE 0x4c45 // LE chars
+
+
+// Signatures for validity checking
+typedef enum
+{
+ chkDdeSrvr = 0x1234,
+ chkDefClient = 0x5678
+} CHK;
+
+
+const DWORD grfCreateStg = STGM_READWRITE | STGM_SHARE_EXCLUSIVE
+ | STGM_DIRECT | STGM_CREATE ;
+
+
+// If we running under WLO, the HIGHWORD of version number will be >= 0x0A00
+#define VER_WLO 0x0A00
+
+extern "C" WORD CheckPointer (LPVOID, int);
+
+#define READ_ACCESS 0
+#define WRITE_ACCESS 1
+
+#define PROBE_READ(lp){\
+ if (!CheckPointer(lp, READ_ACCESS))\
+ return ReportResult(0, E_INVALIDARG, 0, 0); \
+}
+
+#define PROBE_WRITE(lp){\
+ if (!CheckPointer(lp, WRITE_ACCESS))\
+ return ReportResult(0, E_INVALIDARG, 0, 0); \
+}
+
+#define OLE_COMMAND 1
+#define NON_OLE_COMMAND 2
+
+
+#define WT_SRVR 0 // server window
+#define WT_DOC 1 // document window
+
+#define PROBE_BLOCK(lpsrvr) { \
+ if (lpsrvr->bBlock) \
+ return ReportResult(0, S_SERVER_BLOCKED, 0, 0); \
+}
+
+
+#define SET_MSG_STATUS(retval, status) { \
+ if (!FAILED (GetScode (retval))) \
+ status |= 0x8000; \
+ if (GetScode(retval) == RPC_E_SERVERCALL_RETRYLATER)\
+ status |= 0x4000; \
+}
+
+
+/* Codes for CallBack events */
+typedef enum {
+ OLE_CHANGED, /* 0 */
+ OLE_SAVED, /* 1 */
+ OLE_CLOSED, /* 2 */
+ OLE_RENAMED, /* 3 */
+} OLE_NOTIFICATION;
+
+typedef enum { cnvtypNone, cnvtypConvertTo, cnvtypTreatAs } CNVTYP;
+
+typedef struct _QUE : public CPrivAlloc { // nodes in Block/Unblock queue
+ HWND hwnd; //***
+ UINT msg; // window
+ WPARAM wParam; // procedure parameters
+ LPARAM lParam; //***
+ HANDLE hqNext; // handle to next node
+} QUE;
+
+typedef QUE NEAR * PQUE;
+typedef QUE FAR * LPQUE;
+
+// structure for maintaining the client info.
+#define LIST_SIZE 10
+typedef struct _CLILIST : public CPrivAlloc {
+ HANDLE hcliNext;
+ HANDLE info[LIST_SIZE * 2];
+}CLILIST;
+
+typedef CLILIST FAR *LPCLILIST;
+typedef CLILIST *PCLILIST;
+
+
+class FAR CDDEServer
+{
+ public:
+ static HRESULT Create (LPOLESTR lpclass,
+ REFCLSID rclsid,
+ LPDDECLASSINFO lpDdeInfo,
+ HWND FAR * phwnd,
+ ATOM aOriginalClass,
+ CNVTYP cnvtyp);
+
+ INTERNAL_(BOOL) HandleInitMsg (LPARAM);
+ INTERNAL SrvrExecute (HWND, HANDLE, HWND);
+ INTERNAL Revoke (void);
+ INTERNAL_(BOOL) QueryRevokeClassFactory (void);
+ INTERNAL_(LPCLIENT) FindDocObj (LPSTR lpDoc);
+ INTERNAL_(void) Lock (BOOL fLock, HWND hwndClient);
+
+
+ CLSID m_clsid; // Class ID
+ DWORD m_dwClassFactoryKey; // Class factory reg key
+ LPCLASSFACTORY m_pClassFactory; // class factory
+ ICallControl * m_pCallControl; // Call control interface
+ BOOL m_bTerminate; // Set if we are terminating.
+ HWND m_hwnd; // corresponding window
+ HANDLE m_hcli; // handle to the first block of clients list
+ int m_termNo; // termination count
+ int m_cSrvrClients; // no of clients;
+ DWORD m_fcfFlags; // Class factory instance usage flags
+ CNVTYP m_cnvtyp;
+ CHK m_chk;
+
+ ATOM m_aClass; // class atom
+ ATOM m_aOriginalClass; // for TreatAs/ConvertTo case
+ ATOM m_aExe;
+
+ BOOL m_fDoNotDestroyWindow; // When set, server wnd ingores WM_USER
+
+ private:
+ INTERNAL_(void) SendServerTerminateMsg (void);
+ INTERNAL RevokeAllDocObjs (void);
+ INTERNAL FreeSrvrMem (void);
+ INTERNAL CreateInstance (REFCLSID clsid, LPOLESTR lpWidedocName, LPSTR lpdocName,
+ LPUNKNOWN pUnk, LPCLIENT FAR* lplpdocClient,
+ HWND hwndClient);
+
+
+};
+
+
+
+
+BOOL SendInitMsgToChildren (HWND, UINT msg, WPARAM wParam, LPARAM lParam);
+
+INTERNAL RequestDataStd (ATOM, HANDLE FAR *);
+INTERNAL_(BOOL) ValidateSrvrClass (LPOLESTR, ATOM FAR *);
+INTERNAL_(ATOM) GetExeAtom (LPOLESTR);
+INTERNAL_(BOOL) AddClient (LPHANDLE, HANDLE, HANDLE);
+INTERNAL_(HANDLE) FindClient (HANDLE hCli, HANDLE hkey, BOOL fDelete);
+
+INTERNAL_(BOOL) IsSingleServerInstance (void);
+
+INTERNAL_(void) UtilMemCpy (LPSTR, LPSTR, DWORD);
+INTERNAL_(HANDLE) DuplicateData (HANDLE);
+INTERNAL_(LPSTR) ScanBoolArg (LPSTR, BOOL FAR *);
+INTERNAL_(LPSTR) ScanNumArg (LPSTR, LPINT);
+INTERNAL_(LPSTR) ScanArg(LPSTR);
+INTERNAL_(ATOM) MakeDataAtom (ATOM, int);
+INTERNAL_(ATOM) DuplicateAtom (ATOM);
+INTERNAL_(BOOL) CLSIDFromAtom(ATOM aClass, LPCLSID lpclsid);
+INTERNAL CLSIDFromAtomWithTreatAs (ATOM FAR* paClass, LPCLSID lpclsid,
+ CNVTYP FAR* pcnvtyp);
+INTERNAL wFileIsRunning (LPOLESTR szFile);
+INTERNAL wFileBind (LPOLESTR szFile, LPUNKNOWN FAR* ppUnk);
+INTERNAL wCreateStgAroundNative (HANDLE hNative,
+ ATOM aClassOld,
+ ATOM aClassNew,
+ CNVTYP cnvtyp,
+ ATOM aItem,
+ LPSTORAGE FAR* ppstg,
+ LPLOCKBYTES FAR* pplkbyt);
+INTERNAL wCompatibleClasses (ATOM aClient, ATOM aSrvr);
+
+
+
+
+typedef struct FARSTRUCT : public CPrivAlloc {
+ BOOL f; // do we need to send an ack?
+ // If this is FALSE, other fields don't matter
+ HGLOBAL hdata;
+ HWND hwndFrom; // who sent the execute?
+ HWND hwndTo;
+} EXECUTEACK;
+
+
+// client struct definitions.
+
+
+
+class FAR CDefClient : public CPrivAlloc
+{
+ public:
+ static INTERNAL Create
+ (LPSRVR pDdeSrvr,
+ LPUNKNOWN lpunkObj,
+ LPOLESTR lpdocName,
+ const BOOL fSetClientSite,
+ const BOOL fDoAdvise,
+ const BOOL fRunningInSDI = FALSE,
+ HWND FAR* phwnd = NULL);
+
+ INTERNAL DocExecute (HANDLE);
+ INTERNAL DocDoVerbItem (LPSTR, WORD, BOOL, BOOL);
+ INTERNAL DocShowItem (LPSTR, BOOL);
+ INTERNAL DestroyInstance ();
+ INTERNAL_(void) DeleteFromItemsList (HWND h);
+ INTERNAL_(void) RemoveItemFromItemList (void);
+ INTERNAL_(void) ReleasePseudoItems (void);
+ INTERNAL_(void) ReleaseAllItems ();
+ INTERNAL PokeStdItems (HWND, ATOM, HANDLE,int);
+ INTERNAL PokeData (HWND, ATOM, HANDLE);
+ INTERNAL AdviseData (HWND, ATOM, HANDLE, BOOL FAR *);
+ INTERNAL AdviseStdItems (HWND, ATOM, HANDLE, BOOL FAR *);
+ INTERNAL UnAdviseData (HWND, ATOM);
+ INTERNAL RequestData (HWND, ATOM, USHORT, HANDLE FAR *);
+ INTERNAL Revoke (BOOL fRelease=TRUE);
+ INTERNAL ReleaseObjPtrs (void);
+ INTERNAL_(void) DeleteAdviseInfo ();
+ INTERNAL DoOle20Advise (OLE_NOTIFICATION, CLIPFORMAT);
+ INTERNAL DoOle20UnAdviseAll (void);
+ INTERNAL SetClientSite (void);
+ INTERNAL NoItemConnections (void);
+ INTERNAL_(void) SendExecuteAck (HRESULT hresult);
+ INTERNAL DoInitNew(void);
+ INTERNAL Terminate(HWND, HWND);
+
+ CHK m_chk; // signature
+ ICallControl * m_pCallControl; // Call control for this doc
+ IUnknown FAR* m_pUnkOuter;
+ LPOLEOBJECT m_lpoleObj; // corresponding oleobj
+ LPDATAOBJECT m_lpdataObj; // corresponding dataobj
+ BOOL m_bCreateInst; // instance is just created.
+ BOOL m_bTerminate; // REVIEW: The next two fields may not be necessary.
+ int m_termNo;
+ ATOM m_aItem; // item atom or index for some std items
+ HANDLE m_hcli; // handle to the first block of clients list (Document only)
+ CDefClient FAR *m_lpNextItem; // ptr to the next item.
+ BOOL m_bContainer; // Is document?
+ BOOL m_cRef;
+ HWND m_hwnd; // doc window (only needed in document)
+ HANDLE m_hdevInfo; // latest printer dev info sent
+ HANDLE m_hcliInfo; // advise info for each of the clients
+ BOOL m_fDidRealSetHostNames;
+ BOOL m_fDidSetClientSite;
+ BOOL m_fGotDdeAdvise;
+ BOOL m_fCreatedNotConnected;
+ BOOL m_fInOnClose;
+ BOOL m_fInOleSave;
+ EXECUTEACK m_ExecuteAck;
+ DWORD m_dwConnectionOleObj;
+ DWORD m_dwConnectionDataObj;
+ LPLOCKBYTES m_plkbytNative; // These two fields always refer to
+ LPSTORAGE m_pstgNative; // to the same bits:
+ // The server's persistent storage is
+ // used as its native data.
+ BOOL m_fRunningInSDI;// Link case: file was already open in
+ // an SDI app which does not register a
+ // class factory.
+ LPSRVR m_psrvrParent; // (Document only)
+ DVTARGETDEVICE FAR* m_ptd;
+ BOOL m_fGotStdCloseDoc;
+ BOOL m_fGotEditNoPokeNativeYet;
+ BOOL m_fLocked; // locked by CoLockObjectExternal ?
+
+ // If not zero, then we are waiting for a matching TERMINATE
+
+ CALLDATA * m_pCallData;
+
+
+
+
+
+ // REVIEW: These fields might be necssary for doc (old) level object
+ BOOL m_fEmbed; // embedded object (Document only)
+ int m_cClients; // (Document only)
+ LPCLIENT m_pdoc; // containing document (for items) or self (for docs)
+
+
+implementations:
+
+ STDUNKDECL (CDefClient,DefClient);
+
+ /*** IOleClientSite ***/
+ implement COleClientSiteImpl : IOleClientSite
+ {
+ public:
+ // Constructor
+ COleClientSiteImpl (CDefClient FAR* pDefClient)
+ { m_pDefClient = pDefClient;
+ }
+ STDMETHOD(QueryInterface) (REFIID, LPVOID FAR *);
+ STDMETHOD_(ULONG,AddRef) (void);
+ STDMETHOD_(ULONG,Release) (void);
+
+ /*** IOleClientSite methods ***/
+ STDMETHOD(SaveObject) (THIS);
+ STDMETHOD(GetMoniker) (THIS_ DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk);
+ STDMETHOD(GetContainer) (THIS_ LPOLECONTAINER FAR* ppContainer);
+ STDMETHOD(ShowObject) (THIS);
+ STDMETHOD(OnShowWindow) (THIS_ BOOL fShow);
+ STDMETHOD(RequestNewObjectLayout) (THIS);
+
+ private:
+ CDefClient FAR* m_pDefClient;
+ };
+
+ DECLARE_NC (CDefClient, COleClientSiteImpl)
+ COleClientSiteImpl m_OleClientSite;
+
+
+
+ /*** IAdviseSink ***/
+ implement CAdviseSinkImpl : IAdviseSink
+ {
+ public:
+ // Constructor
+ CAdviseSinkImpl (CDefClient FAR* pDefClient)
+ { m_pDefClient = pDefClient;
+ }
+
+ STDMETHOD(QueryInterface) (REFIID, LPVOID FAR *);
+ STDMETHOD_(ULONG,AddRef) (void);
+ STDMETHOD_(ULONG,Release) (void);
+
+ /**** IAdviseSink methods ****/
+ STDMETHOD_(void,OnDataChange)(THIS_ FORMATETC FAR* pFormatetc,
+ STGMEDIUM FAR* pStgmed) ;
+ STDMETHOD_(void,OnViewChange)(THIS_ DWORD aspects, LONG lindex) ;
+ STDMETHOD_(void,OnExtentChange)(DWORD dwAspect, LPSIZEL lpsizel) {}
+ STDMETHOD_(void,OnRename)(THIS_ LPMONIKER pmk) ;
+ STDMETHOD_(void,OnSave)(THIS) ;
+ STDMETHOD_(void,OnClose)(THIS) ;
+
+ private:
+ CDefClient FAR* m_pDefClient;
+ };
+
+ DECLARE_NC (CDefClient, CAdviseSinkImpl)
+ CAdviseSinkImpl m_AdviseSink;
+
+ctor_dtor:
+ CDefClient (LPUNKNOWN pUnkOuter);
+ ~CDefClient (void);
+
+private:
+ INTERNAL ItemCallBack (int msg, LPOLESTR szNewName = NULL);
+ INTERNAL_(void) SendTerminateMsg ();
+ INTERNAL_(BOOL) SendDataMsg1 (HANDLE, WORD);
+ INTERNAL_(BOOL) SendDataMsg (WORD);
+ INTERNAL_(void) TerminateNonRenameClients (LPCLIENT);
+ INTERNAL_(void) SendRenameMsgs (HANDLE);
+ INTERNAL RegisterItem (LPOLESTR, LPCLIENT FAR *, BOOL);
+ INTERNAL FindItem (LPOLESTR, LPCLIENT FAR *);
+ INTERNAL_(LPCLIENT) SearchItem (LPOLESTR);
+ INTERNAL_(void) DeleteAllItems ();
+ INTERNAL SetStdInfo (HWND, LPOLESTR, HANDLE);
+ INTERNAL_(void) SendDevInfo (HWND);
+ INTERNAL_(BOOL) IsFormatAvailable (CLIPFORMAT);
+ INTERNAL GetData (LPFORMATETC, LPSTGMEDIUM);
+};
+
+
+
+
+typedef struct _CLINFO : public CPrivAlloc { /*clInfo*/ // client transaction info
+ HWND hwnd; // client window handle
+ BOOL bnative; // doe sthis client require native
+ int format; // dusplay format
+ int options; // transaction advise time otipns
+ BOOL bdata; // need wdat with advise?
+ HANDLE hdevInfo; // device info handle
+ BOOL bnewDevInfo; // new device info
+} CLINFO;
+
+typedef CLINFO *PCLINFO;
+
+
+
+INTERNAL_(BOOL) MakeDDEData (HANDLE, int, LPHANDLE, BOOL);
+INTERNAL_(HANDLE) MakeGlobal (LPSTR);
+INTERNAL ScanItemOptions (LPOLESTR, int far *);
+INTERNAL_(int) GetStdItemIndex (ATOM);
+INTERNAL_(BOOL) IsAdviseStdItems (ATOM);
+INTERNAL_(HANDLE) MakeItemData (DDEPOKE FAR *, HANDLE, CLIPFORMAT);
+INTERNAL_(BOOL) AddMessage (HWND, unsigned, WORD, LONG, int);
+
+
+
+#define ITEM_FIND 1 // find the item
+#define ITEM_DELETECLIENT 2 // delete the client from item clients
+#define ITEM_DELETE 3 // delete th item window itself
+#define ITEM_SAVED 4 // item saved
+
+// host names data structcure
+typedef struct _HOSTNAMES : public CPrivAlloc {
+ WORD clientNameOffset;
+ WORD documentNameOffset;
+ BYTE data[1];
+} HOSTNAMES;
+
+typedef HOSTNAMES FAR * LPHOSTNAMES;
+
+
+// routines in UTILS.C
+LPOLESTR CreateUnicodeFromAnsi( LPCSTR lpAnsi);
+LPSTR CreateAnsiFromUnicode( LPCOLESTR lpAnsi);
+INTERNAL_(HANDLE) DuplicateData (HANDLE);
+INTERNAL_(LPSTR) ScanLastBoolArg (LPSTR);
+INTERNAL_(LPSTR) ScanArg(LPSTR);
+INTERNAL_(WORD) ScanCommand(LPSTR, WORD, LPSTR FAR *, ATOM FAR *);
+INTERNAL_(ATOM) MakeDataAtom (ATOM, int);
+INTERNAL_(ATOM) DuplicateAtom (ATOM);
+INTERNAL_(WORD) StrToInt (LPOLESTR);
+INTERNAL_(BOOL) PostMessageToClientWithReply (HWND, UINT, WPARAM, LPARAM, UINT);
+INTERNAL_(BOOL) PostMessageToClient (HWND, UINT, WPARAM, LPARAM);
+INTERNAL_(BOOL) IsWindowValid (HWND);
+INTERNAL_(BOOL) IsOleCommand (ATOM, WORD);
+INTERNAL_(BOOL) UtilQueryProtocol (ATOM, LPOLESTR);
+INTERNAL SynchronousPostMessage (HWND, UINT, WPARAM, LPARAM);
+INTERNAL_(BOOL) IsAtom (ATOM);
+INTERNAL_(BOOL) IsFile (ATOM a, BOOL FAR* pfUnsavedDoc = NULL);
+
+
+// routines for queueing messages and posting them
+INTERNAL_(BOOL) UnblockPostMsgs(HWND, BOOL);
+INTERNAL_(BOOL) BlockPostMsg (HWND, WORD, WORD, LONG);
+INTERNAL_(BOOL) IsBlockQueueEmpty (HWND);
+
+// routine in GIVE2GDI.ASM
+extern "C" HANDLE FAR PASCAL GiveToGDI (HANDLE);
+
+
+// routine in item.c
+INTERNAL_(HBITMAP) DuplicateBitmap (HBITMAP);
+INTERNAL_(HANDLE) DuplicateMetaFile (HANDLE);
+INTERNAL_(BOOL) AreNoClients (HANDLE hcli);
+#ifdef _DEBUG
+INTERNAL_(LPOLESTR) a2s (ATOM);
+#endif
+
+// routines in doc.c
+INTERNAL_(void) FreePokeData (HANDLE);
+INTERNAL_(BOOL) FreeGDIdata (HANDLE, CLIPFORMAT);
+INTERNAL DdeHandleIncomingCall(HWND hwndCli, WORD wCallType);
+
+
+// in ddeworkr.cpp
+INTERNAL_(HANDLE) wNewHandle (LPSTR lpstr, DWORD cb);
+INTERNAL wTimedGetMessage (LPMSG pmsg, HWND hwnd, WORD wFirst, WORD wLast);
+INTERNAL_(ATOM) wGlobalAddAtom (LPCOLESTR sz);
diff --git a/private/ole32/com/remote/dde/server/srvrmain.cxx b/private/ole32/com/remote/dde/server/srvrmain.cxx
new file mode 100644
index 000000000..546cb34c0
--- /dev/null
+++ b/private/ole32/com/remote/dde/server/srvrmain.cxx
@@ -0,0 +1,388 @@
+/****************************** Module Header ******************************\
+* Module Name: Srvrmain.c Server Main module
+*
+* Purpose: Includes server intialization and termination code.
+*
+* Created: Oct 1990.
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor (../10/1990) Designed, coded
+* Raor (03/../1992) Modified for OLE 2.0
+*
+\***************************************************************************/
+
+#include "ole2int.h"
+#include <dde.h>
+// #include "cmacs.h"
+#include "srvr.h"
+#include "ddeatoms.h"
+#include "ddedebug.h"
+ASSERTDATA
+
+ATOM aStdExit = NULL; // "StdExit"
+ATOM aStdCreate = NULL; // "StdNewDicument"
+ATOM aStdOpen = NULL; // "StdOpenDocument"
+ATOM aStdEdit = NULL; // "StdOpenDocument"
+ATOM aStdCreateFromTemplate = NULL; // "StdNewFromTemplate"
+ATOM aStdClose = NULL; // "StdCloseDocument"
+ATOM aStdShowItem = NULL; // "StdShowItem"
+ATOM aStdDoVerbItem = NULL; // "StddoVerbItem"
+ATOM aSysTopic = NULL; // "System"
+ATOM aOLE = NULL; // "OLE"
+ATOM aProtocols = NULL; // "Protocols"
+ATOM aTopics = NULL; // "Topics"
+ATOM aFormats = NULL; // "Formats"
+ATOM aStatus = NULL; // "Status"
+ATOM aEditItems = NULL; // "Edit items
+ATOM aTrue = NULL; // "True"
+ATOM aFalse = NULL; // "False"
+
+
+ATOM aStdHostNames;
+ATOM aStdTargetDevice ;
+ATOM aStdDocDimensions;
+ATOM aStdColorScheme;
+ATOM aChange;
+ATOM aSave;
+ATOM aClose;
+ATOM aStdDocName;
+ATOM aMSDraw;
+
+
+HINSTANCE hdllInst = NULL;
+
+UINT cOleInitializeCalled = 0;
+
+INTERNAL_(BOOL) DDELibMain (
+ HANDLE hInst,
+ WORD wDataSeg,
+ WORD cbHeapSize,
+ LPOLESTR lpszCmdLine
+)
+{
+ DDEWNDCLASS wc;
+
+ intrDebugOut((DEB_ITRACE,
+ "%p _IN DDELibMain hInst=%x\n",
+ 0,
+ hInst));
+
+ InterlockedIncrement((LONG *)&cOleInitializeCalled);
+
+ if (cOleInitializeCalled > 1)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "%p OUT DDELibMain cOleIinitalizedCalled > 1\n",0));
+
+
+ // we already did the "once-per-machine" initialization
+ return TRUE;
+ }
+
+ hdllInst = (HINSTANCE)hInst;
+
+#ifdef _NT1X_
+ if( !aStdExit )
+ {
+
+ // On NT3.51, user preregisters all of these formats for us,
+ // thus giving us a big speed improvement during startup (because
+ // these atoms never change).
+ // Chicago and Cairo do not yet have this functionality.
+
+ aStdExit = GlobalFindAtom(OLESTR("StdExit"));
+
+ aStdCreate = aStdExit + 1;
+ Assert(aStdCreate == GlobalFindAtom (OLESTR("StdNewDocument")));
+
+ aStdOpen = aStdExit + 2;
+ Assert(aStdOpen == GlobalFindAtom (OLESTR("StdOpenDocument")));
+
+ aStdEdit = aStdExit + 3;
+ Assert(aStdEdit == GlobalFindAtom (OLESTR("StdEditDocument")));
+
+ aStdCreateFromTemplate = aStdExit + 4;
+ Assert(aStdCreateFromTemplate ==
+ GlobalFindAtom(OLESTR("StdNewfromTemplate")));
+
+ aStdClose = aStdExit + 5;
+ Assert(aStdClose == GlobalFindAtom (OLESTR("StdCloseDocument")));
+
+ aStdShowItem = aStdExit + 6;
+ Assert(aStdShowItem == GlobalFindAtom (OLESTR("StdShowItem")));
+
+ aStdDoVerbItem = aStdExit + 7;
+ Assert(aStdDoVerbItem == GlobalFindAtom (OLESTR("StdDoVerbItem")));
+
+ aSysTopic = aStdExit + 8;
+ Assert(aSysTopic == GlobalFindAtom (OLESTR("System")));
+
+ aOLE = aStdExit + 9;
+ Assert(aOLE == GlobalFindAtom (OLESTR("OLEsystem")));
+
+ aStdDocName = aStdExit + 10;
+ Assert(aStdDocName == GlobalFindAtom (OLESTR("StdDocumentName")));
+
+ aProtocols = aStdExit + 11;
+ Assert(aProtocols == GlobalFindAtom (OLESTR("Protocols")));
+
+ aTopics = aStdExit + 12;
+ Assert(aTopics == GlobalFindAtom (OLESTR("Topics")));
+
+ aFormats = aStdExit + 13;
+ Assert(aFormats == GlobalFindAtom (OLESTR("Formats")));
+
+ aStatus = aStdExit + 14;
+ Assert(aStatus == GlobalFindAtom (OLESTR("Status")));
+
+ aEditItems = aStdExit + 15;
+ Assert(aEditItems == GlobalFindAtom (OLESTR("EditEnvItems")));
+
+ aTrue = aStdExit + 16;
+ Assert(aTrue == GlobalFindAtom (OLESTR("True")));
+
+ aFalse = aStdExit + 17;
+ Assert(aFalse == GlobalFindAtom (OLESTR("False")));
+
+ aChange = aStdExit + 18;
+ Assert(aChange == GlobalFindAtom (OLESTR("Change")));
+
+ aSave = aStdExit + 19;
+ Assert(aSave == GlobalFindAtom (OLESTR("Save")));
+
+ aClose = aStdExit + 20;
+ Assert(aClose == GlobalFindAtom (OLESTR("Close")));
+
+ aMSDraw = aStdExit + 21;
+ Assert(aMSDraw == GlobalFindAtom (OLESTR("MSDraw")));
+
+ }
+
+#else // !_NT1X_
+
+ aStdExit = GlobalAddAtomA("StdExit");
+
+ aStdCreate = GlobalAddAtomA("StdNewDocument");
+ aStdOpen = GlobalAddAtomA("StdOpenDocument");
+ aStdEdit = GlobalAddAtomA("StdEditDocument");
+ aStdCreateFromTemplate = GlobalAddAtomA("StdNewfromTemplate");
+
+ aStdClose = GlobalAddAtomA("StdCloseDocument");
+ aStdShowItem = GlobalAddAtomA("StdShowItem");
+ aStdDoVerbItem = GlobalAddAtomA("StdDoVerbItem");
+ aSysTopic = GlobalAddAtomA("System");
+ aOLE = GlobalAddAtomA("OLEsystem");
+ aStdDocName = GlobalAddAtomA("StdDocumentName");
+
+ aProtocols = GlobalAddAtomA("Protocols");
+ aTopics = GlobalAddAtomA("Topics");
+ aFormats = GlobalAddAtomA("Formats");
+ aStatus = GlobalAddAtomA("Status");
+ aEditItems = GlobalAddAtomA("EditEnvItems");
+
+ aTrue = GlobalAddAtomA("True");
+ aFalse = GlobalAddAtomA("False");
+
+ aChange = GlobalAddAtomA("Change");
+ aSave = GlobalAddAtomA("Save");
+ aClose = GlobalAddAtomA("Close");
+ aMSDraw = GlobalAddAtomA("MSDraw");
+
+#endif // !_NT1X_
+
+
+ wc.style = NULL;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = sizeof(LPVOID) + //Ask for extra space for storing the
+ //ptr to srvr/doc/iteminfo.
+ sizeof (ULONG) + // for LE chars
+ sizeof (HANDLE); // for keeping the hDLLInst.
+
+ wc.hInstance = hdllInst;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+
+
+#ifdef _CHICAGO_
+ if (IsWOWThread())
+ {
+ DWORD dwThreadId= GetCurrentThreadId();
+ wsprintfA(szSYS_CLASSA ,"Ole2SysWndClass %08X",
+ CoGetCurrentProcess());
+ wsprintfA(szCLIENT_CLASSA,"Ole2ClientWndClass %08X",
+ CoGetCurrentProcess());
+ wsprintfA(szSRVR_CLASSA ,"SrvrWndClass %08X",
+ CoGetCurrentProcess());
+ wsprintfA(szDOC_CLASSA ,"ViewObjWndClass %08X",
+ CoGetCurrentProcess());
+ wsprintfA(szITEM_CLASSA ,"ItemWndClass %08X",
+ CoGetCurrentProcess());
+ wsprintfA(szCOMMONCLASSA ,"DdeCommonWindowClass %08X",
+ CoGetCurrentProcess());
+ }
+#endif // _CHICAGO_
+
+ //
+ // Here we are going to register our Window classes. Because it is
+ // possible that a previous application failed to unregister these
+ // classes, we are going to ignore registration errors. If we get
+ // to the point where we are really going to create a window, and the
+ // window isn't registered, the CreateWindow call will fail.
+ //
+
+ // Srvr window class
+ wc.lpfnWndProc = (WNDPROC)SrvrWndProc;
+ wc.lpszClassName= SRVR_CLASS;
+
+ if (!DdeRegisterClass(&wc))
+ {
+ intrDebugOut((DEB_IERROR,
+ "RegisterClass SrvrWndProc failed %x\n",
+ GetLastError()));
+ intrAssert(!"RegisterClass SrvrWndProc failed %x\n");
+ }
+
+
+
+ // document window class
+ wc.lpfnWndProc = (WNDPROC)DocWndProc;
+ wc.lpszClassName = DOC_CLASS;
+
+ if (!DdeRegisterClass(&wc))
+ {
+ intrDebugOut((DEB_IERROR,
+ "RegisterClass SrvrWndProc failed %x\n",
+ GetLastError()));
+ intrAssert(!"RegisterClass SrvrWndProc failed %x\n");
+ }
+
+ //
+ // The following supports code in the client directory.
+ //
+ wc.lpfnWndProc = (WNDPROC) ClientDocWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = sizeof(LONG); //we are storing longs
+ wc.lpszClassName= CLIENT_CLASS;
+
+ if (!DdeRegisterClass(&wc))
+ {
+ intrDebugOut((DEB_IERROR,
+ "RegisterClass ClientDocWndProc failed %x\n",
+ GetLastError()));
+ }
+ wc.lpfnWndProc = (WNDPROC) SysWndProc;
+ wc.lpszClassName = SYS_CLASS;
+
+ if (!DdeRegisterClass(&wc))
+ {
+ intrDebugOut((DEB_IERROR,
+ "RegisterClass ClientDocWndProc failed %x\n",
+ GetLastError()));
+ intrAssert(!"RegisterClass SrvrWndProc failed %x\n");
+ }
+
+
+ return TRUE;
+}
+
+
+INTERNAL_(void) DDEWEP (
+ BOOL fSystemExit
+)
+{
+
+ Puts("DdeWep\r\n");
+
+ //* protect against bogous calls to
+
+ if (0==cOleInitializeCalled) return;
+
+ if (--cOleInitializeCalled > 0)
+ {
+ // not done yet
+ return;
+ }
+
+ if (fSystemExit != WEP_FREE_DLL)
+ {
+ AssertSz (0, "Bad parm to Wep");
+ return;
+ }
+
+ // free the global atoms.
+
+ // on NT3.51, these atoms were pre-allocated for us by user, we do
+ // not need to free them.
+#ifndef _NT1X_
+
+ if (aStdExit)
+ GlobalDeleteAtom (aStdExit);
+ if (aStdCreate)
+ GlobalDeleteAtom (aStdCreate);
+ if (aStdOpen)
+ GlobalDeleteAtom (aStdOpen);
+ if (aStdEdit)
+ GlobalDeleteAtom (aStdEdit);
+ if (aStdCreateFromTemplate)
+ GlobalDeleteAtom (aStdCreateFromTemplate);
+ if (aStdClose)
+ GlobalDeleteAtom (aStdClose);
+ if (aStdShowItem)
+ GlobalDeleteAtom (aStdShowItem);
+ if (aStdDoVerbItem)
+ GlobalDeleteAtom (aStdDoVerbItem);
+ if (aSysTopic)
+ GlobalDeleteAtom (aSysTopic);
+ if (aOLE)
+ GlobalDeleteAtom (aOLE);
+ if (aStdDocName)
+ GlobalDeleteAtom (aStdDocName);
+
+ if (aProtocols)
+ GlobalDeleteAtom (aProtocols);
+ if (aTopics)
+ GlobalDeleteAtom (aTopics);
+ if (aFormats)
+ GlobalDeleteAtom (aFormats);
+ if (aStatus)
+ GlobalDeleteAtom (aStatus);
+ if (aEditItems)
+ GlobalDeleteAtom (aEditItems);
+
+ if (aTrue)
+ GlobalDeleteAtom (aTrue);
+ if (aFalse)
+ GlobalDeleteAtom (aFalse);
+
+ if (aChange)
+ GlobalDeleteAtom (aChange);
+ if (aSave)
+ GlobalDeleteAtom (aSave);
+ if (aClose)
+ GlobalDeleteAtom (aClose);
+
+ if (aMSDraw)
+ GlobalDeleteAtom (aMSDraw);
+
+#endif // !_NT1X_
+
+ //
+ // We aren't checking error codes here. Because the server application
+ // can shut down on a whim, its possible that we had outstanding windows
+ // At this point, there isn't a thing we can do about it.
+ //
+
+ //
+ // No reason to add a bunch of new code to only Unregister
+ // the class at the right moment when Chicago will clean up
+ // for us.
+ //
+ DdeUnregisterClass (SRVR_CLASS, hdllInst);
+ DdeUnregisterClass (DOC_CLASS, hdllInst);
+ DdeUnregisterClass (SYS_CLASS, hdllInst);
+ DdeUnregisterClass (CLIENT_CLASS, hdllInst);
+}