diff options
Diffstat (limited to 'private/ole32/com/dde/client')
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; + |