From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ole32/com/dde/server/daytona/makefile | 10 + private/ole32/com/dde/server/daytona/sources | 86 + private/ole32/com/dde/server/ddeadv.cxx | 132 ++ private/ole32/com/dde/server/ddeatoms.h | 42 + private/ole32/com/dde/server/ddedebug.h | 99 + private/ole32/com/dde/server/ddeerr.h | 78 + private/ole32/com/dde/server/ddeint.h | 181 ++ private/ole32/com/dde/server/ddepack.h | 20 + private/ole32/com/dde/server/ddesink.cxx | 251 +++ private/ole32/com/dde/server/ddesite.cxx | 89 + private/ole32/com/dde/server/ddesrvr.cxx | 757 ++++++++ private/ole32/com/dde/server/ddesrvr.h | 26 + private/ole32/com/dde/server/ddeutils.cxx | 1013 ++++++++++ private/ole32/com/dde/server/dirs | 37 + private/ole32/com/dde/server/doc.cxx | 1653 ++++++++++++++++ private/ole32/com/dde/server/item.cxx | 1210 ++++++++++++ private/ole32/com/dde/server/item2.cxx | 1405 ++++++++++++++ private/ole32/com/dde/server/itemutil.cxx | 516 +++++ private/ole32/com/dde/server/itemutil.h | 14 + private/ole32/com/dde/server/srvr.cxx | 2497 +++++++++++++++++++++++++ private/ole32/com/dde/server/srvr.h | 656 +++++++ private/ole32/com/dde/server/srvrmain.cxx | 253 +++ 22 files changed, 11025 insertions(+) create mode 100644 private/ole32/com/dde/server/daytona/makefile create mode 100644 private/ole32/com/dde/server/daytona/sources create mode 100644 private/ole32/com/dde/server/ddeadv.cxx create mode 100644 private/ole32/com/dde/server/ddeatoms.h create mode 100644 private/ole32/com/dde/server/ddedebug.h create mode 100644 private/ole32/com/dde/server/ddeerr.h create mode 100644 private/ole32/com/dde/server/ddeint.h create mode 100644 private/ole32/com/dde/server/ddepack.h create mode 100644 private/ole32/com/dde/server/ddesink.cxx create mode 100644 private/ole32/com/dde/server/ddesite.cxx create mode 100644 private/ole32/com/dde/server/ddesrvr.cxx create mode 100644 private/ole32/com/dde/server/ddesrvr.h create mode 100644 private/ole32/com/dde/server/ddeutils.cxx create mode 100644 private/ole32/com/dde/server/dirs create mode 100644 private/ole32/com/dde/server/doc.cxx create mode 100644 private/ole32/com/dde/server/item.cxx create mode 100644 private/ole32/com/dde/server/item2.cxx create mode 100644 private/ole32/com/dde/server/itemutil.cxx create mode 100644 private/ole32/com/dde/server/itemutil.h create mode 100644 private/ole32/com/dde/server/srvr.cxx create mode 100644 private/ole32/com/dde/server/srvr.h create mode 100644 private/ole32/com/dde/server/srvrmain.cxx (limited to 'private/ole32/com/dde/server') 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"") +#define ANSICHECK(x) (x?x:"") + +#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 + +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 +} + +#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 +#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 +#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 +#include +#include +#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 +#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 +#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 + +#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 +#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 +#include "ddeatoms.h" +#include "ddedebug.h" +#include "srvr.h" +#include "itemutil.h" +#include "trgt_dev.h" +#include +#include +#ifndef WIN32 +// #include +#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 +// #include "cmacs.h" +#include + +// for RemDdeRevokeClassFactory and HDDESRVR +#include + +#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 +#include +#include "ddeatoms.h" +#include "ddepack.h" +#include +#include +#include +#include + +//#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 +// #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_ +} -- cgit v1.2.3