summaryrefslogtreecommitdiffstats
path: root/private/ole32/com/dde/client
diff options
context:
space:
mode:
Diffstat (limited to 'private/ole32/com/dde/client')
-rw-r--r--private/ole32/com/dde/client/cnct_tbl.cxx182
-rw-r--r--private/ole32/com/dde/client/cnct_tbl.h27
-rw-r--r--private/ole32/com/dde/client/daytona/makefile10
-rw-r--r--private/ole32/com/dde/client/daytona/sources85
-rw-r--r--private/ole32/com/dde/client/ddechc.cxx89
-rw-r--r--private/ole32/com/dde/client/ddechc.hxx115
-rw-r--r--private/ole32/com/dde/client/ddecnvrt.cxx348
-rw-r--r--private/ole32/com/dde/client/ddedo.cxx951
-rw-r--r--private/ole32/com/dde/client/ddeioc.cxx209
-rw-r--r--private/ole32/com/dde/client/ddemnker.cxx511
-rw-r--r--private/ole32/com/dde/client/ddeoo.cxx770
-rw-r--r--private/ole32/com/dde/client/ddeproxy.cxx2884
-rw-r--r--private/ole32/com/dde/client/ddeproxy.h730
-rw-r--r--private/ole32/com/dde/client/ddestg.cxx529
-rw-r--r--private/ole32/com/dde/client/ddewnd.cxx361
-rw-r--r--private/ole32/com/dde/client/ddeworkr.cxx1331
-rw-r--r--private/ole32/com/dde/client/dirs37
-rw-r--r--private/ole32/com/dde/client/modallp.cxx315
-rw-r--r--private/ole32/com/dde/client/packmnkr.cxx333
-rw-r--r--private/ole32/com/dde/client/packmnkr.h63
-rw-r--r--private/ole32/com/dde/client/trgt_dev.h19
21 files changed, 9899 insertions, 0 deletions
diff --git a/private/ole32/com/dde/client/cnct_tbl.cxx b/private/ole32/com/dde/client/cnct_tbl.cxx
new file mode 100644
index 000000000..bc7200223
--- /dev/null
+++ b/private/ole32/com/dde/client/cnct_tbl.cxx
@@ -0,0 +1,182 @@
+// cnct_tbl.cpp
+//
+// class CConnectionTable
+//
+// CConnectionTable maps connection numbers (as returned by ::Advise())
+// to clipformat's for DDE advise connections.
+
+#include "ddeproxy.h"
+#include "cnct_tbl.h"
+
+ASSERTDATA
+
+#define grfMemFlags (GMEM_MOVEABLE | GMEM_ZEROINIT)
+
+// number of INFO entries to grow by
+#define cinfoBlock 10
+
+typedef struct INFO
+{
+ BOOL fUsed; // is this table entry used?
+ DWORD dwConnection; // search key
+ CLIPFORMAT cf; // corresponding cf, for use in DDE_(UN)ADVISE
+ DWORD grfAdvf; // ON_CHANGE or ON_SAVE or ON_CLOSE
+} INFO, FAR* PINFO;
+
+
+
+CDdeConnectionTable::CDdeConnectionTable ()
+{
+ m_h = GlobalAlloc (grfMemFlags, cinfoBlock * sizeof(INFO));
+ Assert (m_h);
+ m_cinfo=cinfoBlock;
+}
+
+
+CDdeConnectionTable::~CDdeConnectionTable ()
+{
+ Assert(m_h);
+ m_h =GlobalFree (m_h);
+ Assert (m_h==NULL);
+ m_cinfo=0;
+}
+
+
+
+
+INTERNAL CDdeConnectionTable::Add
+ (DWORD dwConnection,
+ CLIPFORMAT cf,
+ DWORD grfAdvf)
+{
+ Start:
+ PINFO rginfo;
+
+ if (NULL==(rginfo = (PINFO) GlobalLock(m_h)))
+ {
+ Puts ("ERROR: CDdeConnectionTable::Add out of memory\n");
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+ // Look for an empty table entry
+ for (DWORD i=0; i<m_cinfo; i++)
+ {
+ if (!rginfo[i].fUsed)
+ {
+ rginfo[i].fUsed = TRUE;
+ rginfo[i].dwConnection = dwConnection;
+ rginfo[i].cf = cf;
+ rginfo[i].grfAdvf = grfAdvf;
+ break;
+ }
+ else
+ {
+ Assert (rginfo[i].dwConnection != dwConnection);
+ }
+ }
+ GlobalUnlock (m_h);
+ if (i==m_cinfo) // if no empty entry found
+ {
+ Puts ("Growing the connection table\n");
+ m_h = GlobalReAlloc (m_h,(m_cinfo += cinfoBlock) * sizeof(INFO),
+ grfMemFlags);
+ if (m_h==NULL)
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ goto Start;
+ }
+ else
+ {
+ return NOERROR;
+ }
+}
+
+
+
+
+INTERNAL CDdeConnectionTable::Subtract
+ (DWORD dwConnection,
+ CLIPFORMAT FAR* pcf, // out parm
+ DWORD FAR* pgrfAdvf) // out parm
+{
+ PINFO rginfo;
+ if (dwConnection==0)
+ {
+ Puts ("CDdeConnectionTable::Subtract called with dwConnection==0\n");
+ return ReportResult(0, E_INVALIDARG, 0, 0);
+ }
+
+ if (NULL==(rginfo = (PINFO) GlobalLock(m_h)))
+ {
+ Assert (0);
+ Puts ("ERROR: CDdeConnectionTable::Subtract out of memory\n");
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ for (DWORD i=0; i<m_cinfo; i++)
+ {
+ if (rginfo[i].fUsed && rginfo[i].dwConnection == dwConnection)
+ {
+ Assert (pcf);
+ *pcf = rginfo[i].cf;
+ Assert (pgrfAdvf);
+ *pgrfAdvf = rginfo[i].grfAdvf;
+ rginfo[i].fUsed = FALSE; // remove this connection
+ GlobalUnlock (m_h);
+ return NOERROR;
+ }
+ }
+ GlobalUnlock (m_h);
+ return ReportResult(0, S_FALSE, 0, 0); // not found
+}
+
+
+
+
+INTERNAL CDdeConnectionTable::Lookup
+ (CLIPFORMAT cf, // search key
+ LPDWORD pdwConnection) // out parm. May be NULL on input
+{
+ PINFO rginfo;
+
+ if (NULL==(rginfo = (PINFO) GlobalLock(m_h)))
+ {
+ Puts ("ERROR: CDdeConnectionTable::Lookup out of memory\n");
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ for (DWORD i=0; i<m_cinfo; i++)
+ {
+ if (rginfo[i].fUsed &&
+ rginfo[i].cf == cf)
+ {
+ if (pdwConnection)
+ *pdwConnection = rginfo[i].dwConnection;
+ GlobalUnlock (m_h);
+ return NOERROR;
+ }
+ }
+ GlobalUnlock (m_h);
+ return ReportResult(0, S_FALSE, 0, 0); // not found
+}
+
+
+
+INTERNAL CDdeConnectionTable::Erase
+ (void)
+{
+ PINFO rginfo;
+ Assert (wIsValidHandle(m_h, NULL));
+ if (NULL==(rginfo = (PINFO) GlobalLock(m_h)))
+ {
+ Puts ("ERROR: CDdeConnectionTable::Lookup out of memory\n");
+ Assert (0);
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ for (DWORD i=0; i<m_cinfo; i++)
+ {
+ rginfo[i].fUsed = FALSE;
+ }
+ GlobalUnlock (m_h);
+ return NOERROR;
+}
+
diff --git a/private/ole32/com/dde/client/cnct_tbl.h b/private/ole32/com/dde/client/cnct_tbl.h
new file mode 100644
index 000000000..656b9ce89
--- /dev/null
+++ b/private/ole32/com/dde/client/cnct_tbl.h
@@ -0,0 +1,27 @@
+// cnct_tbl.h
+
+// CConnectionTable maps connection numbers (as returned by ::Advise())
+// to clipformat's for DDE advise connections.
+
+#ifndef fCnct_tbl_h
+#define fCnct_tbl_h
+
+class FAR CDdeConnectionTable : public CPrivAlloc
+{
+ public:
+ CDdeConnectionTable();
+ ~CDdeConnectionTable();
+
+ INTERNAL Add (DWORD dwConnection, CLIPFORMAT cf, DWORD grfAdvf);
+ INTERNAL Subtract (DWORD dwConnection, CLIPFORMAT FAR* pcf, DWORD FAR* pgrfAdvf);
+ INTERNAL Lookup (CLIPFORMAT cf, LPDWORD pdwConnection);
+ INTERNAL Erase (void);
+
+ private:
+ HANDLE m_h; // handle to the table
+ DWORD m_cinfo; // total number of INFO entries
+};
+
+
+#endif
+
diff --git a/private/ole32/com/dde/client/daytona/makefile b/private/ole32/com/dde/client/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/ole32/com/dde/client/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/ole32/com/dde/client/daytona/sources b/private/ole32/com/dde/client/daytona/sources
new file mode 100644
index 000000000..e264f3c35
--- /dev/null
+++ b/private/ole32/com/dde/client/daytona/sources
@@ -0,0 +1,85 @@
+!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= ddecli
+
+#
+# This specifies where the target is to be built. A private target of
+# type LIBRARY or DYNLINK should go to obj, whereas a public target of
+# type LIBRARY or DYNLINK should go to $(BASEDIR)\public\sdk\lib.
+#
+
+TARGETPATH= obj
+
+#
+# This specifies the type of the target, such as PROGRAM, DYNLINK, LIBRARY,
+# etc.
+#
+
+TARGETTYPE= LIBRARY
+
+INCLUDES = ..\..\server;..\..\..\..\common\daytona;..\..\..\..\ih
+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= \
+ ..\cnct_tbl.cxx \
+ ..\ddedo.cxx \
+ ..\ddeioc.cxx \
+ ..\ddemnker.cxx \
+ ..\ddeoo.cxx \
+ ..\ddeproxy.cxx \
+ ..\ddechc.cxx \
+ ..\ddestg.cxx \
+ ..\ddewnd.cxx \
+ ..\ddeworkr.cxx \
+ ..\modallp.cxx \
+ ..\packmnkr.cxx
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+# PRECOMPILED_INCLUDE= ..\headers.cxx
diff --git a/private/ole32/com/dde/client/ddechc.cxx b/private/ole32/com/dde/client/ddechc.cxx
new file mode 100644
index 000000000..e89b7af4f
--- /dev/null
+++ b/private/ole32/com/dde/client/ddechc.cxx
@@ -0,0 +1,89 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: DdeChC.cxx
+//
+// Contents: CDdeChannelControl implementation for DDE. This
+// implementation requires no instance data, therefore it is
+// intended to be static.
+//
+// Functions:
+//
+// History: 08-May-94 Johann Posch (johannp) Created
+// 10-May-94 KevinRo Made simpler
+// 29-May-94 KevinRo Added DDE Server support
+//
+//--------------------------------------------------------------------------
+#include "ddeproxy.h"
+
+//+---------------------------------------------------------------------------
+//
+// Function: DispatchCall
+//
+// Synopsis: DispatchCall is called to handle incoming calls.
+//
+// Effects: Dispatches a call to the specified in the DispatchData.
+// This function is the result of a call in OnData(), which
+// processes incoming calls from the OLE 1.0 server.
+//
+// Arguments: [pDispData] -- Points to the dispatch data structure
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-16-94 JohannP Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL DispatchCall( PDISPATCHDATA pDispData )
+{
+ intrDebugOut((DEB_ITRACE,
+ "DispatchCall(pDispData=%x)\n",
+ pDispData));
+
+ intrAssert(pDispData != NULL);
+ POLE1DISPATCHDATA pData = (POLE1DISPATCHDATA)pDispData->pData;
+ intrAssert(pData != NULL);
+
+ switch (pData->wDispFunc)
+ {
+ case DDE_DISP_SENDONDATACHANGE: // OnDataChange
+ {
+ PDDEDISPATCHDATA pDData = (PDDEDISPATCHDATA)pDispData->pData;
+ return pDData->pCDdeObject->SendOnDataChange(pDData->iArg);
+ }
+
+ case DDE_DISP_OLECALLBACK: // OleCallBack
+ {
+ PDDEDISPATCHDATA pDData = (PDDEDISPATCHDATA)pDispData->pData;
+ return pDData->pCDdeObject->OleCallBack(pDData->iArg,NULL);
+ }
+
+ //
+ // The server window has an incoming call. Look in dde\server\srvr.cxx
+ //
+ case DDE_DISP_SRVRWNDPROC:
+ return(SrvrDispatchIncomingCall((PSRVRDISPATCHDATA)pDispData->pData));
+ //
+ // This dispatches to a Document window
+ //
+ case DDE_DISP_DOCWNDPROC:
+ return(DocDispatchIncomingCall((PDOCDISPATCHDATA)pDispData->pData));
+
+ default:
+ intrAssert(!"Unknown wDispFunc");
+ }
+ return E_FAIL;
+}
diff --git a/private/ole32/com/dde/client/ddechc.hxx b/private/ole32/com/dde/client/ddechc.hxx
new file mode 100644
index 000000000..be75388ec
--- /dev/null
+++ b/private/ole32/com/dde/client/ddechc.hxx
@@ -0,0 +1,115 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: DdeChC.cxx
+//
+// Contents: CDdeChannelControl implementation for DDE. This
+// implementation requires no instance data, therefore it is
+// intended to be static.
+//
+// Functions:
+//
+// History: 08-May-94 Johann Posch (johannp) Created
+// 10-May-94 KevinRo Made simpler and commented
+//
+//--------------------------------------------------------------------------
+#ifndef __DDECHC_HXX__
+#define __DDECHC_HXX__
+
+class CDdeObject;
+//
+// The following are the possible callbacks that would be supported by
+// the CDdeObject
+//
+
+typedef enum
+{
+ DDE_DISP_SENDONDATACHANGE = 1,
+ DDE_DISP_OLECALLBACK = 2 ,
+ DDE_DISP_SRVRWNDPROC = 3 ,
+ DDE_DISP_DOCWNDPROC = 4
+} DDE_DISPATCH_FUNC;
+
+
+//
+// The following defines a base class for the OLE 1.0 support
+//
+
+typedef struct tagOLE1DISPATCHDATA
+{
+ DDE_DISPATCH_FUNC wDispFunc;
+}OLE1DISPATCHDATA, *POLE1DISPATCHDATA;
+
+//
+// The following structure is used by OLE 1.0 server support code
+//
+
+typedef struct tagDDEDISPATCHDATA : public CPrivAlloc, public OLE1DISPATCHDATA
+{
+ CDdeObject *pCDdeObject;
+ UINT iArg;
+} DDEDISPATCHDATA, *PDDEDISPATCHDATA;
+
+
+//
+// The following structure is used by the OLE 1.0 client support code
+// to dispatch incoming calls to Execute from the server window.
+//
+
+typedef struct tagSRVRDISPATCHDATA : public OLE1DISPATCHDATA,public CPrivAlloc
+{
+ HWND hwnd;
+ HANDLE hData;
+ HWND wParam;
+ LPSRVR lpsrvr;
+} SRVRDISPATCHDATA, *PSRVRDISPATCHDATA;
+
+INTERNAL SrvrDispatchIncomingCall(PSRVRDISPATCHDATA psdd);
+
+
+//
+// The following structure is used by the OLE 1.0 client support code
+// to dispatch incoming calls to a document window
+//
+
+typedef struct tagDOCDISPATCHDATA : public OLE1DISPATCHDATA,public CPrivAlloc
+{
+ HWND hwnd;
+ ULONG msg;
+ WPARAM wParam;
+ LPARAM lParam;
+ HANDLE hdata; // If already determined, these two hold
+ ATOM aItem; // valid data. All depends on the message
+ LPCLIENT lpclient;
+} DOCDISPATCHDATA, *PDOCDISPATCHDATA;
+
+INTERNAL DocDispatchIncomingCall(PDOCDISPATCHDATA psdd);
+
+
+
+//
+// DDECALLDATA is all the information needed to transmit the outbound call
+// to the server. Since this DDE channel uses PostMessage, the members
+// should look amazingly alot like the parameters to PostMessage.
+//
+// The hwndCli is used for setting callback information.
+//
+typedef struct tagDDECALLDATA : public CPrivAlloc
+{
+ HWND hwndSvr; // Server DDE window
+ WORD wMsg; // Post parameters
+ WPARAM wParam;
+ LPARAM lParam;
+
+ HWND hwndCli; // Handle to client side window
+ BOOL fFreeOnError;
+ BOOL fDone;
+ class DDE_CHANNEL * pChannel;
+} DDECALLDATA, *PDDECALLDATA;
+
+INTERNAL DispatchCall(PDISPATCHDATA);
+
+
+#endif // __DDECHC__HXX__
diff --git a/private/ole32/com/dde/client/ddecnvrt.cxx b/private/ole32/com/dde/client/ddecnvrt.cxx
new file mode 100644
index 000000000..119c67d15
--- /dev/null
+++ b/private/ole32/com/dde/client/ddecnvrt.cxx
@@ -0,0 +1,348 @@
+
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddecnvrt.cpp
+
+Abstract:
+
+ This module contains the code to read/write PBrush, MSDraw native data
+ formats. This module also contains PBrush native format <->DIbFile stream,
+ and MSDraw native format <-> placeable metafile stream conversion routines.
+
+Author:
+
+ Srini Koppolu (srinik) 06/29/1993
+
+Revision History:
+
+--*/
+
+#ifndef _MAC
+
+
+/************************ FILE FORMATS **********************************
+
+
+Normal Metafile (memory or disk based):
+
+ ------------ ---------------
+ | METAHEADER | Metafile bits |
+ ------------ ---------------
+
+Placeable Metafile:
+
+ --------------------- -----------------
+ | PLACEABLEMETAHEADER | Normal metafile |
+ --------------------- -----------------
+
+Memory Based DIB:
+
+ ------------------ --------------- ----------
+ | BITMAPINFOHEADER | RGBQUAD array | DIB bits |
+ ------------------ --------------- ----------
+
+DIB file format:
+
+ ------------------ ------------------
+ | BITMAPFILEHEADER | Memory based DIB |
+ ------------------ ------------------
+
+Ole10NativeStream Format:
+
+ -------- ----------------------
+ | dwSize | Object's Native data |
+ -------- ----------------------
+
+PBrush Native data format:
+
+ -----------------
+ | Dib File format |
+ -----------------
+
+MSDraw Native data format:
+
+ --------------------- ------------- ------------- -----------------
+ | mapping mode (WORD) | xExt (WORD) | yExt (WORD) | Normal metafile |
+ --------------------- ------------- ------------- -----------------
+
+
+*****************************************************************************/
+
+#include <ole2int.h>
+
+INTERNAL UtGetHMFPICTFromMSDrawNativeStm
+ (LPSTREAM pstm, DWORD dwSize, HANDLE FAR* lphdata)
+{
+ HRESULT error;
+ WORD mfp[3]; // mm, xExt, yExt
+ HMETAFILE hMF = NULL;
+
+ *lphdata = NULL;
+
+ if (error = pstm->Read(mfp, sizeof(mfp), NULL))
+ return error;
+
+ dwSize -= sizeof(mfp);
+
+ if (error = UtGetHMFFromMFStm(pstm, dwSize, FALSE, (void **)&hMF))
+ return error;
+
+ AssertSz(mfp[0] == MM_ANISOTROPIC, "invalid map mode in MsDraw native data");
+
+ if (*lphdata = UtGetHMFPICT(hMF, TRUE, (int) mfp[1], (int) mfp[2]))
+ return NOERROR;
+
+ return ResultFromScode(E_OUTOFMEMORY);
+}
+
+
+INTERNAL UtPlaceableMFStmToMSDrawNativeStm
+ (LPSTREAM pstmPMF, LPSTREAM pstmMSDraw)
+{
+ DWORD dwSize; // size of metafile bits excluding the placeable MF header
+ LONG xExt;
+ LONG yExt;
+ WORD wBuf[5]; // dwSize(DWORD), mm(int), xExt(int), yExt(int)
+ HRESULT error;
+
+ if (error = UtGetSizeAndExtentsFromPlaceableMFStm(pstmPMF, &dwSize,
+ &xExt, &yExt))
+ return error;
+
+ *((DWORD FAR*) wBuf) = dwSize + 3*sizeof(WORD);
+ wBuf[2] = MM_ANISOTROPIC;
+ wBuf[3] = (int) xExt;
+ wBuf[4] = (int) yExt;
+
+ if (error = pstmMSDraw->Write(wBuf, sizeof(wBuf), 0))
+ return error;
+
+ ULARGE_INTEGER ularge_int;
+ ULISet32(ularge_int, dwSize);
+ if ((error = pstmPMF->CopyTo(pstmMSDraw, ularge_int,
+ NULL, NULL)) == NOERROR)
+ StSetSize(pstmMSDraw);
+
+ return error;
+
+}
+
+
+INTERNAL UtDIBFileStmToPBrushNativeStm
+ (LPSTREAM pstmDIBFile, LPSTREAM pstmPBrush)
+{
+ BITMAPFILEHEADER bfh;
+ HRESULT error;
+
+ if (error = pstmDIBFile->Read(&bfh, sizeof(bfh), 0))
+ return error;
+
+ // seek to the begining of the stream
+ LARGE_INTEGER large_int;
+ LISet32( large_int, 0);
+ if (error = pstmDIBFile->Seek(large_int, STREAM_SEEK_SET, 0))
+ return error;
+
+ if (error = pstmPBrush->Write(&(bfh.bfSize), sizeof(DWORD), 0))
+ return error;
+
+ ULARGE_INTEGER ularge_int;
+ ULISet32(ularge_int, bfh.bfSize);
+
+ if ((error = pstmDIBFile->CopyTo(pstmPBrush, ularge_int,
+ NULL, NULL)) == NOERROR)
+ StSetSize(pstmPBrush);
+
+ return error;
+}
+
+
+
+INTERNAL UtContentsStmTo10NativeStm
+ (LPSTORAGE pstg, REFCLSID rclsid, BOOL fDeleteSrcStm, UINT FAR* puiStatus)
+{
+ CLIPFORMAT cf;
+ LPOLESTR lpszUserType = NULL;
+ HRESULT error;
+ LPSTREAM pstmSrc = NULL;
+ LPSTREAM pstmDst = NULL;
+
+ *puiStatus = NULL;
+
+ if (error = ReadFmtUserTypeStg(pstg, &cf, &lpszUserType))
+ return error;
+
+
+ if (! ((cf == CF_DIB && rclsid == CLSID_PBrush)
+ || (cf == CF_METAFILEPICT && rclsid == CLSID_MSDraw))) {
+ error = ResultFromScode(DV_E_CLIPFORMAT);
+ goto errRtn;
+ }
+
+ if (error = pstg->OpenStream(CONTENTS_STREAM, NULL,
+ (STGM_READ|STGM_SHARE_EXCLUSIVE),
+ 0, &pstmSrc)) {
+ *puiStatus |= CONVERT_NOSOURCE;
+
+ // check whether OLE10_NATIVE_STREAM exists
+ if (pstg->OpenStream(OLE10_NATIVE_STREAM, NULL,
+ (STGM_READ|STGM_SHARE_EXCLUSIVE), 0, &pstmDst))
+ *puiStatus |= CONVERT_NODESTINATION;
+ else {
+ pstmDst->Release();
+ pstmDst = NULL;
+ }
+
+ goto errRtn;
+ }
+
+ if (error = OpenOrCreateStream(pstg, OLE10_NATIVE_STREAM, &pstmDst)) {
+ *puiStatus |= CONVERT_NODESTINATION;
+ goto errRtn;
+ }
+
+ if (cf == CF_METAFILEPICT)
+ error = UtPlaceableMFStmToMSDrawNativeStm(pstmSrc, pstmDst);
+ else
+ error = UtDIBFileStmToPBrushNativeStm(pstmSrc, pstmDst);
+
+errRtn:
+ if (pstmDst)
+ pstmDst->Release();
+
+ if (pstmSrc)
+ pstmSrc->Release();
+
+ if (error == NOERROR) {
+ LPOLESTR lpszProgId = NULL;
+ ProgIDFromCLSID(rclsid, &lpszProgId);
+
+ error = WriteFmtUserTypeStg(pstg,
+ RegisterClipboardFormat(lpszProgId),
+ lpszUserType);
+
+ if (lpszProgId)
+ delete lpszProgId;
+ }
+
+ if (error == NOERROR) {
+ if (fDeleteSrcStm)
+ pstg->DestroyElement(CONTENTS_STREAM);
+ } else {
+ pstg->DestroyElement(OLE10_NATIVE_STREAM);
+ }
+
+ if (lpszUserType)
+ delete lpszUserType;
+
+ return error;
+}
+
+
+
+INTERNAL Ut10NativeStmToContentsStm
+ (LPSTORAGE pstg, REFCLSID rclsid, BOOL fDeleteSrcStm)
+{
+ extern CLIPFORMAT cfPBrush;
+ extern CLIPFORMAT cfMSDraw;
+
+ CLIPFORMAT cfOld;
+ CLIPFORMAT cfNew;
+ LPOLESTR lpszUserType = NULL;
+ HRESULT error;
+ LPSTREAM pstmSrc = NULL;
+ LPSTREAM pstmDst = NULL;
+
+
+ if (error = ReadFmtUserTypeStg(pstg, &cfOld, &lpszUserType))
+ return error;
+
+ if (rclsid == CLSID_StaticDib)
+ cfNew = CF_DIB;
+ else if (rclsid == CLSID_StaticMetafile)
+ cfNew = CF_METAFILEPICT;
+ else {
+ AssertSz(FALSE, "Internal Error: this routine shouldn't have been called for this class");
+ return ResultFromScode(E_FAIL);
+ }
+
+ if (cfOld == cfPBrush) {
+ if (cfNew != CF_DIB) {
+ error = ResultFromScode(DV_E_CLIPFORMAT);
+ goto errRtn;
+ }
+ } else if (cfOld == cfMSDraw) {
+ if (cfNew != CF_METAFILEPICT) {
+ error = ResultFromScode(DV_E_CLIPFORMAT);
+ goto errRtn;
+ }
+ } else {
+ // Converted to static object from some class other than PBrush or
+ // MSDraw. The data must be in a proper format in the CONTENTS
+ // stream.
+ return NOERROR;
+ }
+
+ if (error = pstg->OpenStream(OLE10_NATIVE_STREAM, NULL,
+ (STGM_READ|STGM_SHARE_EXCLUSIVE),
+ 0, &pstmSrc))
+ goto errRtn;
+
+ if (error = OpenOrCreateStream(pstg, CONTENTS_STREAM, &pstmDst))
+ goto errRtn;
+
+ DWORD dwSize;
+ if (error = pstmSrc->Read(&dwSize, sizeof(DWORD), NULL))
+ goto errRtn;
+
+ if (cfOld == cfMSDraw) {
+ WORD mfp[3]; // mm, xExt, yExt
+
+ if (error = pstmSrc->Read(mfp, sizeof(mfp), NULL))
+ goto errRtn;
+
+ dwSize -= sizeof(mfp);
+
+ error = UtMFStmToPlaceableMFStm(pstmSrc, dwSize,
+ (LONG) mfp[1], (LONG) mfp[2], pstmDst);
+
+ } else {
+ // The PBrush native data format is DIB File format. So all we got to
+ // do is CopyTo.
+
+ ULARGE_INTEGER ularge_int;
+ ULISet32(ularge_int, dwSize);
+ if ((error = pstmSrc->CopyTo(pstmDst, ularge_int, NULL,
+ NULL)) == NOERROR)
+ StSetSize(pstmDst);
+ }
+
+errRtn:
+ if (pstmDst)
+ pstmDst->Release();
+
+ if (pstmSrc)
+ pstmSrc->Release();
+
+ if (error == NOERROR) {
+ error = WriteFmtUserTypeStg(pstg, cfNew, lpszUserType);
+
+ if (fDeleteSrcStm)
+ pstg->DestroyElement(OLE10_NATIVE_STREAM);
+
+ } else {
+ pstg->DestroyElement(CONTENTS_STREAM);
+ }
+
+ if (lpszUserType)
+ delete lpszUserType;
+
+ return error;
+}
+
+#endif
+
diff --git a/private/ole32/com/dde/client/ddedo.cxx b/private/ole32/com/dde/client/ddedo.cxx
new file mode 100644
index 000000000..b74ba3dd3
--- /dev/null
+++ b/private/ole32/com/dde/client/ddedo.cxx
@@ -0,0 +1,951 @@
+/*
+ddedo.cpp
+DDE Data Object
+
+copyright (c) 1992 Microsoft Corporation
+
+Abstract:
+
+ This module contains the methods for DdeObject::DataObject
+
+Author:
+
+ Jason Fuller (jasonful) 24-July-1992
+
+*/
+
+#include "ddeproxy.h"
+#include <stddef.h>
+#include "trgt_dev.h"
+
+
+#define f10UserModel
+// Should we ignore a request by a 2.0 client to get advise-on-change,
+// so that the user must do an explicit File/Update or File/Close?
+// Probably yes, because:
+// 1) Advise-on-change can be expensive for apps like PaintBrush.
+// 2) It is confusing if the container asks for change updates
+// ONLY on presentation and not on native because when the user
+// closes the server and is asked "Do you want to update?" he'll say no
+// because the picture LOOKS correct even though the container does not
+// have the native data.
+// 3) Excel: if A1 is the first cell you create, changes to other cells
+// will not be sent to the client until you change A1 again.
+// If advises are only sent explicitly, then all the cells extant at that
+// time will be considered part of the object.
+
+
+ASSERTDATA
+
+
+//
+// DataObject methods
+//
+
+STDUNKIMPL_FORDERIVED(DdeObject, DataObjectImpl)
+
+
+static inline INTERNAL_(BOOL) NotEqual
+ (DVTARGETDEVICE FAR* ptd1,
+ DVTARGETDEVICE FAR* ptd2)
+{
+ if (NULL==ptd1 && NULL==ptd2)
+ return FALSE;
+ else if ((ptd1 && !ptd2)
+ || (ptd2 && !ptd1)
+ || (ptd1->tdSize != ptd2->tdSize))
+ {
+ return TRUE;
+ }
+ else
+#ifdef WIN32
+ return 0 != memcmp(ptd1, ptd2, (size_t)ptd1->tdSize);
+#else
+ return 0 != _fmemcmp(ptd1, ptd2, (size_t)ptd1->tdSize);
+#endif
+}
+
+
+
+// GetData
+//
+// The data is copied out of a private cache consisting of
+// DdeObject::m_hNative, DdeObject::m_hPict, and DdeObject::m_hExtra.
+// If the cache is empty, data is requested using WM_DDE_REQUEST.
+// The cache should only be empty before the first DDE_DATA message
+// is received.
+// See DdeObject::KeepData()
+//
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::GetData
+ (LPFORMATETC pformatetcIn,
+ LPSTGMEDIUM pmedium)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetData(%x,pformatetcIn=%x)\n",
+ this,pformatetcIn));
+
+lStart:
+ intrDebugOut((DEB_ITRACE,"::GetData(%x)lStart\n",this));
+
+ LPSTR lpGlobal=NULL;
+ HRESULT hres;
+ VDATEPTROUT (pmedium, STGMEDIUM);
+ pmedium->tymed = TYMED_NULL;
+ pmedium->pUnkForRelease = NULL;
+
+ if ((hres = wVerifyFormatEtc (pformatetcIn)) != NOERROR)
+ {
+ goto exitRtn;
+ }
+
+ hres = E_UNEXPECTED; // assume error unless a clipboard format is found.
+
+ if (DVASPECT_ICON & pformatetcIn->dwAspect)
+ {
+ hres = GetDefaultIcon(m_pDdeObject->m_clsid, NULL, &pmedium->hGlobal);
+ if (hres != NOERROR)
+ {
+ goto exitRtn;
+ }
+ hres = NOERROR;
+ goto lDone;
+ }
+ if (m_pDdeObject->m_fGotCloseData)
+ {
+ // If we already got DDE_DATA on close, don't try requesting more
+ // data. (MSDraw will give a bogus metafile.)
+ hres=OLE_E_NOTRUNNING;
+ goto exitRtn;
+ }
+
+ if (NotEqual (pformatetcIn->ptd, m_pDdeObject->m_ptd))
+ {
+ // If caller is asking for a different target device
+ // (We assume a different pointer points to a different target device)
+
+ if (NOERROR!=m_pDdeObject->SetTargetDevice (pformatetcIn->ptd))
+ {
+ // 1.0 server did not accept target device
+ hres=DATA_E_FORMATETC;
+ goto exitRtn;
+ }
+
+ Assert (hres!=NOERROR); // Must do RequestData with new target device
+ }
+ else
+ {
+ // Pick a member handle (H) to return, based on clipboard format CF.
+ // If caller did not pass in its own medium, we must allocate a new
+ // handle.
+
+
+ #define macro(CF,H) \
+ if (pformatetcIn->cfFormat == CF) { \
+ if (m_pDdeObject->H) { \
+ if (pmedium->tymed == TYMED_NULL) { \
+ intrDebugOut((DEB_ITRACE,"::GetData giving cf==%x hData=%x\n",CF,m_pDdeObject->H)); \
+ pmedium->hGlobal = m_pDdeObject->H; \
+ m_pDdeObject->H = NULL; \
+ } \
+ hres = NOERROR; /* found data in right format */ \
+ } \
+ }
+
+ macro (g_cfNative, m_hNative)
+ else macro (m_pDdeObject->m_cfPict, m_hPict )
+ else macro (m_pDdeObject->m_cfExtra,m_hExtra )
+
+ // If we gave away our picture, we must forget its format.
+ if (pformatetcIn->cfFormat == m_pDdeObject->m_cfPict)
+ m_pDdeObject->m_cfPict = 0;
+ #undef macro
+ }
+
+ if (hres!=NOERROR)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::GetData(%x) posting DDE_REQUEST for cf==%x\n",
+ this,
+ (ULONG)pformatetcIn->cfFormat));
+
+ // Didn't find a handle for the requested format,
+ // or handle was NULL, so request it.
+ // The sequence should be:
+ // GetData -> DDE_REQUEST -> DDE_DATA -> OnData -> return to GetData
+
+ if (hres=m_pDdeObject->RequestData (pformatetcIn->cfFormat) != NOERROR)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::GetData(%x) RequestData returns error %x\n",
+ this,hres));
+
+ hres = DV_E_CLIPFORMAT;
+ goto exitRtn;
+ }
+
+ // By now, a KeepData() should have been done with the right cf,
+ // so try again.
+ intrDebugOut((DEB_ITRACE,
+ "::GetData(%x) KeepData should have been called. Go again\n",
+ this));
+
+ Puts ("KeepData should have been called. Trying GetData again.\n");
+ goto lStart;
+ }
+ lDone:
+ Puts ("pmedium->hGlobal =="); Puth(pmedium->hGlobal); Putn();
+ pmedium->pUnkForRelease = NULL; // Let caller release medium
+ // Must set tymed _after_ the goto loop.
+ // Otherwise it'll be changed the second time around.
+
+ // tell caller what we're returning
+ pmedium->tymed = UtFormatToTymed (pformatetcIn->cfFormat);
+
+
+ intrDebugOut((DEB_ITRACE,
+ "::GetData(%x)tymed=%x cfFormat=%x hGlobal=%x\n",
+ this,
+ pmedium->tymed,
+ (USHORT)pformatetcIn->cfFormat,
+ pmedium->hGlobal));
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "::GetData(%x)hres=%x\n",
+ this,
+ hres));
+ return hres;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::GetDataHere
+ (LPFORMATETC pformatetcIn,
+ LPSTGMEDIUM pmedium)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetDataHere(%x,pformatetcIn=%x)\n",
+ this,
+ pformatetcIn));
+
+ HRESULT hresult = NOERROR;
+ STGMEDIUM medium;
+ if (!(pformatetcIn->tymed & TYMED_HGLOBAL))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::GetDataHere(%x)DV_E_TYMED(%x)\n",
+ this,DV_E_TYMED));
+ // Cannot GetDataHere for GDI objects
+ hresult = DV_E_TYMED;
+ goto exitRtn;
+ }
+ RetErr (GetData (pformatetcIn, &medium));
+ if (medium.tymed != TYMED_HGLOBAL)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::GetDataHere(%x)medium.tymed != TYMED_HGLOBAL\n",
+ this));
+ hresult = ResultFromScode (DV_E_TYMED);
+ goto errRtn;
+ }
+ pmedium->tymed = medium.tymed;
+ pmedium->pUnkForRelease = medium.pUnkForRelease;
+ ErrRtnH (wHandleCopy (pmedium->hGlobal, medium.hGlobal));
+
+ errRtn:
+ ReleaseStgMedium (&medium);
+
+ exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetDataHere(%x) returning %x\n",
+ this,hresult));
+ return hresult;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::QueryGetData
+ (LPFORMATETC pformatetcIn)
+{
+ HRESULT hr;
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDdeObject::QueryGetData(pformatetcIn=%x)\n",
+ this,
+ pformatetcIn));
+
+ hr = wVerifyFormatEtc (pformatetcIn);
+
+ if (hr != NOERROR)
+ {
+ goto exitRtn;
+ }
+ if (pformatetcIn->cfFormat == g_cfEmbeddedObject
+ || pformatetcIn->cfFormat == g_cfEmbedSource
+ || pformatetcIn->cfFormat == g_cfLinkSource
+ || pformatetcIn->cfFormat == g_cfFileName
+ || pformatetcIn->cfFormat == g_cfCustomLinkSource
+ || pformatetcIn->cfFormat == g_cfObjectDescriptor
+ || pformatetcIn->cfFormat == g_cfLinkSrcDescriptor)
+ {
+ hr = S_FALSE;
+ }
+
+ hr = m_pDdeObject->IsFormatAvailable (pformatetcIn);
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDdeObject::QueryGetData returning %x\n",
+ this,hr));
+ return(hr);
+
+}
+
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::SetData
+ (LPFORMATETC pformatetc,
+ STGMEDIUM FAR* pmedium,
+ BOOL fRelease)
+{
+ HANDLE hDdePoke;
+ HRESULT hresult;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDdeObject::SetData(pformatetc=%x)\n",
+ this,
+ pformatetc));
+
+ hresult = wVerifyFormatEtc (pformatetc);
+
+ if (hresult != NOERROR)
+ {
+ goto exitRtn;
+ }
+ intrDebugOut((DEB_ITRACE,
+ "%x ::SetData(pformatetc->cfFormat=%x)\n",
+ this,
+ (ULONG)pformatetc->cfFormat));
+
+ if (pformatetc->dwAspect & DVASPECT_ICON)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "%x ::SetData dwAspect & DVASPECT_ICON\n",
+ this));
+ hresult = DV_E_DVASPECT;
+ goto exitRtn;
+ }
+
+
+ if (pformatetc->ptd != m_pDdeObject->m_ptd)
+ {
+ // If caller is setting with a different target device
+ // (We assume a different pointer points to a different target device)
+
+ if (NOERROR != m_pDdeObject->SetTargetDevice (pformatetc->ptd))
+ {
+ intrDebugOut((DEB_IERROR,
+ "%x ::SetData server did not accept target device\n",
+ this));
+ hresult = DV_E_DVTARGETDEVICE;
+ goto exitRtn;
+ }
+ }
+
+ if (hDdePoke = wPreparePokeBlock (pmedium->hGlobal,
+ pformatetc->cfFormat,
+ m_pDdeObject->m_aClass,
+ m_pDdeObject->m_bOldSvr))
+ {
+ hresult = m_pDdeObject->Poke (m_pDdeObject->m_aItem, hDdePoke);
+ if (fRelease)
+ ReleaseStgMedium (pmedium);
+ goto exitRtn;
+ }
+ else
+ {
+ hresult = E_OUTOFMEMORY;
+ }
+exitRtn:
+
+ intrDebugOut((DEB_ITRACE,"%x _OUT ::SetData returns %x\n",this,hresult));
+ return(hresult);
+
+}
+
+
+
+
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::DAdvise
+ (FORMATETC FAR* pformatetc,
+ DWORD grfAdvf,
+ IAdviseSink FAR* pAdvSink,
+ DWORD FAR* pdwConnection)
+{
+ HRESULT hresult;
+ HRESULT hresLookup;
+ FORMATETC formatetc;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDdeObject::DAdvise(pformatetc=%x,grfAdvf=%x,pAdvSink=%x)\n",
+ this,
+ pformatetc,
+ grfAdvf,
+ pAdvSink));
+
+ VDATEPTROUT (pdwConnection, DWORD);
+ *pdwConnection = 0;
+
+ wNormalize (pformatetc, &formatetc);
+
+ hresult =wVerifyFormatEtc (&formatetc);
+
+ if ( hresult != NOERROR)
+ {
+ goto errRtn;
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "%x ::DAdvise pformatetc->cfFormat=%x\n",
+ this,
+ pformatetc->cfFormat));
+
+ if (NotEqual (formatetc.ptd, m_pDdeObject->m_ptd))
+ {
+ if (NOERROR != m_pDdeObject->SetTargetDevice (formatetc.ptd))
+ {
+ hresult= DV_E_DVTARGETDEVICE;
+ goto errRtn;
+ }
+ }
+
+ hresLookup = m_pDdeObject->m_ConnectionTable.Lookup (formatetc.cfFormat, NULL);
+ if (hresLookup != NOERROR)
+ {
+ // We have not already done a DDE advise for this format
+
+ Puts (" m_iAdvChange = "); Puti (m_pDdeObject->m_iAdvChange); Puts("\n");
+
+ if (m_pDdeObject->m_ulObjType == OT_LINK)
+ {
+ ErrRtnH (m_pDdeObject->AdviseOn (formatetc.cfFormat, ON_CHANGE));
+ ErrRtnH (m_pDdeObject->AdviseOn (formatetc.cfFormat, ON_SAVE));
+ }
+ else
+ {
+ ErrRtnH (m_pDdeObject->AdviseOn (formatetc.cfFormat, ON_SAVE));
+ ErrRtnH (m_pDdeObject->AdviseOn (formatetc.cfFormat, ON_CLOSE));
+ }
+ }
+
+ ErrZS (m_pDdeObject->m_pDataAdvHolder, E_OUTOFMEMORY);
+ hresult = m_pDdeObject->m_pDataAdvHolder->Advise (this, pformatetc, grfAdvf,
+ pAdvSink, pdwConnection);
+
+ m_pDdeObject->m_ConnectionTable.Add (*pdwConnection, formatetc.cfFormat,
+ grfAdvf);
+
+ errRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDdeObject::DAdvise hresult=%x\n",
+ this,
+ hresult));
+ return hresult;
+}
+
+
+
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::DUnadvise
+ (DWORD dwConnection)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::DUnadvise(%x,dwConnection=%x)\n",
+ this,
+ dwConnection));
+
+ CLIPFORMAT cf;
+ HRESULT hres;
+ DWORD grfAdvf;
+
+ // Remove connection from table. Lookup the cf for this connection.
+ if (m_pDdeObject->m_ConnectionTable.Subtract (dwConnection, &cf, &grfAdvf)
+ == NOERROR)
+ {
+ // If there is not another connection that needs this format
+ if (m_pDdeObject->m_ConnectionTable.Lookup (cf, NULL) != NOERROR)
+ {
+ // We did a DDE advise for this connection, so undo it.
+ if (m_pDdeObject->m_ulObjType == OT_LINK)
+ {
+ if (NOERROR != (hres=m_pDdeObject->UnAdviseOn (cf, ON_CHANGE)))
+ {
+ intrDebugOut((DEB_IWARN,
+ "::DUnadvise(%x,dwConnection=%x) ON_CHANGE failed\n",
+ this,
+ dwConnection));
+ }
+ if (NOERROR != (hres=m_pDdeObject->UnAdviseOn (cf, ON_SAVE)))
+ {
+ intrDebugOut((DEB_IWARN,
+ "::DUnadvise(%x,dwConnection=%x) ON_SAVE failed\n",
+ this,
+ dwConnection));
+ }
+ }
+ else
+ {
+ if (NOERROR != (hres=m_pDdeObject->UnAdviseOn (cf, ON_SAVE)))
+ {
+ intrDebugOut((DEB_IWARN,
+ "::DUnadvise(%x,dwConnection=%x) ON_SAVE failed\n",
+ this,
+ dwConnection));
+ }
+ if (NOERROR != (hres=m_pDdeObject->UnAdviseOn (cf, ON_CLOSE)))
+ {
+ intrDebugOut((DEB_IWARN,
+ "::DUnadvise(%x,dwConnection=%x) ON_CLOSE failed\n",
+ this,
+ dwConnection));
+ }
+ }
+ }
+ }
+
+ // Delegate rest of the work to the DataAdviseHolder
+ RetZS (m_pDdeObject->m_pDataAdvHolder, E_OUTOFMEMORY);
+ return m_pDdeObject->m_pDataAdvHolder->Unadvise (dwConnection);
+}
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::EnumDAdvise
+ (THIS_ LPENUMSTATDATA FAR* ppenumAdvise)
+{
+ RetZS (m_pDdeObject->m_pDataAdvHolder, E_OUTOFMEMORY);
+ return m_pDdeObject->m_pDataAdvHolder->EnumAdvise(ppenumAdvise);
+}
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::EnumFormatEtc
+ (DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)
+{
+ return OleRegEnumFormatEtc (m_pDdeObject->m_clsid, dwDirection,
+ ppenumFormatEtc);
+}
+
+
+
+
+STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::GetCanonicalFormatEtc
+(LPFORMATETC pformatetc, LPFORMATETC pformatetcOut)
+{
+ VDATEPTROUT (pformatetcOut, FORMATETC);
+ memcpy (pformatetcOut, pformatetc, sizeof (FORMATETC));
+ return ReportResult(0, DATA_S_SAMEFORMATETC, 0, 0);
+ // We must be very conservative and assume data will be different for
+ // every formatetc
+}
+
+
+
+INTERNAL CDdeObject::RequestData
+ (CLIPFORMAT cf)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::RequestData(%x,cf=%x)\n",
+ this,cf));
+
+ LPARAM lparam;
+ RetZ (m_pDocChannel);
+ intrAssert(wIsValidAtom(m_aItem));
+ ATOM aItem = wDupAtom (m_aItem);
+ intrAssert(wIsValidAtom(aItem));
+
+ lparam = MAKE_DDE_LPARAM (WM_DDE_REQUEST,cf, aItem);
+
+ HRESULT hr = SendMsgAndWaitForReply (m_pDocChannel,
+ AA_REQUEST,
+ WM_DDE_REQUEST,
+ lparam,
+ TRUE);
+ if ( aItem && FAILED(hr) )
+ {
+ GlobalDeleteAtom (aItem);
+ }
+ return hr;
+}
+
+
+// special name
+const char achSpecialName[] = "DISPLAY";
+
+//
+// Return a 1.0 target device for the screen
+//
+
+static INTERNAL DefaultTargetDevice (HANDLE FAR* ph)
+{
+ intrDebugOut((DEB_ITRACE,
+ "DefaultTargetDevice(ph=%x)\n",ph));
+
+ VDATEPTROUT ((LPVOID) ph, HANDLE);
+ LPOLETARGETDEVICE p1=NULL;
+ *ph = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, sizeof (*p1) + 10);
+ RetZS (*ph, E_OUTOFMEMORY);
+ p1 = (LPOLETARGETDEVICE) GlobalLock (*ph);
+ RetZS (p1, E_OUTOFMEMORY);
+ p1->otdDeviceNameOffset = 8;
+ p1->otdDriverNameOffset = 0; // The driver name is at otdData
+ p1->otdPortNameOffset = 9;
+ p1->otdExtDevmodeOffset = 0;
+ p1->otdExtDevmodeSize = 0;
+ p1->otdEnvironmentOffset= 0;
+ p1->otdEnvironmentSize = 0;
+
+ //
+ // Note that memcpy is moving a constant string. Therefore, sizeof()
+ // will include the NULL terminator
+ //
+ //
+ memcpy((LPSTR)p1->otdData, achSpecialName,sizeof(achSpecialName));
+ p1->otdData[8] = 0; // NULL the otdDeviceName
+ p1->otdData[9] = 0; // NULL the PortNameOffset
+ GlobalUnlock (*ph);
+ return NOERROR;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: Convert20TargetDevice
+//
+// Synopsis: Converts a 2.0 TargetDevice into a 1.0 OLETARGETDEVICE
+//
+// Effects: First converts the 2.0 UNICODE target device into ANSI,
+// then converts that into a 1.0 OLETARGETDEVICE. The astute
+// reader would say: Why not just 2.0 UNICODE to OLETARGETDEVICE?
+//
+// Two reasons: time before we ship vs time needed elsewhere.
+//
+// If you can spare some time, please change this to go
+// directly from one to the other.
+//
+// Arguments: [ptd] --
+// [phTD1] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-03-94 kevinro Created
+//
+// Notes:
+//
+// BUGBUG: the NT version of the OLE 1.0 used UINT as the size of the
+// structures members. This was baaaad, since we really need them to be
+// a fixed size. I am currently in the works of changing the NT 1.0 header
+// file to reflect what we really need it to be, which is USHORT's
+//
+//
+// We have a DVTARGETDEVICE, but we want a OLETARGETDEVICE, which looks like
+//
+// typedef struct _OLETARGETDEVICE {
+// USHORT otdDeviceNameOffset;
+// USHORT otdDriverNameOffset;
+// USHORT otdPortNameOffset;
+// USHORT otdExtDevmodeOffset;
+// USHORT otdExtDevmodeSize;
+// USHORT otdEnvironmentOffset;
+// USHORT otdEnvironmentSize;
+// BYTE otdData[1];
+// } OLETARGETDEVICE;
+//
+// A couple things to note:
+//
+// 1) The Names in the OLETARGETDEVICE need to be Ansi
+// 2) The Environment member doens't exist in the DVTARGETDEVICE, and will
+// be created in this conversion
+// 3) The ExtDevmode also needs to be ANSI
+//
+//----------------------------------------------------------------------------
+INTERNAL Convert20TargetDevice
+ (const DVTARGETDEVICE FAR* ptd, // in parm
+ HANDLE FAR* phTD1) // out parm
+{
+ const size_t cbHeader = SIZEOF_DVTARGETDEVICE_HEADER;
+ HRESULT hr;
+ LPOLETARGETDEVICE ptd1 = NULL;
+ size_t cbTD1;
+ size_t cbDevmode;
+ size_t cbOffset;
+ LPDEVMODEA pdevmode;
+
+ intrDebugOut((DEB_ITRACE,
+ "Convert20TargetDevice(ptd=%x)\n",ptd));
+
+ VDATEPTROUT ((LPVOID) phTD1, HANDLE);
+ *phTD1 = NULL;
+
+ //
+ // If no device specified, then return the default
+ //
+
+ if (NULL==ptd)
+ {
+ return DefaultTargetDevice (phTD1);
+ }
+
+ //
+ // Compute information for doing conversion using routines in utils.cpp
+ // The following structure will get the sizes
+ //
+
+ DVTDINFO dvtdInfo;
+
+ hr = UtGetDvtd32Info(ptd,&dvtdInfo);
+
+ if (hr != NOERROR)
+ {
+ return DV_E_DVTARGETDEVICE;
+ }
+
+ //
+ // The conversion routines require us to allocate memory to pass in.
+ //
+
+ DVTARGETDEVICE *pdvtdAnsi = (DVTARGETDEVICE *) PrivMemAlloc(dvtdInfo.cbConvertSize);
+
+ if (pdvtdAnsi == NULL)
+ {
+ return(E_OUTOFMEMORY);
+ }
+
+ //
+ // Convert the UNICODE target device into an ANSI target device
+ //
+
+ hr = UtConvertDvtd32toDvtd16(ptd,&dvtdInfo,pdvtdAnsi);
+
+ if (hr != NOERROR)
+ {
+ goto errRtn;
+ }
+
+ //
+ // pdvtdAnsi now holds an ANSI version of the DVTARGETDEVICE. Turns
+ // out the structure we really want is the DVTARGETDEVICE, plus a
+ // couple of extra header bytes. Therefore, we can just do a block
+ // copy of the DVTARGETDEVICE's data, and fix up our OLETARGETDEVICE
+ // header to have the correct offsets in the data.
+ //
+ // offset of data block from beginning of 2.0 target device
+ //
+ cbOffset = offsetof (DVTARGETDEVICE, tdData);
+
+ //
+ // Calculate a pointer to the DEVMODEA
+ //
+ pdevmode = pdvtdAnsi->tdExtDevmodeOffset ?
+ (LPDEVMODEA)((LPBYTE)pdvtdAnsi + pdvtdAnsi->tdExtDevmodeOffset)
+ : NULL;
+
+ //
+ // Quick sanity check on the resulting pointer.
+ //
+ if (pdevmode && IsBadReadPtr (pdevmode, sizeof(DEVMODEA)))
+ {
+ hr = DV_E_DVTARGETDEVICE;
+ goto errRtn;
+ }
+
+ //
+ // Calculate the size of the devmode part.
+ //
+
+ cbDevmode = (pdevmode ? pdevmode->dmSize + pdevmode->dmDriverExtra:0);
+
+ //
+ // Calculate the total size needed. The DVTARGETDEVICE header has 12 bytes,
+ // and the OLETARGETDEVICE has 14 bytes. We also need to make an extra copy
+ // of the cbDevmode structure to fill in the environment. Therefore, there is
+ // an extra cbDevmode, and a sizeof(USHORT) added to the size. The size includes
+ // the size of the DVTARGETHEADER
+ //
+
+ cbTD1 = (size_t) pdvtdAnsi->tdSize +
+ cbDevmode + // For extra Environment data
+ sizeof (USHORT); // for Environment Size field
+
+ *phTD1 = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, cbTD1);
+ if (NULL== *phTD1)
+ {
+ intrAssert (!"GlobalAlloc Failed");
+ hr = E_OUTOFMEMORY;
+ goto errRtn;
+ }
+
+ ptd1 = (LPOLETARGETDEVICE) GlobalLock (*phTD1);
+ if (NULL== ptd1)
+ {
+ intrAssert (!"GlobalLock Failed");
+ hr = E_OUTOFMEMORY;
+ goto errRtn;
+ }
+
+ // Set x1 (1.0 offset) based on x2 (2.0 offset)
+ //
+ // Note that the OLETARGETDEVICE offsets are relative to the array of bytes,
+ // where the DVTARGETDEVICE is relative to the start of the structure. Thats
+ // why cbOffset is subtracted
+ //
+
+ #define ConvertOffset(x1, x2) (x1 = (x2 ? x2 - cbOffset : 0))
+
+ //
+ // Using the above macro, and assuming
+ //
+
+ ConvertOffset (ptd1->otdDeviceNameOffset, pdvtdAnsi->tdDeviceNameOffset);
+ ConvertOffset (ptd1->otdDriverNameOffset, pdvtdAnsi->tdDriverNameOffset);
+ ConvertOffset (ptd1->otdPortNameOffset , pdvtdAnsi->tdPortNameOffset );
+ ConvertOffset (ptd1->otdExtDevmodeOffset, pdvtdAnsi->tdExtDevmodeOffset);
+ ptd1->otdExtDevmodeSize = cbDevmode;
+
+ //
+ // I found this in the OLE 2 information on OLETARGETDEVICE:
+ //
+ // The otdDeviceNameOffset, otdDriverNameOffset, and otdPortNameOffset
+ // members should be null-terminated. In Windows 3.1, the ability to
+ // connect multiple printers to one port has made the environment
+ // obsolete. The environment information retrieved by the
+ // GetEnvironment function can occasionally be incorrect. To ensure that the
+ // OLETARGETDEVICE structure is initialized correctly, the application
+ // should copy information from the DEVMODEA structure retrieved by a
+ // call to the ExtDeviceMode function to the environment position of
+ // the OLETARGETDEVICE structure.
+ //
+ //
+
+ //
+ // Adjust the environment offset to the end of the converted structure, and
+ // set the size. the sizeof(USHORT) accounts for the addition of the
+ // otdEnvironmentSize field. The offsetof accounts for the fact that the
+ // OLETARGETDEVICE offsets are based from the otdData array.
+ //
+ ptd1->otdEnvironmentOffset = (USHORT) pdvtdAnsi->tdSize +
+ sizeof(USHORT) -
+ offsetof(OLETARGETDEVICE,otdData);
+
+ ptd1->otdEnvironmentSize = cbDevmode;
+
+ // Copy data block
+ if(IsBadWritePtr (ptd1->otdData, (size_t) pdvtdAnsi->tdSize - cbHeader))
+ {
+ hr = E_UNEXPECTED;
+ goto errRtn;
+ }
+ memcpy (ptd1->otdData, pdvtdAnsi->tdData, (size_t) pdvtdAnsi->tdSize - cbHeader);
+
+ if (cbDevmode != 0)
+ {
+ if(IsBadWritePtr (ptd1->otdData, sizeof (DEVMODEA)))
+ {
+ hr = E_UNEXPECTED;
+ goto errRtn;
+ }
+
+ // Copy 2.0 Devmode into 1.0 environment
+
+ memcpy (ptd1->otdData + ptd1->otdEnvironmentOffset,
+ pdvtdAnsi->tdData + pdvtdAnsi->tdExtDevmodeOffset,
+ cbDevmode);
+ }
+
+ hr = NOERROR;
+
+errRtn:
+
+ if (ptd1 != NULL)
+ {
+ GlobalUnlock(*phTD1);
+ }
+
+ if (pdvtdAnsi != NULL)
+ {
+ PrivMemFree(pdvtdAnsi);
+ }
+ intrDebugOut((DEB_ITRACE,
+ "Convert20TargetDevice(ptd=%x) returns %x\n",ptd,hr));
+ return(hr);
+}
+
+
+
+static INTERNAL CopyTargetDevice
+ (const DVTARGETDEVICE FAR* ptd,
+ DVTARGETDEVICE FAR* FAR* pptd)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CopyTargetDevice(ptd=%x)\n",ptd));
+
+ if (*pptd)
+ {
+ delete *pptd; // delete old target device
+ }
+ if (NULL==ptd)
+ {
+ *pptd = NULL;
+ }
+ else
+ {
+ *pptd = (DVTARGETDEVICE FAR*) operator new ((size_t) (ptd->tdSize));
+ if (NULL==*pptd)
+ {
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+ _fmemcpy (*pptd, ptd, (size_t) ptd->tdSize);
+ }
+ return NOERROR;
+}
+
+
+
+INTERNAL CDdeObject::SetTargetDevice
+ (const DVTARGETDEVICE FAR* ptd)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::SetTargetDevice(%x,ptd=%x)\n",
+ this,
+ ptd));
+
+ HANDLE hTD1 = NULL;
+ HANDLE hDdePoke=NULL;
+
+ RetErr (Convert20TargetDevice (ptd, &hTD1));
+
+ Assert (hTD1);
+ Verify (hDdePoke = wPreparePokeBlock (hTD1, g_cfBinary, m_aClass, m_bOldSvr));
+ if (hTD1)
+ {
+ GlobalFree (hTD1);
+ }
+ // Poke new target device to 1.0 server
+ aStdTargetDevice = GlobalAddAtom (L"StdTargetDevice");
+ intrAssert(wIsValidAtom(aStdTargetDevice));
+ RetErr (Poke (aStdTargetDevice, hDdePoke));
+
+ // Remember current target device
+ RetErr (CopyTargetDevice (ptd, &m_ptd));
+ // Flush the cache because it contains a picture for the wrong
+ // target device.
+ if (m_hPict)
+ wFreeData (m_hPict, m_cfPict);
+ m_cfPict = (CLIPFORMAT)0;
+ m_hPict = NULL;
+
+ return NOERROR;
+}
diff --git a/private/ole32/com/dde/client/ddeioc.cxx b/private/ole32/com/dde/client/ddeioc.cxx
new file mode 100644
index 000000000..bca19b47d
--- /dev/null
+++ b/private/ole32/com/dde/client/ddeioc.cxx
@@ -0,0 +1,209 @@
+/*
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddeLink.cpp
+
+Abstract:
+
+ This module contains the DdeObject::OleItemContainer methods
+ and other Link-related code
+
+Author:
+
+ Jason Fuller (jasonful) 19-October-1992
+
+*/
+
+#include "ddeproxy.h"
+// #include <limits.h>
+// #include <utils.h>
+// #include <moniker.h>
+
+
+ASSERTDATA
+
+
+
+STDUNKIMPL_FORDERIVED (DdeObject, OleItemContainerImpl)
+
+
+static INTERNAL_(void) wSkipDelimiter
+ (LPOLESTR * psz)
+{
+ if (wcschr (L"!\"'*+,./:;<=>?@[\\]`|" , **psz))
+ (*psz)++;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::ParseDisplayName
+ (LPBC pbc,
+ LPOLESTR lpszDisplayName,
+ ULONG * pchEaten,
+ LPMONIKER * ppmkOut)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::ParseDisplayName(%x,lpsz=%ws)\n",
+ this,
+ lpszDisplayName));
+
+ LPUNKNOWN pUnk = NULL;
+ VDATEPTROUT(ppmkOut,LPMONIKER);
+ *ppmkOut = NULL;
+ VDATEIFACE(pbc);
+ VDATEPTRIN(lpszDisplayName, char);
+ VDATEPTROUT(pchEaten,ULONG);
+
+ *pchEaten = lstrlen(lpszDisplayName);
+ wSkipDelimiter (&lpszDisplayName);
+ // Validate the item name
+ RetErr (GetObject (lpszDisplayName, BINDSPEED_INDEFINITE, pbc,
+ IID_IUnknown, (LPLPVOID) &pUnk));
+ if (pUnk)
+ pUnk->Release();
+ return CreateItemMoniker (L"!", lpszDisplayName, ppmkOut);
+}
+
+
+
+STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::EnumObjects
+ (DWORD grfFlags,
+ LPENUMUNKNOWN FAR* ppenumUnk)
+
+{
+ // OLE 1.0 provides no way to enumerate all the items in a document.
+ // This method is unlikely to be called since our implementation of
+ // file and item monikers does not call it.
+ Puts ("OleItemContainer::EnumObjects\r\n");
+ if (ppenumUnk)
+ {
+ *ppenumUnk = NULL;
+ return E_NOTIMPL;
+ }
+
+ return E_INVALIDARG;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::LockContainer
+ (BOOL fLock)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::LockContainer(%x,fLock=%x)\n",
+ this,
+ fLock));
+
+ return NOERROR;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::GetObject
+ (LPOLESTR lpszItem,
+ DWORD dwSpeedNeeded,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID * ppvObject)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetObject(%x,szItem=%ws)\n",
+ this,
+ lpszItem));
+
+
+ HRESULT hresult = NOERROR;
+ VDATEPTROUT (ppvObject, LPVOID);
+ *ppvObject=NULL;
+ LPUNKNOWN pUnk = NULL; // These refer to the
+ CDdeObject FAR* pdde = NULL; // same object
+
+ RetZS (pUnk =CDdeObject::Create (NULL,m_pDdeObject->m_clsid,OT_LINK,
+ m_pDdeObject->m_aTopic,lpszItem,&pdde),
+ E_OUTOFMEMORY);
+
+ // For handling invisible updates--propagate information from document
+ // to item.
+ pdde->DeclareVisibility (m_pDdeObject->m_fVisible);
+ pdde->m_fDidLaunchApp = m_pDdeObject->m_fDidLaunchApp;
+ pdde->m_fDidStdOpenDoc = m_pDdeObject->m_fDidStdOpenDoc;
+
+ intrAssert(wIsValidAtom(pdde->m_aItem));
+ ErrZ (0==lstrcmp(lpszItem, wAtomName(pdde->m_aItem)));
+
+ // OPTIMIZATION: Could use a mini Running Object Table to map lpszItem to
+ // LPUNKNOWN and avoiding the Connect() and DDE_REQUEST.
+
+ // Open a DocChannel
+ ErrRtnH (pdde->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL));
+
+ // Request Native data in order to see if the item name is valid
+ Assert (pdde->m_pDocChannel);
+ LPARAM lp;
+ lp=MAKE_DDE_LPARAM (WM_DDE_REQUEST,g_cfNative, wDupAtom(pdde->m_aItem));
+ hresult = pdde->SendMsgAndWaitForReply (pdde->m_pDocChannel,
+ AA_REQUESTAVAILABLE,
+ WM_DDE_REQUEST,
+ lp,
+ TRUE);
+ if ( FAILED( hresult ) )
+ {
+ // Try metafile. Excel can't render large metafiles
+ // but it can render native.
+ lp=MAKE_DDE_LPARAM (WM_DDE_REQUEST,CF_METAFILEPICT, wDupAtom(pdde->m_aItem));
+ hresult = pdde->SendMsgAndWaitForReply (pdde->m_pDocChannel,
+ AA_REQUESTAVAILABLE,
+ WM_DDE_REQUEST,
+ lp,
+ TRUE);
+ if ( FAILED( hresult ) )
+ {
+ Assert (pdde->m_refs==1);
+ hresult = ResultFromScode (MK_E_NOOBJECT);
+ goto errRtn;
+ }
+ }
+
+ // Item name is valid
+ hresult = pdde->m_pUnkOuter->QueryInterface (riid, (LPLPVOID) ppvObject);
+ if (NOERROR==hresult)
+ {
+ m_pDdeObject->m_fDidGetObject = TRUE;
+ }
+ errRtn:
+ if (pUnk)
+ pUnk->Release();
+ return hresult;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::GetObjectStorage
+ (LPOLESTR lpszItem,
+ LPBINDCTX ptc,
+ REFIID riid,
+ LPVOID * ppvStorage)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetObjectStorage(%x,szItem=%ws)\n",
+ this,
+ lpszItem));
+ return MK_E_NOSTORAGE;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::IsRunning
+ (LPOLESTR szItem)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::IsRunning(%x,szItem=%ws)\n",
+ this,
+ szItem));
+
+ // By definition, all items are running
+ return NOERROR;
+}
diff --git a/private/ole32/com/dde/client/ddemnker.cxx b/private/ole32/com/dde/client/ddemnker.cxx
new file mode 100644
index 000000000..23ca2ebe5
--- /dev/null
+++ b/private/ole32/com/dde/client/ddemnker.cxx
@@ -0,0 +1,511 @@
+/*
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddeLink.cpp
+
+Abstract:
+
+ This module implements:
+ DdeBindToObject
+ DdeIsRunning
+
+Author:
+
+ Jason Fuller (jasonful) 19-October-1992
+
+*/
+#include "ddeproxy.h"
+
+
+INTERNAL DdeBindToObject
+ (LPCOLESTR szFileIn,
+ REFCLSID clsid,
+ BOOL fPackageLink,
+ REFIID iid,
+ LPLPVOID ppv)
+{
+ intrDebugOut((DEB_ITRACE,
+ "DdeBindToObject szFileIn(%ws) fPackageLink(%x)\n",
+ szFileIn,
+ fPackageLink));
+
+
+ LPUNKNOWN punk;
+ *ppv = NULL;
+ CDdeObject FAR* pdde=NULL;
+ HRESULT hresult = E_UNEXPECTED;
+ BOOL fSysConnection = FALSE;
+ WCHAR wszTmpFile [MAX_STR+5];
+
+ COleTls Tls;
+ if( Tls->dwFlags & OLETLS_DISABLE_OLE1DDE )
+ {
+ // If DDE use is disabled we shouldn't have gotten here.
+ //
+ Assert(!"Executing DdeBindToObject when DDE is disabled");
+ hresult = CO_E_OLE1DDE_DISABLED;
+ goto exitRtn;
+ }
+
+ //
+ // This protocol doesn't handle the fact that there are two names for
+ // every file. This is a bit of a problem. So, we are going to choose
+ // the short name as the one to look for. This means that DDE objects
+ // using the long filename will not work very well.
+ //
+ WCHAR szFile[MAX_PATH];
+ if ((lstrlenW(szFileIn) == 0) || (GetShortPathName(szFileIn,szFile,MAX_PATH) == 0))
+ {
+ //
+ // Unable to determine a short path for this object. Use whatever we were
+ // handed.
+ //
+ intrDebugOut((DEB_ITRACE,"No conversion for short path. Copy szFileIn\n"));
+ lstrcpyW(szFile,szFileIn);
+ }
+ intrDebugOut((DEB_ITRACE,"Short file szFile(%ws)\n",szFile));
+
+ RetZS (punk=CDdeObject::Create (NULL,clsid,OT_LINK,wGlobalAddAtom(szFile),
+ NULL,&pdde),E_OUTOFMEMORY);
+ RetZ (pdde);
+
+ // Document already running?
+
+ if (NOERROR != (hresult = pdde->DocumentLevelConnect (NULL) ))
+ {
+ if (GetScode (hresult) != S_FALSE)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "DdeBindToObject szFile(%ws) DLC returns %x \n",
+ szFile,hresult));
+ goto exitRtn;
+ }
+
+
+ // If not already running, try to make a sys level connection
+
+ if (!pdde->m_pSysChannel) {
+ if (!pdde->AllocDdeChannel (&pdde->m_pSysChannel, TRUE))
+ {
+ intrAssert( !"Out of memory");
+ hresult = E_OUTOFMEMORY;
+ goto exitRtn;
+ }
+ }
+
+ hresult = ReportResult (0, E_UNEXPECTED, 0, 0);
+
+ if (fPackageLink) {
+ lstrcpy (wszTmpFile, szFile);
+ lstrcat (wszTmpFile, L"/Link");
+ pdde->SetTopic (wGlobalAddAtom(wszTmpFile));
+ }
+
+ if (pdde->InitSysConv())
+ {
+ fSysConnection = TRUE;
+
+ // Try to make the server open the document
+ ErrRtnH (pdde->PostSysCommand (pdde->m_pSysChannel, (LPSTR)&achStdOpenDocument,FALSE));
+ pdde->m_fDidStdOpenDoc = TRUE;
+
+ }
+ else
+ {
+ // launch the server
+ if (!pdde->LaunchApp())
+ {
+ hresult = CO_E_APPNOTFOUND;
+ goto errRtn;
+ }
+ }
+
+ if (fPackageLink)
+ pdde->SetTopic (wGlobalAddAtom(szFile));
+
+ // Connect to document
+ hresult = pdde->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL);
+ if (hresult != NOERROR)
+ {
+ // Excel does not register its document in time if it loads
+ // startup macros. So we force it to open the document.
+ if (pdde->InitSysConv())
+ {
+ fSysConnection = TRUE;
+ // Try to make the server open the document.
+ ErrRtnH (pdde->PostSysCommand (pdde->m_pSysChannel,
+ (LPSTR)&achStdOpenDocument,
+ FALSE));
+ pdde->m_fDidStdOpenDoc = TRUE;
+ }
+ else
+ {
+ ErrRtnH (ResultFromScode (CO_E_APPDIDNTREG));
+ }
+ // Try connecting to document again. Should succeed.
+ hresult = pdde->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL);
+ }
+ }
+ else
+ {
+ // Already running, so assume visible
+ pdde->DeclareVisibility (TRUE);
+ }
+
+errRtn:
+ if (pdde->m_pSysChannel) {
+ if (fSysConnection)
+ pdde->TermConv (pdde->m_pSysChannel);
+ else
+ pdde->DeleteChannel (pdde->m_pSysChannel);
+ }
+
+ if (hresult == NOERROR) {
+ hresult = punk->QueryInterface (iid, ppv);
+ }
+ pdde->m_pUnkOuter->Release();
+ if (hresult!=NOERROR)
+ {
+ Warn ("DdeBindToObject failed");
+ }
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "DdeBindToObject szFile(%ws) returns %x \n",
+ szFile,hresult));
+
+ return hresult;
+}
+
+
+//
+// BUGBUG: This won't work in a multi-threaded world.
+//
+static LPOLESTR szOriginalUNCName;
+static WCHAR cOriginalDrive;
+
+static INTERNAL InitializeIterator
+ (LPCOLESTR wszFile)
+{
+ WCHAR wszDrive[] = L"A:\\";
+
+ if ((wszFile == NULL) || (wszFile[1] != ':'))
+ {
+ return(S_FALSE);
+ }
+
+ wszDrive[0] = (WCHAR)CharUpperW((LPWSTR)wszFile[0]);
+
+ if (GetDriveType(wszDrive) == DRIVE_REMOTE)
+ {
+
+ DWORD cb = MAX_STR;
+ wszDrive[2] = '\0';
+ if (NULL==szOriginalUNCName)
+ {
+ szOriginalUNCName = new WCHAR [MAX_STR];
+ }
+
+
+ if (WN_SUCCESS == OleWNetGetConnection (wszDrive, szOriginalUNCName, &cb))
+ {
+ cOriginalDrive = (WCHAR)CharUpperW((LPWSTR)wszFile[0]);
+ return NOERROR;
+ }
+ }
+ // szFile is not a network file
+ return ReportResult (0, S_FALSE, 0, 0);
+}
+
+
+
+// NextEquivalentNetDrive
+//
+// Change the drive letter of szFile to the next (modulo 'Z') drive letter
+// that is connected to the same net drive
+// Return S_FALSE when there are no more equivalent drives
+//
+// NOTE NOTE NOTE
+//
+// This routine is playing fast and furious with the relationship between
+// the first 128 Unicode characters and the ASCII character set.
+//
+static INTERNAL NextEquivalentNetDrive
+ (LPOLESTR szFile)
+{
+ #define incr(c) (c=='Z' ? c='A' : ++c)
+ WCHAR wszDrive[3]= L"A:";
+ Assert (szFile && szFile[1]==':');
+
+ char cDrive = (char)CharUpperA((LPSTR)szFile[0]);
+
+ while (cOriginalDrive != incr(cDrive))
+ {
+
+ DWORD cb = MAX_PATH;
+ WCHAR szUNCName [MAX_PATH];
+ wszDrive[0] = cDrive;
+
+ Assert (cDrive >= 'A' && cDrive <= 'Z');
+ Assert (szOriginalUNCName);
+
+ if (WN_SUCCESS == OleWNetGetConnection (wszDrive,szUNCName, &cb) &&
+ (0 == lstrcmpW (szUNCName, szOriginalUNCName)))
+ {
+ szFile[0] = cDrive;
+ return NOERROR;
+ }
+ }
+ // We've gone through all the drives
+ return ReportResult (0, S_FALSE, 0, 0);
+}
+
+
+
+// Dde_IsRunning
+//
+// Attempt to open a document-level conversation using the
+// filename as a topic. If the conversation is established we
+// know the file is running and terminate the conversation.
+// Otherwise it is not running.
+//
+INTERNAL DdeIsRunning
+ (CLSID clsid,
+ LPCOLESTR szFileIn,
+ LPBC pbc,
+ LPMONIKER pmkToLeft,
+ LPMONIKER pmkNewlyRunning)
+{
+ intrDebugOut((DEB_ITRACE,
+ "DdeIsRunning szFileIn(%ws)\n",szFileIn));
+
+ ATOM aTopic;
+ CDdeObject FAR* pdde=NULL;
+ HRESULT hres = ReportResult(0, S_FALSE, 0, 0);
+
+ if (NULL==szFileIn || '\0'==szFileIn[0])
+ {
+ // A NULL filename is invalid for our purposes.
+ // But if we did a DDE_INITIATE, NULL would mean "any topic",
+ // and if we were called by RunningMoniker() with CLSID_NULL,
+ // then we would be INITIATEing on "any app, any topic" and
+ // SHELL (if not others) would respond.
+ intrDebugOut((DEB_ITRACE,
+ "DdeIsRunning NULL szFileIn\n"));
+
+ hres = S_FALSE;
+ goto exitRtn;
+ }
+ //
+ // This protocol doesn't handle the fact that there are two names for
+ // every file. This is a bit of a problem. So, we are going to choose
+ // the short name as the one to look for. This means that DDE objects
+ // using the long filename will not work very well.
+ //
+ WCHAR szFile[MAX_PATH];
+ if ((lstrlenW(szFileIn) == 0) || (GetShortPathName(szFileIn,szFile,MAX_PATH) == 0))
+ {
+ //
+ // Unable to determine a short path for this object. Use whatever we were
+ // handed.
+ //
+ intrDebugOut((DEB_ITRACE,"No conversion for short path. Copy szFileIn\n"));
+ lstrcpyW(szFile,szFileIn);
+ }
+ intrDebugOut((DEB_ITRACE,"Short file szFile(%ws)\n",szFile));
+
+ aTopic = wGlobalAddAtom (szFile);
+ intrAssert(wIsValidAtom(aTopic));
+
+ ErrZ (CDdeObject::Create (NULL, clsid, OT_LINK, aTopic, NULL, &pdde));
+
+ if (NOERROR == pdde->DocumentLevelConnect (pbc))
+ {
+ // It is running!
+ // Immediately terminate conversation. We just wanted to know
+ // if it was running.
+ hres = NOERROR;
+ }
+ else
+ {
+ // Not running
+ hres = ReportResult(0, S_FALSE, 0, 0);
+ }
+
+ errRtn:
+
+ if (aTopic)
+ intrAssert(wIsValidAtom(aTopic));
+ GlobalDeleteAtom (aTopic);
+ if (pdde)
+ {
+ Assert (pdde->m_refs==1);
+ pdde->m_pUnkOuter->Release();
+ }
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "DdeIsRunning szFile(%ws) returns %x\n",szFile,hres));
+ return hres;
+}
+
+
+#if 0
+INTERNAL DdeIsRunning
+ (CLSID clsid,
+ LPCSTR cszFile,
+ LPBC pbc,
+ LPMONIKER pmkToLeft,
+ LPMONIKER pmkNewlyRunning)
+{
+ HRESULT hresult = NOERROR;
+ LPSTR szFile = NULL;
+
+ // Normal case
+ if (NOERROR == Dde_IsRunning (clsid, cszFile, pbc, pmkToLeft,
+ pmkNewlyRunning))
+ {
+ return NOERROR;
+ }
+
+ if (cszFile[0]=='\\' && cszFile[1]=='\\')
+ {
+ RetErr (SzFixNet (pbc, (LPSTR)cszFile, &szFile));
+ // Try with a drive letter instead of a UNC name
+ if (NOERROR==Dde_IsRunning (clsid, szFile, pbc, pmkToLeft,
+ pmkNewlyRunning))
+ {
+ hresult = NOERROR;
+ goto errRtn;
+ }
+ }
+ else
+ {
+ szFile = UtDupString (cszFile); // so it can be deleted
+ }
+
+ // If failure, see if the file is running under a different net
+ // drive letter that is mapped to the same drive.
+
+ if (InitializeIterator (szFile) != NOERROR)
+ {
+ // file is probably not on a network drive
+ hresult = ResultFromScode (S_FALSE);
+ goto errRtn;
+ }
+
+ while (NOERROR==NextEquivalentNetDrive (szFile))
+ {
+ if (NOERROR == Dde_IsRunning (clsid, szFile, pbc, pmkToLeft,
+ pmkNewlyRunning))
+ {
+ hresult = NOERROR;
+ goto errRtn;
+ }
+ }
+ // not running
+ hresult = ResultFromScode (S_FALSE);
+
+ errRtn:
+ delete szFile;
+ return hresult;
+}
+#endif
+
+
+
+// CDdeObject::DocumentLevelConnect
+//
+// Try to connect to document (m_aTopic) even if the document is running
+// under a different drive letter that is mapped to the same network drive.
+//
+INTERNAL CDdeObject::DocumentLevelConnect
+ (LPBINDCTX pbc)
+{
+ ATOM aOriginal;
+ ATOM aTopic;
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::DocumentLevelConnect(%x)\n",this));
+ HRESULT hresult = NOERROR;
+
+ // Normal case
+ if (NOERROR==m_ProxyMgr.Connect (IID_NULL, CLSID_NULL))
+ {
+ goto exitRtn;
+ }
+
+
+ WCHAR szFile[MAX_STR];
+ WCHAR szUNCFile[MAX_STR];
+
+ Assert (wIsValidAtom (m_aTopic));
+ if (GlobalGetAtomName (m_aTopic, szFile, MAX_STR) == 0)
+ {
+ hresult = E_UNEXPECTED;
+ goto exitRtn;
+ }
+ aOriginal = wDupAtom (m_aTopic);
+ intrAssert(wIsValidAtom(aOriginal));
+
+ intrDebugOut((DEB_ITRACE,
+ "::DocumentLevelConnect(szFile=%ws)\n",this,szFile));
+ if (NOERROR != InitializeIterator (szFile))
+ {
+ // szFile probably not a network file
+ hresult = ResultFromScode (S_FALSE);
+ goto errRtn;
+ }
+
+ while (NOERROR == NextEquivalentNetDrive (szFile))
+ {
+ SetTopic (aTopic = wGlobalAddAtom (szFile));
+ if (NOERROR==m_ProxyMgr.Connect (IID_NULL, CLSID_NULL))
+ {
+ // Inform client of new drive letter
+ ChangeTopic (wAtomNameA(aTopic));
+ hresult = NOERROR;
+ goto errRtn;
+ }
+ else
+ {
+ SetTopic ((ATOM)0);
+ }
+ }
+
+ // Try with full UNC name
+ lstrcpy (szUNCFile, szOriginalUNCName);
+ lstrcat (szUNCFile, szFile+2); // skip X:
+ SetTopic (aTopic = wGlobalAddAtom (szUNCFile));
+ if (NOERROR==m_ProxyMgr.Connect (IID_NULL, CLSID_NULL))
+ {
+ // Inform client of new name
+ ChangeTopic (wAtomNameA(aTopic));
+ hresult = NOERROR;
+ goto errRtn;
+ }
+ else
+ {
+ SetTopic ((ATOM)0);
+ }
+
+ // Not running
+ hresult = S_FALSE;
+
+errRtn:
+ if (NOERROR != hresult)
+ SetTopic (aOriginal);
+ delete szOriginalUNCName;
+ szOriginalUNCName = NULL;
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::DocumentLevelConnect(%x) returns %x\n",
+ this,hresult));
+
+ return hresult;
+}
+
diff --git a/private/ole32/com/dde/client/ddeoo.cxx b/private/ole32/com/dde/client/ddeoo.cxx
new file mode 100644
index 000000000..97c5a58fe
--- /dev/null
+++ b/private/ole32/com/dde/client/ddeoo.cxx
@@ -0,0 +1,770 @@
+/*
+ddeoo.cpp
+DDE Ole Object
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddeoo.cpp
+
+Abstract:
+
+ This module contains the methods for DdeObject::OleObject
+
+Author:
+
+ Jason Fuller (jasonful) 24-July-1992
+
+*/
+
+#include "ddeproxy.h"
+#include <limits.h>
+
+ASSERTDATA
+
+//
+// OleObject methods
+//
+
+STDUNKIMPL_FORDERIVED(DdeObject, OleObjectImpl)
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetClientSite
+ (IOleClientSite FAR* pClientSite)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::SetClientSite(%x,pClientSite=%x)\n",
+ this,
+ pClientSite));
+
+ ChkD (m_pDdeObject);
+
+ if (m_pDdeObject->m_pOleClientSite)
+ m_pDdeObject->m_pOleClientSite->Release();
+
+ // we've decided to keep the pointer that's been passed to us. So we
+ // must AddRef()
+ if (m_pDdeObject->m_pOleClientSite = pClientSite)
+ pClientSite->AddRef();
+
+ // this pointer need not be sent to the server, because we will always
+ // send our &m_MyDataSite as the client site
+ return NOERROR;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetClientSite
+ (IOleClientSite FAR* FAR* ppClientSite)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetClientSite(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+ // we've been asked to give the pointer so we should AddRef()
+ if (*ppClientSite = m_pDdeObject->m_pOleClientSite)
+ m_pDdeObject->m_pOleClientSite->AddRef();
+ return NOERROR;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::EnumVerbs
+ (IEnumOLEVERB FAR* FAR* ppenumOleVerb)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::EnumVerbs(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+ return ReportResult(0, OLE_S_USEREG, 0, 0);
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Update
+( void )
+{
+ HRESULT hr;
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::Update(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+
+ hr = m_pDdeObject->Update(TRUE);
+ if (hr == NOERROR)
+ {
+ hr = m_pDdeObject->Save(m_pDdeObject->m_pstg);
+ }
+
+ return hr;
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::IsUpToDate
+( void )
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::IsUpToDate(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+ // There is no way to know if a 1.0 server has edited its embedded
+ // object, so we assume it has, to be on the safe side.
+ return ResultFromScode (m_pDdeObject->m_ulObjType==OT_EMBEDDED
+ ? S_FALSE : S_OK);
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetUserClassID
+ (CLSID FAR* pClsid)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetUserClassID(%x)\n",
+ this));
+
+ *pClsid = m_pDdeObject->m_clsid;
+ return NOERROR;
+}
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetUserType
+ (DWORD dwFormOfType,
+ LPOLESTR * pszUserType)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetUserType(%x)\n",
+ this));
+
+ return ReportResult (0, OLE_S_USEREG, 0, 0);
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetExtent
+( DWORD dwAspect, LPSIZEL lpsizel)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::SetExtent(%x)\n",
+ this));
+
+ HANDLE hDdePoke;
+ LPRECT16 lprc;
+
+ ChkD (m_pDdeObject);
+ Puts ("OleObject::SetExtent\n");
+ if (!(dwAspect // at least one bit
+ && !(dwAspect & (dwAspect-1)) // exactly one bit
+ && (dwAspect & DVASPECT_CONTENT))) // a bit we support
+ {
+ return ResultFromScode (DV_E_DVASPECT);
+ }
+
+#ifdef OLD
+ m_pDdeObject->m_cxContentExtent = lpsizel->cx;
+ m_pDdeObject->m_cyContentExtent = lpsizel->cy;
+#endif
+
+ if (!m_pDdeObject->m_pDocChannel)
+ {
+ return OLE_E_NOTRUNNING;
+ }
+
+ lprc = (LPRECT16) wAllocDdePokeBlock (sizeof(RECT16), g_cfBinary, &hDdePoke);
+ lprc->left = lprc->right = (SHORT) min(INT_MAX,lpsizel->cx);
+ lprc->top = lprc->bottom= (SHORT) min(INT_MAX,lpsizel->cy);
+ aStdDocDimensions = GlobalAddAtom (OLESTR("StdDocDimensions"));
+ intrAssert(wIsValidAtom(aStdDocDimensions));
+ GlobalUnlock (hDdePoke);
+ return m_pDdeObject->Poke(aStdDocDimensions, hDdePoke);
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetExtent
+( DWORD dwAspect, LPSIZEL lpsizel)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetExtent(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+
+
+#ifdef OLD
+ VDATEPTROUT (lpsizel, SIZEL);
+ if (!(dwAspect // at least one bit
+ && !(dwAspect & (dwAspect-1)) // exactly one bit
+ && !(dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON)))) // a bit we support
+ {
+ return ResultFromScode (DV_E_DVASPECT);
+ }
+
+ if (dwAspect & DVASPECT_CONTENT)
+ {
+ lpsizel->cx = m_pDdeObject->m_cxContentExtent;
+ lpsizel->cy = m_pDdeObject->m_cyContentExtent;
+ }
+
+ return NOERROR;
+#endif
+ return ResultFromScode(E_NOTIMPL);
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::DoVerb
+//
+// Synopsis: Send the server a message asking it to do a verb.
+//
+// Effects: OLE1.0 servers only know how to do a couple of
+// verbs. Specifically, it will respond to PRIMARY,
+// HIDE, OPEN, and SHOW. All others return error
+//
+//
+// Arguments: [iVerb] -- Verb number
+// [lpmsg] -- Window message (ignored)
+// [pActiveSite] -- ActiveSite (ignored)
+// [lindex] -- Index (ignored)
+// [hwndParent] -- (ignored)
+// [lprcPosRect] -- (ignored)
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Created
+//
+// Notes:
+//
+// ANSI ALERT!
+//
+// The server is going to accept a command string from us. This string
+// needs to be done in ANSI, since we are going to pass it to old
+// servers. Therefore, the following code generates an ANSI string
+// The following are the supported verb strings
+//
+// [StdShowItem("aItem",FALSE)]
+// [StdDoVerbItem("aItem",verb,FALSE,FALSE)]
+//
+//----------------------------------------------------------------------------
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::DoVerb
+ (LONG iVerb, LPMSG lpmsg, LPOLECLIENTSITE pActiveSite,
+ LONG lindex, HWND hwndParent, const RECT FAR* lprcPosRect)
+{
+ WORD len;
+ ULONG size;
+ LPSTR lpdata = NULL;
+ LPSTR lpdataStart = NULL;
+ HANDLE hdata = NULL;
+ BOOL bShow;
+ HRESULT hresult;
+
+ ChkD (m_pDdeObject);
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::DoVerb(%x,iVerb=%x,lindex=%x)\n",
+ this,iVerb,lindex));
+
+ if (iVerb < OLEIVERB_HIDE)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::DoVerb(%x)Returning invalid verb\n",
+ this));
+ return OLEOBJ_E_INVALIDVERB;
+ }
+
+
+ if (iVerb == OLEIVERB_HIDE)
+ {
+ intrDebugOut((DEB_ITRACE,"::DoVerb(%x) OLEIVERB_HIDE\n",this));
+
+ if (m_pDdeObject->m_fVisible || OT_LINK==m_pDdeObject->m_ulObjType)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DoVerb(%x) CANNOT_DOVERB_NOW\n",this));
+ return OLEOBJ_S_CANNOT_DOVERB_NOW;
+ }
+
+ intrDebugOut((DEB_ITRACE,"::DoVerb(%x) returns NOERROR\n",this));
+ return NOERROR;
+ }
+
+ //
+ // Calculate the number of bytes needed to pass the
+ // execute command to the server.
+ //
+ if (bShow = (iVerb == OLEIVERB_SHOW
+ || iVerb == OLEIVERB_OPEN
+ || m_pDdeObject->m_bOldSvr))
+ {
+ //
+ // [StdShowItem("aItem",FALSE)]
+ //
+
+ len = 23 + wAtomLenA (m_pDdeObject->m_aItem) + 1;
+
+ }
+ else
+ {
+ // [StdDoVerbItem("aItem",verb,FALSE,FALSE)]
+ len = 32 + 10 /* for verb */ + wAtomLenA (m_pDdeObject->m_aItem) + 1;
+
+ }
+
+ if (!(hdata = GlobalAlloc (GMEM_DDESHARE, size = len)))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DoVerb(%x) cannot alloc %x bytes\n",
+ this,size));
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+
+ if (!(lpdata = (LPSTR)GlobalLock (hdata)))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DoVerb(%x) cannot lock\n",
+ this));
+ GlobalFree (hdata);
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ lpdataStart = lpdata;
+
+
+ strcpy (lpdata, bShow ? "[StdShowItem(\"" : "[StdDoVerbItem(\"");
+ len = strlen (lpdata);
+ lpdata += len;
+
+ // For links
+ if (m_pDdeObject->m_aItem)
+ lpdata += GlobalGetAtomNameA (m_pDdeObject->m_aItem, lpdata, size - len);
+
+ if (!bShow) {
+ wsprintfA (lpdata,"\",%lu,TRUE,FALSE)]", iVerb);
+ } else {
+ strcpy (lpdata, "\")]");
+ // apps like excel and wingraph do not support activate at item level.
+ }
+
+ intrDebugOut((DEB_ITRACE,"::DoVerb(%x)lpdata(%s)\n",this,lpdataStart));
+
+ Assert (strlen(lpdata) < size);
+
+ GlobalUnlock (hdata);
+
+ hresult = m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel, hdata);
+
+ if (NOERROR==hresult)
+ {
+ // Assume doing a verb makes the server visible.
+ // This is not strictly true.
+ m_pDdeObject->DeclareVisibility (TRUE);
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DoVerb(%x)Execute returned %x\n",
+ this,
+ hresult));
+ }
+ return hresult;
+}
+
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::SetHostNames
+//
+// Synopsis: Sets the host names
+//
+// Effects:
+//
+// Arguments: [szContainerApp] -- Name of container app
+// [szContainerObj] -- Name of contained object
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Created
+//
+// Notes:
+// ANSI ALERT!
+//
+// The server is going to accept a command string from us. This string
+// needs to be done in ANSI, since we are going to pass it to old
+// servers. Therefore, the following code generates an ANSI string
+//
+//----------------------------------------------------------------------------
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetHostNames
+(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::SetHostNames(%x,App=%ws,Obj=%ws)\n",
+ this,szContainerApp,szContainerObj));
+
+ WORD cbName;
+ WORD wSize;
+ LPSTR lpBuf;
+ HANDLE hDdePoke;
+
+ ChkD (m_pDdeObject);
+
+ VDATEPTRIN (szContainerApp, char);
+
+ if (!m_pDdeObject->m_pDocChannel)
+ return NOERROR;
+ if (szContainerObj==NULL)
+ szContainerObj=OLESTR("");
+
+ if (szContainerApp[0]=='\0')
+ szContainerApp = OLESTR("Container Application");
+
+ //
+ // The OLE 1.0 server is going to want ANSI strings.
+ // convert the two that we have
+ //
+
+ char pszContainerApp[MAX_STR];
+ char pszContainerObj[MAX_STR];
+
+ if (WideCharToMultiByte(CP_ACP,
+ 0,
+ szContainerApp,
+ -1,
+ pszContainerApp,
+ MAX_STR,
+ NULL,
+ NULL) == FALSE)
+ {
+ intrDebugOut((DEB_ERROR,
+ "::SetHostNames(%x) can't convert szContainerApp(%ws) err=%x\n",
+ this,szContainerApp,GetLastError()));
+
+ //
+ // Couldn't convert string
+ //
+ return(E_UNEXPECTED);
+ }
+ if (WideCharToMultiByte(CP_ACP,
+ 0,
+ szContainerObj,
+ -1,
+ pszContainerObj,
+ MAX_STR,
+ NULL,
+ NULL) == FALSE)
+ {
+ intrDebugOut((DEB_ERROR,
+ "::SetHostNames(%x) can't convert szContainerObj(%ws) err=%x\n",
+ this,szContainerObj,GetLastError));
+
+ //
+ // Couldn't convert string
+ //
+ return(E_UNEXPECTED);
+ }
+
+
+ //
+ // We have found through experience that some OLE applications, like
+ // Clipart, use a fixed size buffer for these names. Therefore, we
+ // are going to limit the sizes of the strings, in case they are
+ // too long to send. We do this by always sticking a NULL at offset
+ // 80 in the file.
+ //
+ pszContainerApp[80]=0;
+ pszContainerObj[80]=0;
+
+ WORD cbObj;
+
+ wSize = (cbName = strlen(pszContainerApp)+1)
+ + (cbObj = strlen(pszContainerObj)+1)
+ + 2 * sizeof(WORD); // for the two offsets
+
+ lpBuf = wAllocDdePokeBlock ((DWORD)wSize, g_cfBinary, &hDdePoke);
+ ((WORD FAR*)lpBuf)[0] = 0;
+ ((WORD FAR*)lpBuf)[1] = cbName;
+ lpBuf += 2*sizeof(WORD);
+ memcpy (lpBuf,pszContainerApp,cbName);
+ memcpy (lpBuf+cbName, pszContainerObj,cbObj);
+ GlobalUnlock (hDdePoke);
+ aStdHostNames = GlobalAddAtom (OLESTR("StdHostNames"));
+ intrAssert(wIsValidAtom(aStdHostNames));
+ m_pDdeObject->Poke(aStdHostNames, hDdePoke);
+ return NOERROR;
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Close
+ (DWORD dwSaveOption)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::Close(%x,dwSaveOption=%x)\n",
+ this,dwSaveOption));
+
+
+ ChkDR (m_pDdeObject);
+
+ HRESULT hresult;
+ if (m_pDdeObject->m_fDidSendOnClose)
+ return ResultFromScode (RPC_E_CANTCALLOUT_INASYNCCALL);
+
+ if (((OLECLOSE_SAVEIFDIRTY == dwSaveOption) ||
+ (OLECLOSE_PROMPTSAVE==dwSaveOption)) &&
+ (m_pDdeObject->m_clsid != CLSID_Package))
+ {
+ // Packager gives truncated native data (header info with no
+ // actual embedded file) if you DDE_REQUEST it. Bug 3103
+ Update(); // IOleObject::Update
+ m_pDdeObject->OleCallBack (ON_SAVE,NULL);
+ }
+ RetZ (m_pDdeObject->m_pDocChannel);
+ hresult=m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel,
+ wNewHandle ((LPSTR)&achStdCloseDocument,sizeof(achStdCloseDocument)),
+ TRUE);
+ if (NOERROR==hresult)
+ m_pDdeObject->m_fDidStdCloseDoc = TRUE;
+
+ // Client sends StdCloseDocument. Srvr sends ACK. Srvr may or may not
+ // send Terminate. We may interpret the TERMINATE the server sends
+ // as the reply to ours even if he posted first. But since some servers
+ // post first and others wait for the client, this is what we need to do.
+
+ BOOL fVisible = m_pDdeObject->m_fWasEverVisible; // TermConv clears this flag
+ m_pDdeObject->TermConv (m_pDdeObject->m_pDocChannel);
+ if (!fVisible)
+ m_pDdeObject->MaybeUnlaunchApp();
+
+ return hresult;
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetMoniker
+ (DWORD dwWhichMoniker, LPMONIKER pmk)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::SetMoniker(%x,dwWhichMoniker=%x)\n",
+ this,dwWhichMoniker));
+
+ ChkD (m_pDdeObject);
+ Puts ("OleObject::SetMoniker\r\n");
+ // we ignore this always
+ return NOERROR;
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetMoniker
+ (DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetMoniker(%x,dwWhichMoniker=%x)\n",
+ this,dwWhichMoniker));
+
+ ChkD (m_pDdeObject);
+ if (m_pDdeObject->m_pOleClientSite)
+ return m_pDdeObject->m_pOleClientSite->GetMoniker(dwAssign,
+ dwWhichMoniker, ppmk);
+ else {
+ // no client site
+ *ppmk = NULL;
+ return ReportResult(0, E_UNSPEC, 0, 0);
+ }
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::InitFromData
+ (LPDATAOBJECT pDataObject, BOOL fCreation, DWORD dwReserved)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::InitFromData(%x)\n",
+ this));
+
+ Puts ("OleObject::InitFromData\r\n");
+ return ReportResult(0, E_NOTIMPL, 0, 0);
+}
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetClipboardData
+ (DWORD dwReserved, LPDATAOBJECT FAR* ppDataObject)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetClipboardData(%x)\n",
+ this));
+
+ Puts ("OleObject::GetClipboardData\r\n");
+ return ReportResult(0, E_NOTIMPL, 0, 0);
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Advise
+ (IAdviseSink FAR* pAdvSink,
+ DWORD FAR* pdwConnection)
+{
+ HRESULT hres;
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::Advise(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+ Puts ("OleObject::Advise\n");
+ // Esstablish a DDE advise connection.
+ if (m_pDdeObject->m_ulObjType == OT_EMBEDDED
+ && !m_pDdeObject->m_fDidAdvNative)
+ {
+ // Embedded case.
+ // Always advise on Save and Close.
+ if (hres = m_pDdeObject->AdviseOn (g_cfNative, ON_SAVE))
+ return hres;
+ if (hres = m_pDdeObject->AdviseOn (g_cfNative, ON_CLOSE))
+ return hres;
+ if (m_pDdeObject->m_clsid == CLSID_MSDraw)
+ {
+ // MSDraw has (another) bug. If you do not do an Advise on
+ // presentation, then File.Update does not work, and you
+ // cannot close the app unless you answer "no" to the update
+ // dialog. This would happen when you "Display As Icon"
+ // because ordinarily there is no need to advise on presentation.
+ // The following "unnecessary" advise fixes this problem.
+ if (hres = m_pDdeObject->AdviseOn (CF_METAFILEPICT, ON_SAVE))
+ return hres;
+ if (hres = m_pDdeObject->AdviseOn (CF_METAFILEPICT, ON_CLOSE))
+ return hres;
+ }
+ }
+ else {
+ /* Linked case */
+ if (hres = m_pDdeObject->AdviseOn (g_cfBinary, ON_RENAME))
+ return hres;
+ }
+ RetZS (m_pDdeObject->m_pOleAdvHolder, E_OUTOFMEMORY);
+ return m_pDdeObject->m_pOleAdvHolder->Advise (pAdvSink, pdwConnection);
+}
+
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Unadvise
+ (DWORD dwConnection)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::Unadvise(%x,dwConnection=%x)\n",
+ this,dwConnection));
+
+ HRESULT hres;
+ ChkD (m_pDdeObject);
+
+ // Terminate the DDE advise connection
+ if (m_pDdeObject->m_ulObjType == OT_EMBEDDED)
+ {
+ // Embedded case.
+ if (hres = m_pDdeObject->UnAdviseOn (g_cfNative, ON_SAVE))
+ return hres;
+ if (hres = m_pDdeObject->UnAdviseOn (g_cfNative, ON_CLOSE))
+ return hres;
+ }
+ else
+ {
+ /* Linked case */
+ if (hres = m_pDdeObject->UnAdviseOn (g_cfBinary, ON_RENAME))
+ return hres;
+ }
+ RetZS (m_pDdeObject->m_pOleAdvHolder, E_OUTOFMEMORY);
+ return m_pDdeObject->m_pOleAdvHolder->Unadvise (dwConnection);
+}
+
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::EnumAdvise
+ (THIS_ LPENUMSTATDATA FAR* ppenumAdvise)
+{
+ ChkD (m_pDdeObject);
+ RetZS (m_pDdeObject->m_pOleAdvHolder, E_OUTOFMEMORY);
+ return m_pDdeObject->m_pOleAdvHolder->EnumAdvise(ppenumAdvise);
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetMiscStatus
+ (DWORD dwAspect,
+ DWORD FAR* pdwStatus)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::GetMiscStatus(%x)\n",
+ this));
+
+ VDATEPTRIN (pdwStatus, DWORD);
+ *pdwStatus = 0L;
+ return ResultFromScode (OLE_S_USEREG);
+}
+
+
+
+STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetColorScheme
+ (LPLOGPALETTE lpLogpal)
+{
+ HANDLE hDdePoke;
+ LPLOGPALETTE lptmpLogpal;
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::SetColorScheme(%x)\n",
+ this));
+
+ ChkD (m_pDdeObject);
+
+ if (!m_pDdeObject->m_pDocChannel)
+ return NOERROR;
+
+ aStdColorScheme = GlobalAddAtom (OLESTR("StdColorScheme"));
+ intrAssert(wIsValidAtom(aStdColorScheme));
+
+ DWORD dwSize = (lpLogpal->palNumEntries - 1) * sizeof(PALETTEENTRY)
+ + sizeof(LOGPALETTE);
+ lptmpLogpal = (LPLOGPALETTE) wAllocDdePokeBlock (dwSize, g_cfBinary, &hDdePoke);
+ memcpy(lptmpLogpal, lpLogpal, dwSize);
+ GlobalUnlock(hDdePoke);
+
+ return m_pDdeObject->Poke(aStdColorScheme, hDdePoke);
+}
+
+
+
+#ifdef _DEBUG
+STDMETHODIMP_(void) NC(CDdeObject,CDebug)::Dump( IDebugStream FAR * pdbstm)
+{
+}
+
+STDMETHODIMP_(BOOL) NC(CDdeObject,CDebug)::IsValid( BOOL fSuspicious )
+{
+ if( m_pDdeObject->m_refs > 0 && m_pDdeObject->m_chk == chkDdeObj )
+ return TRUE;
+ else
+ return FALSE;
+}
+#endif
diff --git a/private/ole32/com/dde/client/ddeproxy.cxx b/private/ole32/com/dde/client/ddeproxy.cxx
new file mode 100644
index 000000000..bdc87f136
--- /dev/null
+++ b/private/ole32/com/dde/client/ddeproxy.cxx
@@ -0,0 +1,2884 @@
+/*
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddeproxy.cpp
+
+Abstract:
+
+ This module contains the code for the dde proxy (wrapper)
+
+Author:
+
+ Srini Koppolu (srinik) 22-June-1992
+ Jason Fuller (jasonful) 24-July-1992
+*/
+#include "ddeproxy.h"
+#include <tls.h>
+
+
+DebugOnly (static UINT v_cDdeObjects=0;)
+/*
+ * IMPLEMENTATION of CDdeObject
+ *
+ */
+
+#ifdef OLD
+#define UpdateExtent(old,new) do { if ((long)new!=old) {old=(long)new; } } while (0)
+#endif
+
+//+---------------------------------------------------------------------------
+//
+// Function: CreateDdeClientHwnd
+//
+// Synopsis: Creates a per thread ClientDde window.
+//
+// Effects: This window is created so we can keep a list of windows that
+// need to be cleaned up in the event the thread dies or OLE32 is
+// unloaded. In the case of DLL unload, we will fault if we don't
+// cleanup this window, since user will dispatch messages to
+// non-existant code. The easy way to track these windows is to
+// make them children of a common per thread window.
+//
+// This routine is called by the TLSGetDdeClient() routine to
+// create a window per thread. This window doesn't need to respond
+// to DDE Initiates.
+//
+// Arguments: [void] --
+//
+// Returns: HWND to DdeClientWindow.
+//
+// History: 12-10-94 kevinro Created
+//
+//----------------------------------------------------------------------------
+
+HWND CreateDdeClientHwnd(void)
+{
+ return SSCreateWindowExA(0,"STATIC","DdeClientHwnd",WS_DISABLED,
+ 0,0,0,0,NULL,NULL,hinstSO,NULL);
+}
+
+// CreateDdeProxy
+//
+// This corresponds to ProxyManager::Create in 2.0
+//
+
+
+INTERNAL_ (LPUNKNOWN) CreateDdeProxy
+ (IUnknown * pUnkOuter,
+ REFCLSID clsid)
+{
+ LPUNKNOWN punk;
+ intrDebugOut((DEB_ITRACE,"CreateDdeProxy(pUnkOuter=%x)\n",pUnkOuter));
+
+ COleTls Tls;
+ if (Tls->dwFlags & OLETLS_DISABLE_OLE1DDE)
+ {
+ // If DDE use is disabled we shouldn't have gotten here.
+ // This is a bad place to error because we can't return an
+ // HResult.
+ //
+ Assert(!"Executing CreateDdeProxy when DDE is disabled");
+ return NULL;
+ }
+
+ punk = CDdeObject::Create (pUnkOuter, clsid);
+ intrDebugOut((DEB_ITRACE,
+ "CreateDdeProxy(pUnkOuter=%x) returns %x\n",
+ pUnkOuter,
+ punk));
+ return punk;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::Create
+//
+// Synopsis: Creates a CDdeObject
+//
+// Effects:
+//
+// Arguments: [pUnkOuter] -- Controlling IUnknown
+// [clsid] -- OLE1 ClassID
+// [ulObjType] -- Object type. Optional: def to OT_EMBEDDED
+// [aTopic] -- Atom of link. Optional: def to NULL
+// [szItem] -- String for link object (def to NULL)
+// [ppdde] -- Output pointer to CDdeObject (def to NULL)
+// [fAllowNullClsid] -- Is NULL clsid OK? Default: false
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History:
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL_(LPUNKNOWN) CDdeObject::Create
+ (IUnknown * pUnkOuter,
+ REFCLSID clsid,
+ ULONG ulObjType,// optional, default OT_EMBEDDED
+ ATOM aTopic, // optional, only relevant if ulObjType==OT_LINK
+ LPOLESTR szItem, // optional, only relevant if ulObjType==OT_LINK
+ CDdeObject * * ppdde, // optional, thing created
+ BOOL fAllowNullClsid) // default FALSE
+{
+ COleTls Tls;
+ if(Tls->dwFlags & OLETLS_DISABLE_OLE1DDE)
+ {
+ //
+ // If the DDE implementation of OLE1 is disabled
+ // we shouldn't get this far. This is also a bad place
+ // to fail because we this routine is defined to not return
+ // an HResult.
+ //
+ Assert(!"Executing CDdeObject::Create but DDE is Disabled");
+ return NULL;
+ }
+ intrDebugOut((DEB_ITRACE,"CDdeObject::Create(%x,ulObjType=%x)\n",
+ pUnkOuter,
+ ulObjType));
+
+ CDdeObject * pDdeObject;
+ static int iTopic=1; // used to make topic names unique
+ WCHAR szTopic[30];
+ Assert (ulObjType==OT_LINK || ulObjType==OT_EMBEDDED);
+
+ Assert (ulObjType != OT_LINK || wIsValidAtom(aTopic));
+ if (ppdde)
+ *ppdde = NULL;
+
+ if (NULL==(pDdeObject = new CDdeObject (pUnkOuter))
+ || NULL == pDdeObject->m_pDataAdvHolder
+ || NULL == pDdeObject->m_pOleAdvHolder)
+ {
+ Assert (!"new CDdeObject failed");
+ return NULL;
+ }
+
+ pDdeObject->m_refs = 1;
+ pDdeObject->m_clsid = clsid;
+ pDdeObject->m_aClass = wAtomFromCLSID(clsid);
+
+#ifdef OLE1INTEROP
+
+ pDdeObject->m_fOle1interop = TRUE;
+
+#endif
+
+ if (ulObjType==OT_LINK)
+ {
+
+ pDdeObject->m_aTopic = wDupAtom (aTopic);
+ pDdeObject->m_aItem = wGlobalAddAtom (szItem);
+ // Never close a linked document
+ pDdeObject->m_fNoStdCloseDoc = TRUE;
+ }
+ else
+ {
+ // This string may actually be visible in the Window Title Bar for a sec.
+ InterlockedIncrement((long *)&iTopic);
+ wsprintf (szTopic,OLESTR("Embedded Object #%u"), iTopic);
+ Assert (lstrlenW(szTopic) < 30);
+ pDdeObject->m_aItem = NULL;
+ pDdeObject->m_aTopic = wGlobalAddAtom (szTopic);
+ }
+ pDdeObject->m_bOldSvr = wIsOldServer (pDdeObject->m_aClass);
+ pDdeObject->m_ulObjType = ulObjType;
+
+ // we can only run if we have a MFI
+ pDdeObject->m_aExeName = wGetExeNameAtom(clsid);
+
+ intrDebugOut((DEB_ITRACE,
+ "::Create(%x,aTopic=%x,aItem=%x,szItem=%ws,aExeName=%x)\n",
+ pDdeObject,
+ pDdeObject->m_aTopic,
+ pDdeObject->m_aItem,
+ szItem?szItem:L"<NULL>",
+ pDdeObject->m_aExeName));
+
+ if (ppdde)
+ *ppdde = pDdeObject;
+ return &pDdeObject->m_Unknown;
+}
+
+
+
+// Constructor
+CDdeObject::CDdeObject (IUnknown * pUnkOuter) :
+ m_Unknown(this),
+ CONSTRUCT_DEBUG
+ m_Data(this),
+ m_Ole(this),
+ m_PersistStg(this),
+ m_ProxyMgr(this),
+ m_OleItemContainer(this),
+ m_RpcStubBuffer(this)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::CDdeObject(%x)\n",this));
+ if (!pUnkOuter)
+ pUnkOuter = &m_Unknown;
+
+ m_pUnkOuter = pUnkOuter;
+ m_bRunning = FALSE;
+ m_pOleClientSite = NULL;
+ m_pstg = NULL;
+ m_pSysChannel = NULL;
+ m_pDocChannel = NULL;
+ m_bInitNew = NULL;
+ m_hNative = NULL;
+ m_hPict = NULL;
+ m_hExtra = NULL;
+ m_cfExtra = NULL;
+ m_cfPict = 0;
+ m_aItem = NULL;
+ m_iAdvSave = 0;
+ m_iAdvClose = 0;
+ m_iAdvChange = 0;
+ m_fDidAdvNative = FALSE;
+ m_pOleAdvHolder = NULL;
+ m_pDataAdvHolder = NULL;
+ m_fDidSendOnClose = FALSE;
+ m_fNoStdCloseDoc = FALSE;
+ m_fDidStdCloseDoc = FALSE;
+ m_fDidStdOpenDoc = FALSE;
+ m_fDidGetObject = FALSE;
+ m_fDidLaunchApp = FALSE;
+ m_fUpdateOnSave = TRUE;
+ m_fVisible = FALSE;
+ m_fWasEverVisible = FALSE;
+ m_fCalledOnShow = FALSE;
+ m_fGotCloseData = FALSE;
+ m_cLocks = 1; // connections are initially locked
+ m_chk = chkDdeObj;
+ m_ptd = NULL;
+ m_fDoingSendOnDataChange = FALSE;
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ _DelayDelete = NoDelay;
+#endif // _CHICAGO_
+
+ CreateOleAdviseHolder (&m_pOleAdvHolder);
+ Assert (m_pOleAdvHolder);
+ CreateDataAdviseHolder (&m_pDataAdvHolder);
+ Assert (m_pDataAdvHolder);
+
+#ifdef OLD
+ m_cxContentExtent = 2000; // 2 centimeters , totally random default
+ m_cyContentExtent = 2000;
+#endif
+
+ m_wTerminate = Terminate_None;
+
+ DebugOnly (v_cDdeObjects++;)
+ Putsi (v_cDdeObjects);
+}
+
+
+
+CDdeObject::~CDdeObject
+ (void)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::~CDdeObject(%x)\n",this));
+
+ if (m_pDocChannel)
+ {
+ intrDebugOut((DEB_IWARN , "Abnormal situation: Doc Channel not deleted. Server died?"));
+ delete m_pDocChannel;
+ }
+ if (m_pSysChannel)
+ {
+ Warn ("Abnormal situation: Sys Channel not deleted. Server died?");
+ delete m_pSysChannel;
+ }
+ if (m_hNative)
+ {
+ GlobalFree(m_hNative);
+ }
+
+ if (m_hPict)
+ {
+ wFreeData (m_hPict, m_cfPict, TRUE);
+ }
+
+ if (m_hExtra)
+ {
+ wFreeData (m_hExtra, m_cfExtra, TRUE);
+ }
+
+ // release all the pointers that we remember
+
+ if (m_pOleClientSite)
+ {
+ DeclareVisibility (FALSE);
+ m_pOleClientSite->Release();
+ }
+
+ if (m_pDataAdvHolder)
+ m_pDataAdvHolder->Release();
+
+ if (m_pOleAdvHolder)
+ m_pOleAdvHolder->Release();
+
+ if (m_pstg)
+ m_pstg->Release();
+
+ if (m_aExeName)
+ GlobalDeleteAtom (m_aExeName);
+
+ if (m_aClass)
+ GlobalDeleteAtom (m_aClass);
+
+ if (m_aTopic)
+ GlobalDeleteAtom (m_aTopic);
+
+ if (m_aItem)
+ GlobalDeleteAtom (m_aItem);
+
+ if (m_ptd)
+ delete m_ptd;
+
+ m_chk = 0;
+ DebugOnly (v_cDdeObjects--;)
+ Putsi (v_cDdeObjects);
+}
+
+
+
+
+// Handles WM_DDE_ACKs received while in initiate state. If this is the first
+// reply, save its window handle. If multiple replies are received, take the
+// one with the prefered instance, if there is one. Keep a count of
+// WM_DDE_TERMINATEs we send so that we don't shut the window until we get
+// all of the responses for WM_DDE_TERMINATEs.
+
+
+INTERNAL_(void) CDdeObject::OnInitAck (LPDDE_CHANNEL pChannel, HWND hwndSvr)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::OnInitAck(%x,hwndSvr=%x)\n",this,hwndSvr));
+#ifdef _MAC
+#else
+ if (!IsWindow (hwndSvr))
+ {
+ Assert (0);
+ return;
+ }
+ if (pChannel->hwndSvr) { // if we already have a handle
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::OnInitAck(%x,hwndSvr=%x) Already have hwndSvr=%x\n",
+ this,
+ hwndSvr,
+ pChannel->hwndSvr));
+ // just take the very first one. Direct post is OK
+ MPostWM_DDE_TERMINATE(hwndSvr,pChannel->hwndCli);
+ // Expect an extra WM_DDE_TERMINATE
+ ++pChannel->iExtraTerms;
+ } else {
+ // this is the server we want
+ pChannel->hwndSvr = hwndSvr;
+ pChannel->iExtraTerms = NULL;
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::OnInitAck(%x,hwndSvr=%x) Established Connection\n",
+ this,
+ hwndSvr,
+ pChannel->hwndSvr));
+ }
+#endif _MAC
+}
+
+INTERNAL_(BOOL) CDdeObject::OnAck (LPDDE_CHANNEL pChannel, LONG lParam)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::OnAck(%x,lParam=%x)\n",this,lParam));
+
+ BOOL retval = TRUE;
+ ATOM aItem;
+ WORD wStatus;
+ HANDLE hData;
+
+ if( pChannel->iAwaitAck == AA_EXECUTE)
+ {
+ wStatus = GET_WM_DDE_EXECACK_STATUS( NULL, lParam );
+ hData = GET_WM_DDE_EXECACK_HDATA( NULL, lParam );
+ }
+ else
+ {
+ wStatus = GET_WM_DDE_ACK_STATUS( NULL, lParam );
+ aItem = GET_WM_DDE_ACK_ITEM( NULL, lParam );
+ }
+
+
+ // check for busy bit
+ if (wStatus & 0x4000)
+ {
+ // we got busy from the server.
+ pChannel->fRejected = TRUE;
+ // tell the wait loop that we got a busy ack
+ //CoSetAckState(pChannel->pCI , FALSE,TRUE, SERVERCALLEX_RETRYLATER);
+ intrDebugOut((DEB_ITRACE,"::OnAck(%x) Busy SetCallState(SERVERCALLEX_RETRYLATER)\n",this));
+ pChannel->SetCallState(SERVERCALLEX_RETRYLATER);
+ return TRUE;
+ }
+
+ // just reset the flag always
+ m_wTerminate = Terminate_None;
+
+ intrDebugOut((DEB_ITRACE,
+ "::OnAck(%x)aItem=%x(%ws) wStatus=\n",
+ this,
+ aItem,
+ wAtomName(aItem),
+ wStatus));
+
+ if (pChannel->iAwaitAck == AA_EXECUTE)
+ {
+ GlobalFree (hData);
+ pChannel->hCommands = NULL;
+ }
+ else
+ {
+ if (hData)
+ GlobalDeleteAtom ((ATOM)hData);
+ }
+
+
+ // even if the client got terminate we have to go thru this path.
+
+ if (pChannel->wTimer) {
+ KillTimer (pChannel->hwndCli, 1);
+ pChannel->wTimer = 0;
+ }
+
+
+ if (pChannel->iAwaitAck == AA_POKE)
+ // We have to free the data first. OnAck can trigger
+ // another Poke (like pokehostnames)
+ wFreePokeData (pChannel, (m_bOldSvr && m_aClass==aMSDraw));
+
+
+ if (!(wStatus & POSITIVE_ACK))
+ {
+ intrDebugOut((DEB_ITRACE,"::OnAck(%x) OnAck got an ack with fAck==FALSE.\n",this));
+
+ // A negative ack is OK when doing a temporary advise from
+ // IsFormatAvailable(). Also, apps don't seem to positively
+ // ack all unadvises.
+
+ // review: johannp : this is the case were have to inform the reply rejected call
+
+ retval = FALSE;
+ // we got the ack and can leave the wait loop
+ //CoSetAckState(pChannel->pCI, FALSE);
+
+ intrDebugOut((DEB_ITRACE,
+ "::OnAck(%x) ***_ NACK _*** SetCallState(ISHANDLED,RPC_E_DDE_NACK)\n",
+ this));
+
+ pChannel->SetCallState(SERVERCALLEX_ISHANDLED, RPC_E_DDE_NACK);
+
+ // MSDraw frees hOptions even on a NACK, despite official DDE rules.
+ if (pChannel->iAwaitAck == AA_ADVISE && m_clsid != CLSID_MSDraw)
+ GlobalFree (pChannel->hopt);
+ }
+ else
+ {
+ // we got the ack and can leave the wait loop
+ // CoSetAckState(pChannel->pCI, FALSE);
+ intrDebugOut((DEB_ITRACE,
+ "::OnAck(%x) POSITIVE_ACK SetCallState(SERVERCALLEX_ISHANDLED)\n",
+ this));
+ pChannel->SetCallState(SERVERCALLEX_ISHANDLED);
+ }
+
+ pChannel->hopt = NULL;
+ pChannel->iAwaitAck = NULL;
+ return retval;
+
+}
+
+
+
+
+
+INTERNAL_(void) CDdeObject::OnTimer (LPDDE_CHANNEL pChannel)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::OnTimer(%x)\n",this));
+ // Since there is only one timer for each client, just
+ // repost the message and delete the timer.
+#ifdef _MAC
+#else
+ KillTimer (pChannel->hwndCli, 1);
+ pChannel->wTimer = 0;
+
+ if (wPostMessageToServer(pChannel, pChannel->wMsg, pChannel->lParam,FALSE))
+ return ;
+
+ // Postmessage failed. We need to getback to the main stream of
+ // commands for the object.
+ OnAck (pChannel, pChannel->lParam);
+#endif _MAC
+}
+
+
+
+// Called when we get a WM_DDE_DATA message in reponse to
+// a DDE_REQUEST we sent to check if a format is available.
+//
+INTERNAL CDdeObject::OnDataAvailable
+ (LPDDE_CHANNEL pChannel,
+ HANDLE hDdeData,
+ ATOM aItem)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::OnDataAvailable(%x)\n",this));
+ CLIPFORMAT cf;
+ Assert (AA_REQUESTAVAILABLE == pChannel->iAwaitAck);
+ intrAssert( wIsValidAtom(aItem));
+
+ DDEDATA * pDdeData = (DDEDATA *) GlobalLock (hDdeData);
+ RetZS (pDdeData, E_OUTOFMEMORY);
+ if (!pDdeData->fAckReq && aItem)
+ {
+ GlobalDeleteAtom (aItem);
+ }
+ cf = pDdeData->cfFormat;
+ GlobalUnlock (hDdeData);
+ wFreeData (wHandleFromDdeData (hDdeData), cf);
+ return NOERROR;
+}
+
+
+
+// Called for WM_DDE_DATA message. If data is from an ADVISE-ON-CLOSE and this
+// is there are no more outstanding ADVISE-ON-CLOSE requests, close the
+// document and end the conversation.
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::OnData
+//
+// Synopsis: Called when a WM_DDE_DATA message is recieved. If the data
+// is from an ADVISE_ON_CLOSE, and there are no more
+// outstanding ADVISE_ON_CLOSE request, close the document
+// and end the conversation.
+//
+// Effects: The effects of this routine are complex.
+//
+// Wow! What else can be said. This routine does alot of stuff in response
+// to an incoming WM_DDE_DATA message. There are basically two flavors of
+// response here. First is when we were expecting to get this result,
+// in which case we know what we wanted to do with the data. Second is
+// when the data just arrives, but we didn't expect it. These cases could
+// indicate that the server is shutting down.
+//
+//
+// Arguments: [pChannel] -- The DDE channel recieving the message
+// [hDdeData] -- Handle to the data
+// [aItem] -- Atom to the item
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-16-94 kevinro Restructured and commented
+//
+// Notes:
+//
+//
+// Be extra careful you change this routine.
+// This is especially neccesary if you are going to exit early. The
+// way that hDdeData is free'd or kept should be understood before
+// changing.
+//
+//
+//----------------------------------------------------------------------------
+INTERNAL CDdeObject::OnData
+ (LPDDE_CHANNEL pChannel,
+ HANDLE hDdeData,
+ ATOM aItem)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::OnData(%x,pChannel=%x,hDdeData=%x,aItem=%x(%s)iAwaitAck=%x\n",
+ this,
+ pChannel,
+ hDdeData,
+ aItem,
+ wAtomNameA(aItem),
+ pChannel->iAwaitAck));
+#ifdef _MAC
+#else
+ DDEDATA * lpDdeData = NULL;
+ BOOL fAck = TRUE;
+ int iAdvOpt;
+ BOOL fCallBack;
+ HRESULT hresult = NOERROR;
+ BOOL fRequested = FALSE;
+
+ intrAssert(wIsValidAtom(aItem));
+
+ int iAwaitAck = pChannel->iAwaitAck;
+
+ //
+ // If we were waiting for this data, then we are sitting in the
+ // modal loop. Set the call state on the call control interface
+ // to indicate that a response was recieved. Pass NOERROR to indicate
+ // that there was success. If an error is determined later, then
+ // the state will be set a second time.
+ //
+
+ if ((AA_REQUEST == iAwaitAck) || (AA_REQUESTAVAILABLE == iAwaitAck))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OnData(%x) AA_REQUEST/AVAILABLE \n",
+ this));
+
+ //
+ // Regardless of the outcome of this call, we have recieved a
+ // response. Set the Awaiting Ack state to nothing.
+ //
+ pChannel->iAwaitAck = AA_NONE;
+
+ //
+ // Determine if this channels call data is valid
+ //
+
+ if (pChannel->pCD )
+ {
+ //CoSetAckState(pChannel->pCI, FALSE); // clear waiting flag
+ intrDebugOut((DEB_ITRACE,"::OnData(%x) SetCallState(SERVERCALLEX_ISHANDLED)\n",this));
+ pChannel->SetCallState(SERVERCALLEX_ISHANDLED);
+ }
+ }
+
+
+ //
+ // Check the string for aItem, looking for advise options. The variable
+ // iAdvOpt will be set to indicate what type of data we just got, such
+ // as ON_CHANGE, etc. If the option is invalid, then we won't know
+ // what to do with it.
+ //
+
+ if ((hresult=wScanItemOptions (aItem, (int *) &iAdvOpt)) != NOERROR)
+ {
+ intrAssert(!"Item found with unknown advise option\n");
+ LPARAM lp;
+ if(!wPostMessageToServer (pChannel,
+ WM_DDE_ACK,
+ lp = MAKE_DDE_LPARAM (WM_DDE_ACK,NEGATIVE_ACK, aItem),TRUE))
+ {
+ hresult = RPC_E_SERVER_DIED;
+
+ }
+
+ //
+ // Did we need to free hDdeData here? No, according to the DDE spec, if the
+ // receiever responds with a NACK, then the sender is responsible for
+ // freeing the data.
+ //
+ return hresult;
+ }
+
+ //
+ // If the server sent no data, there ain't much we can do about it.
+ //
+
+ if (hDdeData == NULL)
+ {
+ intrDebugOut((DEB_IERROR,
+ "::OnData(%x)hDdeData is NULL!\n",
+ this));
+
+ return(RPC_E_INVALID_PARAMETER);
+ }
+
+ //
+ // Lock the data into memory so we can use it. Be careful, the way
+ // this routine was written originally, there are places that free
+ // and realloc hDdeData. Specifically, the call to KeepData. Carefully
+ // evaluate each place where you are returning, to insure the memory
+ // isn't leaked. (if you have time, please restructure this routine
+ // so it is easier to understand.
+ //
+ if (!(lpDdeData = (DDEDATA FAR *) GlobalLock(hDdeData)))
+ {
+ intrDebugOut((DEB_IERROR,
+ "::OnData(%x)GlobalLock on lpDdeData failed\n",
+ this));
+ //
+ // BUGBUG: (KevinRo)Did we need to free hDdeData here? I think
+ // we should have if the fRelease flag was set. The old code
+ // didn't. Need to research this further (ie you figure it out!)
+ //
+ return ResultFromScode (E_OUTOFMEMORY);
+ }
+
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x) lpDdeData->cfFormat=%x\n",
+ this,
+ (UINT)lpDdeData->cfFormat));
+
+ //
+ // The server will set fAckReq if it wants a response.
+ // don't call HIC for call where not acknoewledge is requested
+ //
+ fAck = lpDdeData->fAckReq;
+
+ if (pChannel->bTerminating) {
+ intrDebugOut((INTR_DDE,"::OnData(%x) Got DDE_DATA in terminate sequence\n",this));
+ //
+ // BUGBUG: this is very dangerous since the pointer on the
+ // hDocWnd does not get deleted and a further will
+ // DDE message will GPF - we need to fix this!!!
+ //
+ GlobalUnlock (hDdeData);
+ GlobalFree (hDdeData);
+ goto exitRtn;
+ }
+
+ //
+ // (KevinRo) Found this comment:
+ //
+ // important that we post the acknowledge first. Otherwise the
+ // messages are not in sync.
+ //
+ // The above comment might be intended to mean that the acknowledge needs to be
+ // send now, because we may call one of the advise functions below, which in
+ // turn may send another message to the OLE 1.0 server. Therefore, we ACK now,
+ // so the messages to the OLE 1.0 server are in the correct order.
+ //
+ if (fAck)
+ {
+ LPARAM lp;
+ if(!wPostMessageToServer (pChannel,
+ WM_DDE_ACK,
+ lp=MAKE_DDE_LPARAM(WM_DDE_ACK,POSITIVE_ACK, aItem),TRUE))
+ {
+ return(RPC_E_SERVER_DIED);
+ }
+ }
+
+ //
+ // this call is now an async call and can not be rejected be HandleIncomingMessage
+ //
+
+ if ((AA_REQUESTAVAILABLE == pChannel->iAwaitAck) && (lpDdeData->fResponse))
+ {
+ //
+ // For some reasons, OnDataAvailable will be the one to delete this data.
+ // I don't understand it, but lets roll with it. (KevinRo)
+ //
+ GlobalUnlock (hDdeData);
+ return OnDataAvailable (pChannel, hDdeData, aItem);
+ }
+
+ //
+ // If the clipboard format is binary, and the topic is aStdDocName, then this
+ // OnData is a RENAME
+ //
+ if (lpDdeData->cfFormat == (short)g_cfBinary && aItem== aStdDocName)
+ {
+ // ON_RENAME
+ //
+ // The data should be the new name, in ANSI.
+ //
+ ChangeTopic ((LPSTR)lpDdeData->Value);
+ GlobalUnlock (hDdeData);
+ GlobalFree (hDdeData);
+ return(NOERROR);
+ }
+
+ //
+ // Based on iAdvOpt, determine if we can callback. This one is a little
+ // hard to understand. I don't either. CanCallBack appears to return
+ // true if the count is 0,1, or 3, but returns FALSE if its 2 or
+ // greater than 3. There are no comments in the old code as to why
+ // this is. I am leaving it, since it must have been put there for
+ // a reason. See CanCallBack in ddeworker.cxx for futher (ie no) details
+ //
+ switch (iAdvOpt)
+ {
+ case ON_SAVE:
+ fCallBack = CanCallBack(&m_iAdvSave);
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x)ON_SAVE m_iAdvSave=%x\n",
+ this,
+ m_iAdvSave));
+
+ break;
+ case ON_CLOSE:
+ fCallBack = CanCallBack(&m_iAdvClose);
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x)ON_CLOSE m_iAdvClose=%x\n",
+ this,
+ m_iAdvClose));
+ break;
+ case ON_CHANGE:
+ fCallBack = TRUE;
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x)ON_CHANGE m_iAdvClose=%x\n",
+ this,
+ m_iAdvClose));
+ break;
+ default:
+ intrAssert( !"Unknown iAdvOpt: Somethings really broke");
+ }
+
+ // Keep the data in a cache for a future GetData call
+ // which may be triggered a few lines later by the
+ // SendOnDataChange().
+
+ fRequested = lpDdeData->fResponse;
+
+
+ // The call to KeepData will change hDdeData and
+ // invalidate lpDdeData. Check out KeepData for details. The net
+ // result is that hDdeData is no longer valid
+
+ GlobalUnlock (hDdeData);
+ lpDdeData=NULL;
+
+ hresult = KeepData (pChannel, hDdeData);
+
+ //
+ // This is unpleasant, but if KeepData fails, we need to
+ // call SetCallState again, resetting the error code. This
+ // code is such a mess that rearranging it to do
+ // it in a rational way is going to be too much work given
+ // the amount of time I have until shipping.
+ //
+ // If you have time, please simplify this code. Thanks
+ //
+ if (hresult != NOERROR)
+ {
+ //
+ // At this point, hDdeData has been unlocked, and deleted by
+ // the KeepData routine. Therefore, the return here doesn't
+ // need to be concerned with cleaning up after hDdeData
+ //
+ intrDebugOut((DEB_ITRACE,
+ "::OnData(%x) KeepData failed %x\n",
+ this,
+ hresult));
+ //
+ // Reset the error code on the call control
+ //
+ if ((AA_REQUEST == iAwaitAck) || (AA_REQUESTAVAILABLE == iAwaitAck))
+ {
+ if (pChannel->pCD )
+ {
+ pChannel->SetCallState(SERVERCALLEX_ISHANDLED, hresult);
+ }
+ }
+ goto exitRtn;
+ }
+
+ if (fRequested)
+ {
+ // We REQUESTed the data. So, we are no longer waiting.
+ // Do NOT call SendOnDataChange because the data hasn't
+ // really changed again, we just requested it to satisfy
+ // a call to GetData, which was probably called by the
+ // real SendOnDataChange.
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x) fRequested DATA\n",
+ this));
+
+ iAwaitAck = NULL;
+ hresult = NOERROR;
+ goto exitRtn;
+
+ }
+
+ //
+ // Now we have decided this is data we had not asked for. This makes
+ // it a change/close/saved notificiation.
+ //
+ intrDebugOut((INTR_DDE,"::OnData(%x) Non requested DATA\n",this));
+ pChannel->AddReference();
+ if (fCallBack && iAdvOpt != ON_CHANGE)
+ {
+ // ON_CHANGE will be handled by OleCallback, below
+
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x)Dispatching SendOnDataChange\n",
+ this));
+
+
+ //
+ // There are a couple of things to note about the following. First,
+ // the iid of the call doesn't matter. Since OLE 1.0 servers don't
+ // do nested calls, the original LID (Logical ID) can be any random
+ // value. Therefore, we don't initalize it.
+ //
+ // According to JohannP, the calltype of these calls is supposed
+ // to be CALLTYPE_SYNC. I don't fully understand why they are.
+ // I am taking is decision on faith.
+ //
+ // Using the new call control interfaces, we do the following.
+ //
+
+ DDEDISPATCHDATA ddedispdata;
+ DISPATCHDATA dispatchdata;
+ DWORD dwFault;
+
+ IUnknown *pUnk = m_pDataAdvHolder;
+
+ //
+ // We are about to call method #6 in the IDataAdviseHolder interface,
+ // which is SendOnDataChange
+ //
+
+ RPCOLEMESSAGE rpcMsg;
+ RPC_SERVER_INTERFACE RpcInterfaceInfo;
+ rpcMsg.reserved2[1] = &RpcInterfaceInfo;
+
+ *MSG_TO_IIDPTR(&rpcMsg) = IID_IDataAdviseHolder;
+
+
+ rpcMsg.Buffer = &dispatchdata;
+ rpcMsg.iMethod = 6;
+
+ dispatchdata.scode = S_OK;
+ dispatchdata.pData = (LPVOID) &ddedispdata;
+
+ ddedispdata.pCDdeObject = this;
+ ddedispdata.wDispFunc = DDE_DISP_SENDONDATACHANGE;
+ ddedispdata.iArg = iAdvOpt;
+
+ // package as RPCMESSAGE and call STAInvoke
+ IRpcStubBuffer * pStub = &m_RpcStubBuffer;
+ hresult = STAInvoke(&rpcMsg, CALLCAT_SYNCHRONOUS, pStub, pChannel, NULL, &dwFault );
+ }
+ if (fCallBack )
+ {
+ // in 1.0 ON_CLOSE comes with data
+ if (iAdvOpt==ON_CLOSE)
+ {
+
+ intrDebugOut((INTR_DDE,
+ "::OnData(%x) iAdvOpt == ON_CLOSE, send ON_SAVE\n",
+ this));
+
+ m_fGotCloseData = TRUE;
+
+ hresult = OleCallBack(ON_SAVE,pChannel);
+ if (hresult != NOERROR)
+ {
+ goto errRel;
+ }
+
+ //ErrRtnH (DdeHandleIncomingCall(pChannel->hwndSvr, CALLTYPE_TOPLEVEL) );
+ //ErrRtnH (OleCallBack (ON_SAVE));
+ }
+
+ // check if app can handle this call
+ // we do not need to call HIC for SendOnClose
+
+ hresult = OleCallBack (iAdvOpt,pChannel);
+ }
+
+errRel:
+ // Don't use pChannel after this. It can get deleted. (srinik)
+ if (pChannel->ReleaseReference() == 0)
+ {
+ m_pDocChannel = NULL;
+ }
+
+exitRtn:
+ if (!fAck && aItem)
+ {
+ GlobalDeleteAtom (aItem);
+ }
+ return hresult;
+#endif _MAC
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::OleCallBack
+//
+// Synopsis: Send all the right notifications whan a Save or Close happens.
+//
+// Effects: OleCallBack is a double duty function. It is called in two
+// different cases.
+//
+// First, is to setup the callback, and call HandleIncomingCall.
+// Second is from DispatchCall() in the CDdeChannelControl.
+//
+// The reason for doing it this way is we localize the setup
+// and processing of these calls to one routine. Therefore,
+// we can go to one spot in the code to find all of the call
+// back information.
+//
+// Arguments: [iAdvOpt] -- Which Advise operation to perform
+// [pChannel] -- Which channel is being called back
+//
+// Requires: pChannel == NULL, and the AdviseHolders are called.
+// pChannel != NULL, and the call is setup, and HandleIncomingCall
+// is setup.
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-23-94 kevinro Created
+//
+// Notes:
+//
+// WARNING: This code sucks completely. One of the major problems you need
+// to know about is that the CDdeObject may go away as part of the normal
+// processing of some of the below. Be very careful about any processing
+// that might occur after an ON_CLOSE
+//
+//----------------------------------------------------------------------------
+INTERNAL CDdeObject::OleCallBack (int iAdvOpt, LPDDE_CHANNEL pChannel)
+{
+ HRESULT hresult = NOERROR;
+ DDEDISPATCHDATA ddedispdata;
+ DISPATCHDATA dispatchdata;
+ RPCOLEMESSAGE rpcMsg;
+ IUnknown *pUnk;
+
+ RPC_SERVER_INTERFACE RpcInterfaceInfo;
+ rpcMsg.reserved2[1] = &RpcInterfaceInfo;
+
+ //
+ // If the channel isn't NULL, then setup the data structures for calling
+ // off to the call control.
+ //
+ if (pChannel != NULL)
+ {
+ //
+ // Only do this work if we really have to
+ //
+
+ dispatchdata.scode = S_OK;
+ dispatchdata.pData = (LPVOID) &ddedispdata;
+
+ ddedispdata.pCDdeObject = this;
+ ddedispdata.wDispFunc = DDE_DISP_OLECALLBACK;
+ ddedispdata.iArg = iAdvOpt;
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::OleCallBack(%x,iAdvOpt=%x,pChannel=%x)\n",
+ this,
+ iAdvOpt,
+ pChannel));
+
+ //
+ // Determine what needs to be done, based on the iAdvOpt. This should be
+ // one of the handled cases below, otherwise its an error.
+ //
+ switch (iAdvOpt)
+ {
+ case ON_CLOSE:
+ if (pChannel != NULL)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OleCallBack(%x) setup for ON_CLOSE\n",
+ this));
+
+ pUnk = m_pOleAdvHolder;
+
+ *MSG_TO_IIDPTR(&rpcMsg) = IID_IOleAdviseHolder;
+ // IOleAdviseHolder::SendOnClose is method 8
+ rpcMsg.iMethod = 8;
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE,"::OleCallBack(%x) ON_CLOSE\n",this));
+ DeclareVisibility (FALSE);
+ RetZ (!m_fDidSendOnClose); // This SendOnClose should happen 1st
+ // Don't let OnTerminate() do it too
+ hresult = SendOnClose();
+
+ //
+ // WARNING WARNING WARNING: SendOnClose() may have caused the
+ // destruction of this CDdeObject. Touch nothing on the way
+ // out. Actually, if you have time, which I currently don't,
+ // see what you can do with reference counting tricks to
+ // insure this object doesn't die during this callback.
+ // Its a tricky problem, and we are shipping in 2 weeks.
+ // (KevinRo 8/6/94)
+ //
+ }
+ break;
+
+ case ON_SAVE:
+ if (pChannel != NULL)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OleCallBack(%x) setup for ON_SAVE\n",
+ this));
+
+ if (m_pOleClientSite == NULL)
+ {
+ pUnk = m_pOleClientSite;
+ *MSG_TO_IIDPTR(&rpcMsg) = IID_IOleClientSite;
+ // IOleClientSite::SaveObject method 7
+ rpcMsg.iMethod = 7;
+ }
+ else
+ {
+ // Going to call the IOleAdviseHolder
+
+ pUnk = m_pOleAdvHolder;
+ *MSG_TO_IIDPTR(&rpcMsg) = IID_IOleAdviseHolder;
+ // IOleAdviseHolder::SendOnSave method 7
+ // (Yes, same ordinal as above, I double checked)
+ rpcMsg.iMethod = 7;
+ }
+ }
+ else
+ {
+
+ intrDebugOut((DEB_ITRACE,"::OleCallBack(%x) ON_SAVE\n",this));
+ if (m_pOleClientSite)
+ {
+ // We just got data from the server, so we don't want to
+ // ask him for it again when the container does a save.
+ m_fUpdateOnSave = FALSE;
+
+ // Harvard Graphics Access Violates if SaveObject is called on the ClientSite from
+ // within OleCreateFromData.
+ __try
+ {
+ m_pOleClientSite->SaveObject();
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ intrDebugOut((DEB_IWARN ,"Warning: Exception in SaveObject\n"));
+ }
+
+ // SendOnSave is called in PS::SaveCompleted
+ m_fUpdateOnSave = TRUE;
+ }
+ else
+ {
+ // Link case
+ RetZS (m_pOleAdvHolder, E_OUTOFMEMORY);
+ m_pOleAdvHolder->SendOnSave();
+ }
+ }
+ break;
+
+ case ON_CHANGE:
+ if (pChannel != NULL)
+ {
+ // Going to call the IDataAdviseHolder
+
+ pUnk = m_pDataAdvHolder;
+ *MSG_TO_IIDPTR(&rpcMsg) = IID_IDataAdviseHolder;
+ // IDataAdviseHolder::SendOnDataChange method 6
+ rpcMsg.iMethod = 6;
+
+ }
+ else
+ {
+ RetZS (m_pDataAdvHolder, E_OUTOFMEMORY);
+ intrDebugOut((DEB_ITRACE,"::OleCallBack(%x) ON_CHANGE\n",this));
+ hresult = SendOnDataChange (ON_CHANGE);
+ }
+ break;
+
+ default:
+
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::OleCallBack(%x,iAdvOpt=%x) UNKNOWN iAdvOpt\n",
+ this,
+ iAdvOpt));
+ intrAssert(!"Unexpected iAdvOpt");
+ return(E_UNEXPECTED);
+ break;
+ }
+
+ //
+ // There are a couple of things to note about the following. First,
+ // the iid of the call doesn't matter. Since OLE 1.0 servers don't
+ // do nested calls, the original LID (Logical ID) can be any random
+ // value. Therefore, we don't initalize it.
+ //
+ // According to JohannP, the calltype of these calls is supposed
+ // to be CALLTYPE_SYNCHRONOUS. I don't fully understand why they are.
+ // I am taking is decision on faith.
+ //
+ //
+ // Its possible that during the handling of this call that this object
+ // will get deleted. This is a pain in the butt. This means that anything
+ // used after this call MUST be protected. lpCallCont happens to be one of
+ // these. We have been having problems with lpCallCont being released as
+ // part of the object cleanup. The call control code will access member
+ // variables on its way out of the HandleDispatch. We need to bracket
+ // the call below so this doesn't happen.
+ //
+ if (pChannel != NULL)
+ {
+ // dont have to worry about call control going away.
+ // package as RPCMESSAGE and call STAInvoke
+
+ DWORD dwFault;
+
+ rpcMsg.Buffer = &dispatchdata;
+
+ // BUGBUG: does it matter if we package up the pUnk?
+ IRpcStubBuffer * pStub = &m_RpcStubBuffer;
+ hresult = STAInvoke(&rpcMsg, CALLCAT_SYNCHRONOUS, pStub, pChannel, NULL, &dwFault);
+ }
+
+ return hresult;
+}
+
+
+INTERNAL CDdeObject::SendOnDataChange
+ (int iAdvOpt)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::SendOnDataChange(%x)\n",this));
+ HRESULT hresult;
+ RetZS (m_pDataAdvHolder, E_OUTOFMEMORY);
+ m_fDoingSendOnDataChange = TRUE;
+ hresult = m_pDataAdvHolder->SendOnDataChange (&m_Data,
+ DVASPECT_CONTENT,
+ 0);
+ if (ON_CLOSE==iAdvOpt)
+ {
+ hresult = m_pDataAdvHolder->SendOnDataChange (&m_Data,
+ DVASPECT_CONTENT,
+ ADVF_DATAONSTOP);
+ }
+ m_fDoingSendOnDataChange = FALSE;
+ return hresult;
+}
+
+
+
+
+INTERNAL CDdeObject::SendOnClose
+ (void)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::SendOnClose(%x)\n",this));
+ RetZS (m_pOleAdvHolder, E_OUTOFMEMORY);
+ m_fDidSendOnClose = TRUE;
+ RetErr (m_pOleAdvHolder->SendOnClose() );
+ return NOERROR;
+}
+
+
+
+
+INTERNAL CDdeObject::OnTerminate
+ (LPDDE_CHANNEL pChannel,
+ HWND hwndPost)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::OnTerminate(%x,pChannel=%x,hwndPost=%x)\n",
+ this,
+ pChannel,
+ hwndPost));
+
+ //
+ // If the hwndPost and hwndSvr are different, then it is one of two
+ // cases. We could have recieved more than one Acknowlege during our
+ // initiate, in which case the count iExtraTerms would have been
+ // incremented, and this terminate is accounted for iExtraTerms.
+ //
+ // The other case is that we were terminated by a window that was
+ // NOT the window we were conversing with.
+ //
+ if (pChannel->hwndSvr != hwndPost)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OnTerminate(%x) Extra terms is 0x%x \n",
+ this,
+ pChannel->iExtraTerms));
+
+ //
+ // iExtraTerms shouldn't go below zero. If it does, something
+ // has gone wrong. We have been seeing some problems with the
+ // HWND mapping layer in the past. If the following condition
+ // ever trips, then it is possible that another mapping
+ // problem has been seen.
+ //
+#if DBG == 1
+ if((pChannel->iExtraTerms == 0 ) &&
+ (((DWORD)pChannel->hwndSvr) & (0xffff)) == ((DWORD)hwndPost & (0xffff)))
+ {
+ intrDebugOut((DEB_ERROR,
+ "*** OnTerminate expected hwnd=%x got hwnd=%x ***\n",
+ pChannel->hwndSvr,hwndPost));
+
+ intrDebugOut((DEB_ERROR,
+ "\n*** Call KevinRo or SanfordS ***\n\n",
+ pChannel->hwndSvr,hwndPost));
+
+ }
+#endif
+ --pChannel->iExtraTerms;
+
+ intrAssert((pChannel->iExtraTerms >= 0) && "Call KevinRo or SanfordS");
+ return NOERROR;
+ }
+ if (m_wTerminate == Terminate_Detect) {
+ // we should only detect the call but not execute the code
+ // set the state to Received
+ m_wTerminate = Terminate_Received;
+ pChannel->iAwaitAck = NULL;
+ // Since Excel incorrectly did not send an ACK, we need to
+ // delete the handle in the DDE message ourselves.
+ if (pChannel->hCommands)
+ {
+ GlobalFree (pChannel->hCommands);
+ pChannel->hCommands = NULL;
+ }
+ //CoSetAckState(pChannel->pCI, FALSE);
+ intrDebugOut((DEB_ITRACE,
+ "::OnTerminate(%x) Terminate_Detect SERVERCALLEX_ISHANDLED\n",
+ this));
+ pChannel->SetCallState(SERVERCALLEX_ISHANDLED, RPC_E_SERVER_DIED);
+ return NOERROR;
+ }
+
+ RetZ (pChannel);
+ ChkDR (this);
+
+ if (!pChannel->bTerminating)
+ {
+ // Got unprompted terminate
+ BOOL bBusy;
+
+ // Necessary safety bracket
+ m_pUnkOuter->AddRef();
+
+ bBusy = wClearWaitState (pChannel);
+
+ if (pChannel->iAwaitAck || bBusy)
+ {
+ pChannel->iAwaitAck = NULL;
+ //CoSetAckState(pChannel->pCI, FALSE);
+ intrDebugOut((DEB_ITRACE,"::OnTerminate(%x) !bTerminating SERVERCALLEX_ISHANDLED,RPC_E_DDE_UNEXP_MSG\n",this));
+ pChannel->SetCallState(SERVERCALLEX_ISHANDLED, RPC_E_DDE_UNEXP_MSG);
+ }
+
+ if (!m_fDidSendOnClose)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OnTerminate(%x) SendOnClose from terminate\n",
+ this));
+
+ BOOL f= m_fNoStdCloseDoc;
+ m_fNoStdCloseDoc = TRUE;
+
+ DeclareVisibility (FALSE);
+ SendOnClose();
+
+ m_fNoStdCloseDoc = f;
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OnTerminate(%x) Already did SendOnClose\n",
+ this));
+ Puts ("Already did SendOnClose\n");
+ }
+ intrDebugOut((DEB_ITRACE,
+ "::OnTerminate(%x) Posting DDE_TERMINATE as reply\n",
+ this));
+
+ wPostMessageToServer (pChannel, WM_DDE_TERMINATE, NULL,FALSE);
+
+ // The terminate that we are sending itself is a reply, so we don't
+ // need to do WaitForReply.
+ DeleteChannel (pChannel);
+
+ // Necessary safety bracket
+ m_pUnkOuter->Release();
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::OnTerminate(%x) Received DDE_TERMINATE in reply\n",
+ this));
+
+ // We sent the WM_DDE_TERMINATE and we got the acknowledge for it
+ pChannel->hwndSvr = NULL;
+ pChannel->iExtraTerms = NULL;
+ pChannel->iAwaitAck = NULL;
+ //CoSetAckState(pChannel->pCI, FALSE);
+ intrDebugOut((DEB_ITRACE,"::OnTerminate(%x) bTerminating SERVERCALLEX_ISHANDLED\n",this));
+ pChannel->SetCallState(SERVERCALLEX_ISHANDLED);
+ }
+ Puts ("OnTerminate() done.\n");
+ return NOERROR;
+}
+
+
+
+
+INTERNAL_(BOOL) CDdeObject::AllocDdeChannel
+ (LPDDE_CHANNEL * lplpChannel, BOOL fSysWndProc)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::AllocDdeChannel(%x,fSysWndClass=%x)\n",
+ this,
+ fSysWndProc));
+
+ //
+ // Now try to allocate a channel
+ //
+
+ if (!(*lplpChannel = (LPDDE_CHANNEL) new DDE_CHANNEL ))
+ {
+ //
+ // This failed
+ //
+ intrAssert(*lplpChannel != NULL);
+ return FALSE;
+ }
+
+ (*lplpChannel)->m_cRefs = 1;
+ (*lplpChannel)->hwndSvr = NULL;
+ (*lplpChannel)->bTerminating = FALSE;
+ (*lplpChannel)->wTimer = NULL;
+ (*lplpChannel)->hDdePoke = NULL;
+ (*lplpChannel)->hCommands = NULL;
+ (*lplpChannel)->hopt = NULL;
+ (*lplpChannel)->dwStartTickCount= 0;
+ (*lplpChannel)->msgFirst = 0;
+ (*lplpChannel)->msgLast = 0;
+ (*lplpChannel)->fRejected = FALSE;
+ (*lplpChannel)->wChannelDeleted = 0;
+ //(*lplpChannel)->pCI = NULL;
+ (*lplpChannel)->pCD = NULL;
+
+ if (!((*lplpChannel)->hwndCli = DdeCreateWindowEx(0,
+ gOleWindowClass,
+ L"DDE Channel",
+ WS_CHILD,
+ 0,0,0,0,
+ (HWND)TLSGetDdeClientWindow(),
+ NULL,
+ hinstSO,
+ NULL)))
+ {
+ intrAssert (!"Could not create AllocDdeChannel window");
+
+ //
+ // DeleteChannel will give back the CallControl
+ //
+
+ DeleteChannel(*lplpChannel);
+ *lplpChannel = NULL;
+ return FALSE;
+ }
+
+ // set the appropriate window procedure
+ if (fSysWndProc)
+ {
+ SetWindowLong ((*lplpChannel)->hwndCli, GWL_WNDPROC, (LONG)SysWndProc);
+ }
+ else
+ {
+ SetWindowLong ((*lplpChannel)->hwndCli, GWL_WNDPROC, (LONG)ClientDocWndProc);
+ }
+
+ SetWindowLong ((*lplpChannel)->hwndCli, 0, (LONG) this);
+ return TRUE;
+}
+
+
+
+INTERNAL_(BOOL) CDdeObject::InitSysConv()
+{
+ DWORD dwResult;
+ intrDebugOut((DEB_ITRACE,"CDdeObject::InitSysConv(%x)\n",this));
+
+ dwResult = wInitiate (m_pSysChannel, m_aClass, aOLE);
+ if (!dwResult)
+ {
+ intrDebugOut((DEB_ITRACE,"\t::InitSysConv(%x) Try aSysTopic\n",this));
+ dwResult = wInitiate (m_pSysChannel, m_aClass, aSysTopic);
+ }
+
+ if (!dwResult)
+ {
+ intrDebugOut((DEB_ITRACE,"\t::InitSysConv(%x) is failing\n",this));
+ }
+ return(dwResult);
+}
+
+
+
+INTERNAL_(void) CDdeObject::SetTopic(ATOM aTopic)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::SetTopic(%x)\n",this));
+ intrAssert(wIsValidAtom(aTopic));
+ if (m_aTopic)
+ GlobalDeleteAtom (m_aTopic);
+
+ m_aTopic = aTopic;
+}
+
+
+
+INTERNAL CDdeObject::TermConv
+ (LPDDE_CHANNEL pChannel,
+ BOOL fWait) // Default==TRUE. FALSE only in ProxyManager::Disconnect
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::TermConv(%x,pChannel=%x)\n",
+ this,
+ pChannel));
+
+ HRESULT hres;
+ if (!pChannel)
+ {
+ return NOERROR;
+ }
+
+ pChannel->bTerminating = TRUE;
+
+ hres = SendMsgAndWaitForReply(pChannel,
+ AA_TERMINATE,
+ WM_DDE_TERMINATE,
+ 0,
+ FALSE,
+ /*fStdCloseDoc*/FALSE,
+ /*fDetectTerminate*/ FALSE,
+ fWait);
+ if (pChannel==m_pDocChannel)
+ {
+ DeclareVisibility (FALSE);
+ if (!m_fDidSendOnClose)
+ {
+ SendOnClose();
+ }
+ }
+
+ DeleteChannel (pChannel);
+ intrDebugOut((DEB_ITRACE,"::TermConv(%x) returns %x\n",this,hres));
+ return hres;
+}
+
+
+
+
+INTERNAL_(void) CDdeObject::DeleteChannel (LPDDE_CHANNEL pChannel)
+{
+ BOOL fDocChannel = FALSE;
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::DeleteChannel(%x,pChannel=%x)\n",
+ this,
+ pChannel));
+
+ if (pChannel == NULL)
+ {
+ return;
+ }
+
+ if (pChannel == m_pDocChannel)
+ fDocChannel = TRUE;
+
+
+
+ // delete any data if we were in busy mode.
+ wClearWaitState (pChannel);
+
+ if (pChannel == m_pDocChannel)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DeleteChannel(%x)Clean up pDocChannel\n",
+ this));
+
+ // Cleanup per-conversation information
+ m_fDidSendOnClose = FALSE;
+ m_fDidStdCloseDoc = FALSE;
+ m_ConnectionTable.Erase();
+ m_iAdvSave = 0;
+ m_iAdvClose= 0;
+ m_fWasEverVisible = FALSE;
+ m_fGotCloseData = FALSE;
+ if (m_ptd)
+ {
+ delete m_ptd;
+ m_ptd = NULL;
+ }
+ if (m_pstg)
+ {
+ m_pstg->Release();
+ m_pstg = NULL;
+ }
+ if (m_pDataAdvHolder)
+ {
+ Verify (0==m_pDataAdvHolder->Release());
+ }
+ CreateDataAdviseHolder (&m_pDataAdvHolder);
+ if (m_pOleAdvHolder)
+ {
+ m_pOleAdvHolder->Release(); // may not return 0 if we are
+ // in a SendOnClose
+ }
+ CreateOleAdviseHolder (&m_pOleAdvHolder);
+ }
+
+ if (pChannel->hwndCli)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DeleteChannel(%x)Destroy hwndCli(%x)\n",
+ this,
+ pChannel->hwndCli));
+
+ Assert (IsWindow (pChannel->hwndCli));
+ Assert (this==(CDdeObject *)GetWindowLong (pChannel->hwndCli, 0));
+ Verify (SSDestroyWindow (pChannel->hwndCli));
+ }
+
+ if (pChannel == m_pDocChannel)
+ {
+ m_pDocChannel = NULL;
+ }
+ else
+ {
+ intrAssert(pChannel == m_pSysChannel);
+ m_pSysChannel = NULL;
+ }
+
+
+ // Channel will be deleted in the modallp.cpp
+ // if flag is on.
+
+ if (pChannel->wChannelDeleted == Channel_InModalloop)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::DeleteChannel(%x) Channel(%x) in Modal Loop\n",
+ this,pChannel));
+
+ pChannel->wChannelDeleted = Channel_DeleteNow;
+ }
+ else
+ {
+ if (pChannel->ReleaseReference() == 0)
+ pChannel = NULL;
+ }
+
+ if (fDocChannel)
+ m_pDocChannel = pChannel;
+}
+
+const WCHAR EMB_STR[]= OLESTR(" -Embedding ") ;
+
+INTERNAL_(BOOL) CDdeObject::LaunchApp (void)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::LaunchApp(%x)\n",this));
+
+ STARTUPINFO startInfo;
+ PROCESS_INFORMATION procInfo;
+ BOOL fProcStarted;
+ WCHAR cmdline[MAX_PATH + sizeof(EMB_STR)];
+ WCHAR exeName[MAX_PATH + sizeof(cmdline)];
+ //
+ // Init all fields of startInfo to zero
+ //
+ memset((void *)&startInfo,0,sizeof(startInfo));
+
+ //
+ // The normal startup is set here.
+ //
+ startInfo.wShowWindow = SW_NORMAL;
+ startInfo.dwFlags = STARTF_USESHOWWINDOW;
+
+ m_fDidLaunchApp = FALSE;
+
+
+ DWORD dw;
+
+ //
+ // Do our best to find the path
+ //
+ intrAssert(wIsValidAtom(m_aExeName));
+
+ if (m_aExeName == 0)
+ {
+ //
+ // There is no exe name to execute. Can't start it.
+ //
+ return(FALSE);
+ }
+
+ dw = SearchPath(NULL,wAtomName(m_aExeName),NULL,MAX_PATH,exeName, NULL);
+
+ if ((dw == 0) || (dw > MAX_PATH))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::LaunchApp(%x) SearchPath failed. Do Default",this));
+ //
+ // SearchPath failed. Use the default
+ //
+ GlobalGetAtomName (m_aExeName, exeName, MAX_PATH);
+ }
+
+ memcpy(cmdline, EMB_STR,sizeof(EMB_STR));
+
+ if (m_ulObjType == OT_LINK)
+ {
+ intrAssert(wIsValidAtom(m_aTopic));
+ // File name
+ Assert (wAtomName (m_aTopic));
+
+ lstrcatW (cmdline, wAtomName (m_aTopic));
+ }
+
+ if (m_clsid == CLSID_ExcelWorksheet // Stupid apps that show themselves
+ || m_clsid == CLSID_ExcelMacrosheet // when they're not supposed to
+ || m_clsid == CLSID_ExcelChart
+ || m_clsid == CLSID_PBrush)
+ {
+ startInfo.wShowWindow = SW_SHOWMINNOACTIVE;
+ }
+
+ //
+ // According to the spec, the most robust way to start the app is to
+ // only use a cmdline that consists of the exe name, followed by the
+ // command line arguments.
+ //
+
+ lstrcatW(exeName,cmdline);
+
+ Assert((lstrlenW(exeName)+1) < sizeof(exeName));
+
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::LaunchApp(%x) Starting '%ws' \n",
+ this,
+ exeName));
+
+ if (IsWOWThread() && IsWOWThreadCallable())
+ {
+ HRESULT hr;
+
+ hr = g_pOleThunkWOW->WinExec16(exeName, startInfo.wShowWindow);
+
+ fProcStarted = SUCCEEDED(hr);
+
+#if DBG==1
+ if (!fProcStarted)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::LaunchApp(%x) in Wow FAILED(%x) TO START %ws \n",
+ this,
+ hr,
+ exeName));
+ }
+#endif
+ }
+ else
+ {
+ fProcStarted = CreateProcess(NULL,
+ exeName,
+ NULL,
+ NULL,
+ FALSE,
+ 0,
+ NULL,
+ NULL,
+ &startInfo,
+ &procInfo);
+ if (fProcStarted)
+ {
+ //
+ // Let's give the server a chance to register itself. On NT,
+ // CreateProcess gets the other process going, but returns
+ // to let it run asynchronously. This isn't good, since we
+ // need some way of knowing when it has started, so we can
+ // send the DDE_INITIATES 'after' they create their DDE
+ // window.
+ //
+ // Maximum timeout we want here shall be set at 30 seconds.
+ // This should give enough time for even a 16bit WOW app to
+ // start. This number was picked by trial and error. Normal
+ // apps that go into an InputIdle state will return as soon
+ // as they are ready. Therefore, we normally won't wait
+ // the full duration.
+ //
+
+ ULONG ulTimeoutDuration = 30000L;
+
+ //
+ // Now modify this start time to handle classes
+ // that have known problems. This list includes:
+ //
+
+ switch(WaitForInputIdle(procInfo.hProcess, ulTimeoutDuration))
+ {
+ case 0:
+ intrDebugOut((DEB_ITRACE,
+ "::LaunchApp, %ws started\n",
+ exeName));
+ break;
+ case WAIT_TIMEOUT:
+ intrDebugOut((DEB_ITRACE,
+ "::LaunchApp, %ws wait timeout at %u (dec) ms. Go Anyway\n",
+ exeName,
+ ulTimeoutDuration));
+ break;
+ default:
+ intrDebugOut((DEB_ITRACE,
+ "::LaunchApp, %ws unknown condition (%x)\n",
+ exeName,
+ GetLastError()));
+ }
+ //
+ // We are already done with the Process and Thread handles
+ //
+ CloseHandle(procInfo.hProcess);
+ CloseHandle(procInfo.hThread);
+ }
+ else
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::LaunchApp(%x) FAILED(%x) TO START %ws \n",
+ this,
+ GetLastError(),
+ exeName));
+ }
+ }
+
+ if (fProcStarted)
+ {
+ // If we ran the server, it should not be visible yet.
+ DeclareVisibility (FALSE);
+ m_fDidLaunchApp = TRUE;
+ }
+
+ return fProcStarted;
+}
+
+
+INTERNAL CDdeObject::MaybeUnlaunchApp (void)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::MaybeUnlaunchApp(%x)\n",this));
+ if (m_fDidLaunchApp
+ && !m_fDidGetObject
+ && (m_clsid == CLSID_ExcelWorksheet
+ || m_clsid == CLSID_ExcelMacrosheet
+ || m_clsid == CLSID_ExcelChart))
+ {
+ return UnlaunchApp();
+ }
+ return NOERROR;
+}
+
+
+
+
+INTERNAL CDdeObject::UnlaunchApp (void)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::UnlaunchApp(%x)\n",this));
+ HANDLE hCommands;
+ HRESULT hresult = NOERROR;
+ RetZS (AllocDdeChannel (&m_pSysChannel, TRUE), E_OUTOFMEMORY);
+ ErrZS (InitSysConv(), E_UNEXPECTED);
+ ErrRtnH (PostSysCommand (m_pSysChannel,(LPSTR) &achStdExit, /*bStdNew*/FALSE,
+ /*fWait*/FALSE));
+ hCommands = m_pSysChannel->hCommands;
+ hresult = TermConv (m_pSysChannel);
+
+ // Since Excel incorrectly did not send an ACK, we need to
+ // delete the handle ("[StdExit]") in the DDE message ourselves.
+ if (hCommands)
+ GlobalFree (hCommands);
+
+ return hresult;
+
+ errRtn:
+ DeleteChannel (m_pSysChannel);
+ return hresult;
+}
+
+
+
+
+INTERNAL CDdeObject::Execute
+ (LPDDE_CHANNEL pChannel,
+ HANDLE hdata,
+ BOOL fStdCloseDoc,
+ BOOL fWait,
+ BOOL fDetectTerminate)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::Execute(%x,hdata=%x)\n",this,hdata));
+
+ LPARAM lp=MAKE_DDE_LPARAM(WM_DDE_EXECUTE,0, hdata);
+
+ HRESULT hr = SendMsgAndWaitForReply (pChannel,
+ AA_EXECUTE,
+ WM_DDE_EXECUTE,
+ lp,
+ TRUE,
+ fStdCloseDoc,
+ fDetectTerminate,
+ fWait);
+ if (hr == DDE_CHANNEL_DELETED)
+ {
+ // the channel was deleted already so dont access it!
+ return S_OK;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (fStdCloseDoc)
+ {
+ // Prepare to free the handle if Excel does not send an Ack
+ pChannel->hCommands = hdata;
+ }
+ return hr;
+ }
+
+ GlobalFree (hdata);
+ return ReportResult(0, RPC_E_DDE_POST, 0, 0);
+}
+
+
+
+
+INTERNAL_(HRESULT) CDdeObject::AdviseOn (CLIPFORMAT cfFormat, int iAdvOn)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::AdviseOn(%x,cfFormat=%x,iAdvOn=%x)\n",
+ this,
+ cfFormat,
+ iAdvOn));
+
+ HANDLE hopt=NULL;
+ DDEADVISE * lpopt=NULL;
+ ATOM aItem=(ATOM)0;
+ HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0);
+
+ RetZ (m_pDocChannel);
+
+ if (NOERROR == m_ConnectionTable.Lookup (cfFormat, NULL))
+ {
+ // We already got a call to DataObject::Advise on this format.
+ intrDebugOut((DEB_ITRACE,
+ "::AdviseOn(%x) Advise had been done on cfFormat=%x\n",
+ this,
+ cfFormat));
+ return NOERROR;
+ }
+
+ UpdateAdviseCounts (cfFormat, iAdvOn, +1);
+
+ if (m_fDidSendOnClose)
+ {
+ intrDebugOut((DEB_ITRACE,"::AdviseOn(%x)Ignoring Advise because we are closing\n",this));
+ return NOERROR;
+ }
+
+ if (!(hopt = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, sizeof(DDEADVISE))))
+ {
+ intrDebugOut((DEB_ITRACE,"::AdviseOn(%x)GlobalAlloc returned NULL\n",this));
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+
+ if (!(lpopt = (DDEADVISE FAR *) GlobalLock (hopt)))
+ {
+ intrDebugOut((DEB_ITRACE,"::AdviseOn(%x)GlobalLock returned NULL\n",this));
+ GlobalFree (hopt);
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ lpopt->fAckReq = TRUE;
+ lpopt->fDeferUpd = FALSE;
+ lpopt->cfFormat = cfFormat;
+ m_pDocChannel->hopt = hopt;
+
+ if (iAdvOn == ON_RENAME)
+ {
+ aItem = wDupAtom (aStdDocName);
+ intrAssert(wIsValidAtom(aItem));
+ }
+ else
+ {
+ intrAssert(wIsValidAtom(m_aItem));
+ aItem = wExtendAtom (m_aItem, iAdvOn);
+ intrAssert(wIsValidAtom(aItem));
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "::AdviseOn(%x) lpopt->cfFormat = %x, aItem=%x (%ws)\n",
+ this,
+ lpopt->cfFormat,
+ aItem,
+ wAtomName(aItem)));
+
+ GlobalUnlock (hopt);
+
+ LPARAM lp=MAKE_DDE_LPARAM(WM_DDE_ADVISE,hopt,aItem);
+ hresult =SendMsgAndWaitForReply (m_pDocChannel,
+ AA_ADVISE,
+ WM_DDE_ADVISE,
+ lp,
+ TRUE);
+ if ( FAILED(hresult) )
+ {
+ intrDebugOut((DEB_ITRACE,"::AdviseOn(%x)wPostMessageToServer failed\n",this));
+ if (aItem)
+ GlobalDeleteAtom (aItem);
+ if (hopt)
+ GlobalFree (hopt);
+ hresult = (RPC_E_DDE_NACK == hresult) ? DV_E_CLIPFORMAT : hresult;
+ intrDebugOut((DEB_ITRACE,
+ "::AdviseOn(%x) errRet, AdviseRejected, returning %x\n",
+ this,hresult));
+ }
+
+ return hresult;
+}
+
+INTERNAL CDdeObject::UpdateAdviseCounts
+ (CLIPFORMAT cf,
+ int iAdvOn,
+ signed int cDelta)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::UpdateAdviseCounts(%x)\n",this));
+ if (cf==g_cfBinary)
+ return NOERROR;
+
+ // Update m_iAdv* flags
+ #define macro(Notif, NOTIF) \
+ if (iAdvOn == ON_##NOTIF) \
+ m_iAdv##Notif += cDelta; \
+ if (m_iAdv##Notif < 0) \
+ m_iAdv##Notif = 0; \
+ else if (m_iAdv##Notif > 2) \
+ m_iAdv##Notif = 2;
+
+ macro (Close, CLOSE)
+ macro (Save, SAVE)
+ macro (Change,CHANGE)
+ #undef macro
+
+ Assert (m_iAdvClose < 3 && m_iAdvSave < 3 && m_iAdvChange < 3);
+ Assert (m_iAdvClose >= 0 && m_iAdvSave >= 0 && m_iAdvChange >= 0);
+
+ if (cf == g_cfNative)
+ {
+ if (iAdvOn != ON_CHANGE)
+ m_fDidAdvNative = (cDelta > 0);
+ else
+ intrDebugOut((DEB_ITRACE,
+ "::UpdateAdviseCounts(%x)Asked advise on cfNative\n",
+ this));
+ }
+
+ return NOERROR;
+}
+
+
+
+
+INTERNAL CDdeObject::UnAdviseOn (CLIPFORMAT cfFormat, int iAdvOn)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::UnAdviseOn(%x,cfFormat=%x,iAdvOn=%x)\n",
+ this,cfFormat,iAdvOn));
+ HRESULT hr;
+ ATOM aItem= (ATOM)0;
+
+ RetZ (m_pDocChannel);
+ UpdateAdviseCounts (cfFormat, iAdvOn, -1);
+ if (m_fDidSendOnClose)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::UnAdviseOn(%x) Ignored because closing\n",
+ this));
+ return NOERROR;
+ }
+ if (wTerminateIsComing (m_pDocChannel))
+ {
+ // We already did a StdCloseDocument, so the server is not willing
+ // to do an unadvise even though the default hanlder asked us to.
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::UnAdviseOn(%x) Terminate coming\n",
+ this));
+ return NOERROR;
+ }
+
+ if (iAdvOn == ON_RENAME)
+ {
+ aItem = wDupAtom (aStdDocName);
+ intrAssert(wIsValidAtom(aItem));
+ }
+ else
+ {
+ intrAssert(wIsValidAtom(m_aItem));
+ aItem = wExtendAtom (m_aItem, iAdvOn);
+ intrAssert(wIsValidAtom(aItem));
+ }
+
+
+ // Wait For Reply
+ hr = SendMsgAndWaitForReply (m_pDocChannel,
+ AA_UNADVISE,
+ WM_DDE_UNADVISE,
+ MAKE_DDE_LPARAM (WM_DDE_UNADVISE,cfFormat,aItem),
+ FALSE,
+ FALSE);
+ if (hr != NOERROR && hr != RPC_E_DDE_NACK)
+ {
+ if (aItem)
+ GlobalDeleteAtom (aItem);
+ intrDebugOut((DEB_ITRACE,
+ "::UnAdviseOn(%x)WaitForReply returns %x\n",
+ this));
+ return hr;
+ }
+
+
+ if (cfFormat==m_cfPict)
+ {
+ if (m_hPict)
+ {
+ // Invalidate the cache so when someone explicitly asks for
+ // the data, they will get fresh data.
+ wFreeData (m_hPict, m_cfPict, TRUE);
+ m_hPict = (HANDLE)0;
+ m_cfPict = 0;
+ }
+ }
+
+ // Due to a bug in the OLE1 libraries, unadvising on a presentation
+ // format effectively unadvises on native.
+ if (cfFormat != g_cfNative && m_fDidAdvNative)
+ {
+ if (iAdvOn == ON_SAVE)
+ {
+ // to reflect the fact that the native advise connection was lost
+ m_iAdvSave--;
+ m_fDidAdvNative = FALSE;
+ RetErr (AdviseOn (g_cfNative, ON_SAVE)); // re-establish
+ }
+ else if (iAdvOn == ON_CLOSE)
+ {
+ // to reflect the fact that the native advise connection was lost
+ m_iAdvClose--;
+ m_fDidAdvNative = FALSE;
+ RetErr (AdviseOn (g_cfNative, ON_CLOSE));
+ }
+ }
+
+ return NOERROR;
+}
+
+
+//
+// Post a message to a 1.0 server (callee) and wait for the acknowledge
+//
+
+
+INTERNAL CDdeObject::Poke
+ (ATOM aItem, HANDLE hDdePoke)
+{
+ HRESULT hr;
+
+ intrDebugOut((DEB_ITRACE,"CDdeObject::Poke(%x)\n",this));
+
+ ATOM aTmpItem;
+
+ intrAssert(wIsValidAtom(aItem));
+
+ aTmpItem = wDupAtom (aItem);
+
+ intrAssert(wIsValidAtom(aTmpItem));
+
+ m_pDocChannel->hDdePoke = hDdePoke;
+
+ LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_POKE,hDdePoke,aTmpItem);
+ hr = SendMsgAndWaitForReply (m_pDocChannel,
+ AA_POKE,
+ WM_DDE_POKE,
+ lp,
+ TRUE);
+ if (S_OK == hr)
+ {
+ intrDebugOut((DEB_ITRACE,"::Poke(%x) returning %x\n",this,hr));
+ return hr;
+ }
+
+ intrDebugOut((DEB_ITRACE,"::Poke(%x)wPostMessage failed %x\n",this,hr));
+ // Error case
+ if (aTmpItem)
+ GlobalDeleteAtom (aTmpItem);
+ wFreePokeData (m_pDocChannel, m_bOldSvr && m_aClass==aMSDraw);
+ hr = RPC_E_DDE_POST;
+ intrDebugOut((DEB_ITRACE,"::Poke(%x)wPostMessage returns %x\n",this,hr));
+ return hr;
+
+}
+
+INTERNAL CDdeObject::PostSysCommand
+ (LPDDE_CHANNEL pChannel,
+ LPCSTR szCmd,
+ BOOL fStdNew,
+ BOOL fWait)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::PostSysCommand(%x,szCmd=%s,fStdNew=%x,fWait=%x)\n",
+ this,
+ szCmd,
+ fStdNew,
+ fWait));
+
+ ULONG size;
+ WORD len;
+ LPSTR lpdata= NULL;
+ HANDLE hdata = NULL;
+ HRESULT hresult;
+
+
+ #define LN_FUDGE 16 // [],(), 3 * 3 (2 double quotes and comma)
+
+ len = strlen (szCmd);
+
+ // for StdNewDocument command add class name
+ if (fStdNew)
+ len += wAtomLenA (m_aClass);
+
+ // Now add the document length.
+ len += wAtomLenA (m_aTopic);
+
+ // now add the fudge factor for the Quotes etc.
+ len += LN_FUDGE;
+
+ // allocate the buffer and set the command.
+ if (!(hdata = GlobalAlloc (GMEM_DDESHARE, size = len)))
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+
+ if (!(lpdata = (LPSTR)GlobalLock (hdata))) {
+ Assert (0);
+ GlobalFree (hdata);
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ strcpy (lpdata, (LPSTR)"["); // [
+ strcat (lpdata, szCmd); // [StdCmd
+ if (strcmp (szCmd, "StdExit"))
+ {
+ strcat (lpdata, "(\""); // [StdCmd("
+
+ if (fStdNew)
+ {
+ len = strlen (lpdata);
+ GlobalGetAtomNameA (m_aClass, (LPSTR)lpdata + len, size-len);
+ // [StdCmd("class
+ strcat (lpdata, "\",\""); // [StdCmd("class","
+ }
+
+ len = strlen (lpdata);
+ // now get the topic name.
+ GlobalGetAtomNameA (m_aTopic, lpdata + len, (WORD)size - len);
+ // [StdCmd("class","topic
+ strcat (lpdata, "\")"); // [StdCmd("class","topic")
+ }
+ strcat (lpdata, "]");
+ Assert (strlen(lpdata) < size);
+ intrDebugOut((DEB_ITRACE,"::PostSysCommand(%x) hData(%s)\n",this,lpdata));
+ GlobalUnlock (hdata);
+
+ // return Execute (m_pSysChannel, hdata, /*fStdClose*/FALSE, fWait);
+ // REVIEW: this fixed bug 1856 (johannp)
+ // JasonFul - does it break something else?
+
+ hresult = Execute (m_pSysChannel,
+ hdata,
+ /*fStdClose*/FALSE,
+ fWait,
+ /*fDetectTerminate*/ TRUE);
+
+ intrDebugOut((DEB_ITRACE,"::PostSysCommand(%x) returns:%x\n",this,hresult));
+ return hresult;
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::KeepData
+//
+// Synopsis: Given the DDEDATA structure from a WM_DDE_DATA message, extract
+// the real data and keep it till GetData or Save is done.
+//
+//
+// Effects:
+//
+// Arguments: [pChannel] --
+// [hDdeData] --
+//
+// Requires:
+//
+// Returns: E_OUTOFMEMORY or E_HANDLE if failure, NOERROR if success
+//
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-14-94 kevinro Commented
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL CDdeObject::KeepData
+ (LPDDE_CHANNEL pChannel, HANDLE hDdeData)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::KeepData(%x)\n",this));
+
+ DDEDATA * lpDdeData = NULL;
+ HANDLE hData;
+ CLIPFORMAT cfFormat;
+
+
+
+ if (!(lpDdeData = (DDEDATA *) (GlobalLock (hDdeData))))
+ {
+ return E_OUTOFMEMORY;;
+ }
+
+
+ cfFormat = lpDdeData->cfFormat;
+ intrDebugOut((DEB_ITRACE,
+ "::KeepData(%x) Keeping cfFormat=%x\n",
+ this,
+ cfFormat));
+
+ GlobalUnlock (hDdeData);
+
+ // Possible Side effect of wHandleFromDdeData() is the freeing of hDdeData
+ if (!(hData = wHandleFromDdeData (hDdeData))
+ || !wIsValidHandle (hData, cfFormat) )
+ {
+ Assert(0);
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+
+ if (cfFormat == g_cfNative) {
+ if (m_hNative)
+ GlobalFree (m_hNative);
+ // Keep the native data
+ RetErr (wTransferHandle (&m_hNative, &hData, cfFormat));
+ }
+ else if (cfFormat == CF_METAFILEPICT ||
+ cfFormat == CF_BITMAP ||
+ cfFormat == CF_DIB)
+ {
+ if (m_hPict)
+ wFreeData (m_hPict, m_cfPict, TRUE);
+ m_cfPict = cfFormat;
+ // Keep the presentation data
+ RetErr (wTransferHandle (&m_hPict, &hData, cfFormat));
+
+#ifdef OLD
+ // Remember size of picture so we can return
+ // a reasonable answer for GetExtent
+ if (cfFormat == CF_METAFILEPICT)
+ {
+ LPMETAFILEPICT lpMfp = (LPMETAFILEPICT) GlobalLock (m_hPict);
+ if (NULL==lpMfp)
+ return E_HANDLE;
+ UpdateExtent (m_cxContentExtent, lpMfp->xExt);
+ UpdateExtent (m_cyContentExtent, lpMfp->yExt);
+ GlobalUnlock (m_hPict);
+ }
+ else if (cfFormat==CF_BITMAP)
+ {
+ BITMAP bm;
+ if (0==GetObject (m_hPict, sizeof(BITMAP), (LPVOID) &bm))
+ return E_HANDLE;
+ UpdateExtent (m_cxContentExtent,
+ wPixelsToHiMetric (bm.bmWidth, giPpliX));
+ UpdateExtent (m_cyContentExtent,
+ wPixelsToHiMetric (bm.bmHeight,giPpliY));
+ }
+ else if (cfFormat==CF_DIB)
+ {
+ BITMAPINFOHEADER * pbminfohdr;
+ pbminfohdr = (BITMAPINFOHEADER *) GlobalLock (m_hPict);
+ if (NULL==pbminfohdr)
+ return E_HANDLE;
+ UpdateExtent (m_cxContentExtent,
+ wPixelsToHiMetric (pbminfohdr->biWidth, giPpliX));
+ UpdateExtent (m_cyContentExtent,
+ wPixelsToHiMetric (pbminfohdr->biHeight,giPpliY));
+ GlobalUnlock (m_hPict);
+ }
+#endif
+
+ }
+ else
+ {
+ if (m_hExtra)
+ wFreeData (m_hExtra, m_cfExtra, TRUE);
+ m_cfExtra = cfFormat;
+ wTransferHandle (&m_hExtra, &hData, cfFormat);
+ }
+
+ return NOERROR;
+}
+
+
+// IsFormatAvailable
+//
+// Does a temporary DDE_REQUEST to see if server supports a format
+// Returns NOERROR if format is available.
+//
+
+
+INTERNAL CDdeObject::IsFormatAvailable
+ (LPFORMATETC pformatetc)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::IsFormatAvailable(%x)\n",this));
+ ATOM aItem=(ATOM)0;
+ HRESULT hresult;
+ LPARAM lp = 0;
+
+ Puts ("DdeObject::IsFormatAvailable\n");
+
+ if (!HasValidLINDEX(pformatetc))
+ {
+ intrDebugOut((DEB_IERROR, "\t!HasValidLINDEX(pformatetc)\n"));
+ return(DV_E_LINDEX);
+ }
+
+ if (0==pformatetc->cfFormat)
+ return ResultFromScode (E_INVALIDARG);
+
+ if (pformatetc->dwAspect & DVASPECT_ICON)
+ {
+ if (pformatetc->cfFormat==CF_METAFILEPICT)
+ {
+ // This is always available. we get it from the exe.
+ return NOERROR;
+ }
+ // an icon must be a metafile
+ return ResultFromScode (S_FALSE);
+ }
+ if (!(pformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_DOCPRINT)))
+ {
+ // 1.0 does not support Thumb.
+ return ReportResult(0, S_FALSE, 0, 0);
+ }
+
+ if (NOERROR == (hresult=m_ConnectionTable.Lookup (pformatetc->cfFormat, NULL)))
+ {
+ // We already got a call to DataObject::Advise on this format,
+ // so it must be available.
+ Puts ("DataObject::Advise had been done on this format.\n");
+ return NOERROR;
+ }
+ else
+ {
+ // Lookup () didn't find this format.
+ ErrZ (GetScode(hresult)==S_FALSE);
+ }
+
+ intrAssert(wIsValidAtom(m_aItem));
+ aItem = wDupAtom (m_aItem);
+ intrAssert(wIsValidAtom(aItem));
+
+ lp = MAKE_DDE_LPARAM (WM_DDE_REQUEST,pformatetc->cfFormat,aItem);
+ if(NOERROR==SendMsgAndWaitForReply (m_pDocChannel,
+ AA_REQUESTAVAILABLE,
+ WM_DDE_REQUEST,
+ lp,
+ TRUE))
+ return NOERROR;
+
+ // Last ditch effort: Advise
+ if (NOERROR== AdviseOn (pformatetc->cfFormat, ON_SAVE))
+ {
+ // We cannot Unadvise because an OLE 1.0 bug
+ // terminates DDE advise connections for ALL formats.
+ //// UnAdviseOn (pformatetc->cfFormat, ON_SAVE);
+ // Instead, just remember we did this advise.
+ m_ConnectionTable.Add (0, pformatetc->cfFormat, ADVFDDE_ONSAVE);
+ return NOERROR;
+ }
+ return ResultFromScode (S_FALSE);
+
+errRtn:
+ AssertSz (0, "Error in CDdeObject::IsFormatAvailable");
+ Puth (hresult); Putn();
+ if (aItem)
+ GlobalDeleteAtom (aItem);
+
+ return hresult;
+}
+
+
+
+
+INTERNAL CDdeObject::ChangeTopic
+ (LPSTR lpszTopic)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::ChangeTopic(%x,lpszTopic=%s)\n",this,lpszTopic));
+ HRESULT hresult;
+ LPMONIKER pmkFile=NULL;
+ LPMONIKER pmkItem=NULL;
+ LPMONIKER pmkComp=NULL;
+ LPMONIKER pmkNewName=NULL;
+ ATOM aTopic = wGlobalAddAtomA (lpszTopic);
+ intrAssert(wIsValidAtom(aTopic));
+
+ // Yet-Another-Excel-Hack
+ // Excel 4.0 sends StdDocumentName every time it saves,
+ // whether or not the file name has actually changed. Bug 2957
+ if (aTopic != m_aTopic)
+ {
+ ErrRtnH (CreateOle1FileMoniker (wAtomName(aTopic), m_clsid, &pmkFile));
+ if (m_aItem)
+ {
+ intrAssert (wIsValidAtom (m_aItem));
+ ErrRtnH (CreateItemMoniker (OLESTR("!"), wAtomName (m_aItem), &pmkItem));
+ ErrRtnH (CreateGenericComposite (pmkFile, pmkItem, &pmkComp));
+ (pmkNewName = pmkComp)->AddRef();
+ }
+ else
+ {
+ (pmkNewName = pmkFile)->AddRef();
+ }
+ RetZS (m_pOleAdvHolder, E_OUTOFMEMORY);
+ RetZ (pmkNewName);
+ ErrRtnH (m_pOleAdvHolder->SendOnRename (pmkNewName));
+ }
+ SetTopic (aTopic);
+ hresult = NOERROR;
+
+ errRtn:
+ if (pmkFile)
+ pmkFile->Release();
+ if (pmkItem)
+ pmkItem->Release();
+ if (pmkComp)
+ pmkComp->Release();
+ if (pmkNewName)
+ pmkNewName->Release();
+ return hresult;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::ChangeItem
+//
+// Synopsis: Changes the m_aItem atom, using an Ansi string
+//
+// Effects:
+//
+// Arguments: [szItem] -- Ansi string for the new item
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL_(void) CDdeObject::ChangeItem
+ (LPSTR szItem)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::ChangeItem(%x,szItem=%s)\n",this,szItem));
+ intrAssert(wIsValidAtom(m_aItem));
+ if (m_aItem)
+ GlobalDeleteAtom (m_aItem);
+ m_aItem = wGlobalAddAtomA (szItem);
+ intrAssert(wIsValidAtom(m_aItem));
+}
+
+
+
+
+INTERNAL CDdeObject::DeclareVisibility
+ (BOOL f,
+ BOOL fCallOnShowIfNec)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::DelcareVisibility(%x)\n",this));
+ if (f)
+ m_fWasEverVisible = TRUE;
+ if ((f && (!m_fVisible || !m_fCalledOnShow)) ||
+ (!f && m_fVisible))
+ {
+ if (m_pOleClientSite && fCallOnShowIfNec && m_clsid != CLSID_Package)
+ {
+ m_pOleClientSite->OnShowWindow (f);
+ m_fCalledOnShow = f;
+ }
+ m_fVisible = f;
+ }
+ return NOERROR;
+}
+
+
+
+INTERNAL CDdeObject::Update
+ (BOOL fRequirePresentation)
+{
+ intrDebugOut((DEB_ITRACE,
+ "CDdeObject::Update(%x,fRequiredPresentation=%x)\n",
+ this,
+ fRequirePresentation));
+ // Get latest data
+ // OLE 1.0 spec says servers must supply metafile format.
+ HRESULT hresult = RequestData (m_cfPict ? m_cfPict : CF_METAFILEPICT);
+ if (fRequirePresentation && hresult!=NOERROR)
+ return hresult;
+ RetErr (RequestData (g_cfNative));
+ SendOnDataChange (ON_CHANGE);
+ return NOERROR;
+}
+
+
+
+INTERNAL CDdeObject::Save
+ (LPSTORAGE pstg)
+{
+ intrDebugOut((DEB_ITRACE,"CDdeObject::Save(%x)\n",this));
+ VDATEIFACE (pstg);
+#ifdef OLE1INTEROP
+ RetErr (StSave10NativeData (pstg, m_hNative, m_fOle1interop));
+#else
+ RetErr (StSave10NativeData (pstg, m_hNative, FALSE));
+#endif
+ if (m_aItem)
+ {
+ intrAssert(wIsValidAtom(m_aItem));
+ RetErr (StSave10ItemName (pstg, wAtomNameA (m_aItem)));
+ }
+ RetErr (wWriteFmtUserType (pstg, m_clsid));
+ return NOERROR;
+}
+
+/*
+ * IMPLEMENTATION of CUnknownImpl
+ *
+ */
+
+
+
+STDMETHODIMP_(ULONG) NC(CDdeObject,CUnknownImpl)::AddRef()
+{
+ ChkD(m_pDdeObject);
+
+ return InterlockedAddRef(&(m_pDdeObject->m_refs));
+}
+
+
+STDMETHODIMP_(ULONG) NC(CDdeObject,CUnknownImpl)::Release()
+{
+ ChkD(m_pDdeObject);
+ Assert (m_pDdeObject->m_refs != 0);
+ ULONG ul;
+
+ if ((ul=InterlockedRelease(&(m_pDdeObject->m_refs))) == 0) {
+ m_pDdeObject->m_ProxyMgr.Disconnect();
+
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ // the object can not be delete if guarded
+ // which is the case if DelayDelete state is 'DelayIt'
+ //
+ if (m_pDdeObject->_DelayDelete == DelayIt)
+ {
+ // set the state to ReadyToDelete and
+ // the object will be deleted at the
+ // UnGuard call
+ m_pDdeObject->_DelayDelete = ReadyToDelete;
+ intrDebugOut((DEB_IWARN ,"Can not release CDdeObject\n"));
+ return 1;
+ }
+#endif //_CHICAGO_
+ delete m_pDdeObject;
+ return 0;
+ }
+ return ul;
+}
+
+
+
+
+STDMETHODIMP NC(CDdeObject,CUnknownImpl)::QueryInterface(REFIID iid, LPLPVOID ppv)
+{
+ ChkD(m_pDdeObject);
+ if (iid == IID_IUnknown) {
+ *ppv = (void FAR *)&m_pDdeObject->m_Unknown;
+ AddRef();
+ return NOERROR;
+ }
+ else if (iid == IID_IOleObject)
+ *ppv = (void FAR *) &(m_pDdeObject->m_Ole);
+ else if (iid == IID_IDataObject)
+ *ppv = (void FAR *) &(m_pDdeObject->m_Data);
+ else if (iid == IID_IPersist || iid == IID_IPersistStorage)
+ *ppv = (void FAR *) &(m_pDdeObject->m_PersistStg);
+ else if (iid == IID_IProxyManager)
+ *ppv = (void FAR *) &(m_pDdeObject->m_ProxyMgr);
+ else if (iid == IID_IOleItemContainer
+ || iid == IID_IOleContainer
+ || iid == IID_IParseDisplayName)
+ *ppv = (void FAR *) &(m_pDdeObject->m_OleItemContainer);
+ else {
+ Puts ("INTERFACE NOT FOUND \r\n");
+ *ppv = NULL;
+ return ReportResult(0, E_NOINTERFACE, 0, 0);
+ }
+
+ m_pDdeObject->m_pUnkOuter->AddRef();
+ return NOERROR;
+}
+
+
+// implementations of IRpcStubBuffer methods
+STDUNKIMPL_FORDERIVED(DdeObject, RpcStubBufferImpl)
+
+
+
+STDMETHODIMP NC(CDdeObject,CRpcStubBufferImpl)::Connect
+ (IUnknown * pUnkServer )
+{
+ // do nothing
+ return S_OK;
+}
+
+STDMETHODIMP_(void) NC(CDdeObject,CRpcStubBufferImpl)::Disconnect
+ ()
+{
+ // do nothing
+}
+
+STDMETHODIMP_(IRpcStubBuffer*) NC(CDdeObject,CRpcStubBufferImpl)::IsIIDSupported
+ (REFIID riid)
+{
+ // do nothing
+ return NULL;
+}
+
+
+STDMETHODIMP_(ULONG) NC(CDdeObject,CRpcStubBufferImpl)::CountRefs
+ ()
+{
+ // do nothing
+ return 1;
+}
+
+STDMETHODIMP NC(CDdeObject,CRpcStubBufferImpl)::DebugServerQueryInterface
+ (void ** ppv )
+{
+ // do nothing
+ *ppv = NULL;
+ return S_OK;
+}
+
+
+STDMETHODIMP_(void) NC(CDdeObject,CRpcStubBufferImpl)::DebugServerRelease
+ (void * pv)
+{
+ // do nothing
+}
+
+STDMETHODIMP NC(CDdeObject,CRpcStubBufferImpl)::Invoke
+ (RPCOLEMESSAGE *_prpcmsg, IRpcChannelBuffer *_pRpcChannelBuffer)
+{
+ PDISPATCHDATA pdispdata = (PDISPATCHDATA) _prpcmsg->Buffer;
+ return DispatchCall( pdispdata );
+}
+
+
+// implementation of IRpcChannelBuffer methods for DDE_CHANNEL
+//
+
+STDMETHODIMP DDE_CHANNEL::QueryInterface ( REFIID riid, LPVOID * ppvObj)
+{
+ *ppvObj = this;
+ return S_OK;
+}
+STDMETHODIMP_(ULONG) DDE_CHANNEL::AddRef ()
+{
+ return 1;
+}
+STDMETHODIMP_(ULONG) DDE_CHANNEL::Release ()
+{
+ return 1;
+}
+
+// Provided IRpcChannelBuffer methods (for callback methods side)
+HRESULT DDE_CHANNEL::GetBuffer(
+/* [in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+/* [in] */ REFIID riid)
+{
+ return S_OK;
+}
+
+HRESULT DDE_CHANNEL::SendReceive(
+/* [out][in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+/* [out] */ ULONG __RPC_FAR *pStatus)
+{
+ return S_OK;
+}
+
+HRESULT DDE_CHANNEL::FreeBuffer(
+/* [in] */ RPCOLEMESSAGE __RPC_FAR *pMessage)
+{
+ return S_OK;
+}
+
+HRESULT DDE_CHANNEL::GetDestCtx(
+/* [out] */ DWORD __RPC_FAR *pdwDestContext,
+/* [out] */ void __RPC_FAR *__RPC_FAR *ppvDestContext)
+{
+ *pdwDestContext = MSHCTX_LOCAL;
+ return S_OK;
+}
+
+HRESULT DDE_CHANNEL::IsConnected( void)
+{
+ return S_OK;
+}
+
+
+
+
diff --git a/private/ole32/com/dde/client/ddeproxy.h b/private/ole32/com/dde/client/ddeproxy.h
new file mode 100644
index 000000000..651f896df
--- /dev/null
+++ b/private/ole32/com/dde/client/ddeproxy.h
@@ -0,0 +1,730 @@
+// ddeproxy.h
+//
+// Used by ddeproxy.cpp ddeDO.cpp ddeOO.cpp
+//
+// Author: Jason Fuller jasonful 24-July-1992
+//
+// Modified: Brian Chapman bchapman Nov 1995
+// - Removed declarations of wAllocDdeChannel() and wGetRequestResponse()
+// because they were not used or even defined anywhere.
+// - Fixed the indention of the declarations of the "worker" routines
+// section.
+//
+//
+#ifndef fDdeProxy_h
+#define fDdeProxy_h
+
+//
+// One of the oleint.h routines redefines GlobalAlloc and friends
+// to perform some memory tracking functions.
+//
+// This doesn't work in these files, since the tracking functions
+// add tail checking, and size to the data structures. GlobalSize
+// is a common function to use to determine how much data to
+// serialize, plus it turns out that the other side of a DDE
+// connection will often be the caller to free the memory.
+//
+// Therefore, OLE_DDE_NO_GLOBAL_TRACKING is used to disable this in the
+// global header file ih\memapi.hxx. Check to insure this
+// flag is set on the compile line
+//
+#if !defined(OLE_DDE_NO_GLOBAL_TRACKING)
+error OLE_DDE_OLE_DDE_NO_GLOBAL_TRACKING must be defined to build this directory
+#endif
+
+
+#include <ole2int.h>
+#include <callctrl.hxx>
+#include <ddeint.h>
+#include <dde.h>
+#include <olerem.h>
+#include <ole1cls.h>
+#include <limits.h>
+// For fDdeCodeInOle2Dll flag
+#include <ddeatoms.h>
+#include <ddepack.h>
+#include <ddedebug.h>
+
+#ifdef OLE_DEBUG_EXT
+#include <ntsdexts.h>
+#endif OLE_DEBUG_EXT
+
+#include "ddechc.hxx"
+#define LPCALLINFO LPVOID
+#include "ddeerr.h"
+#include "cnct_tbl.h"
+
+#define MAX_STR 256
+
+// number of .01 mm per inch
+#define HIMETRIC_PER_INCH 2540
+
+//#define fDebugOutput
+
+// callback notifications
+#define ON_CHANGE 0
+#define ON_SAVE 1
+#define ON_CLOSE 2
+#define ON_RENAME 3
+
+// AwaitAck values
+#define AA_NONE 0
+#define AA_REQUEST 1
+#define AA_ADVISE 2
+#define AA_POKE 3
+#define AA_EXECUTE 4
+#define AA_UNADVISE 5
+#define AA_INITIATE 6
+#define AA_TERMINATE 7
+// A DDE_REQUEST to see if a format is available, not to keep the data.
+#define AA_REQUESTAVAILABLE 8
+
+// Bits for Positive WM_DDE_ACK
+//#define POSITIVE_ACK 0x8000
+//#define NEGATIVE_ACK 0x0000
+
+#define DDE_CHANNEL_DELETED 0xffffffff
+
+typedef DWORD CHK;
+const DWORD chkDdeObj = 0xab01; // magic cookie
+
+
+class DDE_CHANNEL : public CPrivAlloc, public IRpcChannelBuffer2 {
+
+public:
+ // *** IUnknown methods ***
+ STDMETHOD(QueryInterface) ( REFIID riid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) ();
+ STDMETHOD_(ULONG,Release) ();
+
+ // Provided IRpcChannelBuffer methods (for server side)
+ virtual HRESULT __stdcall GetBuffer(
+ /* [in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+ /* [in] */ REFIID riid);
+
+ virtual HRESULT __stdcall SendReceive(
+ /* [out][in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+ /* [out] */ ULONG __RPC_FAR *pStatus);
+
+ virtual HRESULT __stdcall FreeBuffer(
+ /* [in] */ RPCOLEMESSAGE __RPC_FAR *pMessage);
+
+ virtual HRESULT __stdcall GetDestCtx(
+ /* [out] */ DWORD __RPC_FAR *pdwDestContext,
+ /* [out] */ void __RPC_FAR *__RPC_FAR *ppvDestContext);
+
+ virtual HRESULT __stdcall IsConnected( void);
+
+
+ // Provided IRpcChannelBuffer2 methods (for client side)
+ virtual HRESULT __stdcall SendReceive2(
+ /* [out][in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+ /* [out] */ ULONG __RPC_FAR *pStatus);
+
+ void SetCallState(SERVERCALLEX ServerCall, HRESULT hr = S_OK);
+
+ ULONG AddReference()
+ {
+ return ++m_cRefs;
+ }
+ ULONG ReleaseReference()
+ {
+ if (--m_cRefs == 0)
+ {
+ delete this;
+ return(0);
+ }
+ return(m_cRefs);
+ }
+
+ ULONG m_cRefs;
+ HWND hwndCli;
+ HWND hwndSvr;
+ BOOL bTerminating;
+ int iExtraTerms;
+ WORD wTimer;
+ DWORD dwStartTickCount;
+ WORD msgFirst;
+ WORD msgLast;
+ HWND msghwnd; //
+ BOOL fRejected; // because fBusy flag set in DDE_ACK
+ WORD wMsg;
+ LONG lParam;
+ int iAwaitAck;
+ HRESULT hres;
+ HANDLE hopt; // Memory blocks I may have to free for DDE_ADVISE
+ HANDLE hDdePoke; // for DDE_POKE
+ HANDLE hCommands; // for DDE_EXECUTE
+ WORD wChannelDeleted;
+ PDDECALLDATA pCD;
+ SERVERCALLEX CallState;
+} ;
+
+
+#define Channel_InModalloop 1
+#define Channel_DeleteNow 2
+
+
+typedef DDE_CHANNEL * LPDDE_CHANNEL;
+extern BOOL bWndClassesRegistered;
+
+#define hinstSO g_hmodOLE2
+extern HMODULE g_hmodOLE2;
+
+extern INTERNAL_(BOOL) wRegisterClasses (void);
+
+#ifndef _MAC
+extern CLIPFORMAT g_cfNative;
+extern CLIPFORMAT g_cfBinary;
+#endif
+
+#ifdef _CHICAGO_
+//Note:POSTPPC
+//
+// DelayDelete is used to delay deleting the CDdeObject
+// Guard will set it to DelayIt
+// UnGuard will reset it to NoDelay or delete the object
+// if state is ReadyToDelete
+//
+typedef enum
+{
+ NoDelay = 0, // normal state
+ DelayIt = 1, // object is protected and deleting will be delayed
+ ReadyToDelete = 2 // object was is DelayIt state and can be deleted
+} DelayDelete;
+
+#endif // _CHICAGO_
+
+/*
+ * Definition of CDdeObject
+ *
+ */
+class CMsgFilterInfo;
+class CDdeObject;
+
+class CDdeObject : public CPrivAlloc
+{
+public:
+
+ static INTERNAL_(LPUNKNOWN) Create (IUnknown * pUnkOuter,
+ REFCLSID clsidClass,
+ ULONG ulObjType = OT_EMBEDDED,
+ ATOM aTopic = NULL,
+ LPOLESTR szItem = NULL,
+ CDdeObject * * ppdde = NULL,
+ BOOL fAllowNullClsid = FALSE);
+
+ INTERNAL_(void) OnInitAck (LPDDE_CHANNEL pChannel, HWND hwndSvr);
+ INTERNAL_(BOOL) OnAck (LPDDE_CHANNEL pChannel, LONG lParam);
+ INTERNAL_(void) OnTimer (LPDDE_CHANNEL pChannel);
+ INTERNAL OnData (LPDDE_CHANNEL pChannel, HANDLE hData,ATOM aItem);
+ INTERNAL OnDataAvailable (LPDDE_CHANNEL pChannel, HANDLE hData,ATOM aItem);
+ INTERNAL OnTerminate (LPDDE_CHANNEL pChannel, HWND hwndPost);
+
+ INTERNAL_(LPDDE_CHANNEL) GetSysChannel(void)
+ { return m_pSysChannel; }
+
+ INTERNAL_(LPDDE_CHANNEL) GetDocChannel(void)
+ { return m_pDocChannel; }
+
+ INTERNAL_(BOOL) AllocDdeChannel(LPDDE_CHANNEL * lpChannel, BOOL fSysWndProc);
+ INTERNAL_(BOOL) InitSysConv (void);
+ INTERNAL_(void) SetTopic (ATOM aTopic);
+
+ INTERNAL SendOnDataChange (int iAdvOpt);
+ INTERNAL OleCallBack (int iAdvOpt,LPDDE_CHANNEL pChannel);
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ INTERNAL_(void) Guard()
+ {
+ intrDebugOut((DEB_IWARN ,"CDdeObject: %x DelayDelete is set to 'DelayIt'\n", this));
+ _DelayDelete = DelayIt;
+ }
+ INTERNAL_(BOOL) UnGuard()
+ {
+ if (_DelayDelete == ReadyToDelete)
+ {
+ intrDebugOut((DEB_IWARN ,"CDdeObject: %x DelayDelete it set 'ReadyToDelete'\n", this));
+ delete this;
+ intrDebugOut((DEB_IWARN ,"CDdeObject: %x was deleted\n", this));
+ return TRUE;
+ }
+ else
+ {
+ intrDebugOut((DEB_IWARN ,"CDdeObject: %x DelayDelete set to 'NoDelay'\n", this));
+ _DelayDelete = NoDelay;
+ }
+
+ return FALSE;
+ }
+#endif // _CHICAGO_
+
+ BOOL m_fDoingSendOnDataChange;
+ ULONG m_cRefCount;
+
+private:
+
+ CDdeObject (IUnknown * pUnkOuter);
+ ~CDdeObject (void);
+ INTERNAL TermConv (LPDDE_CHANNEL pChannel,
+ BOOL fWait=TRUE);
+ INTERNAL_(void) DeleteChannel (LPDDE_CHANNEL pChannel);
+ INTERNAL_(BOOL) LaunchApp (void);
+ INTERNAL MaybeUnlaunchApp (void);
+ INTERNAL UnlaunchApp (void);
+ INTERNAL Execute (LPDDE_CHANNEL pChannel,
+ HANDLE hdata,
+ BOOL fStdCloseDoc=FALSE,
+ BOOL fWait=TRUE,
+ BOOL fDetectTerminate = TRUE);
+ INTERNAL Advise (void);
+ INTERNAL AdviseOn (CLIPFORMAT cfFormat,
+ int iAdvOn);
+ INTERNAL UnAdviseOn (CLIPFORMAT cfFormat,
+ int iAdvOn);
+ INTERNAL Poke (ATOM aItem, HANDLE hDdePoke);
+ INTERNAL PostSysCommand (LPDDE_CHANNEL pChannel,
+ LPCSTR szCmd,
+ BOOL bStdNew=FALSE,
+ BOOL fWait=TRUE);
+
+#ifdef _CHICAGO_
+ //POSTPPC
+ INTERNAL_(BOOL) CanMakeOutCall(LPDDE_CHANNEL pChannel);
+#endif
+
+ INTERNAL SendMsgAndWaitForReply (LPDDE_CHANNEL pChannel,
+ int iAwaitAck,
+ WORD wMsg,
+ long lparam,
+ BOOL fFreeOnError,
+ BOOL fStdCloseDoc = FALSE,
+ BOOL fDetectTerminate = TRUE,
+ BOOL fWait = TRUE);
+ INTERNAL KeepData (LPDDE_CHANNEL pChannel, HANDLE hDdeData);
+ INTERNAL ChangeTopic (LPSTR lpszTopic);
+ INTERNAL_(void) ChangeItem (LPSTR lpszItem);
+ INTERNAL IsFormatAvailable (LPFORMATETC);
+ INTERNAL_(BOOL) CanCallBack(LPINT);
+ INTERNAL RequestData (CLIPFORMAT);
+ INTERNAL SetTargetDevice (const DVTARGETDEVICE *);
+ INTERNAL DocumentLevelConnect (LPBINDCTX pbc);
+ INTERNAL SendOnClose (void);
+ INTERNAL UpdateAdviseCounts (CLIPFORMAT cf,
+ int iAdvOn,
+ signed int cDelta);
+ INTERNAL DeclareVisibility (BOOL fVisible,
+ BOOL fCallOnShowIfNec=TRUE);
+ INTERNAL Save (LPSTORAGE);
+ INTERNAL Update (BOOL fRequirePresentation);
+
+implementations:
+
+ STDUNKDECL(CDdeObject,DdeObject)
+ STDDEBDECL(CDdeObject,DdeObject)
+
+
+ implement COleObjectImpl : IOleObject
+ {
+ public:
+ COleObjectImpl (CDdeObject * pDdeObject)
+ { m_pDdeObject = pDdeObject; }
+
+ // *** IUnknown methods ***
+ STDMETHOD(QueryInterface) ( REFIID riid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) ();
+ STDMETHOD_(ULONG,Release) ();
+
+ // *** IOleObject methods ***
+ STDMETHOD(SetClientSite) ( LPOLECLIENTSITE pClientSite);
+ STDMETHOD(GetClientSite) ( LPOLECLIENTSITE * ppClientSite);
+ STDMETHOD(SetHostNames) ( LPCOLESTR szContainerApp, LPCOLESTR szContainerObj);
+ STDMETHOD(Close) ( DWORD reserved);
+ STDMETHOD(SetMoniker) ( DWORD dwWhichMoniker, LPMONIKER pmk);
+ STDMETHOD(GetMoniker) ( DWORD dwAssign, DWORD dwWhichMoniker,LPMONIKER * ppmk);
+ STDMETHOD(InitFromData) ( LPDATAOBJECT pDataObject,BOOL fCreation,DWORD dwReserved);
+ STDMETHOD(GetClipboardData) ( DWORD dwReserved,LPDATAOBJECT * ppDataObject);
+
+ STDMETHOD(DoVerb) ( LONG iVerb,
+ LPMSG lpmsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lindex,
+ HWND hwndParent,
+ const RECT * lprcPosRect);
+
+ STDMETHOD(EnumVerbs) ( IEnumOLEVERB * * ppenumOleVerb);
+ STDMETHOD(Update) ();
+ STDMETHOD(IsUpToDate) ();
+ STDMETHOD(GetUserClassID) ( CLSID * pClsid);
+ STDMETHOD(GetUserType) ( DWORD dwFormOfType, LPOLESTR * pszUserType);
+ STDMETHOD(SetExtent) ( DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHOD(GetExtent) ( DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHOD(Advise)( IAdviseSink * pAdvSink, DWORD * pdwConnection) ;
+ STDMETHOD(Unadvise) ( DWORD dwConnection);
+ STDMETHOD(EnumAdvise) ( LPENUMSTATDATA * ppenumAdvise);
+ STDMETHOD(GetMiscStatus) ( DWORD dwAspect, DWORD * pdwStatus);
+ STDMETHOD(SetColorScheme) ( LPLOGPALETTE lpLogpal);
+
+ private:
+ CDdeObject * m_pDdeObject;
+ };
+
+
+ implement CDataObjectImpl : IDataObject
+ {
+ public:
+ CDataObjectImpl (CDdeObject * pDdeObject)
+ { m_pDdeObject = pDdeObject; }
+ // *** IUnknown methods ***
+ STDMETHOD(QueryInterface) ( REFIID riid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) () ;
+ STDMETHOD_(ULONG,Release) ();
+
+ STDMETHOD(GetData) ( LPFORMATETC pformatetcIn,LPSTGMEDIUM pmedium );
+ STDMETHOD(GetDataHere) ( LPFORMATETC pformatetc,LPSTGMEDIUM pmedium );
+ STDMETHOD(QueryGetData) ( LPFORMATETC pformatetc );
+ STDMETHOD(GetCanonicalFormatEtc) ( LPFORMATETC pformatetc,LPFORMATETC pformatetcOut);
+ STDMETHOD(SetData) ( LPFORMATETC pformatetc, STGMEDIUM * pmedium, BOOL fRelease);
+ STDMETHOD(EnumFormatEtc) ( DWORD dwDirection, LPENUMFORMATETC * ppenumFormatEtc);
+ STDMETHOD(DAdvise) ( FORMATETC * pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD * pdwConnection) ;
+ STDMETHOD(DUnadvise) ( DWORD dwConnection) ;
+ STDMETHOD(EnumDAdvise) ( LPENUMSTATDATA * ppenumAdvise) ;
+
+ private:
+ CDdeObject * m_pDdeObject;
+ };
+
+
+ implement CPersistStgImpl : IPersistStorage
+ {
+ public:
+ CPersistStgImpl (CDdeObject * pDdeObject)
+ { m_pDdeObject = pDdeObject; }
+
+ STDMETHOD(QueryInterface) ( REFIID iid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) ();
+ STDMETHOD_(ULONG,Release) ();
+ STDMETHOD(GetClassID) ( LPCLSID pClassID);
+ STDMETHOD(IsDirty) (void);
+ STDMETHOD(InitNew) ( LPSTORAGE pstg);
+ STDMETHOD(Load) ( LPSTORAGE pstg);
+ STDMETHOD(Save) ( LPSTORAGE pstgSave, BOOL fSameAsLoad);
+ STDMETHOD(SaveCompleted) ( LPSTORAGE pstgNew);
+ STDMETHOD(HandsOffStorage) (void);
+
+ private:
+ CDdeObject * m_pDdeObject;
+ };
+
+
+ implement CProxyManagerImpl : IProxyManager
+ {
+ public:
+ CProxyManagerImpl (CDdeObject * pDdeObject)
+ { m_pDdeObject = pDdeObject; }
+
+ STDMETHOD(QueryInterface) ( REFIID iid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) ();
+ STDMETHOD_(ULONG,Release) ();
+
+ STDMETHOD(CreateServer)(REFCLSID rclsid, DWORD clsctx, void *pv);
+ STDMETHOD_(BOOL, IsConnected)(void);
+ STDMETHOD(LockConnection)(BOOL fLock, BOOL fLastUnlockReleases);
+ STDMETHOD_(void, Disconnect)();
+ STDMETHOD(CreateServerWithHandler)(REFCLSID rclsid, DWORD clsctx, void *pv,
+ REFCLSID rclsidHandler, IID iidSrv, void **ppv,
+ IID iidClnt, void *pClientSiteInterface);
+
+ STDMETHOD(Connect)(GUID oid, REFCLSID rclsid);
+ STDMETHOD(EstablishIID)(REFIID iid, LPVOID FAR* ppv);
+
+ private:
+ CDdeObject * m_pDdeObject;
+ };
+
+
+ implement COleItemContainerImpl : IOleItemContainer
+ {
+ public:
+ COleItemContainerImpl (CDdeObject * pDdeObject)
+ { m_pDdeObject = pDdeObject; }
+
+ STDMETHOD(QueryInterface) ( REFIID iid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) ();
+ STDMETHOD_(ULONG,Release) ();
+
+ // IParseDisplayName method
+ STDMETHOD(ParseDisplayName) ( LPBC pbc,
+ LPOLESTR lpszDisplayName,
+ ULONG * pchEaten,
+ LPMONIKER * ppmkOut) ;
+
+ // IOleContainer methods
+ STDMETHOD(EnumObjects) ( DWORD grfFlags,LPENUMUNKNOWN * ppenumUnk);
+
+ STDMETHOD(LockContainer) (BOOL fLock);
+
+ // IOleItemContainer methods
+ STDMETHOD(GetObject) ( LPOLESTR lpszItem,
+ DWORD dwSpeedNeeded,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID * ppvObject) ;
+ STDMETHOD(GetObjectStorage) ( LPOLESTR lpszItem,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID * ppvStorage) ;
+
+ STDMETHOD(IsRunning) ( LPOLESTR lpszItem) ;
+
+ private:
+ CDdeObject * m_pDdeObject;
+ };
+
+
+ implement CRpcStubBufferImpl : public IRpcStubBuffer
+ {
+ public:
+ CRpcStubBufferImpl (CDdeObject * pDdeObject)
+ { m_pDdeObject = pDdeObject; }
+
+ STDMETHOD(QueryInterface) ( REFIID iid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) ();
+ STDMETHOD_(ULONG,Release) ();
+ 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);
+
+ private:
+ CDdeObject * m_pDdeObject;
+ };
+
+ DECLARE_NC(CDdeObject, COleObjectImpl)
+ DECLARE_NC(CDdeObject, CDataObjectImpl)
+ DECLARE_NC(CDdeObject, CPersistStgImpl)
+ DECLARE_NC(CDdeObject, CProxyManagerImpl)
+ DECLARE_NC(CDdeObject, COleItemContainerImpl)
+ DECLARE_NC(CDdeObject, CRpcStubBufferImpl)
+
+ COleObjectImpl m_Ole;
+ CDataObjectImpl m_Data;
+ CPersistStgImpl m_PersistStg;
+ CProxyManagerImpl m_ProxyMgr;
+ COleItemContainerImpl m_OleItemContainer;
+ CRpcStubBufferImpl m_RpcStubBuffer;
+
+shared_state:
+ ULONG m_refs;
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ DelayDelete _DelayDelete;
+#endif // _CHICAGO_
+ ULONG m_ulObjType;
+ CLSID m_clsid;
+ ATOM m_aClass;
+ ATOM m_aExeName;
+ ATOM m_aTopic;
+ ATOM m_aItem;
+ BOOL m_bRunning;
+ IUnknown * m_pUnkOuter;
+ IOleClientSite * m_pOleClientSite;
+ LPSTORAGE m_pstg;
+ BOOL m_bInitNew;
+ BOOL m_bOldSvr;
+ HANDLE m_hNative;
+ HANDLE m_hPict;
+ HANDLE m_hExtra;
+ CLIPFORMAT m_cfPict;
+ CLIPFORMAT m_cfExtra;
+
+ BOOL m_fDidSendOnClose;
+ BOOL m_fNoStdCloseDoc;
+ BOOL m_fDidStdCloseDoc;
+ BOOL m_fDidStdOpenDoc;
+ BOOL m_fDidGetObject;
+ BOOL m_fDidLaunchApp;
+ BOOL m_fUpdateOnSave;
+ BOOL m_fGotCloseData;
+
+#ifdef OLE1INTEROP
+ BOOL m_fOle1interop;
+#endif
+
+ // Invisible update stuff
+ ULONG m_cLocks; // PM::LockConnection lock count (init 1)
+ BOOL m_fVisible; // is server visible (as best we know)?
+ BOOL m_fWasEverVisible;
+ BOOL m_fCalledOnShow; // Did we call IOleClientSite::OnShow
+
+ CHK m_chk;
+ DVTARGETDEVICE * m_ptd;
+
+ // m_iAdvClose and m_iAdvSave are counts (1 or 2) of the number of formats
+ // that have advise connections of a given type (Save or Close)
+ int m_iAdvClose;
+ int m_iAdvSave;
+ int m_iAdvChange;
+
+ BOOL m_fDidAdvNative;
+
+ // Extent info
+#ifdef OLD
+ long m_cxContentExtent;
+ long m_cyContentExtent;
+#endif
+
+ // terminate info - only used to detect a premature WM_DDE_TERMINATE
+ WORD m_wTerminate;
+
+ IDataAdviseHolder * m_pDataAdvHolder;
+ IOleAdviseHolder * m_pOleAdvHolder;
+ CDdeConnectionTable m_ConnectionTable;
+
+
+ // DDE window related stuff
+ LPDDE_CHANNEL m_pSysChannel;
+ LPDDE_CHANNEL m_pDocChannel;
+
+ friend INTERNAL DdeBindToObject
+ (LPCOLESTR szFile,
+ REFCLSID clsid,
+ BOOL fPackageLink,
+ REFIID iid,
+ LPLPVOID ppv);
+
+ friend INTERNAL DdeIsRunning
+ (CLSID clsid,
+ LPCOLESTR szFile,
+ LPBC pbc,
+ LPMONIKER pmkToLeft,
+ LPMONIKER pmkNewlyRunning);
+#ifdef OLE_DEBUG_EXT
+
+#endif OLE_DEBUG_EXT
+};
+//
+// Note: WM_DDE_TERMINATE
+// A state machine is used to delay the executing of a premature WM_DDE_TERMINTE
+// message, which is send by some apps instead of WM_DDE_ACK (or alike).
+// The code is in WaitForReply() and in OnTerminate()
+typedef enum {
+ Terminate_None = 0, // default state - terminate code is executed
+ Terminate_Detect = 1, // window proc will NOT execute terminate code
+ Terminate_Received = 2 // wait loop does not need to run, execute terminate code now
+} TERMINATE_DOCUMENT;
+
+
+
+INTERNAL_(BOOL) wPostMessageToServer(LPDDE_CHANNEL pChannel,
+ WORD wMsg,
+ LONG lParam,
+ BOOL fFreeOnError);
+
+INTERNAL_(ATOM) wAtomFromCLSID(REFCLSID rclsid);
+INTERNAL_(ATOM) wGetExeNameAtom (REFCLSID rclsid);
+INTERNAL_(BOOL) wIsWindowValid (HWND hwnd);
+INTERNAL_(void) wFreeData (HANDLE hData, CLIPFORMAT cfFormat,
+ BOOL fFreeNonGdiHandle=TRUE);
+INTERNAL_(BOOL) wInitiate (LPDDE_CHANNEL pChannel, ATOM aLow, ATOM aHigh);
+INTERNAL wScanItemOptions (ATOM aItem, int * lpoptions);
+INTERNAL_(BOOL) wClearWaitState (LPDDE_CHANNEL pChannel);
+INTERNAL_(HANDLE) wStdCloseDocumentHandle (void);
+INTERNAL_(ATOM) wExtendAtom (ATOM aIitem, int iAdvOn);
+INTERNAL_(int) wAtomLen (ATOM atom);
+INTERNAL_(int) wAtomLenA (ATOM atom);
+INTERNAL_(HANDLE) wHandleFromDdeData(HANDLE hDdeData);
+INTERNAL_(BOOL) wIsOldServer (ATOM aClass);
+INTERNAL_(LPSTR) wAllocDdePokeBlock (DWORD dwSize,
+ CLIPFORMAT cfFormat,
+ LPHANDLE phDdePoke);
+INTERNAL_(void) wFreePokeData (LPDDE_CHANNEL pChannel, BOOL fMSDrawBug);
+INTERNAL_(HANDLE) wPreparePokeBlock (HANDLE hData,
+ CLIPFORMAT cfFormat,
+ ATOM aClass,
+ BOOL bOldSvr);
+INTERNAL_(HANDLE) wNewHandle (LPSTR lpstr, DWORD cb);
+INTERNAL wDupData (LPHANDLE ph, HANDLE h, CLIPFORMAT cf);
+INTERNAL wHandleCopy (HANDLE hDst, HANDLE hSrc);
+INTERNAL wGetItemFromClipboard (ATOM * paItem);
+INTERNAL GetDefaultIcon (REFCLSID clsidIn,
+ LPCOLESTR szFile,
+ HANDLE * phmfp);
+INTERNAL_(BOOL) wTerminateIsComing (LPDDE_CHANNEL);
+INTERNAL wTimedGetMessage (LPMSG pmsg,
+ HWND hwnd,
+ WORD wFirst,
+ WORD wLast);
+
+INTERNAL_(ATOM) wGlobalAddAtom(LPCOLESTR sz);
+INTERNAL_(ATOM) wGlobalAddAtomA(LPCSTR sz);
+
+INTERNAL wVerifyFormatEtc (LPFORMATETC pformatetc);
+INTERNAL wNormalize (LPFORMATETC pfetc, LPFORMATETC pfetcOut);
+INTERNAL wTransferHandle (LPHANDLE phDst,
+ LPHANDLE phSrc,
+ CLIPFORMAT cf);
+INTERNAL wClassesMatch (REFCLSID clsidIn, LPOLESTR szFile);
+
+#if DBG == 1
+INTERNAL_(BOOL) wIsValidHandle (HANDLE h, CLIPFORMAT cf);
+INTERNAL_(BOOL) wIsValidAtom (ATOM a);
+#endif
+
+const char achStdCloseDocument[]="[StdCloseDocument]";
+const char achStdOpenDocument[]="StdOpenDocument";
+const char achStdExit[]="StdExit";
+const char achStdNewDocument[]="StdNewDocument";
+const char achStdEditDocument[]="StdEditDocument";
+
+HWND CreateDdeClientHwnd(void);
+
+//+---------------------------------------------------------------------------
+//
+// Function: TLSGetDdeClientWindow()
+//
+// Synopsis: Returns a pointer to the per thread DdeClient window. If one
+// has not been created, it will create it and return
+//
+// Returns: Pointer to the DdeClientWindow. This window is used for per
+// thread cleanup
+//
+// History: 12-12-94 kevinro Created
+//----------------------------------------------------------------------------
+inline void * TLSGetDdeClientWindow()
+{
+ HRESULT hr;
+ COleTls tls(hr);
+
+ if (SUCCEEDED(hr))
+ {
+ if (tls->hwndDdeClient == NULL)
+ {
+ tls->hwndDdeClient = CreateDdeClientHwnd();
+ }
+ return tls->hwndDdeClient;
+ }
+
+ return NULL;
+}
+
+
+#endif // ddeproxy.h
+
+
+
diff --git a/private/ole32/com/dde/client/ddestg.cxx b/private/ole32/com/dde/client/ddestg.cxx
new file mode 100644
index 000000000..35a7e5f44
--- /dev/null
+++ b/private/ole32/com/dde/client/ddestg.cxx
@@ -0,0 +1,529 @@
+/*
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddeStg.cpp
+
+Abstract:
+
+ This module contains the DdeObject::PersistStg and
+ DdeObject::ProxyManager methods
+
+Author:
+
+ Srini Koppolu (srinik) 22-June-1992
+ Jason Fuller (jasonful) 24-July-1992
+
+*/
+
+#include "ddeproxy.h"
+ASSERTDATA
+
+
+/*
+ * IMPLEMENTATION of CPersistStgImpl methods
+ *
+ */
+
+
+STDUNKIMPL_FORDERIVED(DdeObject, PersistStgImpl)
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_GetClassID)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::GetClassID (CLSID FAR* pClassID)
+{
+ *pClassID = m_pDdeObject->m_clsid;
+ return NOERROR;
+}
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_IsDirty)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::IsDirty ()
+{
+ return NOERROR;
+}
+
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_InitNew)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::InitNew
+ (IStorage FAR* pstg)
+{
+ HRESULT hres;
+ intrDebugOut((DEB_ITRACE,
+ "DdeObejct::InitNew(%x,pstg=%x)\n",
+ this,
+ pstg));
+
+ if (hres = m_pDdeObject->PostSysCommand (m_pDdeObject->m_pSysChannel,
+ (LPSTR)&achStdNewDocument,
+ TRUE))
+ return hres;
+
+ if (hres = m_pDdeObject->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL))
+ return hres;
+
+ RetErr (m_pDdeObject->TermConv (m_pDdeObject->m_pSysChannel));
+ if (m_pDdeObject->m_pstg)
+ {
+ m_pDdeObject->m_pstg->Release();
+ }
+ m_pDdeObject->m_pstg = pstg;
+ pstg->AddRef();
+ return hres;
+}
+
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_Load)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::Load (IStorage FAR* pstg)
+{
+ LPSTR lpBuf=NULL;
+ HANDLE hDdePoke = NULL;
+ DWORD dwSize;
+ CStmBufRead StmRead;
+ CStmBufRead StmReadItem;
+ HRESULT hresult;
+
+ intrDebugOut((DEB_ITRACE,"CDdeObject::Load(%x,pstg=%x)\n",this,pstg));
+
+ {
+
+ if (hresult = StmRead.OpenStream(pstg, OLE10_NATIVE_STREAM))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) OpenStream failed(%x)\n",
+ this,
+ hresult));
+ return hresult;
+ }
+
+
+ if (hresult = StmRead.Read(&dwSize, sizeof(DWORD)))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) StRead failed(%x)\n",
+ this,
+ hresult));
+
+ goto errRtn;
+ }
+
+
+ lpBuf = wAllocDdePokeBlock (dwSize, g_cfNative, &hDdePoke);
+
+ if (lpBuf == NULL)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) wAllocDdePokeBlock failed(%x)\n",
+ this,
+ hresult));
+
+ hresult = E_OUTOFMEMORY;
+ goto errRtn;
+ }
+
+ if (hresult = StmRead.Read(lpBuf, dwSize))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) StRead of cfNative failed(%x)\n",
+ this,
+ hresult));
+ goto errRtn;
+ }
+
+ if (m_pDdeObject->m_hNative)
+ {
+ GlobalFree (m_pDdeObject->m_hNative);
+ }
+ m_pDdeObject->m_hNative = wNewHandle (lpBuf, dwSize);
+
+ if (m_pDdeObject->m_hNative == NULL)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) m_hNative NULL\n",
+ this));
+ }
+ }
+
+ GlobalUnlock (hDdePoke); // done with lpBuf
+
+ if (hresult = m_pDdeObject->PostSysCommand (m_pDdeObject->m_pSysChannel,
+ (LPSTR)&achStdEditDocument,
+ FALSE))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) PostSysCommand %s failed (%x)\n",
+ this,
+ &achStdEditDocument,
+ hresult));
+ goto errRtn;
+ }
+
+
+ // Read Item Name, if there is one
+ if (NOERROR == StmReadItem.OpenStream(pstg, OLE10_ITEMNAME_STREAM))
+ {
+ LPSTR szItemName = NULL;
+
+ ErrRtnH (ReadStringStreamA (StmReadItem, &szItemName));
+ m_pDdeObject->ChangeItem (szItemName);
+ PubMemFree(szItemName);
+ }
+
+ if (hresult = m_pDdeObject->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) ProxyMgr.Connect failed(%x)\n",
+ this,
+ hresult));
+ goto errRtn;
+ }
+
+
+ if ((hresult = m_pDdeObject->Poke(m_pDdeObject->m_aItem, hDdePoke))
+ != NOERROR)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) Poke failed(%x)\n",
+ this,
+ hresult));
+
+ // the Poke calls frees the Poke data even in case of failure.
+#ifdef LATER
+
+ if (hresult = m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel,
+ wNewHandle ((LPSTR)achStdCloseDocument,sizeof(achStdCloseDocument)));
+ goto errDoc;
+#elseif
+ goto errDoc;
+#endif
+ }
+
+ hresult = m_pDdeObject->TermConv (m_pDdeObject->m_pSysChannel);
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Load(%x) TermConv on SysChannel failed(%x)\n",
+ this,
+ hresult));
+ goto errRtn;
+ }
+
+
+ if (m_pDdeObject->m_pstg)
+ {
+ m_pDdeObject->m_pstg->Release();
+ }
+
+ m_pDdeObject->m_pstg = pstg;
+ pstg->AddRef();
+ goto LExit;
+
+errRtn:
+ if (hDdePoke)
+ GlobalFree (hDdePoke);
+ if (m_pDdeObject->m_pDocChannel)
+ m_pDdeObject->TermConv (m_pDdeObject->m_pDocChannel);
+LExit:
+ StmReadItem.Release();
+ StmRead.Release();
+
+ intrDebugOut((DEB_ITRACE,"::Load(%x) returning (%x)\n",this,hresult));
+ return hresult;
+}
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_Save)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::Save
+ (IStorage FAR* pstgSave, BOOL fSameAsLoad)
+{
+ intrDebugOut((DEB_ITRACE,
+ "DdeObject::Save(%x,pstgSave=%x)\n",
+ this,
+ pstgSave));
+
+
+ HRESULT hresult=NOERROR;
+
+ if (m_pDdeObject->m_fUpdateOnSave
+ && (m_pDdeObject->m_clsid != CLSID_Package
+ || m_pDdeObject->m_hNative == NULL))
+ {
+ // Get latest data from server, if it is not shutting down
+ // or telling us to Save, in which case it just gave us data.
+ // (If it is shutting down, it probably won't respond.
+ // Draw does respond, but gives bad data.)
+ // Packager gives truncated native data (header info with no
+ // actual embedded file) if you DDE_REQUEST it. Bug 3103
+ m_pDdeObject->Update (FALSE);
+ }
+
+ if (m_pDdeObject->m_hNative == NULL)
+ {
+ // we still have nothing to save
+ return ResultFromScode (E_BLANK);
+ }
+
+ hresult = m_pDdeObject->Save (pstgSave);
+
+ Puts ("PersistStg::Save done\n");
+ return hresult;
+}
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_SaveCompleted)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::SaveCompleted
+ (IStorage FAR* pstgNew)
+{
+ intrDebugOut((DEB_ITRACE,
+ "DdeObejct::SaveCompleted(%x,pstgNew=%x)\n",
+ this,
+ pstgNew));
+
+ RetZ (m_pDdeObject->m_pOleAdvHolder);
+ m_pDdeObject->m_pOleAdvHolder->SendOnSave();
+ if (pstgNew)
+ {
+ if (m_pDdeObject->m_pstg)
+ m_pDdeObject->m_pstg->Release();
+ m_pDdeObject->m_pstg = pstgNew;
+ pstgNew->AddRef();
+ }
+ return NOERROR;
+}
+
+
+#pragma SEG(CDdeObject_CPersistStgImpl_HandsOffStorage)
+STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::HandsOffStorage(void)
+{
+ intrDebugOut((DEB_ITRACE,"DdeObejct::HandsOffStorage(%x)\n",this));
+ if (m_pDdeObject->m_pstg)
+ {
+ m_pDdeObject->m_pstg->Release();
+ m_pDdeObject->m_pstg = NULL;
+ }
+ return NOERROR;
+}
+
+
+/*
+ * IMPLEMENTATION of CProxyManagerImpl methods
+ *
+ */
+
+
+STDUNKIMPL_FORDERIVED(DdeObject, ProxyManagerImpl)
+
+
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_CreateServer)
+STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::CreateServer(REFCLSID rclsid,
+ DWORD clsctx,
+ void *pv)
+{
+ intrDebugOut((DEB_ITRACE,"DdeObejct::CreateServer(%x)\n",this));
+ HRESULT hresult = NOERROR;
+
+ if (m_pDdeObject->m_pSysChannel)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::CreateServer(%x)m_pSysChannel exists\n",
+ this));
+ return NOERROR;
+ }
+
+ if (m_pDdeObject->m_aExeName == NULL)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::CreateServer(%x) Class Not Registered\n",
+ this));
+ return(REGDB_E_CLASSNOTREG);
+ }
+
+
+ if (!m_pDdeObject->AllocDdeChannel(&m_pDdeObject->m_pSysChannel,TRUE))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::CreateServer(%x)AllocDdeChannel is failing\n",
+ this));
+ return ReportResult(0, E_OUTOFMEMORY,0,0);
+ }
+
+ if (!m_pDdeObject->InitSysConv())
+ {
+ if (!(m_pDdeObject->LaunchApp()))
+ {
+ intrDebugOut((DEB_IERROR,"::CreateServer Could not launch app\n"));
+ hresult = ResultFromScode (CO_E_APPNOTFOUND);
+ goto errRtn;
+ }
+
+ if (!m_pDdeObject->InitSysConv())
+ {
+ intrDebugOut((DEB_IERROR,"::CreateServer Second init failed\n"));
+ hresult = ResultFromScode (CO_E_APPDIDNTREG);
+ goto errRtn;
+ }
+ }
+
+ return NOERROR;
+
+errRtn:
+ intrDebugOut((DEB_ITRACE,"DdeObejct::CreateServer(%x) is failing(%x)\n",this,hresult));
+ m_pDdeObject->DeleteChannel (m_pDdeObject->m_pSysChannel);
+ Assert (hresult != NOERROR); // This is an error path
+ return hresult;
+
+}
+
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_Connect)
+STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::Connect(GUID oid, REFCLSID rclsid)
+{
+ intrDebugOut((DEB_ITRACE,"DdeObject::Connect(%x)\n",this));
+
+ if (m_pDdeObject->m_pDocChannel)
+ return NOERROR;
+
+ if (!m_pDdeObject->AllocDdeChannel (&m_pDdeObject->m_pDocChannel,FALSE))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "::Connect(%x) AllocDdeChannel failed, return E_OUTOFMEMORY\n",
+ this));
+ return ReportResult(0, E_OUTOFMEMORY,0,0);
+ }
+
+ // Bug 3701
+ m_pDdeObject->m_fDidSendOnClose = FALSE;
+ if (wInitiate (m_pDdeObject->m_pDocChannel, m_pDdeObject->m_aClass,
+ m_pDdeObject->m_aTopic))
+ {
+ return NOERROR;
+ }
+
+ intrDebugOut((DEB_ITRACE,"::Connect(%x) wInitiate failed\n",this));
+ m_pDdeObject->DeleteChannel (m_pDdeObject->m_pDocChannel);
+ return ResultFromScode (E_FAIL);
+}
+
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_LockConnection)
+STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::LockConnection(BOOL fLock, BOOL fLastUnlockReleases)
+{
+ intrDebugOut((DEB_ITRACE,
+ "DdeObject::LockConnection(%x,fLock=%x,fLastUnlockReleases=%x)\n",
+ this,
+ fLock,
+ fLastUnlockReleases));
+
+ if (fLock)
+ m_pDdeObject->m_cLocks++;
+ else
+ {
+ if (m_pDdeObject->m_cLocks!=0 && 0 == --m_pDdeObject->m_cLocks &&
+ fLastUnlockReleases && !m_pDdeObject->m_fVisible)
+ (void)m_pDdeObject->m_Ole.Close (OLECLOSE_SAVEIFDIRTY);
+ }
+ return NOERROR;
+}
+
+
+#ifdef NOTNEEDED
+#pragma SEG(CDdeObject_CProxyManagerImpl_GetClassID)
+STDMETHODIMP_(void) NC(CDdeObject, CProxyManagerImpl)::GetClassID(CLSID FAR* pClsid)
+{
+ *pClsid = m_pDdeObject->m_clsid;
+}
+
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_GetOID)
+STDMETHODIMP_(OID) NC(CDdeObject, CProxyManagerImpl)::GetOID()
+{
+ if (m_pDdeObject->m_pSysChannel)
+ return (OID) m_pDdeObject->m_pSysChannel;
+
+ if (m_pDdeObject->m_pDocChannel)
+ return (OID) m_pDdeObject->m_pDocChannel;
+
+ return NULL;
+}
+#endif
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_IsConnected)
+STDMETHODIMP_(BOOL) NC(CDdeObject, CProxyManagerImpl)::IsConnected(void)
+{
+ return m_pDdeObject->m_pDocChannel != NULL;
+}
+
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_EstablishIID)
+STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::EstablishIID(REFIID iid, LPVOID FAR* ppv)
+{
+ // REVIEW: this is correct, but can we be smarter like in the real PM?
+ return QueryInterface(iid, ppv);
+}
+
+
+#pragma SEG(wTerminateIsComing)
+INTERNAL_(BOOL) wTerminateIsComing (LPDDE_CHANNEL pChannel)
+{
+ MSG msg;
+ return SSPeekMessage (&msg, pChannel->hwndCli, 0, 0, PM_NOREMOVE)
+ && msg.message == WM_DDE_TERMINATE
+ && (HWND)msg.wParam==pChannel->hwndSvr;
+}
+
+
+#pragma SEG(CDdeObject_CProxyManagerImpl_Disconnect)
+STDMETHODIMP_(void) NC(CDdeObject, CProxyManagerImpl)::Disconnect()
+{
+ intrDebugOut((DEB_ITRACE,"DdeObject::Disonnect(%x)\n",this));
+
+ if (m_pDdeObject->m_pDocChannel)
+ {
+ BOOL fTermComing = wTerminateIsComing (m_pDdeObject->m_pDocChannel);
+ if ((!m_pDdeObject->m_fNoStdCloseDoc
+ || (!m_pDdeObject->m_fWasEverVisible // invisible update or
+ && !m_pDdeObject->m_fDidGetObject // link from file case.
+ && m_pDdeObject->m_fDidStdOpenDoc)) // only do StdClose if did StdOpen
+ && !m_pDdeObject->m_fDidStdCloseDoc
+ && !fTermComing)
+ {
+ m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel,
+ wNewHandle ((LPSTR)&achStdCloseDocument,sizeof(achStdCloseDocument)),
+ /*fStdClose*/TRUE,
+ /*fWait*/TRUE,
+ /*fDetectTerminate*/TRUE);
+
+ m_pDdeObject->m_fDidStdCloseDoc = TRUE;
+ }
+ if (!m_pDdeObject->m_fDidSendOnClose /*|| fTermComing*/)
+ {
+ // if we did not call SendOnClose() then Disconnect() was called
+ // by a Release method, not by SendOnClose().
+ // This happens when user deletes object in container.
+ BOOL fVisible = m_pDdeObject->m_fWasEverVisible; // TermConv clears this flag
+ m_pDdeObject->TermConv (m_pDdeObject->m_pDocChannel);
+ if (!fVisible)
+ m_pDdeObject->MaybeUnlaunchApp();
+ }
+ }
+
+ if (m_pDdeObject->m_pSysChannel)
+ {
+ intrDebugOut((DEB_IWARN,"Terminating system conversation in Disconnect()\n"));
+ // This should never happen, I think.
+ m_pDdeObject->TermConv (m_pDdeObject->m_pSysChannel);
+ }
+}
+STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::CreateServerWithHandler (REFCLSID rclsid, DWORD clsctx, void *pv,
+ REFCLSID rclsidHandler, IID iidSrv, void **ppv,
+ IID iidClnt, void *pClientSiteInterface)
+{
+ return E_NOTIMPL;
+}
+
+
diff --git a/private/ole32/com/dde/client/ddewnd.cxx b/private/ole32/com/dde/client/ddewnd.cxx
new file mode 100644
index 000000000..de7c8b463
--- /dev/null
+++ b/private/ole32/com/dde/client/ddewnd.cxx
@@ -0,0 +1,361 @@
+/*++
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddewnd.cpp
+
+Abstract:
+
+ This module contains the code for the dde window procs
+
+Author:
+
+ Srini Koppolu (srinik) 20-June-1992
+
+Revision History:
+
+--*/
+#include "ddeproxy.h"
+
+
+
+#define SYS_MSG 0
+#define DOC_MSG 1
+
+// SysWndProc: Window Procedure for System Topic DDE conversations
+// wndproc for system topic
+
+
+STDAPI_(LRESULT) SysWndProc (
+ HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+)
+{
+ StackAssert(SSOnSmallStack());
+ CDdeObject FAR* pDdeObj = NULL;
+ LPDDE_CHANNEL pChannel = NULL;
+
+ if (message>=WM_DDE_FIRST && message <= WM_DDE_LAST)
+ {
+ if (pDdeObj = (CDdeObject FAR*) GetWindowLong (hwnd, 0))
+ {
+ pChannel = pDdeObj->GetSysChannel();
+ }
+
+ if (pChannel == NULL)
+ {
+ intrAssert(pChannel != NULL);
+ return SSDefWindowProc (hwnd, message, wParam, lParam);
+ }
+ }
+ if ( pChannel
+ && ( pChannel->iAwaitAck == AA_EXECUTE
+ || pChannel->iAwaitAck == AA_INITIATE) )
+ {
+ MSG msg;
+ BOOL fDisp = FALSE;
+ while (SSPeekMessage(&msg, hwnd, WM_DDE_ACK, WM_DDE_ACK, PM_REMOVE | PM_NOYIELD) )
+ {
+ intrDebugOut((DEB_WARN, "DDE SysWndProc: dispatching WM_DDE_ACK message (%x)\n",pChannel));
+ SSDispatchMessage(&msg);
+ fDisp = TRUE;
+ }
+ if (fDisp && (pDdeObj = (CDdeObject FAR*) GetWindowLong (hwnd, 0)))
+ {
+ pChannel = pDdeObj->GetSysChannel();
+ }
+
+ if (pChannel == NULL)
+ {
+ intrAssert(pChannel != NULL);
+ return SSDefWindowProc (hwnd, message, wParam, lParam);
+ }
+ }
+
+ switch (message){
+ case WM_DDE_ACK:
+ intrDebugOut((DEB_ITRACE,
+ "SWP: WM_DDE_ACK pChannel(%x)\n",pChannel));
+ if (pChannel->bTerminating)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "SWP: pChannel->bTerminating: no action\n"));
+
+ break;
+ }
+
+ switch (pChannel->iAwaitAck) {
+ case AA_INITIATE:
+ pDdeObj->OnInitAck (pChannel, (HWND)wParam);
+ if (LOWORD(lParam))
+ GlobalDeleteAtom (LOWORD(lParam));
+ if (HIWORD(lParam))
+ GlobalDeleteAtom (HIWORD(lParam));
+ break;
+
+ case AA_EXECUTE:
+ pDdeObj->OnAck (pChannel, lParam);
+ break;
+
+ default:
+ intrDebugOut((DEB_ITRACE,
+ "SWP: WM_DDE_ACK UnhandledpChannel(%x)\n",pChannel));
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ pDdeObj->OnTimer (pChannel);
+ break;
+
+ case WM_DDE_TERMINATE:
+ intrDebugOut((DEB_ITRACE,
+ "SWP: WM_DDE_TERMINATE pChannel(%x)\n",pChannel));
+ pDdeObj->OnTerminate (pChannel, (HWND)wParam);
+ break;
+
+ default:
+ return SSDefWindowProc (hwnd, message, wParam, lParam);
+ }
+
+ return 0L;
+}
+
+
+// ClientDocWndProc: Window procedure used to document DDE conversations
+STDAPI_(LRESULT) ClientDocWndProc (
+ HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+)
+{
+ StackAssert(SSOnSmallStack());
+ CDdeObject FAR* pDdeObj = NULL;
+ LPDDE_CHANNEL pChannel = NULL;
+ HANDLE hData;
+ ATOM aItem;
+
+ if (message>=WM_DDE_FIRST && message <= WM_DDE_LAST)
+ {
+
+ if (pDdeObj = (CDdeObject FAR*) GetWindowLong (hwnd, 0))
+ pChannel = pDdeObj->GetDocChannel();
+
+ if (pChannel == NULL)
+ {
+ //
+ // pChannel == NULL. Something is very wrong! But, lets
+ // not fault on it.
+ //
+ //intrAssert(pChannel != NULL);
+ return SSDefWindowProc (hwnd, message, wParam, lParam);
+ }
+
+ }
+ if ( pChannel
+ && ( pChannel->iAwaitAck == AA_EXECUTE
+ || pChannel->iAwaitAck == AA_INITIATE
+ || pChannel->iAwaitAck == AA_REQUESTAVAILABLE
+ || pChannel->iAwaitAck == AA_REQUEST
+ || pChannel->iAwaitAck == AA_UNADVISE
+ || pChannel->iAwaitAck == AA_EXECUTE
+ || pChannel->iAwaitAck == AA_ADVISE
+ || pChannel->iAwaitAck == AA_POKE) )
+ {
+ MSG msg;
+ BOOL fDisp = FALSE;
+ while (SSPeekMessage(&msg, hwnd, WM_DDE_ACK, WM_DDE_ACK, PM_REMOVE | PM_NOYIELD) )
+ {
+ intrDebugOut((DEB_WARN, "DDE DocWndProc: dispatching WM_DDE_ACK message (%x)\n",pChannel));
+ SSDispatchMessage(&msg);
+ fDisp = TRUE;
+ }
+
+ if (fDisp && (pDdeObj = (CDdeObject FAR*) GetWindowLong (hwnd, 0)))
+ {
+ pChannel = pDdeObj->GetDocChannel();
+ }
+
+ if (pChannel == NULL)
+ {
+ intrAssert(pChannel != NULL);
+ return SSDefWindowProc (hwnd, message, wParam, lParam);
+ }
+ }
+
+ switch (message)
+ {
+ case WM_DDE_ACK:
+
+ intrDebugOut((DEB_ITRACE,
+ "ClientWndProc: WM_DDE_ACK pChannel(%x)\n",
+ pChannel));
+ if (pChannel->bTerminating){
+ // ### this error recovery may not be correct.
+ DEBUG_OUT ("No action due to termination process",0)
+ break;
+ }
+
+ switch(pChannel->iAwaitAck){
+ case AA_INITIATE:
+ pDdeObj->OnInitAck (pChannel, (HWND)wParam);
+ if (LOWORD(lParam))
+ GlobalDeleteAtom (LOWORD(lParam));
+ if (HIWORD(lParam))
+ GlobalDeleteAtom (HIWORD(lParam));
+ break;
+
+ case AA_REQUESTAVAILABLE:
+ case AA_REQUEST:
+ case AA_UNADVISE:
+ case AA_EXECUTE:
+ case AA_ADVISE:
+ pDdeObj->OnAck (pChannel, lParam);
+ break;
+
+ case AA_POKE:
+ // freeing pokedata is done in handleack
+ pDdeObj->OnAck (pChannel, lParam);
+ break;
+
+ default:
+ intrDebugOut((DEB_IERROR,
+ "ClientWndProc: WM_DDE_ACK unhandled\n"));
+ break;
+
+ } // end of switch
+ break;
+
+ case WM_DDE_DATA:
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ pDdeObj->Guard();
+#endif // _CHICAGO_
+ hData = GET_WM_DDE_DATA_HDATA(wParam,lParam);
+ aItem = GET_WM_DDE_DATA_ITEM(wParam,lParam);
+ intrDebugOut((DEB_ITRACE,
+ "CWP: WM_DDE_DATA pChannel(%x) hData(%x) aItem(%x)\n",
+ pChannel,hData,aItem));
+ pDdeObj->OnData (pChannel, hData, aItem);
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ if (pDdeObj->UnGuard())
+ {
+ SetWindowLong(hwnd, 0, (LONG)0);
+ intrDebugOut((DEB_IWARN, "DDE ClientDocWndProc Release on pUnkOuter == 0 (this:%x, hwnd:%x\n",pDdeObj, hwnd ));
+ }
+#endif // _CHICAGO_
+
+ break;
+
+ case WM_DDE_TERMINATE:
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ pDdeObj->Guard();
+#endif // _CHICAGO_
+ intrDebugOut((DEB_ITRACE,
+ "CWP: WM_DDE_TERMINATE pChannel(%x)\n",pChannel));
+
+
+ if (pDdeObj->m_fDoingSendOnDataChange)
+ {
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ BOOL fPostMsg = TRUE;
+#endif
+ //
+ // Cheese alert! This protocol is very bad. The original
+ // 16 bit code something even more worse, so we are stuck
+ // to do something roughly compatible.
+ //
+ // If fDoingSendOnDataChange, the client may be asking for
+ // additional information from the server. The way the code
+ // is structured, it doesn't handle OnTerminate gracefully
+ // in this case.
+ //
+ // To fix this, we first tell the call control that
+ // the server has died. Then we repost the terminate
+ // message so we can handle it later.
+ //
+ // The old code did a
+ // pDdeObj->QueueMsg (hwnd, message, wParam, lParam);
+ //
+ // and the old SendOnDataChange removed the message.
+ // This probably didn't work either, but was never
+ // actually encountered.
+ //
+
+ intrDebugOut((DEB_ITRACE,
+ "CWP: term doing SendOnDataChange \n"));
+ //
+ // If we got here, there should be a CallData assigned
+ // to the channel.
+ //
+ if (pChannel->pCD)
+ {
+ intrDebugOut((DEB_ITRACE,"CWP: Setting call state\n"));
+
+ pChannel->SetCallState(SERVERCALLEX_ISHANDLED, RPC_E_SERVER_DIED);
+
+ }
+ else
+ {
+ //
+ // If there is no call data, then we aren't waiting in
+ // the channel. Terminate the conversation.
+ //
+
+ intrDebugOut((DEB_ERROR,"CWP: No call state exists\n"));
+ pDdeObj->OnTerminate (pChannel, (HWND)wParam);
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ fPostMsg = FALSE;
+#else
+ break;
+#endif //
+ }
+
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ if (fPostMsg)
+ {
+#endif
+ //
+ // Repost the message and try again.
+ //
+ intrDebugOut((DEB_ITRACE,"CWP: Reposting WM_DDE_TERMINATE\n"));
+ PostMessage(hwnd,message,wParam,lParam);
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ }
+#else
+ break;
+#endif
+
+ }
+ else
+ {
+ pDdeObj->OnTerminate (pChannel, (HWND)wParam);
+ }
+#ifdef _CHICAGO_
+ //Note:POSTPPC
+ if (pDdeObj->UnGuard())
+ {
+ SetWindowLong(hwnd, 0, (LONG)0);
+ intrDebugOut((DEB_IWARN, "DDE ClientDocWndProc Release on pUnkOuter == 0 (this:%x, hwnd:%x\n",pDdeObj, hwnd ));
+ }
+#endif // _CHICAGO_
+ break;
+
+ default:
+ return SSDefWindowProc (hwnd, message, wParam, lParam);
+
+ }
+
+ return 0L;
+}
diff --git a/private/ole32/com/dde/client/ddeworkr.cxx b/private/ole32/com/dde/client/ddeworkr.cxx
new file mode 100644
index 000000000..9d117db18
--- /dev/null
+++ b/private/ole32/com/dde/client/ddeworkr.cxx
@@ -0,0 +1,1331 @@
+/*++
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ddeworkr.cpp
+
+Abstract:
+
+ This module contains the code for the worker routines
+
+Author:
+
+ Srini Koppolu (srinik) 22-June-1992
+ Jason Fuller (jasonful) 24-July-1992
+
+Revision History:
+ Kevin Ross (KevinRo) 10-May-1994
+ Mostly added comments, and attempted to clean
+ it up.
+
+--*/
+#include "ddeproxy.h"
+
+ASSERTDATA
+
+/*
+ * WORKER ROUTINES
+ *
+ */
+
+
+INTERNAL_(BOOL) wPostMessageToServer(LPDDE_CHANNEL pChannel,
+ WORD wMsg,
+ LONG lParam,
+ BOOL fFreeOnError)
+{
+ int c=0;
+ intrDebugOut((DEB_ITRACE,
+ "wPostMessageToServer(pChannel=%x,wMsg=%x,lParam=%x,fFreeOnError=%x\n",
+ pChannel,
+ wMsg,
+ lParam,
+ fFreeOnError));
+ if (NULL==pChannel)
+ {
+ AssertSz (0, "Channel missing");
+ return FALSE;
+ }
+ pChannel->wMsg = wMsg;
+ pChannel->lParam = lParam;
+ pChannel->hres = NOERROR;
+
+ while (TRUE && c<10 )
+ {
+ if (!IsWindow (pChannel->hwndSvr))
+ {
+ intrDebugOut((DEB_IWARN,
+ "wPostMessageToServer: invalid window %x\n",
+ pChannel->hwndSvr));
+ goto errRet;
+ }
+ if (wTerminateIsComing (pChannel)
+ && wMsg != WM_DDE_ACK
+ && wMsg != WM_DDE_TERMINATE)
+ {
+ intrDebugOut((DEB_IWARN,"Server sent terminate, cannot post\n"));
+ goto errRet;
+ }
+ if (!PostMessage (pChannel->hwndSvr, wMsg, (WPARAM) pChannel->hwndCli, lParam))
+ {
+ intrDebugOut((DEB_IWARN,
+ "wPostMessageToServer: PostMessageFailed, yielding\n"));
+ Yield ();
+ c++;
+ }
+ else
+ return TRUE;
+ }
+ AssertSz (0, "PostMessage failed");
+
+errRet:
+ intrDebugOut((DEB_IWARN,"wPostMessageToServer returns FALSE\n"));
+ if (fFreeOnError)
+ {
+ DDEFREE(wMsg,lParam);
+ }
+
+ return FALSE;
+}
+
+
+// call Ole1ClassFromCLSID then global add atom; returns NULL if error.
+INTERNAL_(ATOM) wAtomFromCLSID(REFCLSID rclsid)
+{
+ WCHAR szClass[MAX_STR];
+ ATOM aCls;
+
+ if (Ole1ClassFromCLSID2(rclsid, szClass, sizeof(szClass)) == 0)
+ return NULL;
+ aCls = wGlobalAddAtom(szClass);
+ intrAssert(wIsValidAtom(aCls));
+ return aCls;
+}
+
+INTERNAL_(ATOM) wGlobalAddAtom(LPCOLESTR sz)
+{
+ if (sz==NULL || sz[0] == '\0')
+ {
+ return NULL;
+ }
+
+ ATOM a = GlobalAddAtom(sz);
+ intrAssert(wIsValidAtom(a));
+ return a;
+}
+
+INTERNAL_(ATOM) wGlobalAddAtomA(LPCSTR sz)
+{
+ if (sz==NULL || sz[0] == '\0')
+ return NULL;
+ ATOM a = GlobalAddAtomA(sz);
+ intrAssert(wIsValidAtom(a));
+ return a;
+}
+
+
+INTERNAL_(ATOM) wGetExeNameAtom (REFCLSID rclsid)
+{
+ LONG cb = MAX_STR;
+ WCHAR key[MAX_STR];
+ ATOM a;
+
+ if (Ole1ClassFromCLSID2(rclsid, key, sizeof(key)) == 0)
+ return NULL;
+
+ lstrcatW (key, OLESTR("\\protocol\\StdFileEditing\\server"));
+
+ if (RegQueryValue (HKEY_CLASSES_ROOT, key, key, &cb))
+ {
+ Puts ("ERROR: wGetExeNameAtom failed\n");
+ return NULL;
+ }
+ a = wGlobalAddAtom (key);
+ intrAssert(wIsValidAtom(a));
+ return a;
+}
+
+INTERNAL_(void) wFreeData (HANDLE hData, CLIPFORMAT cfFormat,
+ BOOL fFreeNonGdiHandle)
+{
+ intrDebugOut((DEB_ITRACE,
+ "wFreeData(hData=%x,cfFormat=%x,FreeNonGDIHandle=%x\n",
+ hData,
+ (USHORT)cfFormat,
+ fFreeNonGdiHandle));
+
+ AssertSz (hData != NULL, "Trying to free NULL handle");
+ AssertSz (hData != (HANDLE) 0xcccccccc, "Trying to free handle from a deleted object");
+
+ switch (cfFormat) {
+ case CF_METAFILEPICT:
+ LPMETAFILEPICT lpMfp;
+
+ if (lpMfp = (LPMETAFILEPICT) GlobalLock (hData))
+ {
+ intrDebugOut((DEB_ITRACE,
+ "wFreeData freeing metafile %x\n",
+ lpMfp->hMF));
+
+ OleDdeDeleteMetaFile(lpMfp->hMF);
+ GlobalUnlock (hData);
+ }
+ GlobalFree (hData);
+ break;
+
+ case CF_BITMAP:
+ case CF_PALETTE:
+ Verify(DeleteObject (hData));
+ break;
+
+ case CF_DIB:
+ GlobalFree (hData);
+ break;
+
+ default:
+ if (fFreeNonGdiHandle)
+ GlobalFree (hData);
+ break;
+ }
+}
+
+
+
+INTERNAL_(BOOL) wInitiate (LPDDE_CHANNEL pChannel, ATOM aLow, ATOM aHigh)
+{
+ intrDebugOut((DEB_ITRACE,"wInitiate(pChannel=%x,aLow=%x,aHigh=%x)\n",
+ pChannel, aLow, aHigh));
+
+ intrAssert(wIsValidAtom(aLow));
+ if (aLow == (ATOM)0)
+ {
+ intrDebugOut((DEB_IERROR,"wInitiate Failed, aLow == 0\n"));
+ return FALSE;
+ }
+
+ pChannel->iAwaitAck = AA_INITIATE;
+
+ SSSendMessage ((HWND)-1, WM_DDE_INITIATE, (WPARAM) pChannel->hwndCli,
+ MAKE_DDE_LPARAM (WM_DDE_INITIATE, aLow, aHigh));
+
+ pChannel->iAwaitAck = NULL;
+
+ intrDebugOut((DEB_ITRACE,
+ "wInitiate pChannel->hwndSrvr = %x\n",
+ pChannel->hwndSvr));
+
+ return (pChannel->hwndSvr != NULL);
+}
+
+
+
+INTERNAL_(HRESULT) wScanItemOptions (ATOM aItem, int FAR* lpoptions)
+{
+ ATOM aModifier;
+ LPOLESTR lpbuf;
+ WCHAR buf[MAX_STR];
+
+ *lpoptions = ON_CHANGE; // default
+
+ if (!aItem) {
+ // NULL item with no modifier means ON_CHANGE for NULL item
+ return NOERROR;
+ }
+
+ intrAssert(wIsValidAtom(aItem));
+ GlobalGetAtomName (aItem, buf, MAX_STR);
+ lpbuf = buf;
+
+ while ( *lpbuf && *lpbuf != '/')
+ IncLpch (lpbuf);
+
+ // no modifier same as /change
+
+ if (*lpbuf == NULL)
+ return NOERROR;
+
+ *lpbuf++ = NULL; // seperate out the item string
+ // We are using this in the caller.
+
+ if (!(aModifier = GlobalFindAtom (lpbuf)))
+ {
+ Puts ("ERROR: wScanItemOptions found non-atom modifier\n");
+ return ReportResult(0, RPC_E_DDE_SYNTAX_ITEM, 0, 0);
+ }
+
+ intrAssert(wIsValidAtom(aModifier));
+
+ if (aModifier == aChange)
+ return NOERROR;
+
+ // Is it a save?
+ if (aModifier == aSave){
+ *lpoptions = ON_SAVE;
+ return NOERROR;
+ }
+ // Is it a Close?
+ if (aModifier == aClose){
+ *lpoptions = ON_CLOSE;
+ return NOERROR;
+ }
+
+ // unknown modifier
+ Puts ("ERROR: wScanItemOptions found bad modifier\n");
+ return ReportResult(0, RPC_E_DDE_SYNTAX_ITEM, 0, 0);
+}
+
+
+INTERNAL_(BOOL) wClearWaitState (LPDDE_CHANNEL pChannel)
+{
+ Assert (pChannel);
+ // kill if any timer active.
+ if (pChannel->wTimer) {
+ KillTimer (pChannel->hwndCli, 1);
+ pChannel->wTimer = 0;
+
+ if (pChannel->hDdePoke) {
+ GlobalFree (pChannel->hDdePoke);
+ pChannel->hDdePoke = NULL;
+ }
+
+ if (pChannel->hopt) {
+ GlobalFree (pChannel->hopt);
+ pChannel->hopt = NULL;
+ }
+
+ //
+ // If the channel is waiting on an Ack, and there is an
+ // lParam, then we may need to cleanup the data.
+
+ if (pChannel->iAwaitAck && (pChannel->lParam)) {
+ if (pChannel->iAwaitAck == AA_EXECUTE)
+ {
+ //
+ // KevinRo: Found the following comment in the code.
+ // ; // BUGBUG32 - get hData from GET_WM_DDE_EXECUTE_HADATA ??
+ // It appears, by looking at what the 16-bit code does,
+ // that the goal is to free the handle that was passed as
+ // part of the EXECUTE message. Judging by what the 16-bit
+ // code did, I have determined that this is correct.
+ //
+ // The macro used below wanted two parameters. The first was
+ // the WPARAM, the second the LPARAM. We don't have the WPARAM.
+ // However, it isn't actually used by the macro, so I have
+ // cheated and provided 0 as a default
+ //
+ GlobalFree(GET_WM_DDE_EXECUTE_HDATA(0,pChannel->lParam));
+
+#ifdef KEVINRO_HERE_IS_THE_16_BIT_CODE
+ GlobalFree (HIWORD (pChannel->lParam));
+#endif
+ }
+ else
+ {
+ //
+ // All of the other DDE messages pass an Atom in the high word.
+ // Therefore, we should delete the atom.
+ //
+ //
+ ATOM aTmp;
+
+ aTmp = MGetDDElParamHi(pChannel->wMsg,pChannel->lParam);
+
+ intrAssert(wIsValidAtom(aTmp));
+ if (aTmp)
+ {
+ GlobalDeleteAtom (aTmp);
+ }
+ }
+ DDEFREE(pChannel->wMsg,pChannel->lParam);
+
+ // we want to wipe out the lParam
+ pChannel->lParam = 0x0;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+// wNewHandle (LPSTR, DWORD)
+//
+// Copy cb bytes from lpstr into a new memory block and return a handle to it.
+// If lpstr is an ASCIIZ string, cb must include 1 for the null terminator.
+//
+
+INTERNAL_(HANDLE) wNewHandle (LPSTR lpstr, DWORD cb)
+{
+
+ HANDLE hdata = NULL;
+ LPSTR lpdata = NULL;
+
+ hdata = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, cb);
+ if (hdata == NULL || (lpdata = (LPSTR) GlobalLock (hdata)) == NULL)
+ goto errRtn;
+
+ memcpy (lpdata, lpstr, cb);
+ GlobalUnlock (hdata);
+ return hdata;
+
+errRtn:
+ Puts ("ERROR: wNewHandle\n");
+ Assert (0);
+ if (lpdata)
+ GlobalUnlock (hdata);
+
+ if (hdata)
+ GlobalFree (hdata);
+ return NULL;
+}
+
+
+
+// wDupData
+//
+// Copy data from handle h into a new handle which is returned as *ph.
+//
+
+INTERNAL wDupData (LPHANDLE ph, HANDLE h, CLIPFORMAT cf)
+{
+ Assert (ph);
+ RetZ (wIsValidHandle(h, cf));
+ *ph = OleDuplicateData (h, cf, GMEM_DDESHARE | GMEM_MOVEABLE);
+ RetZ (wIsValidHandle (*ph, cf));
+ return NOERROR;
+}
+
+
+// wTransferHandle
+//
+//
+INTERNAL wTransferHandle
+ (LPHANDLE phDst,
+ LPHANDLE phSrc,
+ CLIPFORMAT cf)
+{
+ RetErr (wDupData (phDst, *phSrc, cf));
+ wFreeData (*phSrc, cf, TRUE);
+ *phSrc = (HANDLE)0;
+ return NOERROR;
+}
+
+
+// wHandleCopy
+//
+// copy data from hSrc to hDst.
+// Both handles must already have memory allocated to them.
+//
+
+INTERNAL wHandleCopy (HANDLE hDst, HANDLE hSrc)
+{
+ LPSTR lpDst, lpSrc;
+ DWORD dwSrc;
+
+ if (NULL==hDst || NULL==hSrc)
+ return ResultFromScode (E_INVALIDARG);
+ if (GlobalSize(hDst) < (dwSrc=GlobalSize(hSrc)))
+ {
+ HANDLE hDstNew = GlobalReAlloc (hDst, dwSrc, GMEM_DDESHARE | GMEM_MOVEABLE);
+ if (hDstNew != hDst)
+ return ResultFromScode (E_OUTOFMEMORY);
+ }
+ if (!(lpDst = (LPSTR) GlobalLock(hDst)))
+ {
+ intrAssert(!"ERROR: wHandleCopy hDst");
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+ if (!(lpSrc = (LPSTR) GlobalLock(hSrc)))
+ {
+ GlobalUnlock(hDst);
+ intrAssert (!"ERROR: wHandleCopy hSrc");
+ return ReportResult(0, E_OUTOFMEMORY, 0, 0);
+ }
+ memcpy (lpDst, lpSrc, dwSrc);
+ GlobalUnlock(hDst);
+ GlobalUnlock(hSrc);
+ return NOERROR;
+}
+
+
+// ExtendAtom: Create a new atom, which is the old one plus extension
+
+INTERNAL_(ATOM) wExtendAtom (ATOM aItem, int iAdvOn)
+{
+ WCHAR buffer[MAX_STR+1];
+ LPOLESTR lpext;
+
+ buffer[0] = 0;
+ // aItem==NULL for embedded objects.
+ // If so, there is no item name before the slash.
+ if (aItem)
+ GlobalGetAtomName (aItem, buffer, MAX_STR);
+
+ switch (iAdvOn) {
+ case ON_CHANGE:
+ lpext = OLESTR("");
+ break;
+
+ case ON_SAVE:
+ lpext = OLESTR("/Save");
+ break;
+
+ case ON_CLOSE:
+ lpext = OLESTR("/Close");
+ break;
+
+ default:
+ AssertSz (FALSE, "Unknown Advise option");
+ break;
+
+ }
+
+ lstrcatW (buffer, lpext);
+ if (buffer[0])
+ return wGlobalAddAtom (buffer);
+ else
+ return NULL;
+ // not an error. For embedded object on-change, aItem==NULL
+}
+
+
+
+
+INTERNAL_(ATOM) wDupAtom (ATOM a)
+{
+ WCHAR sz[MAX_STR];
+
+ if (!a)
+ return NULL;
+
+ Assert (wIsValidAtom (a));
+ GlobalGetAtomName (a, sz, MAX_STR);
+ return wGlobalAddAtom (sz);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: wAtomLen
+//
+// Synopsis: Return the length, in characters, of the atom name.
+// The length includes the NULL. This function returns the
+// length of the UNICODE version of the atom.
+//
+// Effects:
+//
+// Arguments: [atom] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL_(int) wAtomLen (ATOM atom)
+{
+ WCHAR buf[MAX_STR];
+
+ if (!atom)
+ return NULL;
+
+ return (GlobalGetAtomName (atom, buf, MAX_STR));
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: wAtomLenA
+//
+// Synopsis: Return the length, in characters, of the atom name.
+// The length includes the NULL This function returns the
+// length of the ANSI version of the atom,
+//
+// Effects:
+//
+// Arguments: [atom] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL_(int) wAtomLenA (ATOM atom)
+{
+ char buf[MAX_STR];
+
+ if (!atom)
+ return NULL;
+
+ return (GlobalGetAtomNameA (atom, (LPSTR)buf, MAX_STR));
+}
+
+
+
+// NOTE: returns address of static buffer. Use return value immediately.
+//
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: wAtomName
+//
+// Synopsis: Returns a STATIC BUFFER that holds the string name of the
+// atom.
+//
+// Effects:
+//
+// Arguments: [atom] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Commented
+//
+// Notes:
+//
+// WARNING: This uses a static buffer, so don't depend on the pointer for
+// very long.
+//
+//----------------------------------------------------------------------------
+INTERNAL_(LPOLESTR) wAtomName (ATOM atom)
+{
+ static WCHAR buf[MAX_STR];
+
+ if (!atom)
+ return NULL;
+
+ if (0==GlobalGetAtomName (atom, buf, MAX_STR))
+ return NULL;
+
+ return buf;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: wAtomName
+//
+// Synopsis: Returns a STATIC BUFFER that holds the string name of the
+// atom.
+//
+// Effects:
+//
+// Arguments: [atom] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-12-94 kevinro Commented
+//
+// Notes:
+//
+// WARNING: This uses a static buffer, so don't depend on the pointer for
+// very long.
+//
+//----------------------------------------------------------------------------
+INTERNAL_(LPSTR) wAtomNameA (ATOM atom)
+{
+ static char buf[MAX_STR];
+
+ if (!atom)
+ return NULL;
+
+ if (0==GlobalGetAtomNameA (atom, (LPSTR)buf, MAX_STR))
+ return NULL;
+
+ return buf;
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: wHandleFromDdeData
+//
+// Synopsis: Return a handle from the DDEDATA passed in.
+//
+// Effects: This function will return the correct data from the
+// DDEDATA that is referenced by the handle passed in.
+//
+// DDEDATA is a small structure that is used in DDE to
+// specify the data type of the buffer, its release
+// semantics, and the actual data.
+//
+// In the case of a known format, the handle to the
+// data is extracted from the DDEDATA structure, and
+// the hDdeData is released.
+//
+// If its a Native format, the data is either moved
+// within the memory block allocated, or is copied to
+// another block, depending on the fRelease flag in
+// the hDdeData.
+//
+// Arguments: [hDdeData] -- Handle to DDEDATA
+//
+// Requires:
+//
+// Returns: A handle to the data. hDdeData will be invalidated
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 5-13-94 kevinro Commented
+//
+// Notes:
+//
+// hDdeData is invalid after calling this function
+//
+//----------------------------------------------------------------------------
+
+
+INTERNAL_(HANDLE) wHandleFromDdeData
+ (HANDLE hDdeData)
+{
+ intrDebugOut((DEB_ITRACE,"wHandleFromDdeData(%x)\n",hDdeData));
+ BOOL fRelease;
+ HGLOBAL h = NULL; // return value
+
+ DDEDATA FAR* lpDdeData = (DDEDATA FAR *) GlobalLock (hDdeData);
+
+ //
+ // If the handle is invalid, then the lpDdeData will be NULL
+ //
+ if (!lpDdeData)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "\twHandleFromDdeData(%x) invalid handle\n",
+ hDdeData));
+ return NULL;
+ }
+
+
+ //
+ // The header section of a DDEDATA consists of 2 shorts.
+ // That makes it 4 bytes. Due to the new packing values,
+ // it turns out that doing a sizeof(DDEDATA) won't work,
+ // because the size gets rounded up to a multple of 2
+ //
+ // We will just hard code the 4 here, since it cannot change
+ // for all time anyway.
+ //
+ #define cbHeader 4
+ Assert (cbHeader==4);
+
+ //
+ // If the cfFormat is BITMAP or METAFILEPICT, then the
+ // handle will be retrieved from the first DWORD of the
+ // buffer
+ //
+ if (lpDdeData->cfFormat == CF_BITMAP ||
+ lpDdeData->cfFormat == CF_METAFILEPICT)
+ {
+ //
+ // The alignment here should be fine, since the Value
+ // field is DWORD aligned. So, we trust this cast
+ //
+ h = *(LPHANDLE)lpDdeData->Value;
+ Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE);
+ fRelease = lpDdeData->fRelease;
+ GlobalUnlock (hDdeData);
+ if (fRelease)
+ {
+ GlobalFree (hDdeData);
+ }
+
+ return h;
+ }
+ else if (lpDdeData->cfFormat == CF_DIB)
+ {
+ //
+ // The alignment here should be fine, since the Value
+ // field is DWORD aligned.
+ //
+ // This changes the memory from fixed to moveable.
+ //
+ h = GlobalReAlloc (*(LPHANDLE)lpDdeData->Value, 0L,
+ GMEM_MODIFY|GMEM_MOVEABLE);
+ Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE);
+ fRelease = lpDdeData->fRelease;
+ GlobalUnlock (hDdeData);
+ if (fRelease)
+ GlobalFree (hDdeData);
+ return h;
+ }
+
+
+ // Native and other data case
+ // dwSize = size of Value array, ie, size of the data itself
+ const DWORD dwSize = GlobalSize (hDdeData) - cbHeader;
+
+ if (lpDdeData->fRelease)
+ {
+ // Move the Value data up over the DDE_DATA header flags.
+ memcpy ((LPSTR)lpDdeData, ((LPSTR)lpDdeData)+cbHeader, dwSize);
+ GlobalUnlock (hDdeData);
+ h = GlobalReAlloc (hDdeData, dwSize, GMEM_MOVEABLE);
+ Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE);
+ return h;
+ }
+ else
+ {
+ // Duplicate the data because the server will free the original.
+ h = wNewHandle (((LPSTR)lpDdeData)+cbHeader, dwSize);
+ Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE);
+ GlobalUnlock (hDdeData);
+ return h;
+ }
+}
+
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDdeObject::CanCallBack
+//
+// Synopsis: This routine apparently was supposed to determine if a
+// call back could be made. However, the PeekMessage stuff
+// was commented out.
+//
+// So, it returns TRUE if 0 or 1, FALSE but increments lpCount
+// if 2, returns true but decrements lpCount if > 3. Why?
+// Dunno. Need to ask JasonFul
+//
+// Effects:
+//
+// Arguments: [lpCount] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-16-94 kevinro Commented, confused, and disgusted
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL_(BOOL) CDdeObject::CanCallBack (LPINT lpCount)
+{
+ switch (*lpCount) {
+ case 0:
+ case 1:
+ return TRUE;
+
+ case 2:
+ {
+// MSG msg;
+ if (0)
+ //!PeekMessage (&msg, m_pDocChannel->hwndCli,0,0, PM_NOREMOVE) ||
+ // msg.message != WM_DDE_DATA)
+ {
+ Puts ("Server only sent one format (hopefully presentation)\n");
+ return TRUE;
+ }
+ else
+ {
+ ++(*lpCount);
+ return FALSE;
+ }
+ }
+
+ case 3:
+ --(*lpCount);
+ return TRUE;
+
+ default:
+ AssertSz (FALSE, "012345" + *lpCount);
+ return FALSE;
+ }
+}
+
+
+INTERNAL_(BOOL) wIsOldServer (ATOM aClass)
+{
+ LONG cb = MAX_STR;
+ WCHAR key[MAX_STR];
+ int len;
+
+ if (aClass==(ATOM)0)
+ return FALSE;
+
+ if (!GlobalGetAtomName (aClass, key, sizeof(key)))
+ return TRUE;
+
+ lstrcatW (key, OLESTR("\\protocol\\StdFileEditing\\verb\\"));
+ len = lstrlenW (key);
+ key [len++] = (char) ('0');
+ key [len++] = 0;
+
+ if (RegQueryValue (HKEY_CLASSES_ROOT, key, key, &cb))
+ return TRUE; // no verbs registered
+
+ return FALSE;
+}
+
+
+
+
+INTERNAL_(void) wFreePokeData
+ (LPDDE_CHANNEL pChannel,
+ BOOL fMSDrawBug)
+{
+ DDEPOKE FAR * lpdde;
+
+ if (!pChannel )
+ return;
+
+ if (!pChannel->hDdePoke)
+ return;
+
+ if (lpdde = (DDEPOKE FAR *) GlobalLock (pChannel->hDdePoke)) {
+
+ // The old version of MSDraw expects the _contents_ of METAFILEPICT
+ // structure, rather than the handle to it, to be part of DDEPOKE.
+
+ if (fMSDrawBug && lpdde->cfFormat==CF_METAFILEPICT) {
+ intrDebugOut((DEB_ITRACE,
+ "wFreePokeData is accomodating MSDraw bug\n"));
+ //
+ // This meta file was created in 32-bits, and was not passed
+ // into us by DDE. Therefore, this metafile should not need to
+ // call WOW to be free'd.
+ //
+ DeleteMetaFile (((LPMETAFILEPICT) ((LPVOID) &lpdde->Value))->hMF);
+ }
+ // If there is a normal metafile handle in the Value field,
+ // it will be freed (if necessary) by the ReleaseStgMedium()
+ // in DO::SetData
+ GlobalUnlock (pChannel->hDdePoke);
+ }
+ GlobalFree (pChannel->hDdePoke);
+ pChannel->hDdePoke = NULL;
+}
+
+
+
+
+INTERNAL_(HANDLE) wPreparePokeBlock
+ (HANDLE hData, CLIPFORMAT cfFormat, ATOM aClass, BOOL bOldSvr)
+{
+ HANDLE hDdePoke;
+ LPSTR lpBuf;
+
+ if (!hData)
+ return NULL;
+
+ // The old version of MSDraw expects the contents of METAFILEPICT
+ // structure to be part of DDEPOKE, rather than the handle to it.
+ if ((cfFormat==CF_METAFILEPICT && !(aClass==aMSDraw && bOldSvr))
+ || (cfFormat == CF_DIB)
+ || (cfFormat == CF_BITMAP)) {
+
+ Verify (lpBuf = wAllocDdePokeBlock (4, cfFormat, &hDdePoke));
+ *((HANDLE FAR*)lpBuf) = hData;
+
+ }
+ else {
+ // Handle the non-metafile case and the MS-Draw bug
+ DWORD dwSize = GlobalSize (hData);
+
+ if ((aClass == aMSDraw) && bOldSvr)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "wPreparePokeBlock is accomodating MSDraw bug\n"));
+ }
+
+ if (lpBuf = wAllocDdePokeBlock (dwSize, cfFormat, &hDdePoke)) {
+ memcpy (lpBuf, GlobalLock(hData), dwSize);
+ GlobalUnlock (hData);
+ }
+ }
+ GlobalUnlock (hDdePoke);
+ return hDdePoke;
+}
+
+
+// wAllocDdePokeBlock
+// The caller must unlock *phDdePoke when it is done using the return value
+// of this function but before a DDe message is sent using *phDdePoke.
+//
+
+INTERNAL_(LPSTR) wAllocDdePokeBlock
+ (DWORD dwSize, CLIPFORMAT cfFormat, LPHANDLE phDdePoke)
+{
+ HANDLE hdde = NULL;
+ DDEPOKE FAR * lpdde = NULL;
+
+ if (!(hdde = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT,
+ (dwSize + sizeof(DDEPOKE) - sizeof(BYTE) ))))
+ return NULL;
+
+ if (!(lpdde = (DDEPOKE FAR*)GlobalLock (hdde))) {
+ GlobalFree (hdde);
+ return NULL;
+ }
+ // hdde will be UnLock'ed in wPreparePokeBlock and Free'd in wFreePokeData
+ lpdde->fRelease = FALSE;
+ lpdde->cfFormat = cfFormat;
+ *phDdePoke = hdde;
+ return (LPSTR) &(lpdde->Value);
+}
+
+
+#ifdef OLD
+INTERNAL_(ULONG) wPixelsToHiMetric
+ (ULONG cPixels,
+ ULONG cPixelsPerInch)
+{
+ return cPixels * HIMETRIC_PER_INCH / cPixelsPerInch;
+}
+#endif
+
+// Can ask for icon based on either CLSID or filename
+//
+
+INTERNAL GetDefaultIcon (REFCLSID clsidIn, LPCOLESTR szFile, HANDLE FAR* phmfp)
+{
+ if (!(*phmfp = OleGetIconOfClass(clsidIn, NULL, TRUE)))
+ return ResultFromScode(E_OUTOFMEMORY);
+
+ return NOERROR;
+}
+
+#ifdef OLD
+ VDATEPTROUT (phmfp, HICON);
+ VDATEPTRIN (szFile, char);
+ WCHAR szExe[MAX_STR];
+ HICON hicon;
+ HDC hdc;
+ METAFILEPICT FAR* pmfp=NULL;
+ HRESULT hresult;
+ static int cxIcon = 0;
+ static int cyIcon = 0;
+ static int cxIconHiMetric = 0;
+ static int cyIconHiMetric = 0;
+
+ *phmfp = NULL;
+ CLSID clsid;
+ if (clsidIn != CLSID_NULL)
+ {
+ clsid = clsidIn;
+ }
+ else
+ {
+ RetErr (GetClassFile (szFile, &clsid));
+ }
+ ATOM aExe = wGetExeNameAtom (clsid);
+ if (0==GlobalGetAtomName (aExe, szExe, MAX_STR))
+ {
+ Assert (0);
+ return ReportResult(0, E_UNEXPECTED, 0, 0);
+ }
+ hicon = ExtractIcon (hmodOLE2, szExe, 0/*first icon*/);
+ if (((HICON) 1)==hicon || NULL==hicon)
+ {
+ // ExtractIcon failed, so we can't support DVASPECT_ICON
+ return ResultFromScode (DV_E_DVASPECT);
+ }
+ *phmfp = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(METAFILEPICT));
+ ErrZS (*phmfp, E_OUTOFMEMORY);
+ pmfp = (METAFILEPICT FAR*) GlobalLock (*phmfp);
+ ErrZS (pmfp, E_OUTOFMEMORY);
+ if (0==cxIcon)
+ {
+ // In units of pixels
+ Verify (cxIcon = GetSystemMetrics (SM_CXICON));
+ Verify (cyIcon = GetSystemMetrics (SM_CYICON));
+ // In units of .01 millimeter
+ cxIconHiMetric = (int)(long)wPixelsToHiMetric (cxIcon, giPpliX) ;
+ cyIconHiMetric = (int)(long)wPixelsToHiMetric (cyIcon, giPpliY) ;
+ }
+ pmfp->mm = MM_ANISOTROPIC;
+ pmfp->xExt = cxIconHiMetric;
+ pmfp->yExt = cyIconHiMetric;
+ hdc = CreateMetaFile (NULL);
+ SetWindowOrg (hdc, 0, 0);
+ SetWindowExt (hdc, cxIcon, cyIcon);
+ DrawIcon (hdc, 0, 0, hicon);
+ pmfp->hMF = CloseMetaFile (hdc);
+ ErrZ (pmfp->hMF);
+ Assert (wIsValidHandle (pmfp->hMF, NULL));
+ GlobalUnlock (*phmfp);
+ Assert (wIsValidHandle (*phmfp, CF_METAFILEPICT));
+ return NOERROR;
+
+ errRtn:
+ if (pmfp)
+ GlobalUnlock (*phmfp);
+ if (*phmfp)
+ GlobalFree (*phmfp);
+ return hresult;
+}
+#endif
+
+#define DWTIMEOUT 1000L
+
+INTERNAL wTimedGetMessage
+ (LPMSG pmsg,
+ HWND hwnd,
+ WORD wFirst,
+ WORD wLast)
+{
+ DWORD dwStartTickCount = GetTickCount();
+ while (!SSPeekMessage (pmsg, hwnd, wFirst, wLast, PM_REMOVE))
+ {
+ if (GetTickCount() - dwStartTickCount > DWTIMEOUT)
+ {
+ if (!IsWindow (hwnd))
+ return ResultFromScode (RPC_E_CONNECTION_LOST);
+ else
+ return ResultFromScode (RPC_E_SERVER_DIED);
+ }
+ }
+ return NOERROR;
+}
+
+
+INTERNAL wNormalize
+ (LPFORMATETC pformatetcIn,
+ LPFORMATETC pformatetcOut)
+{
+ if (pformatetcIn->cfFormat == 0
+ && pformatetcIn->ptd == NULL // Is WildCard
+ && pformatetcIn->dwAspect == -1L
+ && pformatetcIn->lindex == -1L
+ && pformatetcIn->tymed == -1L)
+ {
+ pformatetcOut->cfFormat = CF_METAFILEPICT;
+ pformatetcOut->ptd = NULL;
+ pformatetcOut->dwAspect = DVASPECT_CONTENT;
+ pformatetcOut->lindex = DEF_LINDEX;
+ pformatetcOut->tymed = TYMED_MFPICT;
+ }
+ else
+ {
+ memcpy (pformatetcOut, pformatetcIn, sizeof(FORMATETC));
+ }
+ return NOERROR;
+}
+
+
+
+INTERNAL wVerifyFormatEtc
+ (LPFORMATETC pformatetc)
+{
+ intrDebugOut((DEB_ITRACE,
+ "wVerifyFormatEtc(pformatetc=%x)\n",
+ pformatetc));
+
+ VDATEPTRIN (pformatetc, FORMATETC);
+ if (!HasValidLINDEX(pformatetc))
+ {
+ intrDebugOut((DEB_IERROR, "\t!HasValidLINDEX(pformatetc)\n"));
+ return(DV_E_LINDEX);
+ }
+
+ if (0==(pformatetc->tymed & (TYMED_HGLOBAL | TYMED_MFPICT | TYMED_GDI)))
+ {
+ intrDebugOut((DEB_IERROR,
+ "\t0==(pformatetc->tymed & (TYMED_HGLOBAL | TYMED_MFPICT | TYMED_GDI))\n"));
+ return ResultFromScode (DV_E_TYMED);
+ }
+ if (0==(UtFormatToTymed (pformatetc->cfFormat) & pformatetc->tymed))
+ {
+ intrDebugOut((DEB_IERROR,
+ "\t0==(UtFormatToTymed (pformatetc->cfFormat) & pformatetc->tymed)\n"));
+ return ResultFromScode (DV_E_TYMED);
+ }
+ if (0==(pformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON)))
+ {
+ intrDebugOut((DEB_IERROR,
+ "\t0==(pformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON))\n"));
+
+ return ResultFromScode (DV_E_DVASPECT);
+ }
+ if (pformatetc->dwAspect & DVASPECT_ICON)
+ {
+ if (CF_METAFILEPICT != pformatetc->cfFormat)
+ {
+ intrDebugOut((DEB_IERROR,
+ "\tCF_METAFILEPICT != pformatetc->cfFormat\n"));
+ return ResultFromScode (DV_E_CLIPFORMAT);
+ }
+
+ if (0==(pformatetc->tymed & TYMED_MFPICT))
+ {
+ intrDebugOut((DEB_IERROR,
+ "\t0==(pformatetc->tymed & TYMED_MFPICT)\n"));
+ return ResultFromScode (DV_E_TYMED);
+ }
+ }
+ if (pformatetc->ptd)
+ {
+ if (IsBadReadPtr (pformatetc->ptd, sizeof (DWORD))
+ || IsBadReadPtr (pformatetc->ptd, (size_t)pformatetc->ptd->tdSize))
+ {
+ intrDebugOut((DEB_IERROR,"\tDV_E_DVTARGETDEVICE\n"));
+
+ return ResultFromScode (DV_E_DVTARGETDEVICE);
+ }
+ }
+ return NOERROR;
+}
+
+
+
+INTERNAL wClassesMatch
+ (REFCLSID clsidIn,
+ LPOLESTR szFile)
+{
+ CLSID clsid;
+ if (NOERROR==GetClassFile (szFile, &clsid))
+ {
+ return clsid==clsidIn ? NOERROR : ResultFromScode (S_FALSE);
+ }
+ else
+ {
+ // If we can't determine the class of the file (because it's
+ // not a real file) then OK. Bug 3937.
+ return NOERROR;
+ }
+}
+
+
+
+#ifdef KEVINRO_DUPLICATECODE
+
+This routine also appears in ole1.lib in the OLE232\OLE1 directory
+
+INTERNAL wWriteFmtUserType
+ (LPSTORAGE pstg,
+ REFCLSID clsid)
+{
+ HRESULT hresult = NOERROR;
+ LPOLESTR szProgID = NULL;
+ LPOLESTR szUserType = NULL;
+
+ ErrRtnH (ProgIDFromCLSID (clsid, &szProgID));
+ ErrRtnH (OleRegGetUserType (clsid, USERCLASSTYPE_FULL, &szUserType));
+ ErrRtnH (WriteFmtUserTypeStg (pstg, RegisterClipboardFormat (szProgID),
+ szUserType));
+ errRtn:
+ delete szProgID;
+ delete szUserType;
+ return hresult;
+}
+#endif
+
+#if DBG == 1
+
+INTERNAL_(BOOL) wIsValidHandle
+ (HANDLE h,
+ CLIPFORMAT cf) // cf==NULL means normal memory
+{
+ LPVOID p;
+ if (CF_BITMAP == cf)
+ {
+ BITMAP bm;
+ return (0 != GetObject (h, sizeof(BITMAP), (LPVOID) &bm));
+ }
+ if (CF_PALETTE == cf)
+ {
+ WORD w;
+ return (0 != GetObject (h, sizeof(w), (LPVOID) &w));
+ }
+ if (!(p=GlobalLock(h)))
+ {
+ Puts ("Invalid handle");
+ Puth (h);
+ Putn();
+ return FALSE;
+ }
+ if (IsBadReadPtr (p, (WPARAM) min (UINT_MAX, GlobalSize(h))))
+ {
+ GlobalUnlock (h);
+ return FALSE;
+ }
+ GlobalUnlock (h);
+ return TRUE;
+}
+INTERNAL_(BOOL) wIsValidAtom (ATOM a)
+{
+ WCHAR sz[MAX_STR];
+ if (a==0)
+ return TRUE;
+ if (a < 0xC000)
+ return FALSE;
+ if (0==GlobalGetAtomName (a, sz, MAX_STR))
+ return FALSE;
+ if ('\0'==sz[0])
+ return FALSE;
+ return TRUE;
+}
+
+
+// A "gentle" assert used in reterr.h
+//
+
+
+INTERNAL_(void) wWarn
+ (LPSTR sz,
+ LPSTR szFile,
+ int iLine)
+{
+ intrDebugOut((DEB_WARN,
+ "Warning: %s:%u %s\n",
+ szFile,iLine,sz));
+}
+
+#endif // DBG
+
+
diff --git a/private/ole32/com/dde/client/dirs b/private/ole32/com/dde/client/dirs
new file mode 100644
index 000000000..820fa2392
--- /dev/null
+++ b/private/ole32/com/dde/client/dirs
@@ -0,0 +1,37 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+#
+# This is a list of all subdirectories that build required components.
+# Each subdirectory name should appear on a line by itself. The build
+# follows the order in which the subdirectories are specified.
+#
+
+DIRS=
+
+#
+# This is a list of all subdirectories that build optional components.
+# Each subdirectory name should appear on a line by itself. The build
+# follows the order in which the subdirectories are specified.
+#
+
+OPTIONAL_DIRS= \
+ \
+ daytona
diff --git a/private/ole32/com/dde/client/modallp.cxx b/private/ole32/com/dde/client/modallp.cxx
new file mode 100644
index 000000000..a9faa18c1
--- /dev/null
+++ b/private/ole32/com/dde/client/modallp.cxx
@@ -0,0 +1,315 @@
+/*
+
+copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ modallp.cpp
+
+Abstract:
+
+ This module contains the code to wait for reply on a remote call.
+
+Author:
+ Johann Posch (johannp) 01-March-1993 modified to use CoRunModalLoop
+
+*/
+
+#include "ddeproxy.h"
+
+
+#define DebWarn(x)
+#define DebError(x)
+#define DebAction(x)
+#if DBG==1
+static unsigned iCounter=0;
+#endif
+//
+// Called after posting a message (call) to a server
+//
+#pragma SEG(CDdeObject_WaitForReply)
+
+
+
+INTERNAL CDdeObject::SendMsgAndWaitForReply
+ (LPDDE_CHANNEL pChannel,
+ int iAwaitAck,
+ WORD wMsg,
+ long lparam,
+ BOOL fFreeOnError,
+ BOOL fStdCloseDoc,
+ BOOL fDetectTerminate,
+ BOOL fWait )
+{
+#ifdef _MAC
+#else
+ DDECALLDATA DdeCD;
+ BOOL fPending;
+ HRESULT hres;
+ ULONG status = 0;
+
+
+
+#if DBG == 1
+ unsigned iAutoCounter;
+ intrDebugOut((INTR_DDE,
+ "DdeObject::WaitForReply(%x) Call#(%x) awaiting %x\n",
+ this,
+ iAutoCounter=++iCounter,
+ iAwaitAck));
+#endif
+
+ // make sure we have a call control. if OLE2 stuff has never been run,
+ // then we might not yet have a call control (since
+ // ChannelThreadInitialize may not have been be called).
+
+ COleTls tls;
+ CAptCallCtrl *pCallCtrl = tls->pCallCtrl;
+
+ if (pCallCtrl == NULL)
+ {
+ // OLE2 stuff has never been run and we dont yet have a CallCtrl
+ // for this thread. Go create one now. ctor adds it to the tls.
+
+ pCallCtrl = new CAptCallCtrl;
+ if (pCallCtrl == NULL)
+ {
+ intrDebugOut((DEB_ERROR,"SendRecieve2 couldn't alloc CallCtrl\n"));
+ return RPC_E_OUT_OF_RESOURCES;
+ }
+ }
+
+ // see if we can send the message, and then send it...
+
+ CALLCATEGORY CallCat = fWait ? CALLCAT_SYNCHRONOUS : CALLCAT_ASYNC;
+
+ if (pChannel->pCD != NULL)
+ {
+ // a DDE call is already in progress, dont let another DDE call out.
+ hres = E_UNEXPECTED;
+ }
+ else
+ {
+ // we dont know what interface is being called on, but we do
+ // know it is NOT IRemUnknown (IRundown) so it does not matter
+ // what we pass here as long as it is not IRemUnknown (IRundown).
+ hres = CanMakeOutCall(CallCat, IID_IUnknown);
+ }
+
+ if ( FAILED(hres) )
+ {
+ intrDebugOut((INTR_DDE, "CanMakeOutCall failed:%x\n", hres));
+ return hres;
+ }
+
+ // Note: this is to detect a premature DDE_TERMINATE
+ // here we care about if we receive a WM_DDE_TERMINATE instead ACK
+ // the next call to WaitForReply will detect this state and return
+ // since the terminate was send prematurly (Excel is one of this sucker)
+ //
+ if ( fDetectTerminate ) {
+ Assert(m_wTerminate == Terminate_None);
+ // if this flag is on terminate should not execute the default code
+ // in the window procedure
+ m_wTerminate = Terminate_Detect;
+ }
+
+
+ pChannel->iAwaitAck = iAwaitAck;
+ pChannel->dwStartTickCount = GetTickCount();
+
+ // start looking only for dde messages first
+ pChannel->msgFirst = WM_DDE_FIRST;
+ pChannel->msgLast = WM_DDE_LAST;
+ pChannel->msghwnd = pChannel->hwndCli;
+
+ pChannel->fRejected = FALSE;
+ // see if there is a thread window for lrpc communication
+ // if so we have to dispatch this messages as well
+ fPending = FALSE;
+
+ intrDebugOut((DEB_ITRACE,
+ "+++ Waiting for reply: server: %x, client %x Call#(%x) +++\n",
+ pChannel->hwndSvr,
+ pChannel->hwndCli,
+ iAutoCounter));
+
+ // prepare and enter the modal loop
+ DdeCD.hwndSvr = pChannel->hwndSvr;
+ DdeCD.hwndCli = pChannel->hwndCli;
+ DdeCD.wMsg = wMsg;
+ DdeCD.wParam = (WPARAM) pChannel->hwndCli,
+ DdeCD.lParam = lparam;
+ DdeCD.fDone = FALSE;
+ DdeCD.fFreeOnError = fFreeOnError;
+ DdeCD.pChannel = pChannel;
+
+ pChannel->pCD = &DdeCD;
+
+ //
+ // Setting this value tells DeleteChannel NOT to delete itself.
+ // If the value changes to Channel_DeleteNow while we are in
+ // the modal loop, this routine will delete the channel
+ //
+ pChannel->wChannelDeleted = Channel_InModalloop;
+
+ //
+ // hres will be the return code from the message
+ // handlers, or from the channel itself. The return
+ // code comes from calls to SetCallState. Most of the
+ // time, it will be things like RPC_E_DDE_NACK. However,
+ // it may also return OUTOFMEMORY, or other ModalLoop
+ // problems.
+ //
+
+ RPCOLEMESSAGE RpcOleMsg;
+ RpcOleMsg.Buffer = &DdeCD;
+
+ // Figure out the call category of this call by looking at the bit
+ // values in the rpc message flags.
+
+ DWORD dwMsgQInputFlag = gMsgQInputFlagTbl[CallCat];
+
+ // 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
+ {
+ hres = CML.SendReceive(&RpcOleMsg, &status, pChannel);
+
+ } while (hres == RPC_E_SERVERCALL_RETRYLATER);
+
+
+ if (hres != NOERROR)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "**************** CallRunModalLoop returns %x ***\n",
+ hres));
+ }
+
+ if (m_wTerminate == Terminate_Received) {
+ intrAssert(fDetectTerminate);
+ //
+ // There really wasn't an error, its just that the server decided
+ // to terminate. If we return an error here, the app may decide
+ // that things have gone awry. Excel, for example, will decide
+ // that the object could not be activated, even though it has
+ // already updated its cache information.
+ //
+ hres = NOERROR;
+ intrDebugOut((DEB_ITRACE,
+ "::WaitForReply setting hres=%x\n",
+ hres));
+ intrDebugOut((DEB_ITRACE,
+ "::WaitForReply posting TERMINATE to self hwnd=%x\n",
+ DdeCD.hwndCli));
+ // set state to normal and repost message
+ Verify (PostMessage (DdeCD.hwndCli, WM_DDE_TERMINATE,
+ (WPARAM)DdeCD.hwndSvr, (LPARAM)0));
+ }
+ m_wTerminate = Terminate_None;
+
+ //
+ // If the channel is to be deleted, then do it now. This flag would
+ // have been set in the DeleteChannel routine.
+ //
+ if (pChannel->wChannelDeleted == Channel_DeleteNow)
+ {
+ intrDebugOut((INTR_DDE,
+ "::WaitForReply(%x) Channel_DeleteNow pChannel(%x)\n",
+ pChannel));
+
+ // If the channel is closed then its pointer in the DdeChannel must
+ // be NULL. This assumes that the passed in "pChannel" is always
+ // equal to either the "Doc" or "Sys" member channels.
+ // This code fragment is patterned after a code fragment
+ // found in CDdechannel::DeleteChannel().
+
+ if(0 == pChannel->ReleaseReference())
+ {
+ if(pChannel == m_pDocChannel)
+ {
+ m_pDocChannel = NULL;
+ }
+ else
+ {
+ Assert(pChannel == m_pSysChannel);
+ m_pSysChannel = NULL;
+ }
+ }
+
+ // Excel will send TERMINATE before sending an ACK to StdCloseDoc
+ return ResultFromScode (fStdCloseDoc ? DDE_CHANNEL_DELETED : RPC_E_DDE_POST);
+ }
+ pChannel->wChannelDeleted = 0;
+
+ pChannel->iAwaitAck = 0;
+ pChannel->pCD = NULL;
+
+ intrDebugOut((DEB_ITRACE,
+ "### Waiting for reply done: server: %x, client %x hres(%x)###\n",
+ pChannel->hwndSvr,
+ pChannel->hwndCli,
+ hres));
+
+ return hres;
+#endif _MAC
+}
+
+// Provided IRpcChannelBuffer2 methods
+HRESULT DDE_CHANNEL::SendReceive2(
+ /* [out][in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+ /* [out] */ ULONG __RPC_FAR *pStatus)
+{
+ pCD = (DDECALLDATA *) pMessage->Buffer;
+
+ if(!wPostMessageToServer(pCD->pChannel,
+ pCD->wMsg,
+ pCD->lParam,
+ pCD->fFreeOnError))
+ {
+ intrDebugOut((DEB_ITRACE, "SendRecieve2(%x)wPostMessageToServer failed", this));
+ return RPC_E_SERVER_DIED;
+ }
+
+
+ CAptCallCtrl *pCallCtrl = GetAptCallCtrl();
+
+ CCliModalLoop *pCML = pCallCtrl->GetTopCML();
+
+ hres = S_OK;
+ BOOL fWait = !pCD->fDone;
+
+ while (fWait)
+ {
+ HRESULT hr = OleModalLoopBlockFn(NULL, pCML, NULL);
+
+ if (pCD->fDone)
+ {
+ fWait = FALSE;
+ }
+ else if (hr != RPC_S_CALLPENDING)
+ {
+ fWait = FALSE;
+ hres = hr; // return result from OleModalLoopBlockFn()
+ }
+ }
+
+ if (FAILED(hres))
+ {
+ intrDebugOut((DEB_ITRACE, "**** CallRunModalLoop returns %x ***\n", hres));
+ }
+ return hres;
+}
+
+
+void DDE_CHANNEL::SetCallState(SERVERCALLEX ServerCall, HRESULT hr)
+{
+ CallState = ServerCall;
+ hres = hr;
+ Win4Assert(pCD);
+ pCD->fDone = TRUE;
+}
diff --git a/private/ole32/com/dde/client/packmnkr.cxx b/private/ole32/com/dde/client/packmnkr.cxx
new file mode 100644
index 000000000..eddc1adde
--- /dev/null
+++ b/private/ole32/com/dde/client/packmnkr.cxx
@@ -0,0 +1,333 @@
+/*
+ PackMnkr.cpp
+ PackageMoniker
+
+ This module implements the CPackagerMoniker class and
+ CreatePackagerMoniker()
+
+ Author:
+ Jason Fuller jasonful Nov-2-1992
+
+ Copyright (c) 1992 Microsoft Corporation
+*/
+
+#include <ole2int.h>
+#include "packmnkr.h"
+#include "..\server\ddedebug.h"
+#include <ole1cls.h>
+#include <winerror.h>
+
+ASSERTDATA
+
+
+STDMETHODIMP CPackagerMoniker::QueryInterface
+ (REFIID riid, LPVOID * ppvObj)
+{
+ M_PROLOG(this);
+ VDATEIID (riid);
+ VDATEPTROUT (ppvObj, LPVOID);
+
+ if ((riid == IID_IMoniker) || (riid == IID_IUnknown) ||
+ (riid == IID_IPersistStream) || (riid == IID_IInternalMoniker))
+ {
+ *ppvObj = this;
+ ++m_refs;
+ return NOERROR;
+ }
+ AssertSz (0, "Could not find interface\r\n");
+ *ppvObj = NULL;
+ return ReportResult(0, E_NOINTERFACE, 0, 0);
+}
+
+
+
+STDMETHODIMP_(ULONG) CPackagerMoniker::AddRef()
+{
+ M_PROLOG(this);
+ return ++m_refs;
+}
+
+
+
+STDMETHODIMP_(ULONG) CPackagerMoniker::Release()
+{
+ M_PROLOG(this);
+ Assert (m_refs > 0);
+ if (0 == --m_refs)
+ {
+ if (m_pmk)
+ {
+ m_pmk->Release();
+ }
+
+ if (m_szFile)
+ {
+ delete m_szFile;
+ }
+
+ delete this;
+ return 0;
+ }
+ return m_refs;
+}
+
+
+
+STDMETHODIMP CPackagerMoniker::GetClassID (THIS_ LPCLSID lpClassID)
+{
+ M_PROLOG(this);
+ *lpClassID = CLSID_PackagerMoniker;
+ return NOERROR;
+}
+
+
+
+STDMETHODIMP CPackagerMoniker::BindToObject (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
+ REFIID riidResult, LPVOID * ppvResult)
+{
+ M_PROLOG(this);
+ WIN32_FIND_DATA fd;
+ HRESULT hr;
+
+ COleTls Tls;
+ if( Tls->dwFlags & OLETLS_DISABLE_OLE1DDE )
+ {
+ // If this app doesn't want or can tolerate having a DDE
+ // window then currently it can't use OLE1 classes because
+ // they are implemented using DDE windows.
+ //
+ return CO_E_OLE1DDE_DISABLED;
+ }
+
+ // The following code ensures that the file exists before we try to bind it.
+ HANDLE hFind = FindFirstFile(m_szFile, &fd);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ hr = DdeBindToObject (m_szFile, CLSID_Package, m_fLink, riidResult, ppvResult);
+ FindClose(hFind);
+ }
+ else
+ hr = MK_E_CANTOPENFILE;
+ return hr;
+}
+
+STDMETHODIMP CPackagerMoniker::IsRunning (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
+ LPMONIKER pmkNewlyRunning)
+{
+ M_PROLOG(this);
+ VDATEIFACE (pbc);
+
+ if (pmkToLeft)
+ VDATEIFACE (pmkToLeft);
+ if (pmkNewlyRunning)
+ VDATEIFACE (pmkNewlyRunning);
+
+ // There is no way to tell if a packaged object is running
+ return ReportResult (0, S_FALSE, 0, 0);
+}
+
+
+STDAPI CreatePackagerMoniker(LPOLESTR szFile,LPMONIKER *ppmk,BOOL fLink)
+{
+ return CPackagerMoniker::Create (szFile,NULL,fLink,ppmk);
+}
+
+STDAPI CreatePackagerMonikerEx(LPOLESTR szFile,LPMONIKER lpFileMoniker,BOOL fLink,LPMONIKER * ppmk)
+{
+ return CPackagerMoniker::Create (szFile,lpFileMoniker,fLink,ppmk);
+}
+
+
+HRESULT CPackagerMoniker::Create(LPOLESTR szFile,LPMONIKER lpFileMoniker, BOOL fLink, LPMONIKER * ppmk)
+{
+HRESULT hresult = E_OUTOFMEMORY;
+CPackagerMoniker *pmkPack = NULL;
+
+ VDATEPTROUT (ppmk, LPMONIKER);
+ *ppmk = NULL;
+
+ if (NULL == szFile)
+ {
+ return MK_E_SYNTAX;
+ }
+
+ pmkPack = new CPackagerMoniker;
+ if (NULL != pmkPack)
+ {
+ pmkPack->m_fLink = fLink;
+ pmkPack->m_refs = 1;
+
+ // an exception could be caused by szFile being bogus
+ __try
+ {
+ pmkPack->m_szFile = new WCHAR [lstrlenW(szFile)+1];
+ if (NULL != pmkPack->m_szFile)
+ {
+ lstrcpyW (pmkPack->m_szFile, szFile);
+
+ // If we weren't given a FileMoniker try to create one now, else just hold on to the one given.
+ if (NULL == lpFileMoniker)
+ {
+ if (NOERROR == (hresult = CreateFileMoniker (szFile, &(pmkPack->m_pmk))))
+ {
+ *ppmk = pmkPack;
+ }
+ }
+ else
+ {
+ pmkPack->m_pmk = lpFileMoniker;
+ pmkPack->m_pmk->AddRef();
+ *ppmk = pmkPack;
+ hresult = NOERROR;
+ }
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ hresult = MK_E_SYNTAX;
+ }
+
+ }
+
+ if ((NOERROR != hresult) && pmkPack)
+ {
+ Assert(0);
+ pmkPack->Release();
+ }
+
+ return hresult;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////
+// The rest of these methods just delegate to m_pmk
+// or return some error code.
+
+
+STDMETHODIMP CPackagerMoniker::IsDirty (THIS)
+{
+ M_PROLOG(this);
+ return ReportResult(0, S_FALSE, 0, 0);
+ // monikers are immutable so they are either always dirty or never dirty.
+ //
+}
+
+STDMETHODIMP CPackagerMoniker::Load (THIS_ LPSTREAM pStm)
+{
+ M_PROLOG(this);
+ return m_pmk->Load(pStm);
+}
+
+
+STDMETHODIMP CPackagerMoniker::Save (THIS_ LPSTREAM pStm,
+ BOOL fClearDirty)
+{
+ M_PROLOG(this);
+ return m_pmk->Save(pStm, fClearDirty);
+}
+
+
+STDMETHODIMP CPackagerMoniker::GetSizeMax (THIS_ ULARGE_INTEGER * pcbSize)
+{
+ M_PROLOG(this);
+ return m_pmk->GetSizeMax (pcbSize);
+}
+
+ // *** IMoniker methods ***
+STDMETHODIMP CPackagerMoniker::BindToStorage (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
+ REFIID riid, LPVOID * ppvObj)
+{
+ M_PROLOG(this);
+ *ppvObj = NULL;
+ return ReportResult(0, E_NOTIMPL, 0, 0);
+}
+
+STDMETHODIMP CPackagerMoniker::Reduce (THIS_ LPBC pbc, DWORD dwReduceHowFar, LPMONIKER *
+ ppmkToLeft, LPMONIKER * ppmkReduced)
+{
+ M_PROLOG(this);
+ return m_pmk->Reduce (pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
+}
+
+STDMETHODIMP CPackagerMoniker::ComposeWith (THIS_ LPMONIKER pmkRight, BOOL fOnlyIfNotGeneric,
+ LPMONIKER * ppmkComposite)
+{
+ M_PROLOG(this);
+ return m_pmk->ComposeWith (pmkRight, fOnlyIfNotGeneric, ppmkComposite);
+}
+
+STDMETHODIMP CPackagerMoniker::Enum (THIS_ BOOL fForward, LPENUMMONIKER * ppenumMoniker)
+{
+ M_PROLOG(this);
+ return m_pmk->Enum (fForward, ppenumMoniker);
+}
+
+STDMETHODIMP CPackagerMoniker::IsEqual (THIS_ LPMONIKER pmkOtherMoniker)
+{
+ M_PROLOG(this);
+ return m_pmk->IsEqual (pmkOtherMoniker);
+}
+
+STDMETHODIMP CPackagerMoniker::Hash (THIS_ LPDWORD pdwHash)
+{
+ M_PROLOG(this);
+ return m_pmk->Hash (pdwHash);
+}
+
+STDMETHODIMP CPackagerMoniker::GetTimeOfLastChange (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
+ FILETIME * pfiletime)
+{
+ M_PROLOG(this);
+ return m_pmk->GetTimeOfLastChange (pbc, pmkToLeft, pfiletime);
+}
+
+STDMETHODIMP CPackagerMoniker::Inverse (THIS_ LPMONIKER * ppmk)
+{
+ M_PROLOG(this);
+ return m_pmk->Inverse (ppmk);
+}
+
+STDMETHODIMP CPackagerMoniker::CommonPrefixWith (LPMONIKER pmkOther, LPMONIKER *
+ ppmkPrefix)
+{
+ M_PROLOG(this);
+ return m_pmk->CommonPrefixWith (pmkOther, ppmkPrefix);
+}
+
+STDMETHODIMP CPackagerMoniker::RelativePathTo (THIS_ LPMONIKER pmkOther, LPMONIKER *
+ ppmkRelPath)
+{
+ M_PROLOG(this);
+ return m_pmk->RelativePathTo (pmkOther, ppmkRelPath);
+}
+
+STDMETHODIMP CPackagerMoniker::GetDisplayName (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
+ LPOLESTR * lplpszDisplayName)
+{
+ M_PROLOG(this);
+ return m_pmk->GetDisplayName (pbc, pmkToLeft, lplpszDisplayName);
+}
+
+STDMETHODIMP CPackagerMoniker::ParseDisplayName (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
+ LPOLESTR lpszDisplayName, ULONG * pchEaten,
+ LPMONIKER * ppmkOut)
+{
+ M_PROLOG(this);
+ return m_pmk->ParseDisplayName (pbc, pmkToLeft, lpszDisplayName, pchEaten,
+ ppmkOut);
+}
+
+
+STDMETHODIMP CPackagerMoniker::IsSystemMoniker (THIS_ LPDWORD pdwMksys)
+{
+ M_PROLOG(this);
+ VDATEPTROUT (pdwMksys, DWORD);
+
+ *pdwMksys = MKSYS_NONE;
+ return NOERROR;
+}
+
+
+
+
diff --git a/private/ole32/com/dde/client/packmnkr.h b/private/ole32/com/dde/client/packmnkr.h
new file mode 100644
index 000000000..cf91ef62d
--- /dev/null
+++ b/private/ole32/com/dde/client/packmnkr.h
@@ -0,0 +1,63 @@
+/*
+ packmnkr.h
+*/
+
+class CPackagerMoniker : public IMoniker
+{
+ public:
+ // *** IUnknown methods ***
+ STDMETHOD(QueryInterface) ( REFIID riid, LPVOID * ppvObj) ;
+ STDMETHOD_(ULONG,AddRef) () ;
+ STDMETHOD_(ULONG,Release) () ;
+
+ // *** IPersist methods ***
+ STDMETHOD(GetClassID) ( LPCLSID lpClassID) ;
+
+ // *** IPersistStream methods ***
+ STDMETHOD(IsDirty) () ;
+ STDMETHOD(Load) ( LPSTREAM pStm) ;
+ STDMETHOD(Save) ( LPSTREAM pStm,
+ BOOL fClearDirty) ;
+ STDMETHOD(GetSizeMax) ( ULARGE_INTEGER * pcbSize) ;
+
+ // *** IMoniker methods ***
+ STDMETHOD(BindToObject) ( LPBC pbc, LPMONIKER pmkToLeft,
+ REFIID riidResult, LPVOID * ppvResult) ;
+ STDMETHOD(BindToStorage) ( LPBC pbc, LPMONIKER pmkToLeft,
+ REFIID riid, LPVOID * ppvObj) ;
+ STDMETHOD(Reduce) ( LPBC pbc, DWORD dwReduceHowFar, LPMONIKER *
+ ppmkToLeft, LPMONIKER * ppmkReduced) ;
+ STDMETHOD(ComposeWith) ( LPMONIKER pmkRight, BOOL fOnlyIfNotGeneric,
+ LPMONIKER * ppmkComposite) ;
+ STDMETHOD(Enum) ( BOOL fForward, LPENUMMONIKER * ppenumMoniker)
+ ;
+ STDMETHOD(IsEqual) ( LPMONIKER pmkOtherMoniker) ;
+ STDMETHOD(Hash) ( LPDWORD pdwHash) ;
+ STDMETHOD(IsRunning) ( LPBC pbc, LPMONIKER pmkToLeft, LPMONIKER
+ pmkNewlyRunning) ;
+ STDMETHOD(GetTimeOfLastChange) ( LPBC pbc, LPMONIKER pmkToLeft,
+ FILETIME * pfiletime) ;
+ STDMETHOD(Inverse) ( LPMONIKER * ppmk) ;
+ STDMETHOD(CommonPrefixWith) ( LPMONIKER pmkOther, LPMONIKER *
+ ppmkPrefix) ;
+ STDMETHOD(RelativePathTo) ( LPMONIKER pmkOther, LPMONIKER *
+ ppmkRelPath) ;
+ STDMETHOD(GetDisplayName) ( LPBC pbc, LPMONIKER pmkToLeft,
+ LPOLESTR * lplpszDisplayName) ;
+ STDMETHOD(ParseDisplayName) ( LPBC pbc, LPMONIKER pmkToLeft,
+ LPOLESTR lpszDisplayName, ULONG * pchEaten,
+ LPMONIKER * ppmkOut) ;
+ STDMETHOD(IsSystemMoniker) ( LPDWORD pdwMksys) ;
+
+ static HRESULT Create ( LPOLESTR szFile,LPMONIKER lpFileMoniker,BOOL fLink,LPMONIKER * ppmk) ;
+
+ private:
+
+ ULONG m_refs;
+ LPOLESTR m_szFile;
+ LPMONIKER m_pmk;
+ BOOL m_fLink;
+
+
+};
+
diff --git a/private/ole32/com/dde/client/trgt_dev.h b/private/ole32/com/dde/client/trgt_dev.h
new file mode 100644
index 000000000..a2de2d4b3
--- /dev/null
+++ b/private/ole32/com/dde/client/trgt_dev.h
@@ -0,0 +1,19 @@
+// trgt_dev.h
+
+// OLE 1.0 Target Device
+
+typedef struct _OLETARGETDEVICE
+{
+ USHORT otdDeviceNameOffset;
+ USHORT otdDriverNameOffset;
+ USHORT otdPortNameOffset;
+ USHORT otdExtDevmodeOffset;
+ USHORT otdExtDevmodeSize;
+ USHORT otdEnvironmentOffset;
+ USHORT otdEnvironmentSize;
+ BYTE otdData[1];
+} OLETARGETDEVICE;
+
+typedef OLETARGETDEVICE const FAR* LPCOLETARGETDEVICE;
+typedef OLETARGETDEVICE FAR* LPOLETARGETDEVICE;
+