summaryrefslogtreecommitdiffstats
path: root/private/ole32/com/dde/server
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/dde/server
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 'private/ole32/com/dde/server')
-rw-r--r--private/ole32/com/dde/server/daytona/makefile10
-rw-r--r--private/ole32/com/dde/server/daytona/sources86
-rw-r--r--private/ole32/com/dde/server/ddeadv.cxx132
-rw-r--r--private/ole32/com/dde/server/ddeatoms.h42
-rw-r--r--private/ole32/com/dde/server/ddedebug.h99
-rw-r--r--private/ole32/com/dde/server/ddeerr.h78
-rw-r--r--private/ole32/com/dde/server/ddeint.h181
-rw-r--r--private/ole32/com/dde/server/ddepack.h20
-rw-r--r--private/ole32/com/dde/server/ddesink.cxx251
-rw-r--r--private/ole32/com/dde/server/ddesite.cxx89
-rw-r--r--private/ole32/com/dde/server/ddesrvr.cxx757
-rw-r--r--private/ole32/com/dde/server/ddesrvr.h26
-rw-r--r--private/ole32/com/dde/server/ddeutils.cxx1013
-rw-r--r--private/ole32/com/dde/server/dirs37
-rw-r--r--private/ole32/com/dde/server/doc.cxx1653
-rw-r--r--private/ole32/com/dde/server/item.cxx1210
-rw-r--r--private/ole32/com/dde/server/item2.cxx1405
-rw-r--r--private/ole32/com/dde/server/itemutil.cxx516
-rw-r--r--private/ole32/com/dde/server/itemutil.h14
-rw-r--r--private/ole32/com/dde/server/srvr.cxx2497
-rw-r--r--private/ole32/com/dde/server/srvr.h656
-rw-r--r--private/ole32/com/dde/server/srvrmain.cxx253
22 files changed, 11025 insertions, 0 deletions
diff --git a/private/ole32/com/dde/server/daytona/makefile b/private/ole32/com/dde/server/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/ole32/com/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/dde/server/daytona/sources b/private/ole32/com/dde/server/daytona/sources
new file mode 100644
index 000000000..6b5d83a57
--- /dev/null
+++ b/private/ole32/com/dde/server/daytona/sources
@@ -0,0 +1,86 @@
+!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
+
+!include ..\..\..\..\daytona.inc
+
+#
+# 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
+INCLUDES = $(INCLUDES);..\..\..\dcomrem;..\..\..\inc;..\..\..\dcomidl\daytona;
+INCLUDES = $(INCLUDES);..\..\..\class;..\..\..\objact;
+INCLUDES = $(INCLUDES);..\..\..\..\ole232\inc
+INCLUDES = $(INCLUDES);$(BASEDIR)\private\dcomidl\obj
+
+
+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/dde/server/ddeadv.cxx b/private/ole32/com/dde/server/ddeadv.cxx
new file mode 100644
index 000000000..0d03789ed
--- /dev/null
+++ b/private/ole32/com/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/dde/server/ddeatoms.h b/private/ole32/com/dde/server/ddeatoms.h
new file mode 100644
index 000000000..ba105ba17
--- /dev/null
+++ b/private/ole32/com/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/dde/server/ddedebug.h b/private/ole32/com/dde/server/ddedebug.h
new file mode 100644
index 000000000..dfb7401e6
--- /dev/null
+++ b/private/ole32/com/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/dde/server/ddeerr.h b/private/ole32/com/dde/server/ddeerr.h
new file mode 100644
index 000000000..f35a88b63
--- /dev/null
+++ b/private/ole32/com/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/dde/server/ddeint.h b/private/ole32/com/dde/server/ddeint.h
new file mode 100644
index 000000000..c59274f9e
--- /dev/null
+++ b/private/ole32/com/dde/server/ddeint.h
@@ -0,0 +1,181 @@
+//+---------------------------------------------------------------------------
+//
+// 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)
+
+// global OLE class used to create windows in OLE.
+extern LPTSTR gOleWindowClass;
+extern HINSTANCE g_hinst;
+
+// names of the DDE window classes
+#ifdef _CHICAGO_
+// Note: we have to create a unique string so that we
+// register a unique class for each 16 bit app.
+// The class space is global on chicago.
+//
+
+extern LPSTR szOLE_CLASSA;
+extern LPSTR szSYS_CLASSA;
+
+#define OLE_CLASSA szOLE_CLASSA
+#define SRVR_CLASSA szSRVR_CLASSA
+
+#define DDEWNDCLASS WNDCLASSA
+#define DdeRegisterClass RegisterClassA
+#define DdeUnregisterClass UnregisterClassA
+#define DdeCreateWindowEx SSCreateWindowExA
+
+#else
+
+#define OLE_CLASS L"Ole2WndClass"
+#define OLE_CLASSA "Ole2WndClass"
+
+#define SRVR_CLASS (OLESTR("SrvrWndClass"))
+#define SRVR_CLASSA ("SrvrWndClass")
+
+#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
+
+
+typedef struct tagDISPATCHDATA
+{
+ SCODE scode; // might be no necessary
+ LPVOID pData; // pointer to channel data
+} DISPATCHDATA, *PDISPATCHDATA;
+
+
+// SERVERCALLEX is an extension of SERVERCALL and represents the set of
+// valid responses from IMessageFilter::HandleIncoming Call.
+
+typedef enum tagSERVERCALLEX
+{
+ SERVERCALLEX_ISHANDLED = 0, // server can handle the call now
+ SERVERCALLEX_REJECTED = 1, // server can not handle the call
+ SERVERCALLEX_RETRYLATER = 2, // server suggests trying again later
+ SERVERCALLEX_ERROR = 3, // error?
+ SERVERCALLEX_CANCELED = 5 // client suggests canceling
+} SERVERCALLEX;
+
+
+
+
+//
+// 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/dde/server/ddepack.h b/private/ole32/com/dde/server/ddepack.h
new file mode 100644
index 000000000..ef250cafb
--- /dev/null
+++ b/private/ole32/com/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/dde/server/ddesink.cxx b/private/ole32/com/dde/server/ddesink.cxx
new file mode 100644
index 000000000..302db683e
--- /dev/null
+++ b/private/ole32/com/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/dde/server/ddesite.cxx b/private/ole32/com/dde/server/ddesite.cxx
new file mode 100644
index 000000000..6f1a4e503
--- /dev/null
+++ b/private/ole32/com/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/dde/server/ddesrvr.cxx b/private/ole32/com/dde/server/ddesrvr.cxx
new file mode 100644
index 000000000..b571c2f3a
--- /dev/null
+++ b/private/ole32/com/dde/server/ddesrvr.cxx
@@ -0,0 +1,757 @@
+/*
+ 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 szOLE_CLASSA = "Ole2WndClass 0x######## ";
+LPSTR szSRVR_CLASSA = "SrvrWndClass 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);
+ }
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// 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;
+
+
+ COleTls tls;
+ if (tls->dwFlags & OLETLS_DISABLE_OLE1DDE)
+ {
+ // If DDE use is disabled we shouldn't have gotten here.
+ //
+ Assert(!"Executing CreateCommonDdeWindow when DDE is disabled");
+ hr = CO_E_OLE1DDE_DISABLED;
+ goto exitRtn;
+ }
+
+ //
+ // 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.
+ //
+
+ if (tls->hwndDdeServer != NULL || tls->cOleInits == 0)
+ {
+ goto exitRtn;
+ }
+
+ if (!(hwndDdeServer = DdeCreateWindowEx(0, gOleWindowClass,
+ 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;
+ }
+
+ // fix up the WindowProc entry point.
+ SetWindowLong(hwndDdeServer, GWL_WNDPROC, (LONG)DdeCommonWndProc);
+
+ 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;
+
+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 = S_OK;
+ COleTls tls;
+
+ HWND hwndDdeServer = tls->hwndDdeServer;
+
+ if (hwndDdeServer == NULL)
+ {
+ goto errRtn;
+ }
+
+
+ //
+ // The map from the common window got deleted in DdeCommonWndProc
+ //
+
+ //
+ // If destroying this window fails, there isn't much we can
+ // do about it.
+ //
+ if(!SSDestroyWindow (hwndDdeServer))
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ // NULL out the TLS
+ tls->hwndDdeServer = NULL;
+
+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/dde/server/ddesrvr.h b/private/ole32/com/dde/server/ddesrvr.h
new file mode 100644
index 000000000..291b2c389
--- /dev/null
+++ b/private/ole32/com/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/dde/server/ddeutils.cxx b/private/ole32/com/dde/server/ddeutils.cxx
new file mode 100644
index 000000000..e40436759
--- /dev/null
+++ b/private/ole32/com/dde/server/ddeutils.cxx
@@ -0,0 +1,1013 @@
+/****************************** 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 "ole2int.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/dde/server/dirs b/private/ole32/com/dde/server/dirs
new file mode 100644
index 000000000..820fa2392
--- /dev/null
+++ b/private/ole32/com/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= \
+ \
+ daytona
diff --git a/private/ole32/com/dde/server/doc.cxx b/private/ole32/com/dde/server/doc.cxx
new file mode 100644
index 000000000..fe1b6165c
--- /dev/null
+++ b/private/ole32/com/dde/server/doc.cxx
@@ -0,0 +1,1653 @@
+/***************************************************************************\
+* Module Name: Doc.c Document Main module
+*
+* Purpose: Includes All the document level object communication related.
+*
+* Created: Oct 1990.
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor (../10/1990) Designed, coded (modified for 2.0)
+*
+\***************************************************************************/
+
+#include "ole2int.h"
+//#include "cmacs.h"
+#include <dde.h>
+
+#include "srvr.h"
+#include "ddedebug.h"
+#include "valid.h"
+ASSERTDATA
+
+extern ATOM aStdClose;
+extern ATOM aStdShowItem;
+extern ATOM aStdDoVerbItem;
+extern ATOM aStdDocName;
+extern ATOM aTrue;
+extern ATOM aFalse;
+
+extern HANDLE hddeRename;
+extern HWND hwndRename;
+
+#ifdef _CHICAGO_
+#define szDDEViewObj "DDE ViewObj"
+#else
+#define szDDEViewObj L"DDE ViewObj"
+#endif
+
+
+// HRESULT DdeHandleIncomingCall(HWND hwndCli, WORD wCallType);
+
+//
+// Call CoHandleIncomingCall which will call the message filter
+// Note: only call this functions with:
+// - CALLTYPE_TOPLEVEL ... for synchranous calls
+// - CALLTYPE_ASYNC ... for async calls
+//
+HRESULT DdeHandleIncomingCall(HWND hwndCli, WORD wCallType)
+{
+
+ Assert(!"DdeHandleIncomingCall not implemented");
+
+ return(RPC_E_CALL_REJECTED);
+
+ // Review: bug: get the correcr hwnd
+ switch ( /* CoHandleIncomingCall(hwndCli, wCallType, NULL) */ wCallType) {
+ default:
+ case SERVERCALL_ISHANDLED: // call can be proccesed
+ return NOERROR;
+
+ case SERVERCALL_REJECTED: // call rejected
+ return ResultFromScode(RPC_E_CALL_REJECTED);
+
+ case SERVERCALL_RETRYLATER: // call should be retried later
+ return ResultFromScode(RPC_E_DDE_BUSY);
+ }
+}
+
+
+INTERNAL CDefClient::Create
+(
+ LPSRVR lhOLESERVER,
+ LPUNKNOWN lpunkObj,
+ LPOLESTR lpdocName,
+ const BOOL fSetClientSite,
+ const BOOL fDoAdvise,
+ const BOOL fRunningInSDI, // optional
+ HWND FAR* phwnd // optional
+)
+{
+ LPSRVR lpsrvr = NULL;
+ LPCLIENT lpclient = NULL;
+ HANDLE hclient = NULL;
+ HRESULT hresult = NOERROR;
+
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN CDefClient::Create(lpsrvr=%x,lpdocName=%ws)\n",
+ lhOLESERVER,WIDECHECK(lpdocName)));
+
+ // REVIEW: server's termination has already started. Are
+ // we going to see this condition in the synchronous mode.
+ lpsrvr = (LPSRVR)lhOLESERVER;
+ if (lpsrvr && lpsrvr->m_bTerminate)
+ {
+ Assert(0);
+ return ReportResult(0, RPC_E_DDE_REVOKE, 0, 0);
+ }
+
+#ifdef FIREWALLS
+ PROBE_READ(lpunkObj);
+ PROBE_READ(lpmkObj);
+ PROBE_WRITE(lplhobj);
+#endif
+
+ lpclient = new CDefClient (/*pUnkOuter==*/NULL);;
+
+ Assert(lpclient->m_pUnkOuter);
+
+ lpclient->m_aItem = wGlobalAddAtom (/*lpszObjName*/lpdocName);
+ lpclient->m_fRunningInSDI = fRunningInSDI;
+ lpclient->m_psrvrParent = lpsrvr;
+ // A doc has itself as its containing document
+ lpclient->m_pdoc = lpclient;
+
+ ErrRtnH (lpunkObj->QueryInterface (IID_IOleObject,
+ (LPLPVOID) &lpclient->m_lpoleObj));
+
+ ErrRtnH (lpunkObj->QueryInterface (IID_IDataObject,
+ (LPLPVOID) &lpclient->m_lpdataObj));
+
+ // Lock object; do after the QI so that ReleaseObjPtrs will unlock correctly
+ lpclient->m_fLocked =
+ (NOERROR==CoLockObjectExternal (lpunkObj, TRUE, /*dont care*/ FALSE));
+
+ if (!(lpclient->m_hwnd = DdeCreateWindowEx(0, gOleWindowClass,szDDEViewObj,
+ WS_CHILD,0,0,0,0,lpsrvr->m_hwnd,NULL, g_hinst, NULL)))
+ {
+ intrDebugOut((DEB_ITRACE,"CDefClient::Create() couldn't create window\n"));
+ goto errRtn;
+ }
+
+ // fix up the WindowProc entry point.
+ SetWindowLong(lpclient->m_hwnd, GWL_WNDPROC, (LONG)DocWndProc);
+
+ if (fDoAdvise)
+ {
+ // This is for Packager, in particular, and manual links.
+ // If client does not advise on any data, we still need
+ // to do an OLE advise so we can get OnClose notifications.
+ ErrRtnH (lpclient->DoOle20Advise (OLE_CLOSED, (CLIPFORMAT)0));
+ }
+
+ intrDebugOut((DEB_ITRACE," Doc window %x created\n",lpclient->m_hwnd));
+
+ // Set out parm (window)
+ if (phwnd != NULL)
+ {
+ *phwnd = lpclient->m_hwnd;
+ }
+
+ if (fSetClientSite)
+ {
+ // Should not set the client site if the object has not been
+ // initialized yet, by BindMoniker (i.e. PersistFile::Load)
+ // or PersistStorage::Load
+ if (lpclient->SetClientSite() != NOERROR)
+ {
+ goto errRtn;
+ }
+ }
+
+ Putsi(lpclient->m_cRef);
+
+ SetWindowLong (lpclient->m_hwnd, 0, (LONG)lpclient);
+ SetWindowWord (lpclient->m_hwnd, WW_LE, WC_LE);
+ SetWindowLong (lpclient->m_hwnd,WW_HANDLE,
+ (GetWindowLong (lpsrvr->m_hwnd, WW_HANDLE)));
+
+ hresult = NOERROR;
+
+exitRtn:
+
+ intrDebugOut((DEB_ITRACE,
+ "0 _OUT CDefClient::Create(lpsrvr=%x,lpdocName=%ws) hr=%x\n",
+ lhOLESERVER,
+ WIDECHECK(lpdocName),
+ hresult));
+
+
+ return(hresult);
+errRtn:
+ intrDebugOut((DEB_ITRACE,"CDefClient::Create() in error handling routine\n"));
+ if (lpclient)
+ {
+ if (lpclient->m_hwnd)
+ SSDestroyWindow (lpclient->m_hwnd);
+
+ if (lpclient->m_aItem)
+ GlobalDeleteAtom (lpclient->m_aItem);
+ delete lpclient;
+ }
+ hresult = E_OUTOFMEMORY;
+ goto exitRtn;
+}
+
+
+
+INTERNAL CDefClient::Revoke (BOOL fRelease)
+{
+ Puts ("DefClient::Revoke "); Puth(this); Puta(m_aItem); Putn();
+
+ ChkC(this);
+
+
+ ReleaseObjPtrs();
+
+ // We are done with this CDefClient but someone may still have a reference
+ // to an instance of one of our nested classes. In particular, an advise
+ // holder may be holding on to our sink, or an item may have a pointer
+ // to us if we are its parent document. So we cannot actually do a
+ // "delete this".
+ // The corresponding AddRef is in CDefClient::Create
+ // or CDefClient::RegisterItem
+
+ m_pUnkOuter->Release();
+
+ Puts ("DefClient::Revoke done\r\n");
+ return NOERROR;
+}
+
+
+
+INTERNAL CDefClient::ReleaseObjPtrs
+ (void)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%p _IN CDefClient::ReleaseObjPtrs\n",
+ this));
+
+ ULONG ulResult;
+
+ if (m_lpoleObj && m_fLocked)
+ {
+ // Unlock object. Set m_fLocked to FALSE first to prevent reentrant
+ // problems (unlock causes close which causes this routine to be called)
+
+ m_fLocked = FALSE;
+ CoLockObjectExternal(m_lpoleObj, FALSE, TRUE);
+ }
+ if (m_lpoleObj)
+ {
+ if (m_fDidSetClientSite)
+ m_lpoleObj->SetClientSite(NULL);
+ DoOle20UnAdviseAll();
+ Assert (m_lpoleObj);
+ if (m_lpoleObj)
+ {
+ ulResult = m_lpoleObj->Release();
+ m_lpoleObj = NULL;
+ }
+ intrDebugOut((DEB_ITRACE,
+ "%p _OUT ::ReleaseObjPtrs lpoleObj ulResult=%x\n",
+ this,ulResult));
+ }
+ if (m_lpdataObj)
+ {
+ // Must do it this way because the Release can cause recursion
+ LPDATAOBJECT pdata = m_lpdataObj;
+ m_lpdataObj = NULL;
+ ulResult = pdata->Release();
+ intrDebugOut((DEB_ITRACE,
+ "%p _OUT ::ReleaseObjPtrs pdata ulResult=%x\n",
+ this,ulResult));
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "%p _OUT CDefClient::ReleaseObjPtrs\n",
+ this));
+ return NOERROR;
+}
+#if 000
+//RevokeAllDocs : revokes all the doc objects attached to a given
+//server.
+
+INTERNAL_(HRESULT) CDDEServer::RevokeAllDocObjs ()
+{
+
+ HWND hwnd;
+ HWND hwndnext;
+ LPCLIENT lpclient;
+ Puts ("RevokeAllDocObjs\r\n");
+ ChkS(this);
+
+ hwnd = GetWindow (m_hwnd, GW_CHILD);
+
+ // Go thru each of the child windows and revoke the corresponding
+ // document. Doc windows are child windows for the server window.
+
+ while (hwnd){
+ // sequence is important
+ hwndnext = GetWindow (hwnd, GW_HWNDNEXT);
+ lpclient = ((LPCLIENT)GetWindowLong (hwnd, 0));
+ lpclient->Revoke();
+ hwnd = hwndnext;
+ }
+ return NOERROR;
+}
+#endif
+
+// FindDoc: Given a doc obj, searches for the doc obj
+// in the given class factory tree. returns true if the
+// doc obj is available.
+
+
+INTERNAL_(LPCLIENT) CDDEServer::FindDocObj
+(
+LPSTR lpdocname
+)
+{
+ ATOM aItem;
+ HWND hwnd;
+ LPCLIENT lpclient;
+
+ ChkS(this);
+ aItem = (ATOM)GlobalFindAtomA (lpdocname);
+ Assert (IsWindowValid (m_hwnd));
+ hwnd = GetWindow (m_hwnd, GW_CHILD);
+ Assert (NULL==hwnd || IsWindowValid (hwnd));
+
+ while (hwnd)
+ {
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+ if (lpclient->m_aItem == aItem)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "FindDocObj found %s lpclient=%x\n",
+ lpdocname,
+ lpclient));
+ return lpclient;
+ }
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+ return NULL;
+}
+
+BOOL PostAckToClient(HWND hwndClient,HWND hwndServer,ATOM aItem,DWORD retval)
+{
+ HRESULT hr = TRUE;
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN PostAckToClient(hwndClient=%x,hwndServer=%x,aItem=%x(%ws)\n",
+ hwndClient,
+ hwndServer,
+ aItem,
+ wAtomName(aItem)));
+
+ DWORD status = 0;
+ SET_MSG_STATUS (retval, status);
+
+ LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem);
+
+ if (!PostMessageToClient (hwndClient,
+ WM_DDE_ACK,
+ (UINT)hwndServer,
+ lp))
+ {
+ DDEFREE(WM_DDE_ACK,lp);
+ hr = FALSE;
+ }
+ intrDebugOut((DEB_ITRACE,
+ "0 _OUT PostAckToClient returns %x\n",
+ hr));
+
+ return hr;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: DocHandleIncomingCall
+//
+// Synopsis: Setup and call the CallControl to dispatch a call to the doc
+//
+// Effects: A call has been made from the client that requires us to call
+// into our server. This must be routed through the call control.
+// This routine sets up the appropriate data structures, and
+// calls into the CallControl. The CallControl will in turn
+// call DocDispatchIncomingCall to actually process the call.
+//
+// This routine should only be called by the DocWndProc
+//
+//
+// Arguments: [pDocData] -- Points to DOCDISPATCHDATA for this call
+// This contains all required information for
+// handling the message.
+//
+// Requires:
+//
+// Returns: If an error is returned, it is assumed that the Dispatch
+// routine was not reached. DocDispatchIncomingCall() should
+// not be returning an error.
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-05-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+// This is a co-routine with DocDispatchIncomingCall. See that routine
+// for more details
+//
+//----------------------------------------------------------------------------
+INTERNAL DocHandleIncomingCall(PDOCDISPATCHDATA pDocData)
+{
+ HRESULT hresult = NOERROR;
+ DISPATCHDATA dispatchdata;
+ DWORD callcat;
+
+ intrAssert(pDocData != NULL);
+
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN DocHandleIncomingCall lpclient=%x pDocData=%x\n",
+ pDocData->lpclient,
+ pDocData));
+
+ //
+ // TERMINATE messages must always be handled ASYNC, and cannot
+ // be rejected.
+ //
+ if (pDocData->msg == WM_DDE_TERMINATE)
+ {
+ callcat = CALLCAT_ASYNC;
+ }
+ else
+ {
+ callcat = CALLCAT_SYNCHRONOUS;
+ }
+
+ dispatchdata.pData = (LPVOID) pDocData;
+ pDocData->wDispFunc = DDE_DISP_DOCWNDPROC;
+
+ RPCOLEMESSAGE rpcMsg;
+ RPC_SERVER_INTERFACE RpcInterfaceInfo;
+ DWORD dwFault;
+
+ rpcMsg.iMethod = 0;
+ rpcMsg.Buffer = &dispatchdata;
+ rpcMsg.cbBuffer = sizeof(dispatchdata);
+ rpcMsg.reserved2[1] = &RpcInterfaceInfo;
+ *MSG_TO_IIDPTR(&rpcMsg) = GUID_NULL;
+
+
+ IRpcStubBuffer * pStub = &(pDocData->lpclient->m_pCallMgr);
+ IRpcChannelBuffer * pChannel = &(pDocData->lpclient->m_pCallMgr);
+ hresult = STAInvoke(&rpcMsg, callcat, pStub, pChannel, NULL, &dwFault);
+
+ intrDebugOut((DEB_ITRACE,
+ "0 _OUT DocHandleIncomingCall hresult=%x\n",
+ hresult));
+
+ return(hresult);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: DocDispatchIncomingCall
+//
+// Synopsis: Dispatch a call into the client.
+//
+// Effects: This is a co-routine to DocHandleIncomingCall. This routine
+// is called to implement functions that call into the CDefClient
+// object. It is dispatched by the call control stuff, and helps
+// to insure the server is ready to accept these calls.
+//
+// This routine is coded as a continuation of the DocWndProc.
+// There is a switch on the message. Each message does slightly
+// different things. The code to handle each message was snatched
+// from the original DocWndProc, before it was converted to the
+// new call control mechanism.
+//
+//
+// Arguments: [pDocData] -- Points to Doc Dispatch Data, which are the
+// parameters to DocWndProc which need processing
+//
+// Requires:
+// pDocData cannot be NULL
+//
+// Returns:
+// This routine will always return NOERROR. There are no useful
+// error returns to be made from here. If you decide to return
+// an error, check the DocHandleIncomingCall and DocWndProc to be
+// sure the error paths are correctly handled. Some of the
+// cases do additional error processing in the DocWndProc on
+// error.
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-05-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL DocDispatchIncomingCall(PDOCDISPATCHDATA pDocData)
+{
+ LPCLIENT lpclient = pDocData->lpclient;
+ BOOL fack;
+ HANDLE hdata = pDocData->hdata;
+ ATOM aItem = pDocData->aItem;
+ WPARAM wParam = pDocData->wParam;
+ HWND hwnd = pDocData->hwnd;
+ HRESULT retval;
+
+
+
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN DocDispatchIncomingCall pDocData(%x)\n",
+ pDocData));
+
+ intrAssert(pDocData);
+
+ //
+ // This switch statement is intended to continue the functionality found
+ // in the DocWndProc. These routines are directly interrelated to the
+ // same cases in DocWndProc, and need special care before changing.
+ //
+ switch (pDocData->msg)
+ {
+ case WM_DDE_TERMINATE:
+ {
+ intrDebugOut((DEB_ITRACE,
+ "DDIC: WM_DDE_TERMINATE hwnd=%x \n",
+ pDocData->hwnd));
+
+ //
+ // Here is a fine hack for you. 32-bit applications appear to shut
+ // down slightly differently than 16-bit applications. There is a
+ // problem with Lotus Notes interacting with 32-bit OFFICE apps.
+ // When notes has done an OleCreateFromFile, it starts the
+ // 32-bit hidden, and does a normal DDE conversation. However,
+ // on termination, the 32-bit Doc Window was going away during
+ // this routine. Since the world is now multi-tasking, Lotus
+ // Notes was seeing its server window die because we get
+ // pre-empted during DeleteItemsFromList giving the 16-bit app a
+ // chance to run. Since Lotus is in the
+ // standard OleQueryReleaseStatus() loop, it will detect that the
+ // server has shutdown BEFORE it gets the terminate message.
+ // Go figure. So, insure that we post the reply DDE_TERMINATE
+ // before destroying our window, or the 16-bit applications
+ // won't like us.
+ //
+ PostMessageToClient ((HWND)wParam, WM_DDE_TERMINATE,
+ (UINT) hwnd, NULL);
+
+ // Client initiated the termination. So, we should remove
+ // his window from any of our doc or items' lists.
+ lpclient->DeleteFromItemsList ((HWND)wParam
+ /*, lpclient->m_fEmbed*/);
+
+ ChkC (lpclient);
+
+
+ // REVIEW: If the termination is sent from the client side,
+ // lpoleObj will not be NULL.
+ if (lpclient->m_cClients == 0 && lpclient->m_fEmbed)
+ {
+ Assert (lpclient->m_chk==chkDefClient);
+ lpclient->ReleaseAllItems ();
+ Assert (lpclient->m_chk==chkDefClient);
+ Assert (NULL==lpclient->m_lpoleObj &&
+ NULL==lpclient->m_lpdataObj) ;
+
+ }
+ break;
+ }
+
+ case WM_DDE_EXECUTE:
+ {
+
+ intrDebugOut((DEB_ITRACE,
+ "DDIC: WM_DDE_EXECUTE hwnd=%x hdata=%x\n",
+ pDocData->hwnd,
+ pDocData->hdata));
+
+ //
+ // The following state variables appear to be used by
+ // the execute code.
+ //
+ lpclient->m_ExecuteAck.f = TRUE; // assume we will need to
+ lpclient->m_ExecuteAck.hdata = hdata;
+ lpclient->m_ExecuteAck.hwndFrom = (HWND)wParam;
+ lpclient->m_ExecuteAck.hwndTo = hwnd;
+
+ //
+ // In the event that the command is a StdClose, we need
+ // to force the client to stay around for the duration of
+ // the call.
+ //
+ lpclient->m_pUnkOuter->AddRef();
+
+ retval = lpclient->DocExecute (hdata);
+
+ if (lpclient->m_ExecuteAck.f)
+ {
+ lpclient->SendExecuteAck (retval);
+ }
+
+ lpclient->m_pUnkOuter->Release();
+ break;
+
+ }
+ case WM_DDE_POKE:
+ {
+ int iStdItem;
+ intrDebugOut((DEB_ITRACE,
+ "DDIC: WM_DDE_POKE hwnd=%x aItem=%x(%ws) hdata=%x\n",
+ hwnd,
+ aItem,
+ wAtomName(aItem),
+ hdata));
+
+ if (iStdItem = GetStdItemIndex (aItem))
+ {
+ retval = lpclient->PokeStdItems ((HWND)wParam,
+ aItem,
+ hdata,
+ iStdItem);
+ }
+ else
+ {
+ retval = lpclient->PokeData ((HWND)wParam,
+ aItem,
+ hdata);
+ // This is allowed to fail. PowerPoint tries to poke
+ // data with cfFormat=="StdSave" and "StdFont"
+ }
+
+ if (!PostAckToClient((HWND)wParam,hwnd,aItem,retval))
+ {
+ goto errRtn;
+ }
+ break;
+ }
+ case WM_DDE_ADVISE:
+ {
+ intrDebugOut((DEB_ITRACE,
+ "DDIC: WM_DDE_ADVISE hwnd=%x aItem=%x(%ws) hdata=%x\n",
+ hwnd,
+ aItem,
+ wAtomName(aItem),
+ hdata));
+
+ if (IsAdviseStdItems (aItem))
+ {
+ retval = lpclient->AdviseStdItems ((HWND)wParam,
+ aItem,
+ hdata,
+ (BOOL FAR *)&fack);
+ }
+ else
+ {
+ retval = lpclient->AdviseData ((HWND)wParam,
+ aItem,
+ hdata,
+ (BOOL FAR *)&fack);
+ }
+
+ if (fack)
+ {
+ if (!PostAckToClient((HWND)wParam,hwnd,aItem,retval))
+ {
+ GlobalFree(hdata);
+ }
+ }
+ else if (aItem != NULL)
+ {
+ GlobalDeleteAtom (aItem);
+ }
+ break;
+ }
+ case WM_DDE_UNADVISE:
+ {
+ intrDebugOut((DEB_ITRACE,
+ "DDIC: WM_DDE_UNADVISE hwnd=%x aItem=%x(%ws)\n",
+ hwnd,
+ aItem,
+ wAtomName(aItem)));
+
+ retval = lpclient->UnAdviseData ((HWND)wParam, aItem);
+
+ if (!PostAckToClient((HWND)wParam,hwnd,aItem,retval))
+ {
+ goto errRtn;
+ }
+ break;
+ }
+ case WM_DDE_REQUEST:
+ {
+ intrDebugOut((DEB_ITRACE,
+ "DDIC: WM_DDE_REQUEST hwnd=%x aItem=%x(%ws) cfFormat=%x\n",
+ hwnd,
+ aItem,
+ wAtomName(aItem),
+ (USHORT)LOWORD(pDocData->lParam)));
+
+ retval = lpclient->RequestData ((HWND)wParam,
+ aItem,
+ LOWORD(pDocData->lParam),
+ (HANDLE FAR *)&hdata);
+
+ if (retval == NOERROR)
+ {
+ // post the data message and we are not asking for any
+ // acknowledge.
+
+ intrDebugOut((DEB_ITRACE,
+ "DDIC: posting WM_DDE_DATA\n"));
+
+ LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_DATA,hdata,aItem);
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_DATA, (UINT) hwnd,lp))
+ {
+ // hdata will be freed by the client because fRelease
+ // was set to true by MakeDdeData (called by RequestData)
+
+ DDEFREE(WM_DDE_DATA,lp);
+ goto errRtn;
+ }
+ }
+ else
+ {
+ if (!PostAckToClient((HWND)wParam,hwnd,aItem,retval))
+ {
+ goto errRtn;
+ }
+ }
+ break;
+ }
+ default:
+ //
+ // Whoops, this is very bad. We should never get here.
+ //
+ intrAssert(!"Unknown MSG in DocWndProc: Very Bad indeed");
+
+
+ }
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "0 _OUT DocDispatchIncomingCall pDocData(%x) hr = 0\n",
+ pDocData));
+
+ return(NOERROR);
+errRtn:
+ intrDebugOut((DEB_IERROR,
+ "***** ERROR DDIC pDocData(%x) Post ACK failed. \n",
+ pDocData));
+
+ if (aItem != NULL)
+ {
+ GlobalDeleteAtom (aItem);
+ }
+ goto exitRtn;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DocWndProc
+//
+// Synopsis: Document Window Procedure
+//
+// Effects: Processes DDE messages for a document window.
+//
+// Arguments: [hwnd] --
+// [msg] --
+// [wParam] --
+// [lParam] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-05-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+// When running in a VDM, it is possible that this window was dispatched
+// without having a full window handle. This happens when the getmessage
+// was dispatched from 16-bit. Therefore, we need to convert the hwnd to
+// a full hwnd before doing any comparision functions.
+//
+//----------------------------------------------------------------------------
+STDAPI_(LRESULT) DocWndProc (
+HWND hwndIn,
+UINT msg,
+WPARAM wParam,
+LPARAM lParam
+)
+{
+
+ //
+ // Since this is the DocWndProc, we aren't going to initialize
+ // any of the local variables. This function is called as a WNDPROC,
+ // which is pretty often.
+ //
+
+ DOCDISPATCHDATA docData;
+ LPCLIENT lpclient;
+ WORD status=0;
+ HANDLE hdata;
+ ATOM aItem;
+ HRESULT retval;
+ LPOLEOBJECT lpoleObj;
+ HWND hwnd;
+ DebugOnly (HWND hwndClient;)
+
+ // REVIEW: We need to take care of the bug, related to
+ // Excel. Excel does the sys level connection and sends
+ // terminates immediately before making the connection
+ // to the doc level. If we send release to classfactory
+ // app may revoke the classfactory.
+
+
+ // REVIEW: It may not be necessary to do the blocking.
+ // ReVIEW: For fixing the ref count right way for
+ // CreateInstance Vs. WM_DDE_INIT
+
+#ifdef LATER
+ if (AddMessage (hwnd, msg, wParam, lParam, WT_DOC))
+ return 0L;
+#endif
+
+ switch (msg){
+
+ case WM_CREATE:
+ intrDebugOut((DEB_ITRACE,
+ "DocWndProc: CreateWindow hwndIn=%x\n",
+ hwndIn));
+ break;
+
+
+ case WM_DDE_INITIATE:
+ hwnd = ConvertToFullHWND(hwndIn);
+ intrAssert(IsWindowValid(hwnd));
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+
+ intrDebugOut((DEB_ITRACE,
+ "DocWndProc: WM_DDE_INITIATE hwnd=%x\n",
+ hwnd));
+
+ ChkC(lpclient);
+
+
+ // REVIEW: We may not allow initiates to get thru
+ // while we are waiting for terminates. So, this case
+ // may not arise
+
+ // Need to verify that m_pCI is not NULL during incoming
+ // calls from the client.
+ //
+ if (lpclient->m_fCallData)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "DocWndProc: No initiates while waiting on terminate\n"));
+
+ break;
+ }
+ // if we are the document then respond.
+
+ if (! (lpclient->m_aItem == (ATOM)(HIWORD(lParam))))
+ {
+ break;
+ }
+
+ // We can enterain this client. Put this window in the client list
+ // and acknowledge the initiate.
+
+ if (!AddClient ((LPHANDLE)&lpclient->m_hcli, (HWND)wParam, (HWND)wParam))
+ {
+ break;
+ }
+
+
+ // post the acknowledge
+ DuplicateAtom (LOWORD(lParam));
+ DuplicateAtom (HIWORD(lParam));
+ SSSendMessage ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, lParam);
+
+ lpclient->m_cClients++;
+ lpclient->m_fCreatedNotConnected = FALSE;
+ lpoleObj = lpclient->m_lpoleObj;
+
+ // we have added an addref because of createinstance.
+
+ if (lpclient->m_bCreateInst)
+ {
+ lpclient->m_bCreateInst = FALSE;
+ }
+
+ return 1L; // fAckSent
+ break;
+
+
+ case WM_DDE_EXECUTE:
+ {
+ hwnd = ConvertToFullHWND(hwndIn);
+ intrAssert(IsWindowValid(hwnd));
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+
+ hdata = GET_WM_DDE_EXECUTE_HDATA(wParam,lParam);
+ intrDebugOut((DEB_ITRACE,
+ "DocWndProc: WM_DDE_EXECUTE hwnd=%x hdata=%x\n",
+ hwnd,
+ hdata));
+
+ ChkC(lpclient);
+
+#ifdef FIREWALLS
+ // find the client in the client list.
+ hwndClient = FindClient (lpclient->m_hcli, (HWND)wParam, FALSE);
+ AssertSz (hwndClient, "Client is missing from the server");
+#endif
+ if (!IsWindowValid ((HWND)wParam) || lpclient->m_fCallData)
+ {
+ if (lpclient->m_fCallData)
+ {
+ // This means the terminate has already been sent
+ // to this window (from AdviseSink::OnClose) so
+ // we can ignore the StdCloseDocument.
+ }
+ else
+ {
+ intrAssert(!"Execute received from dead sending window");
+ }
+ // Since we are not sending an ACK, the sender will not
+ // have the chance to free the hCommands handle.
+ DDEFREE(WM_DDE_ACK,lParam);
+ // GlobalFree (hdata);
+ break;
+ }
+
+ //
+ // Fill in the used items in DocData
+ //
+ docData.hwnd = hwnd;
+ docData.msg = msg;
+ docData.wParam = wParam;
+ docData.hdata = hdata;
+ docData.lpclient = lpclient;
+
+ retval = DocHandleIncomingCall(&docData);
+
+ //
+ // If error return, then we didn't call DocDispatchIncomingCall
+ // and therefore need to send a NACK
+ //
+ if (retval != NOERROR)
+ {
+ lpclient->SendExecuteAck (retval);
+ }
+ break;
+ }
+ case WM_DDE_TERMINATE:
+ hwnd = ConvertToFullHWND(hwndIn);
+ intrAssert(IsWindowValid(hwnd));
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+
+ intrDebugOut((DEB_ITRACE,
+ "DocWndProc: WM_DDE_TERMINATE hwnd=%x\n",
+ hwnd));
+
+ ChkC(lpclient);
+
+ //
+ // If m_fCallData, then we are are waiting for a terminate, which
+ // means we generated the original terminate message. If
+ // this is so, then we are waiting for a reply to the
+ // terminate. Set the AckState and break;
+ //
+ if (lpclient->m_fCallData)
+ {
+ lpclient->SetCallState(SERVERCALLEX_ISHANDLED);
+ break;
+ }
+
+
+#ifdef _DEBUG
+ // find the client in the client list.
+ hwndClient = (HWND)FindClient (lpclient->m_hcli,(HWND)wParam, FALSE);
+ AssertSz(hwndClient, "Client is missing from the server");
+#endif
+ AssertIsDoc (lpclient);
+ Assert (lpclient->m_cClients > 0);
+ lpclient->m_cClients--;
+
+ // Necessary safety bracket
+ lpclient->m_pUnkOuter->AddRef();
+
+ // terminate has to be handled always
+ // The DocHandleIncomingCall() routine will set the
+ // calltype to be CALLTYPE_ASYNC
+ // async calls are never rejected
+
+ docData.hwnd = hwnd;
+ docData.msg = msg;
+ docData.wParam = wParam;
+ docData.lpclient = lpclient;
+
+ retval = DocHandleIncomingCall(&docData);
+
+ intrAssert(retval == NOERROR);
+
+ // Necessary safety bracket
+ lpclient->m_pUnkOuter->Release();
+ break;
+
+ case WM_DESTROY:
+
+ intrDebugOut((DEB_ITRACE,
+ "DocWndProc: WM_DESTROY\n"));
+ break;
+
+ case WM_DDE_POKE:
+ {
+ hwnd = ConvertToFullHWND(hwndIn);
+ intrAssert(IsWindowValid(hwnd));
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+ hdata = GET_WM_DDE_POKE_HDATA(wParam,lParam);
+ aItem = GET_WM_DDE_POKE_ITEM(wParam,lParam);
+ ChkC(lpclient);
+
+ if (!IsWindowValid ((HWND) wParam) || lpclient->m_fCallData)
+ {
+ // The sending window is invalid or we have already sent a
+ // TERMINATE to it (as indicated by m_pCI != NULL).
+ // We cannot ACK the message, so we must free any
+ // handles or atoms.
+ Warn ("Ignoring message");
+
+ FreePokeData (hdata);
+LDeleteAtom:
+
+ if (aItem != NULL)
+ {
+ GlobalDeleteAtom (aItem);
+ }
+ break;
+ }
+
+ docData.hwnd = hwnd;
+ docData.msg = msg;
+ docData.wParam = wParam;
+ docData.hdata = hdata;
+ docData.aItem = aItem;
+ docData.lpclient = lpclient;
+
+ retval = DocHandleIncomingCall(&docData);
+ if (retval != NOERROR)
+ {
+ SET_MSG_STATUS (retval, status);
+
+ // !!! If the fRelease is false and the post fails
+ // then we are not freeing the hdata. Are we supposed to
+
+ // REVIEW: The assumption is
+ LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem);
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (UINT) hwnd,lp))
+ {
+ DDEFREE(WM_DDE_ACK,lp);
+ goto LDeleteAtom;
+ }
+ }
+ // johannp: set the busy bit here in the status word
+ break;
+ }
+
+
+ case WM_DDE_ADVISE:
+ {
+ hwnd = ConvertToFullHWND(hwndIn);
+ intrAssert(IsWindowValid(hwnd));
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+ HANDLE hOptions = GET_WM_DDE_ADVISE_HOPTIONS(wParam,lParam);
+ aItem = GET_WM_DDE_ADVISE_ITEM(wParam,lParam);
+
+ ChkC(lpclient);
+ if (!IsWindowValid ((HWND)wParam) || lpclient->m_fCallData)
+ {
+AdviseErr:
+ Warn ("Ignoring advise message");
+ //
+ // GlobalFree wants a handle, we are giving it a DWORD.
+ //
+ GlobalFree (hOptions);
+ break;
+ }
+ docData.hwnd = hwnd;
+ docData.msg = msg;
+ docData.wParam = wParam;
+ docData.hdata = hOptions;
+ docData.aItem = aItem;
+ docData.lpclient = lpclient;
+
+ retval = DocHandleIncomingCall(&docData);
+
+ if (retval != NOERROR)
+ {
+ SET_MSG_STATUS (retval, status);
+
+ LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem);
+
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (UINT) hwnd,lp))
+ {
+ DDEFREE(WM_DDE_ACK,lp);
+ goto AdviseErr;
+ }
+ }
+ break;
+ }
+ case WM_DDE_UNADVISE:
+ {
+ hwnd = ConvertToFullHWND(hwndIn);
+ intrAssert(IsWindowValid(hwnd));
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+
+ aItem = HIWORD(lParam);
+ ChkC(lpclient);
+ if (!IsWindowValid ((HWND)wParam) || lpclient->m_fCallData)
+ {
+ goto LDeleteAtom;
+ }
+ docData.hwnd = hwnd;
+ docData.msg = msg;
+ docData.wParam = wParam;
+ docData.aItem = aItem;
+ docData.lpclient = lpclient;
+
+ retval = DocHandleIncomingCall(&docData);
+
+ if (retval != NOERROR)
+ {
+ SET_MSG_STATUS (retval, status);
+ LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem);
+
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (UINT) hwnd,lp))
+ {
+ DDEFREE(WM_DDE_ACK,lp);
+ goto LDeleteAtom;
+ }
+ }
+
+ break;
+ }
+ case WM_DDE_REQUEST:
+ {
+ hwnd = ConvertToFullHWND(hwndIn);
+ intrAssert(IsWindowValid(hwnd));
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+
+ aItem = HIWORD(lParam);
+
+ ChkC(lpclient);
+ if (!IsWindowValid ((HWND) wParam) || lpclient->m_fCallData)
+ {
+ goto LDeleteAtom;
+ }
+ docData.hwnd = hwnd;
+ docData.msg = msg;
+ docData.wParam = wParam;
+ docData.lParam = lParam;
+ docData.aItem = aItem;
+ docData.lpclient = lpclient;
+
+ retval = DocHandleIncomingCall(&docData);
+ if (retval != NOERROR)
+ {
+ if (retval == RPC_E_DDE_BUSY)
+ {
+ status = 0x4000;
+ }
+ else
+ {
+ status = 0; // negative acknowledge
+ }
+
+ LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem);
+ // if request failed, then acknowledge with error.
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (UINT) hwnd,lp))
+ {
+ DDEFREE(WM_DDE_ACK,lp);
+ goto LDeleteAtom;
+ }
+ }
+ break;
+ }
+ default:
+ return SSDefWindowProc (hwndIn, msg, wParam, lParam);
+
+ }
+
+ return 0L;
+
+}
+
+
+
+
+INTERNAL_(void) CDefClient::SendExecuteAck
+ (HRESULT hresult)
+{
+ AssertIsDoc (this);
+ WORD status = NULL;
+ SET_MSG_STATUS (hresult, status);
+
+ m_ExecuteAck.f = FALSE;
+
+ LPARAM lParam = MAKE_DDE_LPARAM (WM_DDE_ACK,status,
+ (UINT) m_ExecuteAck.hdata);
+ // Post the acknowledge to the client
+ if (!PostMessageToClient (m_ExecuteAck.hwndFrom, WM_DDE_ACK,
+ (UINT) m_ExecuteAck.hwndTo, lParam))
+ {
+ Assert (0);
+ // the window either died or post failed, delete the data
+ DDEFREE (WM_DDE_ACK,lParam);
+ GlobalFree (m_ExecuteAck.hdata);
+ }
+}
+
+
+
+//DocExecute: Interprets the execute command for the
+//document conversation.
+
+
+INTERNAL CDefClient::DocExecute
+ (HANDLE hdata)
+{
+
+ ATOM acmd;
+ BOOL fShow;
+ BOOL fActivate;
+
+ HANDLE hdup = NULL;
+ HRESULT retval = ReportResult(0, S_OOM, 0, 0);
+
+ LPSTR lpitemname;
+ LPSTR lpopt;
+ LPSTR lpnextarg;
+ LPSTR lpdata = NULL;
+ LPSTR lpverb = NULL;
+ INT verb;
+ WORD wCmdType;
+
+ ChkC(this);
+
+ intrDebugOut((DEB_ITRACE,
+ "%p _IN CDefClient::DocExecute(hdata=%x)\n",
+ this,
+ hdata));
+
+ // !!!Can we modify the string which has been passed to us
+ // rather than duplicating the data. This will get some speed
+ // and save some space.
+
+ if(!(hdup = UtDupGlobal(hdata,GMEM_MOVEABLE)))
+ goto errRtn;
+
+ if (!(lpdata = (LPSTR)GlobalLock (hdup)))
+ goto errRtn;
+
+ retval = ReportResult(0, RPC_E_DDE_SYNTAX_EXECUTE, 0, 0);
+
+ intrDebugOut((DEB_ITRACE,
+ "%p _IN CDefClient::DocExecute command=(%s)\n",
+ this,
+ lpdata));
+
+ if(*lpdata++ != '[') // commands start with the left sqaure bracket
+ goto errRtn;
+
+ // scan the command and scan upto the first arg.
+ if (!(wCmdType = ScanCommand(lpdata, WT_DOC, &lpnextarg, &acmd)))
+ goto errRtn;
+
+ if (wCmdType == NON_OLE_COMMAND) {
+
+#ifdef LATER
+ if (lpsrvr = (LPSRVR) GetWindowLong (GetParent (hwnd), 0)) {
+ if (!UtilQueryProtocol (lpsrvr->aClass, PROTOCOL_EXECUTE))
+ retval = OLE_ERROR_PROTOCOL;
+ else {
+#ifdef FIREWALLS
+ if (!CheckPointer (lpoledoc, WRITE_ACCESS))
+ AssertSz (0, "Invalid LPOLESERVERDOC");
+ else if (!CheckPointer (lpoledoc->lpvtbl, WRITE_ACCESS))
+ AssertSz (0, "Invalid LPOLESERVERDOCVTBL");
+ else
+ AssertSz (lpoledoc->lpvtbl->Execute,
+ "Invalid pointer to Execute method");
+#endif
+
+ retval = (*lpoledoc->lpvtbl->Execute) (lpoledoc, hdata);
+ }
+
+ }
+#endif
+ AssertSz(0, "Doc level execute is being called");
+
+ goto errRtn;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdCloseDocument]
+ //
+ //////////////////////////////////////////////////////////////////////////
+ if (acmd == aStdClose){
+
+ LPCLIENT lpclient=NULL;
+ // if not terminated by NULL error
+ if (*lpnextarg)
+ goto errRtn;
+
+ if ((retval = FindItem (NULL, (LPCLIENT FAR *)&lpclient)) != NOERROR)
+ return retval;
+
+
+ lpclient->m_fGotStdCloseDoc = TRUE;
+ retval = lpclient->m_lpoleObj->Close (OLECLOSE_SAVEIFDIRTY);
+ goto end;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdDoVerbItem("itemname", verb, BOOL, BOOL]
+ //
+ //////////////////////////////////////////////////////////////////////////
+ if (acmd == aStdDoVerbItem){
+ lpitemname = lpnextarg;
+
+ if(!(lpverb = ScanArg(lpnextarg)))
+ goto errRtn;
+
+
+ if(!(lpnextarg = ScanNumArg(lpverb, &verb)))
+ goto errRtn;
+
+#ifdef FIREWALLS
+ AssertSz (verb < 9 , "Unexpected verb number");
+#endif
+
+ // now scan the show BOOL
+
+ if (!(lpnextarg = ScanBoolArg (lpnextarg, (BOOL FAR *)&fShow)))
+ goto errRtn;
+
+ fActivate = FALSE;
+
+ // if activate BOOL is present, scan it.
+
+ if (*lpnextarg) {
+ if (!(lpnextarg = ScanBoolArg (lpnextarg, (BOOL FAR *)&fActivate)))
+ goto errRtn;
+ }
+
+ if (*lpnextarg)
+ goto errRtn;
+
+ if (m_fEmbed)
+ {
+ // This is a totally bogus call to SetHostNames whose only
+ // purpose is to notify the server that this is an embedded
+ // (not linked) object.
+ if (!m_fDidRealSetHostNames)
+ {
+ Puts ("Bogus call to SetHostNames before DoVerb\r\n");
+ m_lpoleObj->SetHostNames (OLESTR("Container"), OLESTR("Object"));
+ }
+ }
+ // REVIEW: We are assuming that calling the Docdoverb method
+ // will not post any more DDE messahes.
+
+ retval = DocDoVerbItem (lpitemname, verb, fShow, !fActivate);
+ goto end;
+ }
+
+
+
+
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdShowItem("itemname"[, "true"])]
+ //
+ //////////////////////////////////////////////////////////////////////////
+ if (acmd != aStdShowItem)
+ goto errRtn;
+
+ lpitemname = lpnextarg;
+
+ if(!(lpopt = ScanArg(lpitemname)))
+ goto errRtn;
+
+ // Now scan for optional parameter.
+
+ fActivate = FALSE;
+
+ if (*lpopt) {
+
+ if(!(lpnextarg = ScanBoolArg (lpopt, (BOOL FAR *)&fActivate)))
+ goto errRtn;
+
+ if (*lpnextarg)
+ goto errRtn;
+
+
+ }
+
+ if (m_fEmbed)
+ {
+ // This is a totally bogus call to SetHostNames whose only
+ // purpose is to notify the server that this is an embedded
+ // (not linked) object.
+ // REVIEW LINK
+ if (!m_fDidRealSetHostNames)
+ {
+ Puts ("Bogus call to SetHostNames before ShowItem\r\n");
+ m_lpoleObj->SetHostNames (OLESTR("Container"), OLESTR("Object"));
+ }
+ }
+
+ retval = DocShowItem (lpitemname, !fActivate);
+
+end:
+errRtn:
+ if (lpdata)
+ GlobalUnlock (hdup);
+
+ if (hdup)
+ GlobalFree (hdup);
+
+ intrDebugOut((DEB_ITRACE,
+ "%p _OUT CDefClient::DocExecute(hdata=%x) hresult=%x\n",
+ this,
+ hdata,
+ retval));
+
+ return (HRESULT)retval;
+}
+
+
+
+INTERNAL_(HRESULT) CDefClient::DocShowItem
+(
+LPSTR lpAnsiitemname,
+BOOL fAct
+)
+{
+ LPCLIENT lpclient;
+ HRESULT retval;
+ LPOLEOBJECT lpoleObj;
+
+ ChkC(this);
+ WCHAR lpitemname[MAX_STR];
+
+ if (MultiByteToWideChar(CP_ACP,0,lpAnsiitemname,-1,lpitemname,MAX_STR) == FALSE)
+ {
+ Assert(!"Unable to convert characters");
+ return(E_UNEXPECTED);
+ }
+
+ if ((retval = FindItem (lpitemname, (LPCLIENT FAR *)&lpclient))
+ != NOERROR)
+ return retval;
+
+ ChkC(lpclient);
+
+ lpoleObj = lpclient->m_lpoleObj;
+
+
+#ifdef FIREWALLS1
+ if (!CheckPointer (lpoleObj->lpvtbl, WRITE_ACCESS))
+ AssertSz (0, "Invalid LPOLEOBJECTVTBL");
+ else
+ AssertSz (lpoleObj->lpvtbl->DoVerb,
+ "Invalid pointer to DoVerb method");
+#endif
+
+ // protocol sends false for activating and TRUE for not activating.
+ // for api send TRUE for avtivating and FALSE for not activating.
+ return lpclient->m_lpoleObj->DoVerb(OLEVERB_SHOW, NULL, NULL, NULL, NULL, NULL);
+}
+
+
+
+INTERNAL_(HRESULT) CDefClient::DocDoVerbItem
+(
+LPSTR lpAnsiitemname,
+WORD verb,
+BOOL fShow,
+BOOL fAct
+)
+{
+ LPCLIENT lpclient;
+ HRESULT retval;
+
+ WCHAR lpitemname[MAX_STR];
+
+ if (MultiByteToWideChar(CP_ACP,0,lpAnsiitemname,-1,lpitemname,MAX_STR) == FALSE)
+ {
+ Assert(!"Unable to convert characters");
+ return(E_UNEXPECTED);
+ }
+
+ ChkC(this);
+ Puts ("DefClient::DocDoVerbItem\r\n");
+ if ((retval = FindItem (lpitemname, (LPCLIENT FAR *)&lpclient))
+ != NOERROR)
+ return retval;
+ ChkC(lpclient);
+
+#ifdef FIREWALLS1
+ if (!CheckPointer (lpclient->lpoleObj->lpvtbl, WRITE_ACCESS))
+ AssertSz (0, "Invalid LPOLEOBJECTVTBL");
+ else
+ AssertSz (lpclient->lpoleObj->lpvtbl->DoVerb,
+ "Invalid pointer to DoVerb method");
+#endif
+
+ // pass TRUE to activate and False not to activate. Differnt from
+ // protocol.
+
+ retval = lpclient->m_lpoleObj->DoVerb(verb, NULL, &m_OleClientSite, NULL, NULL, NULL);
+ // Apparently an obsolete version of Lotus Notes is the only
+ // container (other than Cltest) that sets fShow=FALSE
+ if (!fShow && lpclient->m_lpoleObj && lpclient->m_fEmbed)
+ lpclient->m_lpoleObj->DoVerb(OLEIVERB_HIDE, NULL, &m_OleClientSite, NULL, NULL, NULL);
+ return retval;
+}
+
+INTERNAL CDefClient::DoInitNew()
+{
+ HRESULT hresult;
+ ATOM aClass;
+ LPPERSISTSTORAGE pPersistStg=NULL;
+
+ hresult = m_lpoleObj->QueryInterface(IID_IPersistStorage,
+ (LPLPVOID)&pPersistStg);
+ if (hresult == NOERROR)
+ {
+ CLSID clsid;
+ RetZ (pPersistStg);
+ ErrRtnH (CreateILockBytesOnHGlobal ((HGLOBAL)NULL,
+ /*fDeleteOnRelease*/ TRUE,
+ &m_plkbytNative));
+ ErrZS (m_plkbytNative, E_OUTOFMEMORY);
+
+ ErrRtnH (StgCreateDocfileOnILockBytes
+ (m_plkbytNative,
+ grfCreateStg, 0,
+ &m_pstgNative));
+
+ ErrZS (m_pstgNative, E_OUTOFMEMORY);
+
+ aClass = m_psrvrParent->m_cnvtyp == cnvtypTreatAs ? m_psrvrParent->m_aOriginalClass
+ : m_psrvrParent->m_aClass;
+ // Write appropriate class tag
+ ErrZS (CLSIDFromAtom (aClass,(LPCLSID)&clsid),
+ REGDB_E_CLASSNOTREG);
+ ErrRtnH (WriteClassStg (m_pstgNative, clsid));
+
+ // Provide server with a storage to use for its persistent
+ // storage, i.e., native data. We remember this IStorage and the
+ // ILockBytes it is built on.
+ ErrRtnH (pPersistStg->InitNew(m_pstgNative));
+ m_fGotEditNoPokeNativeYet = FALSE;
+
+ // Now that we have initialized the object, we are allowed to
+ // set the client site, and advise.
+ ErrRtnH (SetClientSite());
+
+ // This is for Packager, in particular. If client does not advise
+ // on any data, we still need to do an OLE advise so we can get
+ // OnClose notifications.
+ DoOle20Advise (OLE_CLOSED, (CLIPFORMAT)0);
+ }
+ else
+ {
+ AssertSz (0, "Can't get IPersistStorage from OleObj\r\n");
+ }
+
+ m_fEmbed = TRUE;
+
+errRtn:
+ if (pPersistStg)
+ pPersistStg->Release();
+ return hresult;
+}
+
+
+// FreePokeData: Frees the poked dats.
+INTERNAL_(void) FreePokeData
+(
+HANDLE hdde
+)
+{
+ DDEPOKE FAR * lpdde;
+ Puts ("FreePokeData\r\n");
+
+ if (hdde) {
+ if (lpdde = (DDEPOKE FAR *) GlobalLock (hdde)) {
+ GlobalUnlock (hdde);
+ FreeGDIdata (*(LPHANDLE)lpdde->Value, lpdde->cfFormat);
+ }
+
+ GlobalFree (hdde);
+ }
+}
+
+
+
+// Returns TRUE if GDI format else returns FALSE
+
+INTERNAL_(BOOL) FreeGDIdata
+(
+HANDLE hData,
+CLIPFORMAT cfFormat
+)
+{
+ Puts ("FreeGDIData\r\n");
+ if (cfFormat == CF_METAFILEPICT) {
+ LPMETAFILEPICT lpMfp;
+
+ if (lpMfp = (LPMETAFILEPICT) GlobalLock (hData)) {
+ GlobalUnlock (hData);
+ DeleteMetaFile (lpMfp->hMF);
+ }
+
+ GlobalFree (hData);
+ }
+ else if (cfFormat == CF_BITMAP)
+ DeleteObject (hData);
+ else if (cfFormat == CF_DIB)
+ GlobalFree (hData);
+ else
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/private/ole32/com/dde/server/item.cxx b/private/ole32/com/dde/server/item.cxx
new file mode 100644
index 000000000..f268cdbcc
--- /dev/null
+++ b/private/ole32/com/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/dde/server/item2.cxx b/private/ole32/com/dde/server/item2.cxx
new file mode 100644
index 000000000..05a1f9c0c
--- /dev/null
+++ b/private/ole32/com/dde/server/item2.cxx
@@ -0,0 +1,1405 @@
+//+---------------------------------------------------------------------------
+//
+// 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>
+#include <limits.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));
+
+ DDECALLDATA DdeCD;
+ HRESULT hresult;
+
+ DdeCD.hwndSvr = hwndTo;
+ DdeCD.hwndCli = hwndFrom;
+ DdeCD.wMsg = WM_DDE_TERMINATE;
+ DdeCD.wParam = (WPARAM)hwndFrom,
+ DdeCD.lParam = 0;
+
+ //
+ // Setting the fCallData 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_fCallData = TRUE;
+
+ RPCOLEMESSAGE RpcOleMsg;
+ RpcOleMsg.Buffer = &DdeCD;
+
+ // Figure out the MsgQ input flags based on the callcat of the call.
+ DWORD dwMsgQInputFlag = gMsgQInputFlagTbl[CALLCAT_SYNCHRONOUS];
+
+ // Now construct a modal loop object for the call that is about to
+ // be made. It maintains the call state and exits when the call has
+ // been completed, cancelled, or rejected.
+
+ CCliModalLoop CML(0, dwMsgQInputFlag);
+
+ do
+ {
+ DWORD status = 0;
+ hresult = CML.SendReceive(&RpcOleMsg, &status, &m_pCallMgr);
+
+ } while (hresult == RPC_E_SERVERCALL_RETRYLATER);
+
+
+ m_fCallData = FALSE;
+
+ 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),
+ m_pCallMgr (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_fCallData = FALSE;
+ // 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);
+ }
+ 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/dde/server/itemutil.cxx b/private/ole32/com/dde/server/itemutil.cxx
new file mode 100644
index 000000000..c0ba1b0f0
--- /dev/null
+++ b/private/ole32/com/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/dde/server/itemutil.h b/private/ole32/com/dde/server/itemutil.h
new file mode 100644
index 000000000..e9af61df2
--- /dev/null
+++ b/private/ole32/com/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/dde/server/srvr.cxx b/private/ole32/com/dde/server/srvr.cxx
new file mode 100644
index 000000000..2f2d8eb40
--- /dev/null
+++ b/private/ole32/com/dde/server/srvr.cxx
@@ -0,0 +1,2497 @@
+
+/****************************** 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
+
+#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);
+
+ // 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, gOleWindowClass,
+ szCDDEServer,
+ WS_OVERLAPPED | WS_CHILD,
+ 0,0,0,0,
+ (HWND)TLSGetDdeServer(),
+ NULL,
+ g_hinst, NULL)))
+ {
+ goto errReturn;
+ }
+
+ // fix up the WindowProc entry point.
+ SetWindowLong(lpDDEsrvr->m_hwnd, GWL_WNDPROC, (LONG)SrvrWndProc);
+
+ //
+ // 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_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);
+ }
+
+ 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;
+ SRVRDISPATCHDATA srvrdispdata;
+ DISPATCHDATA dispatchdata;
+
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN SrvrHandleIncomingCall lpsrvr=%x hwnd=%x hdata=%x wParam=%x\n",
+ lpsrvr,
+ hwnd,
+ hdata,
+ wParam));
+
+ srvrdispdata.wDispFunc = DDE_DISP_SRVRWNDPROC;
+ srvrdispdata.hwnd = hwnd;
+ srvrdispdata.hData = hdata;
+ srvrdispdata.wParam = wParam;
+ srvrdispdata.lpsrvr = lpsrvr;
+
+ dispatchdata.pData = &srvrdispdata;
+
+ RPCOLEMESSAGE rpcMsg;
+ RPC_SERVER_INTERFACE RpcInterfaceInfo;
+ DWORD dwFault;
+
+ rpcMsg.iMethod = 0;
+ rpcMsg.Buffer = &dispatchdata;
+ rpcMsg.cbBuffer = sizeof(dispatchdata);
+ rpcMsg.reserved2[1] = &RpcInterfaceInfo;
+ *MSG_TO_IIDPTR(&rpcMsg) = GUID_NULL;
+
+
+ IRpcStubBuffer * pStub = &(lpsrvr->m_pCallMgr);
+ IRpcChannelBuffer * pChannel = &(lpsrvr->m_pCallMgr);
+ hresult = STAInvoke(&rpcMsg, CALLCAT_SYNCHRONOUS, pStub, pChannel, NULL, &dwFault);
+
+ 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;
+}
+
+
+// implementations of IRpcStubBuffer methods
+STDMETHODIMP CDdeServerCallMgr::QueryInterface
+ ( REFIID iid, LPVOID * ppvObj )
+{
+ return S_OK;
+}
+
+STDMETHODIMP_(ULONG)CDdeServerCallMgr::AddRef ()
+{
+ return 1;
+}
+
+STDMETHODIMP_(ULONG)CDdeServerCallMgr::Release ()
+{
+ return 1;
+}
+
+
+STDMETHODIMP CDdeServerCallMgr::Connect
+ (IUnknown * pUnkServer )
+{
+ // do nothing
+ return S_OK;
+}
+
+STDMETHODIMP_(void) CDdeServerCallMgr::Disconnect
+ ()
+{
+ // do nothing
+}
+
+STDMETHODIMP_(IRpcStubBuffer*) CDdeServerCallMgr::IsIIDSupported
+ (REFIID riid)
+{
+ // do nothing
+ return NULL;
+}
+
+
+STDMETHODIMP_(ULONG) CDdeServerCallMgr::CountRefs
+ ()
+{
+ // do nothing
+ return 1;
+}
+
+STDMETHODIMP CDdeServerCallMgr::DebugServerQueryInterface
+ (void ** ppv )
+{
+ // do nothing
+ *ppv = NULL;
+ return S_OK;
+}
+
+
+STDMETHODIMP_(void) CDdeServerCallMgr::DebugServerRelease
+ (void * pv)
+{
+ // do nothing
+}
+
+STDMETHODIMP CDdeServerCallMgr::Invoke
+ (RPCOLEMESSAGE *_prpcmsg, IRpcChannelBuffer *_pRpcChannelBuffer)
+{
+ DISPATCHDATA *pdispdata = (PDISPATCHDATA) _prpcmsg->Buffer;
+ return DispatchCall( pdispdata );
+}
+
+
+// Provided IRpcChannelBuffer methods (for callback methods side)
+STDMETHODIMP CDdeServerCallMgr::GetBuffer(
+/* [in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+/* [in] */ REFIID riid)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CDdeServerCallMgr::SendReceive(
+/* [out][in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+/* [out] */ ULONG __RPC_FAR *pStatus)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CDdeServerCallMgr::FreeBuffer(
+/* [in] */ RPCOLEMESSAGE __RPC_FAR *pMessage)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CDdeServerCallMgr::GetDestCtx(
+/* [out] */ DWORD __RPC_FAR *pdwDestContext,
+/* [out] */ void __RPC_FAR *__RPC_FAR *ppvDestContext)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CDdeServerCallMgr::IsConnected( void)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CDdeServerCallMgr::SendReceive2(
+/* [out][in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+/* [out] */ ULONG __RPC_FAR *pStatus)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%p _IN CDdeServerCallMgr::SendReceive2(pMessage=%x,pStatus=%x)\n",
+ this,
+ pMessage,
+ pStatus));
+
+ DDECALLDATA *pCD = ((DDECALLDATA *) pMessage->Buffer);
+
+ if(!PostMessageToClient(pCD->hwndSvr,
+ pCD->wMsg,
+ pCD->wParam,
+ pCD->lParam))
+ {
+ intrDebugOut((DEB_ITRACE, "SendRecieve2(%x)PostMessageToClient failed", this));
+ return RPC_E_SERVER_DIED;
+ }
+
+
+ CAptCallCtrl *pCallCtrl = GetAptCallCtrl();
+
+ CCliModalLoop *pCML = pCallCtrl->GetTopCML();
+
+ HRESULT hres = S_OK;
+ BOOL fWait = !(m_pDefClient->m_CallState == SERVERCALLEX_ISHANDLED);
+
+ while (fWait)
+ {
+ HRESULT hr = OleModalLoopBlockFn(NULL, pCML, NULL);
+
+ if (m_pDefClient->m_CallState == SERVERCALLEX_ISHANDLED)
+ {
+ fWait = FALSE;
+ }
+ else if (hr != RPC_S_CALLPENDING)
+ {
+ fWait = FALSE;
+ hres = hr; // return result from OleModalLoopBlockFn()
+ }
+ }
+
+ if (FAILED(hres))
+ {
+ intrDebugOut((DEB_ITRACE, "**** CDdeServerCallMgr::SendReceive2 OleModalLoopBlockFn returned %x ***\n", hres));
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "%p _OUT CDdeServerCallMgr::SendReceive2(pMessage=%x,pStatus=%x)\n",
+ this,
+ pMessage,
+ pStatus));
+
+ return hres;
+}
diff --git a/private/ole32/com/dde/server/srvr.h b/private/ole32/com/dde/server/srvr.h
new file mode 100644
index 000000000..f2e410f33
--- /dev/null
+++ b/private/ole32/com/dde/server/srvr.h
@@ -0,0 +1,656 @@
+/****************************** 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 <callctrl.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;
+
+
+// this is an object to be embedded in both CDefClient and CDDEServer to glue
+// to the new(est) call control interface
+class CDdeServerCallMgr : public IRpcStubBuffer, public IRpcChannelBuffer2 {
+
+ private:
+ CDefClient * m_pDefClient; // our embeddor (either a CDefClient or a CDDEServer)
+ CDDEServer * m_pDDEServer; // one of these is NULL;
+
+ public:
+ CDdeServerCallMgr (CDefClient * pDefClient)
+ { m_pDefClient = pDefClient;
+ m_pDDEServer = NULL;}
+
+ CDdeServerCallMgr (CDDEServer * pDefClient)
+ { m_pDefClient = NULL;
+ m_pDDEServer = pDefClient;}
+
+ STDMETHOD(QueryInterface) ( REFIID iid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) ();
+ STDMETHOD_(ULONG,Release) ();
+
+ // IRpcStubBuffer methods
+ STDMETHOD(Connect)(
+ /* [in] */ IUnknown *pUnkServer);
+
+ STDMETHOD_(void,Disconnect)( void);
+
+ STDMETHOD(Invoke)(
+ /* [in] */ RPCOLEMESSAGE *_prpcmsg,
+ /* [in] */ IRpcChannelBuffer *_pRpcChannelBuffer);
+
+ STDMETHOD_(IRpcStubBuffer *,IsIIDSupported)(
+ /* [in] */ REFIID riid);
+
+ STDMETHOD_(ULONG,CountRefs)( void);
+
+ STDMETHOD(DebugServerQueryInterface)(
+ void * *ppv);
+
+ STDMETHOD_(void,DebugServerRelease)(
+ void *pv);
+
+
+
+ // IRpcChannelBuffer methods
+ STDMETHOD(GetBuffer) (
+ /* [in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+ /* [in] */ REFIID riid);
+
+ STDMETHOD(SendReceive) (
+ /* [out][in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+ /* [out] */ ULONG __RPC_FAR *pStatus);
+
+ STDMETHOD(FreeBuffer) (
+ /* [in] */ RPCOLEMESSAGE __RPC_FAR *pMessage);
+
+ STDMETHOD(GetDestCtx) (
+ /* [out] */ DWORD __RPC_FAR *pdwDestContext,
+ /* [out] */ void __RPC_FAR *__RPC_FAR *ppvDestContext);
+
+ STDMETHOD(IsConnected) ( void);
+
+ STDMETHOD(SendReceive2) (
+ /* [out][in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+ /* [out] */ ULONG __RPC_FAR *pStatus);
+};
+
+
+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
+ CDdeServerCallMgr m_pCallMgr; // call management interfaces
+ 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);
+
+public:
+ //ctor
+ CDDEServer()
+ : m_pCallMgr( this )
+ {
+ }
+
+
+};
+
+
+
+
+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);
+ INTERNAL_(void) SetCallState (SERVERCALLEX State)
+ {
+ m_CallState = State;
+ }
+
+ CHK m_chk; // signature
+ CDdeServerCallMgr m_pCallMgr; // call management interfaces
+ SERVERCALLEX m_CallState;
+
+ 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 FALSE, then we are waiting for a matching TERMINATE
+
+ BOOL m_fCallData;
+
+
+
+
+
+ // 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);
+
+//+---------------------------------------------------------------------------
+//
+// Function: TLSSetDdeServer
+//
+// Synopsis: Sets hwnd to CommonDdeServer window
+//
+// Arguments: [hwndDdeServer] --
+//
+// History: 5-13-94 kevinro Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+inline BOOL TLSSetDdeServer(HWND hwndDdeServer)
+{
+ HRESULT hr;
+ COleTls tls(hr);
+
+ if (SUCCEEDED(hr))
+ {
+ tls->hwndDdeServer = hwndDdeServer;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: TLSGetDdeServer
+//
+// Synopsis: Returns a handle to the per thread DdeServer window
+//
+// Returns: hwndDdeServer for thread
+//
+// History: 5-13-94 kevinro Created
+//
+// Notes:
+//----------------------------------------------------------------------------
+inline HWND TLSGetDdeServer()
+{
+ HRESULT hr;
+ COleTls tls(hr);
+
+ if (SUCCEEDED(hr))
+ {
+ return tls->hwndDdeServer;
+ }
+
+ return NULL;
+}
diff --git a/private/ole32/com/dde/server/srvrmain.cxx b/private/ole32/com/dde/server/srvrmain.cxx
new file mode 100644
index 000000000..67a13dcc7
--- /dev/null
+++ b/private/ole32/com/dde/server/srvrmain.cxx
@@ -0,0 +1,253 @@
+/****************************** 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;
+
+
+INTERNAL_(BOOL) DDELibMain (
+ HANDLE hInst,
+ WORD wDataSeg,
+ WORD cbHeapSize,
+ LPOLESTR lpszCmdLine
+)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%p _IN DDELibMain hInst=%x\n",
+ 0,
+ hInst));
+
+ if( !aStdExit )
+ {
+#ifndef _CHICAGO_
+ // 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 // _CHICAGO_
+
+ 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");
+
+ }
+
+ if (IsWowThread())
+ {
+ wsprintfA(szOLE_CLASSA, "Ole2WndClass %08X", CoGetCurrentProcess());
+ }
+#endif // _CHICAGO_
+
+ return TRUE;
+}
+
+
+INTERNAL_(void) DDEWEP (
+ BOOL fSystemExit
+)
+{
+#if DBG==1
+ Puts("DdeWep\r\n");
+
+ if (fSystemExit != WEP_FREE_DLL)
+ {
+ AssertSz (0, "Bad parm to Wep");
+ return;
+ }
+#endif // DBG==1
+
+ // free the global atoms.
+
+ // on NT3.51, these atoms were pre-allocated for us by user, we do
+ // not need to free them.
+#ifdef _CHICAGO_
+
+ 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 // _CHICAGO_
+}