diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ole32/com/remote/dde | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to '')
44 files changed, 20878 insertions, 0 deletions
diff --git a/private/ole32/com/remote/dde/client/cnct_tbl.cxx b/private/ole32/com/remote/dde/client/cnct_tbl.cxx new file mode 100644 index 000000000..bc7200223 --- /dev/null +++ b/private/ole32/com/remote/dde/client/cnct_tbl.cxx @@ -0,0 +1,182 @@ +// cnct_tbl.cpp +// +// class CConnectionTable +// +// CConnectionTable maps connection numbers (as returned by ::Advise()) +// to clipformat's for DDE advise connections. + +#include "ddeproxy.h" +#include "cnct_tbl.h" + +ASSERTDATA + +#define grfMemFlags (GMEM_MOVEABLE | GMEM_ZEROINIT) + +// number of INFO entries to grow by +#define cinfoBlock 10 + +typedef struct INFO +{ + BOOL fUsed; // is this table entry used? + DWORD dwConnection; // search key + CLIPFORMAT cf; // corresponding cf, for use in DDE_(UN)ADVISE + DWORD grfAdvf; // ON_CHANGE or ON_SAVE or ON_CLOSE +} INFO, FAR* PINFO; + + + +CDdeConnectionTable::CDdeConnectionTable () +{ + m_h = GlobalAlloc (grfMemFlags, cinfoBlock * sizeof(INFO)); + Assert (m_h); + m_cinfo=cinfoBlock; +} + + +CDdeConnectionTable::~CDdeConnectionTable () +{ + Assert(m_h); + m_h =GlobalFree (m_h); + Assert (m_h==NULL); + m_cinfo=0; +} + + + + +INTERNAL CDdeConnectionTable::Add + (DWORD dwConnection, + CLIPFORMAT cf, + DWORD grfAdvf) +{ + Start: + PINFO rginfo; + + if (NULL==(rginfo = (PINFO) GlobalLock(m_h))) + { + Puts ("ERROR: CDdeConnectionTable::Add out of memory\n"); + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + } + // Look for an empty table entry + for (DWORD i=0; i<m_cinfo; i++) + { + if (!rginfo[i].fUsed) + { + rginfo[i].fUsed = TRUE; + rginfo[i].dwConnection = dwConnection; + rginfo[i].cf = cf; + rginfo[i].grfAdvf = grfAdvf; + break; + } + else + { + Assert (rginfo[i].dwConnection != dwConnection); + } + } + GlobalUnlock (m_h); + if (i==m_cinfo) // if no empty entry found + { + Puts ("Growing the connection table\n"); + m_h = GlobalReAlloc (m_h,(m_cinfo += cinfoBlock) * sizeof(INFO), + grfMemFlags); + if (m_h==NULL) + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + goto Start; + } + else + { + return NOERROR; + } +} + + + + +INTERNAL CDdeConnectionTable::Subtract + (DWORD dwConnection, + CLIPFORMAT FAR* pcf, // out parm + DWORD FAR* pgrfAdvf) // out parm +{ + PINFO rginfo; + if (dwConnection==0) + { + Puts ("CDdeConnectionTable::Subtract called with dwConnection==0\n"); + return ReportResult(0, E_INVALIDARG, 0, 0); + } + + if (NULL==(rginfo = (PINFO) GlobalLock(m_h))) + { + Assert (0); + Puts ("ERROR: CDdeConnectionTable::Subtract out of memory\n"); + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + } + + for (DWORD i=0; i<m_cinfo; i++) + { + if (rginfo[i].fUsed && rginfo[i].dwConnection == dwConnection) + { + Assert (pcf); + *pcf = rginfo[i].cf; + Assert (pgrfAdvf); + *pgrfAdvf = rginfo[i].grfAdvf; + rginfo[i].fUsed = FALSE; // remove this connection + GlobalUnlock (m_h); + return NOERROR; + } + } + GlobalUnlock (m_h); + return ReportResult(0, S_FALSE, 0, 0); // not found +} + + + + +INTERNAL CDdeConnectionTable::Lookup + (CLIPFORMAT cf, // search key + LPDWORD pdwConnection) // out parm. May be NULL on input +{ + PINFO rginfo; + + if (NULL==(rginfo = (PINFO) GlobalLock(m_h))) + { + Puts ("ERROR: CDdeConnectionTable::Lookup out of memory\n"); + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + } + + for (DWORD i=0; i<m_cinfo; i++) + { + if (rginfo[i].fUsed && + rginfo[i].cf == cf) + { + if (pdwConnection) + *pdwConnection = rginfo[i].dwConnection; + GlobalUnlock (m_h); + return NOERROR; + } + } + GlobalUnlock (m_h); + return ReportResult(0, S_FALSE, 0, 0); // not found +} + + + +INTERNAL CDdeConnectionTable::Erase + (void) +{ + PINFO rginfo; + Assert (wIsValidHandle(m_h, NULL)); + if (NULL==(rginfo = (PINFO) GlobalLock(m_h))) + { + Puts ("ERROR: CDdeConnectionTable::Lookup out of memory\n"); + Assert (0); + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + } + + for (DWORD i=0; i<m_cinfo; i++) + { + rginfo[i].fUsed = FALSE; + } + GlobalUnlock (m_h); + return NOERROR; +} + diff --git a/private/ole32/com/remote/dde/client/cnct_tbl.h b/private/ole32/com/remote/dde/client/cnct_tbl.h new file mode 100644 index 000000000..656b9ce89 --- /dev/null +++ b/private/ole32/com/remote/dde/client/cnct_tbl.h @@ -0,0 +1,27 @@ +// cnct_tbl.h + +// CConnectionTable maps connection numbers (as returned by ::Advise()) +// to clipformat's for DDE advise connections. + +#ifndef fCnct_tbl_h +#define fCnct_tbl_h + +class FAR CDdeConnectionTable : public CPrivAlloc +{ + public: + CDdeConnectionTable(); + ~CDdeConnectionTable(); + + INTERNAL Add (DWORD dwConnection, CLIPFORMAT cf, DWORD grfAdvf); + INTERNAL Subtract (DWORD dwConnection, CLIPFORMAT FAR* pcf, DWORD FAR* pgrfAdvf); + INTERNAL Lookup (CLIPFORMAT cf, LPDWORD pdwConnection); + INTERNAL Erase (void); + + private: + HANDLE m_h; // handle to the table + DWORD m_cinfo; // total number of INFO entries +}; + + +#endif + diff --git a/private/ole32/com/remote/dde/client/daytona/makefile b/private/ole32/com/remote/dde/client/daytona/makefile new file mode 100644 index 000000000..1d3728d41 --- /dev/null +++ b/private/ole32/com/remote/dde/client/daytona/makefile @@ -0,0 +1,10 @@ +############################################################################ +# +# Copyright (C) 1992, Microsoft Corporation. +# +# All rights reserved. +# +############################################################################ + +!include $(NTMAKEENV)\makefile.def + diff --git a/private/ole32/com/remote/dde/client/daytona/sources b/private/ole32/com/remote/dde/client/daytona/sources new file mode 100644 index 000000000..468aff4b2 --- /dev/null +++ b/private/ole32/com/remote/dde/client/daytona/sources @@ -0,0 +1,83 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + David Plummer (davepl) 19-Mar-94 + + Modifed by via awk to include global project include file + and to wrap precompiled header line within a conditional + that can be set in this include file. + + Donna Liu (DonnaLi) 19-Dec-1993 + +!ENDIF + +MAJORCOMP = cairole +MINORCOMP = com + +# +# This is the name of the target built from the source files specified +# below. The name should include neither the path nor the file extension. +# + +TARGETNAME= ddecli + +# +# This specifies where the target is to be built. A private target of +# type LIBRARY or DYNLINK should go to obj, whereas a public target of +# type LIBRARY or DYNLINK should go to $(BASEDIR)\public\sdk\lib. +# + +TARGETPATH= obj + +# +# This specifies the type of the target, such as PROGRAM, DYNLINK, LIBRARY, +# etc. +# + +TARGETTYPE= LIBRARY + +INCLUDES = ..\..\server;..\..\..\..\..\common\daytona;..\..\..\..\..\ih;..\..\..;..\..\..\..\inc;..\..\..\..\idl\daytona;..\..\..\..\class;..\..\..\..\objact;..\..\..\..\..\ole232\inc;..\..\..; + +!include ..\..\..\..\..\daytona.inc + +C_DEFINES= -DOLE_DDE_NO_GLOBAL_TRACKING=1\ + $(C_DEFINES) \ + + +SOURCES= \ + ..\cnct_tbl.cxx \ + ..\ddedo.cxx \ + ..\ddeioc.cxx \ + ..\ddemnker.cxx \ + ..\ddeoo.cxx \ + ..\ddeproxy.cxx \ + ..\ddechc.cxx \ + ..\ddestg.cxx \ + ..\ddewnd.cxx \ + ..\ddeworkr.cxx \ + ..\modallp.cxx \ + ..\packmnkr.cxx + +UMTYPE= windows +UMAPPL= +UMTEST= +UMLIBS= + +# PRECOMPILED_INCLUDE= ..\headers.cxx + + diff --git a/private/ole32/com/remote/dde/client/ddechc.cxx b/private/ole32/com/remote/dde/client/ddechc.cxx new file mode 100644 index 000000000..0034b5ef3 --- /dev/null +++ b/private/ole32/com/remote/dde/client/ddechc.cxx @@ -0,0 +1,265 @@ +//+------------------------------------------------------------------------- +// +// Microsoft Windows +// Copyright (C) Microsoft Corporation, 1992 - 1993. +// +// File: DdeChC.cxx +// +// Contents: CDdeChannelControl implementation for DDE. This +// implementation requires no instance data, therefore it is +// intended to be static. +// +// Functions: +// +// History: 08-May-94 Johann Posch (johannp) Created +// 10-May-94 KevinRo Made simpler +// 29-May-94 KevinRo Added DDE Server support +// +//-------------------------------------------------------------------------- +#include "ddeproxy.h" + +// +// All threads can use a single instance of this class. Therefore, we +// provide the following global variable that generates the instance. +// + +CDdeChannelControl g_CDdeChannelControl; + +STDMETHODIMP CDdeChannelControl::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj) +{ + if (IsEqualIID(riid, IID_IUnknown) +// || IsEqualIID(riid, IID_IChannelControl) + ) + { + *ppvObj = (IChannelControl *) this; + } + else + { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + return S_OK; +} + +STDMETHODIMP_(ULONG) CDdeChannelControl::Release( THIS ) +{ + return(1); +} + +STDMETHODIMP_(ULONG) CDdeChannelControl::AddRef( THIS ) +{ + return 1; +} + + +//+--------------------------------------------------------------------------- +// +// Method: CDdeChannelControl::DispatchCall +// +// Synopsis: DispatchCall is called to handle incoming calls. +// +// Effects: Dispatches a call to the specified in the DispatchData. +// This function is the result of a call in OnData(), which +// processes incoming calls from the OLE 1.0 server. +// +// Arguments: [pDispData] -- Points to the dispatch data structure +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 5-16-94 JohannP Created +// +// Notes: +// +//---------------------------------------------------------------------------- +STDMETHODIMP CDdeChannelControl::DispatchCall( PDISPATCHDATA pDispData ) +{ + intrDebugOut((DEB_ITRACE, + "CDdeChannelControl::DispatchCall(%x,pDispData=%x)\n", + this, + pDispData)); + + intrAssert(pDispData != NULL); + POLE1DISPATCHDATA pData = (POLE1DISPATCHDATA)pDispData->pData; + intrAssert(pData != NULL); + + switch (pData->wDispFunc) + { + case DDE_DISP_SENDONDATACHANGE: // OnDataChange + { + PDDEDISPATCHDATA pDData = (PDDEDISPATCHDATA)pDispData->pData; + return pDData->pCDdeObject->SendOnDataChange(pDData->iArg); + } + + case DDE_DISP_OLECALLBACK: // OleCallBack + { + PDDEDISPATCHDATA pDData = (PDDEDISPATCHDATA)pDispData->pData; + return pDData->pCDdeObject->OleCallBack(pDData->iArg,NULL); + } + + // + // The server window has an incoming call. Look in dde\server\srvr.cxx + // + case DDE_DISP_SRVRWNDPROC: + return(SrvrDispatchIncomingCall((PSRVRDISPATCHDATA)pDispData->pData)); + // + // This dispatches to a Document window + // + case DDE_DISP_DOCWNDPROC: + return(DocDispatchIncomingCall((PDOCDISPATCHDATA)pDispData->pData)); + + default: + intrAssert(!"Unknown wDispFunc"); + } + return E_FAIL; +} + +//+--------------------------------------------------------------------------- +// +// Method: CDdeChannelControl::OnEvent +// +// Synopsis: OnEvent should never be called on this channel +// +// Effects: +// +// Arguments: [pCallData] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 5-16-94 JohannP Created +// +// Notes: +// +//---------------------------------------------------------------------------- +STDMETHODIMP CDdeChannelControl::OnEvent( PCALLDATA pCallData ) +{ + // should be never called + + intrAssert(!"CDdeChannelControl::OnEvent( PCALLDATA pCallData ) not implemented\n"); + return E_FAIL; +} + +//+--------------------------------------------------------------------------- +// +// Method: CDdeChannelControl::TransmitCall +// +// Synopsis: Transmit the parameters to the server. +// +// Effects: This function transmits the pCallData to the server. This +// may be called multiple times, if a retry is required. +// +// A by product of the way the DDE channel was implemented +// atop existing code is that the existing code may transmit +// the first round of data on its own. If it does this, it +// will set the fInitialSend to TRUE. Therefore, if this +// routine sees the flag as true, it will not send the data, +// but will set the flag to FALSE for a possible retry later. +// +// Arguments: [pCallData] -- Points to the DDE specific call data +// +// Requires: +// +// Returns: If the Post fails, this function returns E_FAIL +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 5-16-94 JohannP Created +// +// Notes: +// +//---------------------------------------------------------------------------- +STDMETHODIMP CDdeChannelControl::TransmitCall( PCALLDATA pCallData ) +{ + intrDebugOut((DEB_ITRACE, + "CDdeChannelControl::TransmitCall(%x,pCallData=%x)\n", + this, + pCallData)); + // reset the event + pCallData->Event = 0; + pCallData->fDirectedYield = FALSE; + + PDDECALLDATA pDdeCD = (PDDECALLDATA)pCallData->pRpcMsg; + + // + // If the routine wPostServerMessage has already posted the + // first send, then fInitialSend will be TRUE. In that case, + // don't TransmitCall() this time, but reset the flag for + // future retries. + // + + if (!pDdeCD->fInitialSend) + { + intrDebugOut((DEB_ITRACE, + "::TransmitCall(%x) PostMessage(%x,%x,%x,%x)\n", + this, + pDdeCD->hwndSvr, + pDdeCD->wMsg, + (WPARAM) pDdeCD->hwndCli, + pDdeCD->lParam)); + + if(!PostMessage (pDdeCD->hwndSvr, + pDdeCD->wMsg, + (WPARAM) pDdeCD->hwndCli, + pDdeCD->lParam)) + { + return(E_FAIL); + } + } + else + { + intrDebugOut((DEB_ITRACE, + "::TransmitCall(%x) Already Posted Message\n", + this)); + + pDdeCD->fInitialSend = FALSE; + } + + // + // Figure out if we want the call control to do a directed yield. + // Do this only if the server is in the same VDM as us. + // + + + if (IsWOWProcess()) + { + DWORD dwPID, dwTID; + dwTID = GetWindowThreadProcessId(pDdeCD->hwndSvr, &dwPID); + + if (dwPID == GetCurrentProcessId()) + { + // Make sure we have the right thread id to yield to + pCallData->TIDCallee = dwTID; + + // same VDM so do directed yield + pCallData->fDirectedYield = TRUE; + } + } + + return NOERROR; +} diff --git a/private/ole32/com/remote/dde/client/ddechc.hxx b/private/ole32/com/remote/dde/client/ddechc.hxx new file mode 100644 index 000000000..d896f2378 --- /dev/null +++ b/private/ole32/com/remote/dde/client/ddechc.hxx @@ -0,0 +1,135 @@ +//+------------------------------------------------------------------------- +// +// Microsoft Windows +// Copyright (C) Microsoft Corporation, 1992 - 1993. +// +// File: DdeChC.cxx +// +// Contents: CDdeChannelControl implementation for DDE. This +// implementation requires no instance data, therefore it is +// intended to be static. +// +// Functions: +// +// History: 08-May-94 Johann Posch (johannp) Created +// 10-May-94 KevinRo Made simpler and commented +// +//-------------------------------------------------------------------------- +#ifndef __DDECHC_HXX__ +#define __DDECHC_HXX__ + +class CDdeObject; +// +// The following are the possible callbacks that would be supported by +// the CDdeObject +// + +typedef enum +{ + DDE_DISP_SENDONDATACHANGE = 1, + DDE_DISP_OLECALLBACK = 2 , + DDE_DISP_SRVRWNDPROC = 3 , + DDE_DISP_DOCWNDPROC = 4 +} DDE_DISPATCH_FUNC; + + +// +// The following defines a base class for the OLE 1.0 support +// + +typedef struct tagOLE1DISPATCHDATA +{ + DDE_DISPATCH_FUNC wDispFunc; +}OLE1DISPATCHDATA, *POLE1DISPATCHDATA; + +// +// The following structure is used by OLE 1.0 server support code +// + +typedef struct tagDDEDISPATCHDATA : public CPrivAlloc, public OLE1DISPATCHDATA +{ + CDdeObject *pCDdeObject; + UINT iArg; +} DDEDISPATCHDATA, *PDDEDISPATCHDATA; + + +// +// The following structure is used by the OLE 1.0 client support code +// to dispatch incoming calls to Execute from the server window. +// + +typedef struct tagSRVRDISPATCHDATA : public OLE1DISPATCHDATA,public CPrivAlloc +{ + HWND hwnd; + HANDLE hData; + HWND wParam; + LPSRVR lpsrvr; +} SRVRDISPATCHDATA, *PSRVRDISPATCHDATA; + +INTERNAL SrvrDispatchIncomingCall(PSRVRDISPATCHDATA psdd); + + +// +// The following structure is used by the OLE 1.0 client support code +// to dispatch incoming calls to a document window +// + +typedef struct tagDOCDISPATCHDATA : public OLE1DISPATCHDATA,public CPrivAlloc +{ + HWND hwnd; + ULONG msg; + WPARAM wParam; + LPARAM lParam; + HANDLE hdata; // If already determined, these two hold + ATOM aItem; // valid data. All depends on the message + LPCLIENT lpclient; +} DOCDISPATCHDATA, *PDOCDISPATCHDATA; + +INTERNAL DocDispatchIncomingCall(PDOCDISPATCHDATA psdd); + + + +// +// DDECALLDATA is all the information needed to transmit the outbound call +// to the server. Since this DDE channel uses PostMessage, the members +// should look amazingly alot like the parameters to PostMessage. +// +// The hwndCli is used for setting callback information. +// fInitialSend is used by IChannelControl::Transmit(). +// +typedef struct tagDDECALLDATA : public CPrivAlloc +{ + HWND hwndSvr; // Server DDE window + WORD wMsg; // Post parameters + WPARAM wParam; + LPARAM lParam; + + HWND hwndCli; // Handle to client side window + BOOL fInitialSend; // True if the first post has been made + // already. +} DDECALLDATA, *PDDECALLDATA; + + +class CDdeChannelControl : public IChannelControl +{ + public: + // IUnknown methods + STDMETHOD (QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj); + STDMETHOD_(ULONG,AddRef) ( void ); + STDMETHOD_(ULONG,Release) ( void ); + + // IChannelControl + STDMETHOD (DispatchCall)( PDISPATCHDATA ); + STDMETHOD (OnEvent) ( PCALLDATA ); + STDMETHOD (TransmitCall)( PCALLDATA ); +}; + +// +// All threads can use a single instance of this class. Therefore, we +// provide the following global variable +// + +extern CDdeChannelControl g_CDdeChannelControl; + +#endif // __DDECHC__HXX__ + diff --git a/private/ole32/com/remote/dde/client/ddecnvrt.cxx b/private/ole32/com/remote/dde/client/ddecnvrt.cxx new file mode 100644 index 000000000..119c67d15 --- /dev/null +++ b/private/ole32/com/remote/dde/client/ddecnvrt.cxx @@ -0,0 +1,348 @@ + +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + ddecnvrt.cpp + +Abstract: + + This module contains the code to read/write PBrush, MSDraw native data + formats. This module also contains PBrush native format <->DIbFile stream, + and MSDraw native format <-> placeable metafile stream conversion routines. + +Author: + + Srini Koppolu (srinik) 06/29/1993 + +Revision History: + +--*/ + +#ifndef _MAC + + +/************************ FILE FORMATS ********************************** + + +Normal Metafile (memory or disk based): + + ------------ --------------- + | METAHEADER | Metafile bits | + ------------ --------------- + +Placeable Metafile: + + --------------------- ----------------- + | PLACEABLEMETAHEADER | Normal metafile | + --------------------- ----------------- + +Memory Based DIB: + + ------------------ --------------- ---------- + | BITMAPINFOHEADER | RGBQUAD array | DIB bits | + ------------------ --------------- ---------- + +DIB file format: + + ------------------ ------------------ + | BITMAPFILEHEADER | Memory based DIB | + ------------------ ------------------ + +Ole10NativeStream Format: + + -------- ---------------------- + | dwSize | Object's Native data | + -------- ---------------------- + +PBrush Native data format: + + ----------------- + | Dib File format | + ----------------- + +MSDraw Native data format: + + --------------------- ------------- ------------- ----------------- + | mapping mode (WORD) | xExt (WORD) | yExt (WORD) | Normal metafile | + --------------------- ------------- ------------- ----------------- + + +*****************************************************************************/ + +#include <ole2int.h> + +INTERNAL UtGetHMFPICTFromMSDrawNativeStm + (LPSTREAM pstm, DWORD dwSize, HANDLE FAR* lphdata) +{ + HRESULT error; + WORD mfp[3]; // mm, xExt, yExt + HMETAFILE hMF = NULL; + + *lphdata = NULL; + + if (error = pstm->Read(mfp, sizeof(mfp), NULL)) + return error; + + dwSize -= sizeof(mfp); + + if (error = UtGetHMFFromMFStm(pstm, dwSize, FALSE, (void **)&hMF)) + return error; + + AssertSz(mfp[0] == MM_ANISOTROPIC, "invalid map mode in MsDraw native data"); + + if (*lphdata = UtGetHMFPICT(hMF, TRUE, (int) mfp[1], (int) mfp[2])) + return NOERROR; + + return ResultFromScode(E_OUTOFMEMORY); +} + + +INTERNAL UtPlaceableMFStmToMSDrawNativeStm + (LPSTREAM pstmPMF, LPSTREAM pstmMSDraw) +{ + DWORD dwSize; // size of metafile bits excluding the placeable MF header + LONG xExt; + LONG yExt; + WORD wBuf[5]; // dwSize(DWORD), mm(int), xExt(int), yExt(int) + HRESULT error; + + if (error = UtGetSizeAndExtentsFromPlaceableMFStm(pstmPMF, &dwSize, + &xExt, &yExt)) + return error; + + *((DWORD FAR*) wBuf) = dwSize + 3*sizeof(WORD); + wBuf[2] = MM_ANISOTROPIC; + wBuf[3] = (int) xExt; + wBuf[4] = (int) yExt; + + if (error = pstmMSDraw->Write(wBuf, sizeof(wBuf), 0)) + return error; + + ULARGE_INTEGER ularge_int; + ULISet32(ularge_int, dwSize); + if ((error = pstmPMF->CopyTo(pstmMSDraw, ularge_int, + NULL, NULL)) == NOERROR) + StSetSize(pstmMSDraw); + + return error; + +} + + +INTERNAL UtDIBFileStmToPBrushNativeStm + (LPSTREAM pstmDIBFile, LPSTREAM pstmPBrush) +{ + BITMAPFILEHEADER bfh; + HRESULT error; + + if (error = pstmDIBFile->Read(&bfh, sizeof(bfh), 0)) + return error; + + // seek to the begining of the stream + LARGE_INTEGER large_int; + LISet32( large_int, 0); + if (error = pstmDIBFile->Seek(large_int, STREAM_SEEK_SET, 0)) + return error; + + if (error = pstmPBrush->Write(&(bfh.bfSize), sizeof(DWORD), 0)) + return error; + + ULARGE_INTEGER ularge_int; + ULISet32(ularge_int, bfh.bfSize); + + if ((error = pstmDIBFile->CopyTo(pstmPBrush, ularge_int, + NULL, NULL)) == NOERROR) + StSetSize(pstmPBrush); + + return error; +} + + + +INTERNAL UtContentsStmTo10NativeStm + (LPSTORAGE pstg, REFCLSID rclsid, BOOL fDeleteSrcStm, UINT FAR* puiStatus) +{ + CLIPFORMAT cf; + LPOLESTR lpszUserType = NULL; + HRESULT error; + LPSTREAM pstmSrc = NULL; + LPSTREAM pstmDst = NULL; + + *puiStatus = NULL; + + if (error = ReadFmtUserTypeStg(pstg, &cf, &lpszUserType)) + return error; + + + if (! ((cf == CF_DIB && rclsid == CLSID_PBrush) + || (cf == CF_METAFILEPICT && rclsid == CLSID_MSDraw))) { + error = ResultFromScode(DV_E_CLIPFORMAT); + goto errRtn; + } + + if (error = pstg->OpenStream(CONTENTS_STREAM, NULL, + (STGM_READ|STGM_SHARE_EXCLUSIVE), + 0, &pstmSrc)) { + *puiStatus |= CONVERT_NOSOURCE; + + // check whether OLE10_NATIVE_STREAM exists + if (pstg->OpenStream(OLE10_NATIVE_STREAM, NULL, + (STGM_READ|STGM_SHARE_EXCLUSIVE), 0, &pstmDst)) + *puiStatus |= CONVERT_NODESTINATION; + else { + pstmDst->Release(); + pstmDst = NULL; + } + + goto errRtn; + } + + if (error = OpenOrCreateStream(pstg, OLE10_NATIVE_STREAM, &pstmDst)) { + *puiStatus |= CONVERT_NODESTINATION; + goto errRtn; + } + + if (cf == CF_METAFILEPICT) + error = UtPlaceableMFStmToMSDrawNativeStm(pstmSrc, pstmDst); + else + error = UtDIBFileStmToPBrushNativeStm(pstmSrc, pstmDst); + +errRtn: + if (pstmDst) + pstmDst->Release(); + + if (pstmSrc) + pstmSrc->Release(); + + if (error == NOERROR) { + LPOLESTR lpszProgId = NULL; + ProgIDFromCLSID(rclsid, &lpszProgId); + + error = WriteFmtUserTypeStg(pstg, + RegisterClipboardFormat(lpszProgId), + lpszUserType); + + if (lpszProgId) + delete lpszProgId; + } + + if (error == NOERROR) { + if (fDeleteSrcStm) + pstg->DestroyElement(CONTENTS_STREAM); + } else { + pstg->DestroyElement(OLE10_NATIVE_STREAM); + } + + if (lpszUserType) + delete lpszUserType; + + return error; +} + + + +INTERNAL Ut10NativeStmToContentsStm + (LPSTORAGE pstg, REFCLSID rclsid, BOOL fDeleteSrcStm) +{ + extern CLIPFORMAT cfPBrush; + extern CLIPFORMAT cfMSDraw; + + CLIPFORMAT cfOld; + CLIPFORMAT cfNew; + LPOLESTR lpszUserType = NULL; + HRESULT error; + LPSTREAM pstmSrc = NULL; + LPSTREAM pstmDst = NULL; + + + if (error = ReadFmtUserTypeStg(pstg, &cfOld, &lpszUserType)) + return error; + + if (rclsid == CLSID_StaticDib) + cfNew = CF_DIB; + else if (rclsid == CLSID_StaticMetafile) + cfNew = CF_METAFILEPICT; + else { + AssertSz(FALSE, "Internal Error: this routine shouldn't have been called for this class"); + return ResultFromScode(E_FAIL); + } + + if (cfOld == cfPBrush) { + if (cfNew != CF_DIB) { + error = ResultFromScode(DV_E_CLIPFORMAT); + goto errRtn; + } + } else if (cfOld == cfMSDraw) { + if (cfNew != CF_METAFILEPICT) { + error = ResultFromScode(DV_E_CLIPFORMAT); + goto errRtn; + } + } else { + // Converted to static object from some class other than PBrush or + // MSDraw. The data must be in a proper format in the CONTENTS + // stream. + return NOERROR; + } + + if (error = pstg->OpenStream(OLE10_NATIVE_STREAM, NULL, + (STGM_READ|STGM_SHARE_EXCLUSIVE), + 0, &pstmSrc)) + goto errRtn; + + if (error = OpenOrCreateStream(pstg, CONTENTS_STREAM, &pstmDst)) + goto errRtn; + + DWORD dwSize; + if (error = pstmSrc->Read(&dwSize, sizeof(DWORD), NULL)) + goto errRtn; + + if (cfOld == cfMSDraw) { + WORD mfp[3]; // mm, xExt, yExt + + if (error = pstmSrc->Read(mfp, sizeof(mfp), NULL)) + goto errRtn; + + dwSize -= sizeof(mfp); + + error = UtMFStmToPlaceableMFStm(pstmSrc, dwSize, + (LONG) mfp[1], (LONG) mfp[2], pstmDst); + + } else { + // The PBrush native data format is DIB File format. So all we got to + // do is CopyTo. + + ULARGE_INTEGER ularge_int; + ULISet32(ularge_int, dwSize); + if ((error = pstmSrc->CopyTo(pstmDst, ularge_int, NULL, + NULL)) == NOERROR) + StSetSize(pstmDst); + } + +errRtn: + if (pstmDst) + pstmDst->Release(); + + if (pstmSrc) + pstmSrc->Release(); + + if (error == NOERROR) { + error = WriteFmtUserTypeStg(pstg, cfNew, lpszUserType); + + if (fDeleteSrcStm) + pstg->DestroyElement(OLE10_NATIVE_STREAM); + + } else { + pstg->DestroyElement(CONTENTS_STREAM); + } + + if (lpszUserType) + delete lpszUserType; + + return error; +} + +#endif + diff --git a/private/ole32/com/remote/dde/client/ddedo.cxx b/private/ole32/com/remote/dde/client/ddedo.cxx new file mode 100644 index 000000000..b982d6245 --- /dev/null +++ b/private/ole32/com/remote/dde/client/ddedo.cxx @@ -0,0 +1,954 @@ +/* +ddedo.cpp +DDE Data Object + +copyright (c) 1992 Microsoft Corporation + +Abstract: + + This module contains the methods for DdeObject::DataObject + +Author: + + Jason Fuller (jasonful) 24-July-1992 + +*/ + +#include "ddeproxy.h" +#include <stddef.h> +#include "trgt_dev.h" + + +#define f10UserModel +// Should we ignore a request by a 2.0 client to get advise-on-change, +// so that the user must do an explicit File/Update or File/Close? +// Probably yes, because: +// 1) Advise-on-change can be expensive for apps like PaintBrush. +// 2) It is confusing if the container asks for change updates +// ONLY on presentation and not on native because when the user +// closes the server and is asked "Do you want to update?" he'll say no +// because the picture LOOKS correct even though the container does not +// have the native data. +// 3) Excel: if A1 is the first cell you create, changes to other cells +// will not be sent to the client until you change A1 again. +// If advises are only sent explicitly, then all the cells extant at that +// time will be considered part of the object. + + +ASSERTDATA + + +// +// DataObject methods +// + +STDUNKIMPL_FORDERIVED(DdeObject, DataObjectImpl) + + +static inline INTERNAL_(BOOL) NotEqual + (DVTARGETDEVICE FAR* ptd1, + DVTARGETDEVICE FAR* ptd2) +{ + if (NULL==ptd1 && NULL==ptd2) + return FALSE; + else if ((ptd1 && !ptd2) + || (ptd2 && !ptd1) + || (ptd1->tdSize != ptd2->tdSize)) + { + return TRUE; + } + else +#ifdef WIN32 + return 0 != memcmp(ptd1, ptd2, (size_t)ptd1->tdSize); +#else + return 0 != _fmemcmp(ptd1, ptd2, (size_t)ptd1->tdSize); +#endif +} + + + +// GetData +// +// The data is copied out of a private cache consisting of +// DdeObject::m_hNative, DdeObject::m_hPict, and DdeObject::m_hExtra. +// If the cache is empty, data is requested using WM_DDE_REQUEST. +// The cache should only be empty before the first DDE_DATA message +// is received. +// See DdeObject::KeepData() +// +STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::GetData + (LPFORMATETC pformatetcIn, + LPSTGMEDIUM pmedium) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::GetData(%x,pformatetcIn=%x)\n", + this,pformatetcIn)); + +lStart: + intrDebugOut((DEB_ITRACE,"::GetData(%x)lStart\n",this)); + + LPSTR lpGlobal=NULL; + HRESULT hres; + VDATEPTROUT (pmedium, STGMEDIUM); + pmedium->tymed = TYMED_NULL; + pmedium->pUnkForRelease = NULL; + + if ((hres = wVerifyFormatEtc (pformatetcIn)) != NOERROR) + { + goto exitRtn; + } + + hres = E_UNEXPECTED; // assume error unless a clipboard format is found. + + if (DVASPECT_ICON & pformatetcIn->dwAspect) + { + hres = GetDefaultIcon(m_pDdeObject->m_clsid, NULL, &pmedium->hGlobal); + if (hres != NOERROR) + { + goto exitRtn; + } + hres = NOERROR; + goto lDone; + } + if (m_pDdeObject->m_fGotCloseData) + { + // If we already got DDE_DATA on close, don't try requesting more + // data. (MSDraw will give a bogus metafile.) + hres=OLE_E_NOTRUNNING; + goto exitRtn; + } + + if (NotEqual (pformatetcIn->ptd, m_pDdeObject->m_ptd)) + { + // If caller is asking for a different target device + // (We assume a different pointer points to a different target device) + + if (NOERROR!=m_pDdeObject->SetTargetDevice (pformatetcIn->ptd)) + { + // 1.0 server did not accept target device + hres=DATA_E_FORMATETC; + goto exitRtn; + } + + Assert (hres!=NOERROR); // Must do RequestData with new target device + } + else + { + // Pick a member handle (H) to return, based on clipboard format CF. + // If caller did not pass in its own medium, we must allocate a new + // handle. + + + #define macro(CF,H) \ + if (pformatetcIn->cfFormat == CF) { \ + if (m_pDdeObject->H) { \ + if (pmedium->tymed == TYMED_NULL) { \ + intrDebugOut((DEB_ITRACE,"::GetData giving cf==%x hData=%x\n",CF,m_pDdeObject->H)); \ + pmedium->hGlobal = m_pDdeObject->H; \ + m_pDdeObject->H = NULL; \ + } \ + hres = NOERROR; /* found data in right format */ \ + } \ + } + + macro (g_cfNative, m_hNative) + else macro (m_pDdeObject->m_cfPict, m_hPict ) + else macro (m_pDdeObject->m_cfExtra,m_hExtra ) + + // If we gave away our picture, we must forget its format. + if (pformatetcIn->cfFormat == m_pDdeObject->m_cfPict) + m_pDdeObject->m_cfPict = 0; + #undef macro + } + + if (hres!=NOERROR) + { + intrDebugOut((DEB_ITRACE, + "::GetData(%x) posting DDE_REQUEST for cf==%x\n", + this, + (ULONG)pformatetcIn->cfFormat)); + + // Didn't find a handle for the requested format, + // or handle was NULL, so request it. + // The sequence should be: + // GetData -> DDE_REQUEST -> DDE_DATA -> OnData -> return to GetData + + if (hres=m_pDdeObject->RequestData (pformatetcIn->cfFormat) != NOERROR) + { + intrDebugOut((DEB_ITRACE, + "::GetData(%x) RequestData returns error %x\n", + this,hres)); + + hres = DV_E_CLIPFORMAT; + goto exitRtn; + } + + // By now, a KeepData() should have been done with the right cf, + // so try again. + intrDebugOut((DEB_ITRACE, + "::GetData(%x) KeepData should have been called. Go again\n", + this)); + + Puts ("KeepData should have been called. Trying GetData again.\n"); + goto lStart; + } + lDone: + Puts ("pmedium->hGlobal =="); Puth(pmedium->hGlobal); Putn(); + pmedium->pUnkForRelease = NULL; // Let caller release medium + // Must set tymed _after_ the goto loop. + // Otherwise it'll be changed the second time around. + + // tell caller what we're returning + pmedium->tymed = UtFormatToTymed (pformatetcIn->cfFormat); + + + intrDebugOut((DEB_ITRACE, + "::GetData(%x)tymed=%x cfFormat=%x hGlobal=%x\n", + this, + pmedium->tymed, + (USHORT)pformatetcIn->cfFormat, + pmedium->hGlobal)); +exitRtn: + intrDebugOut((DEB_ITRACE, + "::GetData(%x)hres=%x\n", + this, + hres)); + return hres; +} + + + +STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::GetDataHere + (LPFORMATETC pformatetcIn, + LPSTGMEDIUM pmedium) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::GetDataHere(%x,pformatetcIn=%x)\n", + this, + pformatetcIn)); + + HRESULT hresult = NOERROR; + STGMEDIUM medium; + if (!(pformatetcIn->tymed & TYMED_HGLOBAL)) + { + intrDebugOut((DEB_ITRACE, + "::GetDataHere(%x)DV_E_TYMED(%x)\n", + this,DV_E_TYMED)); + // Cannot GetDataHere for GDI objects + hresult = DV_E_TYMED; + goto exitRtn; + } + RetErr (GetData (pformatetcIn, &medium)); + if (medium.tymed != TYMED_HGLOBAL) + { + intrDebugOut((DEB_ITRACE, + "::GetDataHere(%x)medium.tymed != TYMED_HGLOBAL\n", + this)); + hresult = ResultFromScode (DV_E_TYMED); + goto errRtn; + } + pmedium->tymed = medium.tymed; + pmedium->pUnkForRelease = medium.pUnkForRelease; + ErrRtnH (wHandleCopy (pmedium->hGlobal, medium.hGlobal)); + + errRtn: + ReleaseStgMedium (&medium); + + exitRtn: + intrDebugOut((DEB_ITRACE, + "CDdeObject::GetDataHere(%x) returning %x\n", + this,hresult)); + return hresult; +} + + + +STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::QueryGetData + (LPFORMATETC pformatetcIn) +{ + HRESULT hr; + intrDebugOut((DEB_ITRACE, + "%x _IN CDdeObject::QueryGetData(pformatetcIn=%x)\n", + this, + pformatetcIn)); + + hr = wVerifyFormatEtc (pformatetcIn); + + if (hr != NOERROR) + { + goto exitRtn; + } + if (pformatetcIn->cfFormat == g_cfEmbeddedObject + || pformatetcIn->cfFormat == g_cfEmbedSource + || pformatetcIn->cfFormat == g_cfLinkSource + || pformatetcIn->cfFormat == g_cfFileName + || pformatetcIn->cfFormat == g_cfCustomLinkSource + || pformatetcIn->cfFormat == g_cfObjectDescriptor + || pformatetcIn->cfFormat == g_cfLinkSrcDescriptor) + { + hr = S_FALSE; + } + + hr = m_pDdeObject->IsFormatAvailable (pformatetcIn); + +exitRtn: + intrDebugOut((DEB_ITRACE, + "%x _OUT CDdeObject::QueryGetData returning %x\n", + this,hr)); + return(hr); + +} + + +STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::SetData + (LPFORMATETC pformatetc, + STGMEDIUM FAR* pmedium, + BOOL fRelease) +{ + HANDLE hDdePoke; + HRESULT hresult; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDdeObject::SetData(pformatetc=%x)\n", + this, + pformatetc)); + + hresult = wVerifyFormatEtc (pformatetc); + + if (hresult != NOERROR) + { + goto exitRtn; + } + intrDebugOut((DEB_ITRACE, + "%x ::SetData(pformatetc->cfFormat=%x)\n", + this, + (ULONG)pformatetc->cfFormat)); + + if (pformatetc->dwAspect & DVASPECT_ICON) + { + intrDebugOut((DEB_ITRACE, + "%x ::SetData dwAspect & DVASPECT_ICON\n", + this)); + hresult = DV_E_DVASPECT; + goto exitRtn; + } + + + if (pformatetc->ptd != m_pDdeObject->m_ptd) + { + // If caller is setting with a different target device + // (We assume a different pointer points to a different target device) + + if (NOERROR != m_pDdeObject->SetTargetDevice (pformatetc->ptd)) + { + intrDebugOut((DEB_IERROR, + "%x ::SetData server did not accept target device\n", + this)); + hresult = DV_E_DVTARGETDEVICE; + goto exitRtn; + } + } + + if (hDdePoke = wPreparePokeBlock (pmedium->hGlobal, + pformatetc->cfFormat, + m_pDdeObject->m_aClass, + m_pDdeObject->m_bOldSvr)) + { + hresult = m_pDdeObject->Poke (m_pDdeObject->m_aItem, hDdePoke); + if (fRelease) + ReleaseStgMedium (pmedium); + goto exitRtn; + } + else + { + hresult = E_OUTOFMEMORY; + } +exitRtn: + + intrDebugOut((DEB_ITRACE,"%x _OUT ::SetData returns %x\n",this,hresult)); + return(hresult); + +} + + + + + +STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::DAdvise + (FORMATETC FAR* pformatetc, + DWORD grfAdvf, + IAdviseSink FAR* pAdvSink, + DWORD FAR* pdwConnection) +{ + HRESULT hresult; + HRESULT hresLookup; + FORMATETC formatetc; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDdeObject::DAdvise(pformatetc=%x,grfAdvf=%x,pAdvSink=%x)\n", + this, + pformatetc, + grfAdvf, + pAdvSink)); + + VDATEPTROUT (pdwConnection, DWORD); + *pdwConnection = 0; + + wNormalize (pformatetc, &formatetc); + + hresult =wVerifyFormatEtc (&formatetc); + + if ( hresult != NOERROR) + { + goto errRtn; + } + + intrDebugOut((DEB_ITRACE, + "%x ::DAdvise pformatetc->cfFormat=%x\n", + this, + pformatetc->cfFormat)); + + if (NotEqual (formatetc.ptd, m_pDdeObject->m_ptd)) + { + if (NOERROR != m_pDdeObject->SetTargetDevice (formatetc.ptd)) + { + hresult= DV_E_DVTARGETDEVICE; + goto errRtn; + } + } + + hresLookup = m_pDdeObject->m_ConnectionTable.Lookup (formatetc.cfFormat, NULL); + if (hresLookup != NOERROR) + { + // We have not already done a DDE advise for this format + + Puts (" m_iAdvChange = "); Puti (m_pDdeObject->m_iAdvChange); Puts("\n"); + + if (m_pDdeObject->m_ulObjType == OT_LINK) + { + ErrRtnH (m_pDdeObject->AdviseOn (formatetc.cfFormat, ON_CHANGE)); + ErrRtnH (m_pDdeObject->AdviseOn (formatetc.cfFormat, ON_SAVE)); + } + else + { + ErrRtnH (m_pDdeObject->AdviseOn (formatetc.cfFormat, ON_SAVE)); + ErrRtnH (m_pDdeObject->AdviseOn (formatetc.cfFormat, ON_CLOSE)); + } + } + + ErrZS (m_pDdeObject->m_pDataAdvHolder, E_OUTOFMEMORY); + hresult = m_pDdeObject->m_pDataAdvHolder->Advise (this, pformatetc, grfAdvf, + pAdvSink, pdwConnection); + + m_pDdeObject->m_ConnectionTable.Add (*pdwConnection, formatetc.cfFormat, + grfAdvf); + + errRtn: + intrDebugOut((DEB_ITRACE, + "%x _OUT CDdeObject::DAdvise hresult=%x\n", + this, + hresult)); + return hresult; +} + + + + +STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::DUnadvise + (DWORD dwConnection) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::DUnadvise(%x,dwConnection=%x)\n", + this, + dwConnection)); + + CLIPFORMAT cf; + HRESULT hres; + DWORD grfAdvf; + + // Remove connection from table. Lookup the cf for this connection. + if (m_pDdeObject->m_ConnectionTable.Subtract (dwConnection, &cf, &grfAdvf) + == NOERROR) + { + // If there is not another connection that needs this format + if (m_pDdeObject->m_ConnectionTable.Lookup (cf, NULL) != NOERROR) + { + // We did a DDE advise for this connection, so undo it. + if (m_pDdeObject->m_ulObjType == OT_LINK) + { + if (NOERROR != (hres=m_pDdeObject->UnAdviseOn (cf, ON_CHANGE))) + { + intrDebugOut((DEB_IWARN, + "::DUnadvise(%x,dwConnection=%x) ON_CHANGE failed\n", + this, + dwConnection)); + } + if (NOERROR != (hres=m_pDdeObject->UnAdviseOn (cf, ON_SAVE))) + { + intrDebugOut((DEB_IWARN, + "::DUnadvise(%x,dwConnection=%x) ON_SAVE failed\n", + this, + dwConnection)); + } + } + else + { + if (NOERROR != (hres=m_pDdeObject->UnAdviseOn (cf, ON_SAVE))) + { + intrDebugOut((DEB_IWARN, + "::DUnadvise(%x,dwConnection=%x) ON_SAVE failed\n", + this, + dwConnection)); + } + if (NOERROR != (hres=m_pDdeObject->UnAdviseOn (cf, ON_CLOSE))) + { + intrDebugOut((DEB_IWARN, + "::DUnadvise(%x,dwConnection=%x) ON_CLOSE failed\n", + this, + dwConnection)); + } + } + } + } + + // Delegate rest of the work to the DataAdviseHolder + RetZS (m_pDdeObject->m_pDataAdvHolder, E_OUTOFMEMORY); + return m_pDdeObject->m_pDataAdvHolder->Unadvise (dwConnection); +} + +STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::EnumDAdvise + (THIS_ LPENUMSTATDATA FAR* ppenumAdvise) +{ + RetZS (m_pDdeObject->m_pDataAdvHolder, E_OUTOFMEMORY); + return m_pDdeObject->m_pDataAdvHolder->EnumAdvise(ppenumAdvise); +} + +STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::EnumFormatEtc + (DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc) +{ + return OleRegEnumFormatEtc (m_pDdeObject->m_clsid, dwDirection, + ppenumFormatEtc); +} + + + + +STDMETHODIMP NC(CDdeObject,CDataObjectImpl)::GetCanonicalFormatEtc +(LPFORMATETC pformatetc, LPFORMATETC pformatetcOut) +{ + VDATEPTROUT (pformatetcOut, FORMATETC); + memcpy (pformatetcOut, pformatetc, sizeof (FORMATETC)); + return ReportResult(0, DATA_S_SAMEFORMATETC, 0, 0); + // We must be very conservative and assume data will be different for + // every formatetc +} + + + +INTERNAL CDdeObject::RequestData + (CLIPFORMAT cf) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::RequestData(%x,cf=%x)\n", + this,cf)); + + LPARAM lparam; + RetZ (m_pDocChannel); + intrAssert(wIsValidAtom(m_aItem)); + ATOM aItem = wDupAtom (m_aItem); + intrAssert(wIsValidAtom(aItem)); + + lparam = MAKE_DDE_LPARAM (WM_DDE_REQUEST,cf, aItem); + + if (!wPostMessageToServer (m_pDocChannel, + WM_DDE_REQUEST, + lparam, + TRUE)) + { + + if (aItem) + GlobalDeleteAtom (aItem); + + return RPC_E_SERVER_DIED; + } + + return WaitForReply(m_pDocChannel, AA_REQUEST); +} + + +// special name +const char achSpecialName[] = "DISPLAY"; + +// +// Return a 1.0 target device for the screen +// + +static INTERNAL DefaultTargetDevice (HANDLE FAR* ph) +{ + intrDebugOut((DEB_ITRACE, + "DefaultTargetDevice(ph=%x)\n",ph)); + + VDATEPTROUT ((LPVOID) ph, HANDLE); + LPOLETARGETDEVICE p1=NULL; + *ph = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, sizeof (*p1) + 10); + RetZS (*ph, E_OUTOFMEMORY); + p1 = (LPOLETARGETDEVICE) GlobalLock (*ph); + RetZS (p1, E_OUTOFMEMORY); + p1->otdDeviceNameOffset = 8; + p1->otdDriverNameOffset = 0; // The driver name is at otdData + p1->otdPortNameOffset = 9; + p1->otdExtDevmodeOffset = 0; + p1->otdExtDevmodeSize = 0; + p1->otdEnvironmentOffset= 0; + p1->otdEnvironmentSize = 0; + + // + // Note that memcpy is moving a constant string. Therefore, sizeof() + // will include the NULL terminator + // + // + memcpy((LPSTR)p1->otdData, achSpecialName,sizeof(achSpecialName)); + p1->otdData[8] = 0; // NULL the otdDeviceName + p1->otdData[9] = 0; // NULL the PortNameOffset + GlobalUnlock (*ph); + return NOERROR; +} + + + +//+--------------------------------------------------------------------------- +// +// Function: Convert20TargetDevice +// +// Synopsis: Converts a 2.0 TargetDevice into a 1.0 OLETARGETDEVICE +// +// Effects: First converts the 2.0 UNICODE target device into ANSI, +// then converts that into a 1.0 OLETARGETDEVICE. The astute +// reader would say: Why not just 2.0 UNICODE to OLETARGETDEVICE? +// +// Two reasons: time before we ship vs time needed elsewhere. +// +// If you can spare some time, please change this to go +// directly from one to the other. +// +// Arguments: [ptd] -- +// [phTD1] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-03-94 kevinro Created +// +// Notes: +// +// BUGBUG: the NT version of the OLE 1.0 used UINT as the size of the +// structures members. This was baaaad, since we really need them to be +// a fixed size. I am currently in the works of changing the NT 1.0 header +// file to reflect what we really need it to be, which is USHORT's +// +// +// We have a DVTARGETDEVICE, but we want a OLETARGETDEVICE, which looks like +// +// typedef struct _OLETARGETDEVICE { +// USHORT otdDeviceNameOffset; +// USHORT otdDriverNameOffset; +// USHORT otdPortNameOffset; +// USHORT otdExtDevmodeOffset; +// USHORT otdExtDevmodeSize; +// USHORT otdEnvironmentOffset; +// USHORT otdEnvironmentSize; +// BYTE otdData[1]; +// } OLETARGETDEVICE; +// +// A couple things to note: +// +// 1) The Names in the OLETARGETDEVICE need to be Ansi +// 2) The Environment member doens't exist in the DVTARGETDEVICE, and will +// be created in this conversion +// 3) The ExtDevmode also needs to be ANSI +// +//---------------------------------------------------------------------------- +INTERNAL Convert20TargetDevice + (const DVTARGETDEVICE FAR* ptd, // in parm + HANDLE FAR* phTD1) // out parm +{ + const size_t cbHeader = SIZEOF_DVTARGETDEVICE_HEADER; + HRESULT hr; + LPOLETARGETDEVICE ptd1 = NULL; + size_t cbTD1; + size_t cbDevmode; + size_t cbOffset; + LPDEVMODEA pdevmode; + + intrDebugOut((DEB_ITRACE, + "Convert20TargetDevice(ptd=%x)\n",ptd)); + + VDATEPTROUT ((LPVOID) phTD1, HANDLE); + *phTD1 = NULL; + + // + // If no device specified, then return the default + // + + if (NULL==ptd) + { + return DefaultTargetDevice (phTD1); + } + + // + // Compute information for doing conversion using routines in utils.cpp + // The following structure will get the sizes + // + + DVTDINFO dvtdInfo; + + hr = UtGetDvtd32Info(ptd,&dvtdInfo); + + if (hr != NOERROR) + { + return DV_E_DVTARGETDEVICE; + } + + // + // The conversion routines require us to allocate memory to pass in. + // + + DVTARGETDEVICE *pdvtdAnsi = (DVTARGETDEVICE *) PrivMemAlloc(dvtdInfo.cbConvertSize); + + if (pdvtdAnsi == NULL) + { + return(E_OUTOFMEMORY); + } + + // + // Convert the UNICODE target device into an ANSI target device + // + + hr = UtConvertDvtd32toDvtd16(ptd,&dvtdInfo,pdvtdAnsi); + + if (hr != NOERROR) + { + goto errRtn; + } + + // + // pdvtdAnsi now holds an ANSI version of the DVTARGETDEVICE. Turns + // out the structure we really want is the DVTARGETDEVICE, plus a + // couple of extra header bytes. Therefore, we can just do a block + // copy of the DVTARGETDEVICE's data, and fix up our OLETARGETDEVICE + // header to have the correct offsets in the data. + // + // offset of data block from beginning of 2.0 target device + // + cbOffset = offsetof (DVTARGETDEVICE, tdData); + + // + // Calculate a pointer to the DEVMODEA + // + pdevmode = pdvtdAnsi->tdExtDevmodeOffset ? + (LPDEVMODEA)((LPBYTE)pdvtdAnsi + pdvtdAnsi->tdExtDevmodeOffset) + : NULL; + + // + // Quick sanity check on the resulting pointer. + // + if (pdevmode && IsBadReadPtr (pdevmode, sizeof(DEVMODEA))) + { + hr = DV_E_DVTARGETDEVICE; + goto errRtn; + } + + // + // Calculate the size of the devmode part. + // + + cbDevmode = (pdevmode ? pdevmode->dmSize + pdevmode->dmDriverExtra:0); + + // + // Calculate the total size needed. The DVTARGETDEVICE header has 12 bytes, + // and the OLETARGETDEVICE has 14 bytes. We also need to make an extra copy + // of the cbDevmode structure to fill in the environment. Therefore, there is + // an extra cbDevmode, and a sizeof(USHORT) added to the size. The size includes + // the size of the DVTARGETHEADER + // + + cbTD1 = (size_t) pdvtdAnsi->tdSize + + cbDevmode + // For extra Environment data + sizeof (USHORT); // for Environment Size field + + *phTD1 = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, cbTD1); + if (NULL== *phTD1) + { + intrAssert (!"GlobalAlloc Failed"); + hr = E_OUTOFMEMORY; + goto errRtn; + } + + ptd1 = (LPOLETARGETDEVICE) GlobalLock (*phTD1); + if (NULL== ptd1) + { + intrAssert (!"GlobalLock Failed"); + hr = E_OUTOFMEMORY; + goto errRtn; + } + + // Set x1 (1.0 offset) based on x2 (2.0 offset) + // + // Note that the OLETARGETDEVICE offsets are relative to the array of bytes, + // where the DVTARGETDEVICE is relative to the start of the structure. Thats + // why cbOffset is subtracted + // + + #define ConvertOffset(x1, x2) (x1 = (x2 ? x2 - cbOffset : 0)) + + // + // Using the above macro, and assuming + // + + ConvertOffset (ptd1->otdDeviceNameOffset, pdvtdAnsi->tdDeviceNameOffset); + ConvertOffset (ptd1->otdDriverNameOffset, pdvtdAnsi->tdDriverNameOffset); + ConvertOffset (ptd1->otdPortNameOffset , pdvtdAnsi->tdPortNameOffset ); + ConvertOffset (ptd1->otdExtDevmodeOffset, pdvtdAnsi->tdExtDevmodeOffset); + ptd1->otdExtDevmodeSize = cbDevmode; + + // + // I found this in the OLE 2 information on OLETARGETDEVICE: + // + // The otdDeviceNameOffset, otdDriverNameOffset, and otdPortNameOffset + // members should be null-terminated. In Windows 3.1, the ability to + // connect multiple printers to one port has made the environment + // obsolete. The environment information retrieved by the + // GetEnvironment function can occasionally be incorrect. To ensure that the + // OLETARGETDEVICE structure is initialized correctly, the application + // should copy information from the DEVMODEA structure retrieved by a + // call to the ExtDeviceMode function to the environment position of + // the OLETARGETDEVICE structure. + // + // + + // + // Adjust the environment offset to the end of the converted structure, and + // set the size. the sizeof(USHORT) accounts for the addition of the + // otdEnvironmentSize field. The offsetof accounts for the fact that the + // OLETARGETDEVICE offsets are based from the otdData array. + // + ptd1->otdEnvironmentOffset = (USHORT) pdvtdAnsi->tdSize + + sizeof(USHORT) - + offsetof(OLETARGETDEVICE,otdData); + + ptd1->otdEnvironmentSize = cbDevmode; + + // Copy data block + if(IsBadWritePtr (ptd1->otdData, (size_t) pdvtdAnsi->tdSize - cbHeader)) + { + hr = E_UNEXPECTED; + goto errRtn; + } + memcpy (ptd1->otdData, pdvtdAnsi->tdData, (size_t) pdvtdAnsi->tdSize - cbHeader); + + if (cbDevmode != 0) + { + if(IsBadWritePtr (ptd1->otdData, sizeof (DEVMODEA))) + { + hr = E_UNEXPECTED; + goto errRtn; + } + + // Copy 2.0 Devmode into 1.0 environment + + memcpy (ptd1->otdData + ptd1->otdEnvironmentOffset, + pdvtdAnsi->tdData + pdvtdAnsi->tdExtDevmodeOffset, + cbDevmode); + } + + hr = NOERROR; + +errRtn: + + if (ptd1 != NULL) + { + GlobalUnlock(*phTD1); + } + + if (pdvtdAnsi != NULL) + { + PrivMemFree(pdvtdAnsi); + } + intrDebugOut((DEB_ITRACE, + "Convert20TargetDevice(ptd=%x) returns %x\n",ptd,hr)); + return(hr); +} + + + +static INTERNAL CopyTargetDevice + (const DVTARGETDEVICE FAR* ptd, + DVTARGETDEVICE FAR* FAR* pptd) +{ + intrDebugOut((DEB_ITRACE, + "CopyTargetDevice(ptd=%x)\n",ptd)); + + if (*pptd) + { + delete *pptd; // delete old target device + } + if (NULL==ptd) + { + *pptd = NULL; + } + else + { + *pptd = (DVTARGETDEVICE FAR*) operator new ((size_t) (ptd->tdSize)); + if (NULL==*pptd) + { + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + } + _fmemcpy (*pptd, ptd, (size_t) ptd->tdSize); + } + return NOERROR; +} + + + +INTERNAL CDdeObject::SetTargetDevice + (const DVTARGETDEVICE FAR* ptd) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::SetTargetDevice(%x,ptd=%x)\n", + this, + ptd)); + + HANDLE hTD1 = NULL; + HANDLE hDdePoke=NULL; + + RetErr (Convert20TargetDevice (ptd, &hTD1)); + + Assert (hTD1); + Verify (hDdePoke = wPreparePokeBlock (hTD1, g_cfBinary, m_aClass, m_bOldSvr)); + if (hTD1) + { + GlobalFree (hTD1); + } + // Poke new target device to 1.0 server + aStdTargetDevice = GlobalAddAtom (L"StdTargetDevice"); + intrAssert(wIsValidAtom(aStdTargetDevice)); + RetErr (Poke (aStdTargetDevice, hDdePoke)); + + // Remember current target device + RetErr (CopyTargetDevice (ptd, &m_ptd)); + // Flush the cache because it contains a picture for the wrong + // target device. + if (m_hPict) + wFreeData (m_hPict, m_cfPict); + m_cfPict = (CLIPFORMAT)0; + m_hPict = NULL; + + return NOERROR; +} diff --git a/private/ole32/com/remote/dde/client/ddeioc.cxx b/private/ole32/com/remote/dde/client/ddeioc.cxx new file mode 100644 index 000000000..cb97a244b --- /dev/null +++ b/private/ole32/com/remote/dde/client/ddeioc.cxx @@ -0,0 +1,213 @@ +/* + +copyright (c) 1992 Microsoft Corporation + +Module Name: + + ddeLink.cpp + +Abstract: + + This module contains the DdeObject::OleItemContainer methods + and other Link-related code + +Author: + + Jason Fuller (jasonful) 19-October-1992 + +*/ + +#include "ddeproxy.h" +// #include <limits.h> +// #include <utils.h> +// #include <moniker.h> + + +ASSERTDATA + + + +STDUNKIMPL_FORDERIVED (DdeObject, OleItemContainerImpl) + + +static INTERNAL_(void) wSkipDelimiter + (LPOLESTR * psz) +{ + if (wcschr (L"!\"'*+,./:;<=>?@[\\]`|" , **psz)) + (*psz)++; +} + + + +STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::ParseDisplayName + (LPBC pbc, + LPOLESTR lpszDisplayName, + ULONG * pchEaten, + LPMONIKER * ppmkOut) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::ParseDisplayName(%x,lpsz=%ws)\n", + this, + lpszDisplayName)); + + LPUNKNOWN pUnk = NULL; + VDATEPTROUT(ppmkOut,LPMONIKER); + *ppmkOut = NULL; + VDATEIFACE(pbc); + VDATEPTRIN(lpszDisplayName, char); + VDATEPTROUT(pchEaten,ULONG); + + *pchEaten = lstrlenW(lpszDisplayName); + wSkipDelimiter (&lpszDisplayName); + // Validate the item name + RetErr (GetObject (lpszDisplayName, BINDSPEED_INDEFINITE, pbc, + IID_IUnknown, (LPLPVOID) &pUnk)); + if (pUnk) + pUnk->Release(); + return CreateItemMoniker (L"!", lpszDisplayName, ppmkOut); +} + + + +STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::EnumObjects + (DWORD grfFlags, + LPENUMUNKNOWN FAR* ppenumUnk) + +{ + // OLE 1.0 provides no way to enumerate all the items in a document. + // This method is unlikely to be called since our implementation of + // file and item monikers does not call it. + Puts ("OleItemContainer::EnumObjects\r\n"); + if (ppenumUnk) + { + *ppenumUnk = NULL; + return E_NOTIMPL; + } + + return E_INVALIDARG; +} + + + +STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::LockContainer + (BOOL fLock) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::LockContainer(%x,fLock=%x)\n", + this, + fLock)); + + return NOERROR; +} + + + +STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::GetObject + (LPOLESTR lpszItem, + DWORD dwSpeedNeeded, + LPBINDCTX pbc, + REFIID riid, + LPVOID * ppvObject) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::GetObject(%x,szItem=%ws)\n", + this, + lpszItem)); + + + HRESULT hresult = NOERROR; + VDATEPTROUT (ppvObject, LPVOID); + *ppvObject=NULL; + LPUNKNOWN pUnk = NULL; // These refer to the + CDdeObject FAR* pdde = NULL; // same object + + RetZS (pUnk =CDdeObject::Create (NULL,m_pDdeObject->m_clsid,OT_LINK, + m_pDdeObject->m_aTopic,lpszItem,&pdde), + E_OUTOFMEMORY); + + // For handling invisible updates--propagate information from document + // to item. + pdde->DeclareVisibility (m_pDdeObject->m_fVisible); + pdde->m_fDidLaunchApp = m_pDdeObject->m_fDidLaunchApp; + pdde->m_fDidStdOpenDoc = m_pDdeObject->m_fDidStdOpenDoc; + + intrAssert(wIsValidAtom(pdde->m_aItem)); + ErrZ (0==lstrcmpW(lpszItem, wAtomName(pdde->m_aItem))); + + // OPTIMIZATION: Could use a mini Running Object Table to map lpszItem to + // LPUNKNOWN and avoiding the Connect() and DDE_REQUEST. + + // Open a DocChannel + ErrRtnH (pdde->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL)); + + // Request Native data in order to see if the item name is valid + Assert (pdde->m_pDocChannel); + LPARAM lp; + if (!wPostMessageToServer (pdde->m_pDocChannel, + WM_DDE_REQUEST, + lp=MAKE_DDE_LPARAM (WM_DDE_REQUEST,g_cfNative, wDupAtom(pdde->m_aItem)),TRUE)) + { + Assert (pdde->m_refs==1); + hresult = ResultFromScode (MK_E_NOOBJECT); + goto errRtn; + } + if (NOERROR != pdde->WaitForReply (pdde->m_pDocChannel, AA_REQUESTAVAILABLE)) + { + // Try metafile. Excel can't render large metafiles + // but it can render native. + if (!wPostMessageToServer (pdde->m_pDocChannel, + WM_DDE_REQUEST, + lp=MAKE_DDE_LPARAM (WM_DDE_REQUEST,CF_METAFILEPICT, wDupAtom(pdde->m_aItem)),TRUE)) + { + Assert (pdde->m_refs==1); + hresult = ResultFromScode (MK_E_NOOBJECT); + goto errRtn; + } + if (NOERROR != pdde->WaitForReply (pdde->m_pDocChannel, AA_REQUESTAVAILABLE)) + { + Assert (pdde->m_refs==1); + hresult = ResultFromScode (MK_E_NOOBJECT); + goto errRtn; + } + } + + // Item name is valid + hresult = pdde->m_pUnkOuter->QueryInterface (riid, (LPLPVOID) ppvObject); + if (NOERROR==hresult) + { + m_pDdeObject->m_fDidGetObject = TRUE; + } + errRtn: + if (pUnk) + pUnk->Release(); + return hresult; +} + + + +STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::GetObjectStorage + (LPOLESTR lpszItem, + LPBINDCTX ptc, + REFIID riid, + LPVOID * ppvStorage) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::GetObjectStorage(%x,szItem=%ws)\n", + this, + lpszItem)); + return MK_E_NOSTORAGE; +} + + + +STDMETHODIMP NC(CDdeObject, COleItemContainerImpl)::IsRunning + (LPOLESTR szItem) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::IsRunning(%x,szItem=%ws)\n", + this, + szItem)); + + // By definition, all items are running + return NOERROR; +} diff --git a/private/ole32/com/remote/dde/client/ddemnker.cxx b/private/ole32/com/remote/dde/client/ddemnker.cxx new file mode 100644 index 000000000..2331b02ad --- /dev/null +++ b/private/ole32/com/remote/dde/client/ddemnker.cxx @@ -0,0 +1,527 @@ +/* + +copyright (c) 1992 Microsoft Corporation + +Module Name: + + ddeLink.cpp + +Abstract: + + This module implements: + DdeBindToObject + DdeIsRunning + +Author: + + Jason Fuller (jasonful) 19-October-1992 + +*/ +#include "ddeproxy.h" +// #include <ctype.h> + + +INTERNAL DdeBindToObject + (LPCOLESTR szFileIn, + REFCLSID clsid, + BOOL fPackageLink, + REFIID iid, + LPLPVOID ppv) +{ + intrDebugOut((DEB_ITRACE, + "DdeBindToObject szFileIn(%ws) fPackageLink(%x)\n", + szFileIn, + fPackageLink)); + + + LPUNKNOWN punk; + *ppv = NULL; + CDdeObject FAR* pdde=NULL; + HRESULT hresult = E_UNEXPECTED; + BOOL fSysConnection = FALSE; + WCHAR wszTmpFile [MAX_STR+5]; + + // + // This protocol doesn't handle the fact that there are two names for + // every file. This is a bit of a problem. So, we are going to choose + // the short name as the one to look for. This means that DDE objects + // using the long filename will not work very well. + // + WCHAR szFile[MAX_PATH]; + if ((lstrlenW(szFileIn) == 0) || (GetShortPathName(szFileIn,szFile,MAX_PATH) == 0)) + { + // + // Unable to determine a short path for this object. Use whatever we were + // handed. + // + intrDebugOut((DEB_ITRACE,"No conversion for short path. Copy szFileIn\n")); + lstrcpyW(szFile,szFileIn); + } + intrDebugOut((DEB_ITRACE,"Short file szFile(%ws)\n",szFile)); + + RetZS (punk=CDdeObject::Create (NULL,clsid,OT_LINK,wGlobalAddAtom(szFile), + NULL,&pdde),E_OUTOFMEMORY); + RetZ (pdde); + + // Document already running? + + if (NOERROR != (hresult = pdde->DocumentLevelConnect (NULL) )) + { + if (GetScode (hresult) != S_FALSE) + { + intrDebugOut((DEB_ITRACE, + "DdeBindToObject szFile(%ws) DLC returns %x \n", + szFile,hresult)); + goto exitRtn; + } + + + // If not already running, try to make a sys level connection + + if (!pdde->m_pSysChannel) { + if (!pdde->AllocDdeChannel (&pdde->m_pSysChannel, SYS_CLASSA)) + { + intrAssert( !"Out of memory"); + hresult = E_OUTOFMEMORY; + goto exitRtn; + } + } + + hresult = ReportResult (0, E_UNEXPECTED, 0, 0); + + if (fPackageLink) { + lstrcpyW (wszTmpFile, szFile); + lstrcatW (wszTmpFile, L"/Link"); + pdde->SetTopic (wGlobalAddAtom(wszTmpFile)); + } + + if (pdde->InitSysConv()) + { + fSysConnection = TRUE; + + // Try to make the server open the document + ErrRtnH (pdde->PostSysCommand (pdde->m_pSysChannel, (LPSTR)&achStdOpenDocument,FALSE)); + pdde->m_fDidStdOpenDoc = TRUE; + + } + else + { + // launch the server + if (!pdde->LaunchApp()) + { + hresult = CO_E_APPNOTFOUND; + goto errRtn; + } + } + + if (fPackageLink) + pdde->SetTopic (wGlobalAddAtom(szFile)); + + // Connect to document + hresult = pdde->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL); + if (hresult != NOERROR) + { + // Excel does not register its document in time if it loads + // startup macros. So we force it to open the document. + if (pdde->InitSysConv()) + { + fSysConnection = TRUE; + // Try to make the server open the document. + ErrRtnH (pdde->PostSysCommand (pdde->m_pSysChannel, + (LPSTR)&achStdOpenDocument, + FALSE)); + pdde->m_fDidStdOpenDoc = TRUE; + } + else + { + ErrRtnH (ResultFromScode (CO_E_APPDIDNTREG)); + } + // Try connecting to document again. Should succeed. + hresult = pdde->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL); + } + } + else + { + // Already running, so assume visible + pdde->DeclareVisibility (TRUE); + } + +errRtn: + if (pdde->m_pSysChannel) { + if (fSysConnection) + pdde->TermConv (pdde->m_pSysChannel); + else + pdde->DeleteChannel (pdde->m_pSysChannel); + } + + if (hresult == NOERROR) { + hresult = punk->QueryInterface (iid, ppv); + } + pdde->m_pUnkOuter->Release(); + if (hresult!=NOERROR) + { + Warn ("DdeBindToObject failed"); + } + +exitRtn: + intrDebugOut((DEB_ITRACE, + "DdeBindToObject szFile(%ws) returns %x \n", + szFile,hresult)); + + return hresult; +} + + +// +// BUGBUG: This won't work in a multi-threaded world. +// +static LPOLESTR szOriginalUNCName; +static WCHAR cOriginalDrive; + +static INTERNAL InitializeIterator + (LPCOLESTR wszFile) +{ + WCHAR wszDrive[] = L"A:\\"; + + if ((wszFile == NULL) || (wszFile[1] != ':')) + { + return(S_FALSE); + } + + wszDrive[0] = (WCHAR)CharUpperW((LPWSTR)wszFile[0]); + + if (GetDriveType(wszDrive) == DRIVE_REMOTE) + { + + DWORD cb = MAX_STR; + wszDrive[2] = '\0'; + if (NULL==szOriginalUNCName) + { + szOriginalUNCName = new WCHAR [MAX_STR]; + } + + + if (WN_SUCCESS == OleWNetGetConnection (wszDrive, szOriginalUNCName, &cb)) + { + cOriginalDrive = (WCHAR)CharUpperW((LPWSTR)wszFile[0]); + return NOERROR; + } + } + // szFile is not a network file + return ReportResult (0, S_FALSE, 0, 0); +} + + + +// NextEquivalentNetDrive +// +// Change the drive letter of szFile to the next (modulo 'Z') drive letter +// that is connected to the same net drive +// Return S_FALSE when there are no more equivalent drives +// +static INTERNAL NextEquivalentNetDrive + (LPOLESTR szFile) +{ + #define incr(c) (c=='Z' ? c='A' : ++c) + WCHAR wszDrive[3]= L"A:"; + Assert (szFile && szFile[1]==':'); + + char cDrive = (char)CharUpperW((LPWSTR)szFile[0]); + + while (cOriginalDrive != incr(cDrive)) + { + + DWORD cb = MAX_PATH; + WCHAR szUNCName [MAX_PATH]; + wszDrive[0] = cDrive; + + Assert (cDrive >= 'A' && cDrive <= 'Z'); + Assert (szOriginalUNCName); + + if (WN_SUCCESS == OleWNetGetConnection (wszDrive,szUNCName, &cb) && + (0 == lstrcmpW (szUNCName, szOriginalUNCName))) + { + szFile[0] = cDrive; + return NOERROR; + } + } + // We've gone through all the drives + return ReportResult (0, S_FALSE, 0, 0); +} + + + +// Dde_IsRunning +// +// Attempt to open a document-level conversation using the +// filename as a topic. If the conversation is established we +// know the file is running and terminate the conversation. +// Otherwise it is not running. +// +INTERNAL DdeIsRunning + (CLSID clsid, + LPCOLESTR szFileIn, + LPBC pbc, + LPMONIKER pmkToLeft, + LPMONIKER pmkNewlyRunning) +{ + intrDebugOut((DEB_ITRACE, + "DdeIsRunning szFileIn(%ws)\n",szFileIn)); + + ATOM aTopic; + CDdeObject FAR* pdde=NULL; + HRESULT hres = ReportResult(0, S_FALSE, 0, 0); + + if (NULL==szFileIn || '\0'==szFileIn[0]) + { + // A NULL filename is invalid for our purposes. + // But if we did a DDE_INITIATE, NULL would mean "any topic", + // and if we were called by RunningMoniker() with CLSID_NULL, + // then we would be INITIATEing on "any app, any topic" and + // SHELL (if not others) would respond. + intrDebugOut((DEB_ITRACE, + "DdeIsRunning NULL szFileIn\n")); + + hres = S_FALSE; + goto exitRtn; + } + // + // This protocol doesn't handle the fact that there are two names for + // every file. This is a bit of a problem. So, we are going to choose + // the short name as the one to look for. This means that DDE objects + // using the long filename will not work very well. + // + WCHAR szFile[MAX_PATH]; + if ((lstrlenW(szFileIn) == 0) || (GetShortPathName(szFileIn,szFile,MAX_PATH) == 0)) + { + // + // Unable to determine a short path for this object. Use whatever we were + // handed. + // + intrDebugOut((DEB_ITRACE,"No conversion for short path. Copy szFileIn\n")); + lstrcpyW(szFile,szFileIn); + } + intrDebugOut((DEB_ITRACE,"Short file szFile(%ws)\n",szFile)); + +#ifdef KEVINRO_OLDCODE + +We have removed SzFixNet from the system, since the file system is +capable of dealing with UNC names now. Therefore, I have removed the +following lines. I am pretty sure this is going to work, but I am +leaving this code here until we decide that it is a good decision. +If you find this, and I haven't removed it, chances are that I forgot +to remove this code. + HRESULT hresFixNet; + UINT dummy; + + // If UNC name, change to drive letter + LPOLESTR szFile = NULL; + dummy = 0xFFFF; + + hresFixNet = SzFixNet (pbc, szFile, &szFile, &dummy); + // SzFixNet may return NOERROR and szFile==NULL + if (szFile==NULL || hresFixNet != NOERROR) + { + aTopic = wGlobalAddAtom(szFile); + intrAssert(wIsValidAtom(aTopic)); + } + else + { + aTopic = wGlobalAddAtom (szFile); + intrAssert(wIsValidAtom(aTopic)); + delete szFile; + } +#else + aTopic = wGlobalAddAtom (szFile); + intrAssert(wIsValidAtom(aTopic)); +#endif // KEVINRO_OLDCODE + + + ErrZ (CDdeObject::Create (NULL, clsid, OT_LINK, aTopic, NULL, &pdde)); + + if (NOERROR == pdde->DocumentLevelConnect (pbc)) + { + // It is running! + // Immediately terminate conversation. We just wanted to know + // if it was running. + hres = NOERROR; + } + else + { + // Not running + hres = ReportResult(0, S_FALSE, 0, 0); + } + + errRtn: + + if (aTopic) + intrAssert(wIsValidAtom(aTopic)); + GlobalDeleteAtom (aTopic); + if (pdde) + { + Assert (pdde->m_refs==1); + pdde->m_pUnkOuter->Release(); + } + +exitRtn: + intrDebugOut((DEB_ITRACE, + "DdeIsRunning szFile(%ws) returns %x\n",szFile,hres)); + return hres; +} + + +#if 0 +INTERNAL DdeIsRunning + (CLSID clsid, + LPCSTR cszFile, + LPBC pbc, + LPMONIKER pmkToLeft, + LPMONIKER pmkNewlyRunning) +{ + HRESULT hresult = NOERROR; + LPSTR szFile = NULL; + + // Normal case + if (NOERROR == Dde_IsRunning (clsid, cszFile, pbc, pmkToLeft, + pmkNewlyRunning)) + { + return NOERROR; + } + + if (cszFile[0]=='\\' && cszFile[1]=='\\') + { + RetErr (SzFixNet (pbc, (LPSTR)cszFile, &szFile)); + // Try with a drive letter instead of a UNC name + if (NOERROR==Dde_IsRunning (clsid, szFile, pbc, pmkToLeft, + pmkNewlyRunning)) + { + hresult = NOERROR; + goto errRtn; + } + } + else + { + szFile = UtDupString (cszFile); // so it can be deleted + } + + // If failure, see if the file is running under a different net + // drive letter that is mapped to the same drive. + + if (InitializeIterator (szFile) != NOERROR) + { + // file is probably not on a network drive + hresult = ResultFromScode (S_FALSE); + goto errRtn; + } + + while (NOERROR==NextEquivalentNetDrive (szFile)) + { + if (NOERROR == Dde_IsRunning (clsid, szFile, pbc, pmkToLeft, + pmkNewlyRunning)) + { + hresult = NOERROR; + goto errRtn; + } + } + // not running + hresult = ResultFromScode (S_FALSE); + + errRtn: + delete szFile; + return hresult; +} +#endif + + + +// CDdeObject::DocumentLevelConnect +// +// Try to connect to document (m_aTopic) even if the document is running +// under a different drive letter that is mapped to the same network drive. +// +INTERNAL CDdeObject::DocumentLevelConnect + (LPBINDCTX pbc) +{ + ATOM aOriginal; + ATOM aTopic; + + intrDebugOut((DEB_ITRACE, + "CDdeObject::DocumentLevelConnect(%x)\n",this)); + HRESULT hresult = NOERROR; + + // Normal case + if (NOERROR==m_ProxyMgr.Connect (IID_NULL, CLSID_NULL)) + { + goto exitRtn; + } + + + WCHAR szFile[MAX_STR]; + WCHAR szUNCFile[MAX_STR]; + + Assert (wIsValidAtom (m_aTopic)); + if (GlobalGetAtomName (m_aTopic, szFile, MAX_STR) == 0) + { + hresult = E_UNEXPECTED; + goto exitRtn; + } + aOriginal = wDupAtom (m_aTopic); + intrAssert(wIsValidAtom(aOriginal)); + + intrDebugOut((DEB_ITRACE, + "::DocumentLevelConnect(szFile=%ws)\n",this,szFile)); + if (NOERROR != InitializeIterator (szFile)) + { + // szFile probably not a network file + hresult = ResultFromScode (S_FALSE); + goto errRtn; + } + + while (NOERROR == NextEquivalentNetDrive (szFile)) + { + SetTopic (aTopic = wGlobalAddAtom (szFile)); + if (NOERROR==m_ProxyMgr.Connect (IID_NULL, CLSID_NULL)) + { + // Inform client of new drive letter + ChangeTopic (wAtomNameA(aTopic)); + hresult = NOERROR; + goto errRtn; + } + else + { + SetTopic ((ATOM)0); + } + } + + // Try with full UNC name + lstrcpyW (szUNCFile, szOriginalUNCName); + lstrcatW (szUNCFile, szFile+2); // skip X: + SetTopic (aTopic = wGlobalAddAtom (szUNCFile)); + if (NOERROR==m_ProxyMgr.Connect (IID_NULL, CLSID_NULL)) + { + // Inform client of new name + ChangeTopic (wAtomNameA(aTopic)); + hresult = NOERROR; + goto errRtn; + } + else + { + SetTopic ((ATOM)0); + } + + // Not running + hresult = S_FALSE; + +errRtn: + if (NOERROR != hresult) + SetTopic (aOriginal); + delete szOriginalUNCName; + szOriginalUNCName = NULL; + +exitRtn: + intrDebugOut((DEB_ITRACE, + "CDdeObject::DocumentLevelConnect(%x) returns %x\n", + this,hresult)); + + return hresult; +} diff --git a/private/ole32/com/remote/dde/client/ddeoo.cxx b/private/ole32/com/remote/dde/client/ddeoo.cxx new file mode 100644 index 000000000..491756634 --- /dev/null +++ b/private/ole32/com/remote/dde/client/ddeoo.cxx @@ -0,0 +1,770 @@ +/* +ddeoo.cpp +DDE Ole Object + +copyright (c) 1992 Microsoft Corporation + +Module Name: + + ddeoo.cpp + +Abstract: + + This module contains the methods for DdeObject::OleObject + +Author: + + Jason Fuller (jasonful) 24-July-1992 + +*/ + +#include "ddeproxy.h" +#include <limits.h> + +ASSERTDATA + +// +// OleObject methods +// + +STDUNKIMPL_FORDERIVED(DdeObject, OleObjectImpl) + + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetClientSite + (IOleClientSite FAR* pClientSite) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::SetClientSite(%x,pClientSite=%x)\n", + this, + pClientSite)); + + ChkD (m_pDdeObject); + + if (m_pDdeObject->m_pOleClientSite) + m_pDdeObject->m_pOleClientSite->Release(); + + // we've decided to keep the pointer that's been passed to us. So we + // must AddRef() + if (m_pDdeObject->m_pOleClientSite = pClientSite) + pClientSite->AddRef(); + + // this pointer need not be sent to the server, because we will always + // send our &m_MyDataSite as the client site + return NOERROR; +} + + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetClientSite + (IOleClientSite FAR* FAR* ppClientSite) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::GetClientSite(%x)\n", + this)); + + ChkD (m_pDdeObject); + // we've been asked to give the pointer so we should AddRef() + if (*ppClientSite = m_pDdeObject->m_pOleClientSite) + m_pDdeObject->m_pOleClientSite->AddRef(); + return NOERROR; +} + + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::EnumVerbs + (IEnumOLEVERB FAR* FAR* ppenumOleVerb) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::EnumVerbs(%x)\n", + this)); + + ChkD (m_pDdeObject); + return ReportResult(0, OLE_S_USEREG, 0, 0); +} + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Update +( void ) +{ + HRESULT hr; + + intrDebugOut((DEB_ITRACE, + "CDdeObject::Update(%x)\n", + this)); + + ChkD (m_pDdeObject); + + hr = m_pDdeObject->Update(TRUE); + if (hr == NOERROR) + { + hr = m_pDdeObject->Save(m_pDdeObject->m_pstg); + } + + return hr; +} + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::IsUpToDate +( void ) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::IsUpToDate(%x)\n", + this)); + + ChkD (m_pDdeObject); + // There is no way to know if a 1.0 server has edited its embedded + // object, so we assume it has, to be on the safe side. + return ResultFromScode (m_pDdeObject->m_ulObjType==OT_EMBEDDED + ? S_FALSE : S_OK); +} + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetUserClassID + (CLSID FAR* pClsid) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::GetUserClassID(%x)\n", + this)); + + *pClsid = m_pDdeObject->m_clsid; + return NOERROR; +} + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetUserType + (DWORD dwFormOfType, + LPOLESTR * pszUserType) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::GetUserType(%x)\n", + this)); + + return ReportResult (0, OLE_S_USEREG, 0, 0); +} + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetExtent +( DWORD dwAspect, LPSIZEL lpsizel) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::SetExtent(%x)\n", + this)); + + HANDLE hDdePoke; + LPRECT16 lprc; + + ChkD (m_pDdeObject); + Puts ("OleObject::SetExtent\n"); + if (!(dwAspect // at least one bit + && !(dwAspect & (dwAspect-1)) // exactly one bit + && (dwAspect & DVASPECT_CONTENT))) // a bit we support + { + return ResultFromScode (DV_E_DVASPECT); + } + +#ifdef OLD + m_pDdeObject->m_cxContentExtent = lpsizel->cx; + m_pDdeObject->m_cyContentExtent = lpsizel->cy; +#endif + + if (!m_pDdeObject->m_pDocChannel) + { + return OLE_E_NOTRUNNING; + } + + lprc = (LPRECT16) wAllocDdePokeBlock (sizeof(RECT16), g_cfBinary, &hDdePoke); + lprc->left = lprc->right = (SHORT) min(INT_MAX,lpsizel->cx); + lprc->top = lprc->bottom= (SHORT) min(INT_MAX,lpsizel->cy); + aStdDocDimensions = GlobalAddAtom (OLESTR("StdDocDimensions")); + intrAssert(wIsValidAtom(aStdDocDimensions)); + GlobalUnlock (hDdePoke); + return m_pDdeObject->Poke(aStdDocDimensions, hDdePoke); +} + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetExtent +( DWORD dwAspect, LPSIZEL lpsizel) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::GetExtent(%x)\n", + this)); + + ChkD (m_pDdeObject); + + +#ifdef OLD + VDATEPTROUT (lpsizel, SIZEL); + if (!(dwAspect // at least one bit + && !(dwAspect & (dwAspect-1)) // exactly one bit + && !(dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON)))) // a bit we support + { + return ResultFromScode (DV_E_DVASPECT); + } + + if (dwAspect & DVASPECT_CONTENT) + { + lpsizel->cx = m_pDdeObject->m_cxContentExtent; + lpsizel->cy = m_pDdeObject->m_cyContentExtent; + } + + return NOERROR; +#endif + return ResultFromScode(E_NOTIMPL); + +} + +//+--------------------------------------------------------------------------- +// +// Method: CDdeObject::DoVerb +// +// Synopsis: Send the server a message asking it to do a verb. +// +// Effects: OLE1.0 servers only know how to do a couple of +// verbs. Specifically, it will respond to PRIMARY, +// HIDE, OPEN, and SHOW. All others return error +// +// +// Arguments: [iVerb] -- Verb number +// [lpmsg] -- Window message (ignored) +// [pActiveSite] -- ActiveSite (ignored) +// [lindex] -- Index (ignored) +// [hwndParent] -- (ignored) +// [lprcPosRect] -- (ignored) +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 5-12-94 kevinro Created +// +// Notes: +// +// ANSI ALERT! +// +// The server is going to accept a command string from us. This string +// needs to be done in ANSI, since we are going to pass it to old +// servers. Therefore, the following code generates an ANSI string +// The following are the supported verb strings +// +// [StdShowItem("aItem",FALSE)] +// [StdDoVerbItem("aItem",verb,FALSE,FALSE)] +// +//---------------------------------------------------------------------------- +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::DoVerb + (LONG iVerb, LPMSG lpmsg, LPOLECLIENTSITE pActiveSite, + LONG lindex, HWND hwndParent, const RECT FAR* lprcPosRect) +{ + WORD len; + ULONG size; + LPSTR lpdata = NULL; + LPSTR lpdataStart = NULL; + HANDLE hdata = NULL; + BOOL bShow; + HRESULT hresult; + + ChkD (m_pDdeObject); + + intrDebugOut((DEB_ITRACE, + "CDdeObject::DoVerb(%x,iVerb=%x,lindex=%x)\n", + this,iVerb,lindex)); + + if (iVerb < OLEIVERB_HIDE) + { + intrDebugOut((DEB_ITRACE, + "CDdeObject::DoVerb(%x)Returning invalid verb\n", + this)); + return OLEOBJ_E_INVALIDVERB; + } + + + if (iVerb == OLEIVERB_HIDE) + { + intrDebugOut((DEB_ITRACE,"::DoVerb(%x) OLEIVERB_HIDE\n",this)); + + if (m_pDdeObject->m_fVisible || OT_LINK==m_pDdeObject->m_ulObjType) + { + intrDebugOut((DEB_ITRACE, + "::DoVerb(%x) CANNOT_DOVERB_NOW\n",this)); + return OLEOBJ_S_CANNOT_DOVERB_NOW; + } + + intrDebugOut((DEB_ITRACE,"::DoVerb(%x) returns NOERROR\n",this)); + return NOERROR; + } + + // + // Calculate the number of bytes needed to pass the + // execute command to the server. + // + if (bShow = (iVerb == OLEIVERB_SHOW + || iVerb == OLEIVERB_OPEN + || m_pDdeObject->m_bOldSvr)) + { + // + // [StdShowItem("aItem",FALSE)] + // + + len = 23 + wAtomLenA (m_pDdeObject->m_aItem) + 1; + + } + else + { + // [StdDoVerbItem("aItem",verb,FALSE,FALSE)] + len = 32 + 10 /* for verb */ + wAtomLenA (m_pDdeObject->m_aItem) + 1; + + } + + if (!(hdata = GlobalAlloc (GMEM_DDESHARE, size = len))) + { + intrDebugOut((DEB_ITRACE, + "::DoVerb(%x) cannot alloc %x bytes\n", + this,size)); + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + } + + + if (!(lpdata = (LPSTR)GlobalLock (hdata))) + { + intrDebugOut((DEB_ITRACE, + "::DoVerb(%x) cannot lock\n", + this)); + GlobalFree (hdata); + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + } + + lpdataStart = lpdata; + + + strcpy (lpdata, bShow ? "[StdShowItem(\"" : "[StdDoVerbItem(\""); + len = strlen (lpdata); + lpdata += len; + + // For links + if (m_pDdeObject->m_aItem) + lpdata += GlobalGetAtomNameA (m_pDdeObject->m_aItem, lpdata, size - len); + + if (!bShow) { + wsprintfA (lpdata,"\",%lu,TRUE,FALSE)]", iVerb); + } else { + strcpy (lpdata, "\")]"); + // apps like excel and wingraph do not support activate at item level. + } + + intrDebugOut((DEB_ITRACE,"::DoVerb(%x)lpdata(%s)\n",this,lpdataStart)); + + Assert (strlen(lpdata) < size); + + GlobalUnlock (hdata); + + hresult = m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel, hdata); + + if (NOERROR==hresult) + { + // Assume doing a verb makes the server visible. + // This is not strictly true. + m_pDdeObject->DeclareVisibility (TRUE); + } + else + { + intrDebugOut((DEB_ITRACE, + "::DoVerb(%x)Execute returned %x\n", + this, + hresult)); + } + return hresult; +} + + + + + +//+--------------------------------------------------------------------------- +// +// Method: CDdeObject::SetHostNames +// +// Synopsis: Sets the host names +// +// Effects: +// +// Arguments: [szContainerApp] -- Name of container app +// [szContainerObj] -- Name of contained object +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 5-12-94 kevinro Created +// +// Notes: +// ANSI ALERT! +// +// The server is going to accept a command string from us. This string +// needs to be done in ANSI, since we are going to pass it to old +// servers. Therefore, the following code generates an ANSI string +// +//---------------------------------------------------------------------------- +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetHostNames +(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::SetHostNames(%x,App=%ws,Obj=%ws)\n", + this,szContainerApp,szContainerObj)); + + WORD cbName; + WORD wSize; + LPSTR lpBuf; + HANDLE hDdePoke; + + ChkD (m_pDdeObject); + + VDATEPTRIN (szContainerApp, char); + + if (!m_pDdeObject->m_pDocChannel) + return NOERROR; + if (szContainerObj==NULL) + szContainerObj=OLESTR(""); + + if (szContainerApp[0]=='\0') + szContainerApp = OLESTR("Container Application"); + + // + // The OLE 1.0 server is going to want ANSI strings. + // convert the two that we have + // + + char pszContainerApp[MAX_STR]; + char pszContainerObj[MAX_STR]; + + if (WideCharToMultiByte(CP_ACP, + 0, + szContainerApp, + -1, + pszContainerApp, + MAX_STR, + NULL, + NULL) == FALSE) + { + intrDebugOut((DEB_ERROR, + "::SetHostNames(%x) can't convert szContainerApp(%ws) err=%x\n", + this,szContainerApp,GetLastError())); + + // + // Couldn't convert string + // + return(E_UNEXPECTED); + } + if (WideCharToMultiByte(CP_ACP, + 0, + szContainerObj, + -1, + pszContainerObj, + MAX_STR, + NULL, + NULL) == FALSE) + { + intrDebugOut((DEB_ERROR, + "::SetHostNames(%x) can't convert szContainerObj(%ws) err=%x\n", + this,szContainerObj,GetLastError)); + + // + // Couldn't convert string + // + return(E_UNEXPECTED); + } + + + // + // We have found through experience that some OLE applications, like + // Clipart, use a fixed size buffer for these names. Therefore, we + // are going to limit the sizes of the strings, in case they are + // too long to send. We do this by always sticking a NULL at offset + // 80 in the file. + // + pszContainerApp[80]=0; + pszContainerObj[80]=0; + + WORD cbObj; + + wSize = (cbName = strlen(pszContainerApp)+1) + + (cbObj = strlen(pszContainerObj)+1) + + 2 * sizeof(WORD); // for the two offsets + + lpBuf = wAllocDdePokeBlock ((DWORD)wSize, g_cfBinary, &hDdePoke); + ((WORD FAR*)lpBuf)[0] = 0; + ((WORD FAR*)lpBuf)[1] = cbName; + lpBuf += 2*sizeof(WORD); + memcpy (lpBuf,pszContainerApp,cbName); + memcpy (lpBuf+cbName, pszContainerObj,cbObj); + GlobalUnlock (hDdePoke); + aStdHostNames = GlobalAddAtom (OLESTR("StdHostNames")); + intrAssert(wIsValidAtom(aStdHostNames)); + m_pDdeObject->Poke(aStdHostNames, hDdePoke); + return NOERROR; +} + + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Close + (DWORD dwSaveOption) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::Close(%x,dwSaveOption=%x)\n", + this,dwSaveOption)); + + + ChkDR (m_pDdeObject); + + HRESULT hresult; + if (m_pDdeObject->m_fDidSendOnClose) + return ResultFromScode (RPC_E_CANTCALLOUT_INASYNCCALL); + + if (((OLECLOSE_SAVEIFDIRTY == dwSaveOption) || + (OLECLOSE_PROMPTSAVE==dwSaveOption)) && + (m_pDdeObject->m_clsid != CLSID_Package)) + { + // Packager gives truncated native data (header info with no + // actual embedded file) if you DDE_REQUEST it. Bug 3103 + Update(); // IOleObject::Update + m_pDdeObject->OleCallBack (ON_SAVE,NULL); + } + RetZ (m_pDdeObject->m_pDocChannel); + hresult=m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel, + wNewHandle ((LPSTR)&achStdCloseDocument,sizeof(achStdCloseDocument)), + TRUE); + if (NOERROR==hresult) + m_pDdeObject->m_fDidStdCloseDoc = TRUE; + + // Client sends StdCloseDocument. Srvr sends ACK. Srvr may or may not + // send Terminate. We may interpret the TERMINATE the server sends + // as the reply to ours even if he posted first. But since some servers + // post first and others wait for the client, this is what we need to do. + + BOOL fVisible = m_pDdeObject->m_fWasEverVisible; // TermConv clears this flag + m_pDdeObject->TermConv (m_pDdeObject->m_pDocChannel); + if (!fVisible) + m_pDdeObject->MaybeUnlaunchApp(); + + return hresult; +} + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetMoniker + (DWORD dwWhichMoniker, LPMONIKER pmk) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::SetMoniker(%x,dwWhichMoniker=%x)\n", + this,dwWhichMoniker)); + + ChkD (m_pDdeObject); + Puts ("OleObject::SetMoniker\r\n"); + // we ignore this always + return NOERROR; +} + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetMoniker + (DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::GetMoniker(%x,dwWhichMoniker=%x)\n", + this,dwWhichMoniker)); + + ChkD (m_pDdeObject); + if (m_pDdeObject->m_pOleClientSite) + return m_pDdeObject->m_pOleClientSite->GetMoniker(dwAssign, + dwWhichMoniker, ppmk); + else { + // no client site + *ppmk = NULL; + return ReportResult(0, E_UNSPEC, 0, 0); + } +} + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::InitFromData + (LPDATAOBJECT pDataObject, BOOL fCreation, DWORD dwReserved) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::InitFromData(%x)\n", + this)); + + Puts ("OleObject::InitFromData\r\n"); + return ReportResult(0, E_NOTIMPL, 0, 0); +} + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetClipboardData + (DWORD dwReserved, LPDATAOBJECT FAR* ppDataObject) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::GetClipboardData(%x)\n", + this)); + + Puts ("OleObject::GetClipboardData\r\n"); + return ReportResult(0, E_NOTIMPL, 0, 0); +} + + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Advise + (IAdviseSink FAR* pAdvSink, + DWORD FAR* pdwConnection) +{ + HRESULT hres; + intrDebugOut((DEB_ITRACE, + "CDdeObject::Advise(%x)\n", + this)); + + ChkD (m_pDdeObject); + Puts ("OleObject::Advise\n"); + // Esstablish a DDE advise connection. + if (m_pDdeObject->m_ulObjType == OT_EMBEDDED + && !m_pDdeObject->m_fDidAdvNative) + { + // Embedded case. + // Always advise on Save and Close. + if (hres = m_pDdeObject->AdviseOn (g_cfNative, ON_SAVE)) + return hres; + if (hres = m_pDdeObject->AdviseOn (g_cfNative, ON_CLOSE)) + return hres; + if (m_pDdeObject->m_clsid == CLSID_MSDraw) + { + // MSDraw has (another) bug. If you do not do an Advise on + // presentation, then File.Update does not work, and you + // cannot close the app unless you answer "no" to the update + // dialog. This would happen when you "Display As Icon" + // because ordinarily there is no need to advise on presentation. + // The following "unnecessary" advise fixes this problem. + if (hres = m_pDdeObject->AdviseOn (CF_METAFILEPICT, ON_SAVE)) + return hres; + if (hres = m_pDdeObject->AdviseOn (CF_METAFILEPICT, ON_CLOSE)) + return hres; + } + } + else { + /* Linked case */ + if (hres = m_pDdeObject->AdviseOn (g_cfBinary, ON_RENAME)) + return hres; + } + RetZS (m_pDdeObject->m_pOleAdvHolder, E_OUTOFMEMORY); + return m_pDdeObject->m_pOleAdvHolder->Advise (pAdvSink, pdwConnection); +} + + + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::Unadvise + (DWORD dwConnection) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::Unadvise(%x,dwConnection=%x)\n", + this,dwConnection)); + + HRESULT hres; + ChkD (m_pDdeObject); + + // Terminate the DDE advise connection + if (m_pDdeObject->m_ulObjType == OT_EMBEDDED) + { + // Embedded case. + if (hres = m_pDdeObject->UnAdviseOn (g_cfNative, ON_SAVE)) + return hres; + if (hres = m_pDdeObject->UnAdviseOn (g_cfNative, ON_CLOSE)) + return hres; + } + else + { + /* Linked case */ + if (hres = m_pDdeObject->UnAdviseOn (g_cfBinary, ON_RENAME)) + return hres; + } + RetZS (m_pDdeObject->m_pOleAdvHolder, E_OUTOFMEMORY); + return m_pDdeObject->m_pOleAdvHolder->Unadvise (dwConnection); +} + + + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::EnumAdvise + (THIS_ LPENUMSTATDATA FAR* ppenumAdvise) +{ + ChkD (m_pDdeObject); + RetZS (m_pDdeObject->m_pOleAdvHolder, E_OUTOFMEMORY); + return m_pDdeObject->m_pOleAdvHolder->EnumAdvise(ppenumAdvise); +} + + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::GetMiscStatus + (DWORD dwAspect, + DWORD FAR* pdwStatus) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::GetMiscStatus(%x)\n", + this)); + + VDATEPTRIN (pdwStatus, DWORD); + *pdwStatus = 0L; + return ResultFromScode (OLE_S_USEREG); +} + + + +STDMETHODIMP NC(CDdeObject,COleObjectImpl)::SetColorScheme + (LPLOGPALETTE lpLogpal) +{ + HANDLE hDdePoke; + LPLOGPALETTE lptmpLogpal; + + intrDebugOut((DEB_ITRACE, + "CDdeObject::SetColorScheme(%x)\n", + this)); + + ChkD (m_pDdeObject); + + if (!m_pDdeObject->m_pDocChannel) + return NOERROR; + + aStdColorScheme = GlobalAddAtom (OLESTR("StdColorScheme")); + intrAssert(wIsValidAtom(aStdColorScheme)); + + DWORD dwSize = (lpLogpal->palNumEntries - 1) * sizeof(PALETTEENTRY) + + sizeof(LOGPALETTE); + lptmpLogpal = (LPLOGPALETTE) wAllocDdePokeBlock (dwSize, g_cfBinary, &hDdePoke); + memcpy(lptmpLogpal, lpLogpal, dwSize); + GlobalUnlock(hDdePoke); + + return m_pDdeObject->Poke(aStdColorScheme, hDdePoke); +} + + + +#ifdef _DEBUG +STDMETHODIMP_(void) NC(CDdeObject,CDebug)::Dump( IDebugStream FAR * pdbstm) +{ +} + +STDMETHODIMP_(BOOL) NC(CDdeObject,CDebug)::IsValid( BOOL fSuspicious ) +{ + if( m_pDdeObject->m_refs > 0 && m_pDdeObject->m_chk == chkDdeObj ) + return TRUE; + else + return FALSE; +} +#endif diff --git a/private/ole32/com/remote/dde/client/ddeproxy.cxx b/private/ole32/com/remote/dde/client/ddeproxy.cxx new file mode 100644 index 000000000..f02ee8137 --- /dev/null +++ b/private/ole32/com/remote/dde/client/ddeproxy.cxx @@ -0,0 +1,2899 @@ +/* +copyright (c) 1992 Microsoft Corporation + +Module Name: + + ddeproxy.cpp + +Abstract: + + This module contains the code for the dde proxy (wrapper) + +Author: + + Srini Koppolu (srinik) 22-June-1992 + Jason Fuller (jasonful) 24-July-1992 +*/ +#include "ddeproxy.h" +#include <tls.h> + +DebugOnly (static UINT v_cDdeObjects=0;) +/* + * IMPLEMENTATION of CDdeObject + * + */ + +#ifdef OLD +#define UpdateExtent(old,new) do { if ((long)new!=old) {old=(long)new; } } while (0) +#endif + +//+--------------------------------------------------------------------------- +// +// Function: CreateDdeClientHwnd +// +// Synopsis: Creates a per thread ClientDde window. +// +// Effects: This window is created so we can keep a list of windows that +// need to be cleaned up in the event the thread dies or OLE32 is +// unloaded. In the case of DLL unload, we will fault if we don't +// cleanup this window, since user will dispatch messages to +// non-existant code. The easy way to track these windows is to +// make them children of a common per thread window. +// +// This routine is called by the TLSGetDdeClient() routine to +// create a window per thread. This window doesn't need to respond +// to DDE Initiates. +// +// Arguments: [void] -- +// +// Returns: HWND to DdeClientWindow. +// +// History: 12-10-94 kevinro Created +// +//---------------------------------------------------------------------------- + +HWND CreateDdeClientHwnd(void) +{ + return SSCreateWindowExA(0,"STATIC","DdeClientHwnd",WS_DISABLED, + 0,0,0,0,NULL,NULL,hinstSO,NULL); +} + +//+--------------------------------------------------------------------------- +// +// Function: GetDdeCallControlInterface +// +// Synopsis: Gets the thread specific instance of the DDE CallControl +// +// Effects: If there is already a per thread CallControl interface, +// AddRef() it and return the value. Otherwise, get one and +// set it in the TLS data structure. The TLS structure is +// a global per thread structure that contains various values. +// +// Each threads per instance version of the CallControl will +// be stored in a global place. ReleaseDdeCallControlInterface +// is used to free up instances of the interface. +// +// Arguments: (none) +// +// Requires: +// +// Returns: Per thread instance of ICallControl. NULL if error +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-13-94 kevinro Created +// +// Notes: +// +//---------------------------------------------------------------------------- +PCALLCONTROL GetDdeCallControlInterface() +{ + PCALLCONTROL pDdeControl = (PCALLCONTROL)TLSGetDdeCallControl(); + + if (pDdeControl != NULL) + { + pDdeControl->AddRef(); + return(pDdeControl); + } + // + // There wasn't one in the TLS data. Create one, and return it. + // + ORIGINDATA origindata; + + // + // There is a single channel control (static implementation) + // for all DDE windows in the process. The hwndCli is set + // to NULL, since DDE messages are handled specially by + // the MessageFilter code. + // + origindata.pChCont = (PCHANNELCONTROL)&g_CDdeChannelControl; + origindata.CallOrigin = CALLORIGIN_DDE; + origindata.hwnd = (HWND)0; + origindata.wFirstMsg = WM_DDE_FIRST; + origindata.wLastMsg = WM_DDE_LAST; + + if(CoGetCallControl(&origindata, &pDdeControl) == NOERROR) + { + TLSSetDdeCallControl(pDdeControl); + } + else + { + intrAssert(!"Could not CoGetCallControl"); + pDdeControl = NULL; + } + return(pDdeControl); +} + +//+--------------------------------------------------------------------------- +// +// Function: ReleaseDdeCallControlInterface +// +// Synopsis: This function will release the per thread CallControl +// interface. If the Release() returns zero, then the +// function will set the per thread instance to NULL. +// +// Effects: +// +// Arguments: (none) +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-13-94 kevinro Created +// +// Notes: +// +//---------------------------------------------------------------------------- +void ReleaseDdeCallControlInterface() +{ + PCALLCONTROL pDdeControl = (PCALLCONTROL)TLSGetDdeCallControl(); + + intrAssert(pDdeControl != NULL); +#if DBG == 1 + if (pDdeControl == NULL) + { + DebugBreak(); + } +#endif + if ((pDdeControl != NULL) && (pDdeControl->Release() == 0)) + { + TLSSetDdeCallControl(NULL); + } +} + + +// CreateDdeProxy +// +// This corresponds to ProxyManager::Create in 2.0 +// + + +INTERNAL_ (LPUNKNOWN) CreateDdeProxy + (IUnknown * pUnkOuter, + REFCLSID clsid) +{ + LPUNKNOWN punk; + intrDebugOut((DEB_ITRACE,"CreateDdeProxy(pUnkOuter=%x)\n",pUnkOuter)); + punk = CDdeObject::Create (pUnkOuter, clsid); + intrDebugOut((DEB_ITRACE, + "CreateDdeProxy(pUnkOuter=%x) returns %x\n", + pUnkOuter, + punk)); + return punk; +} + +//+--------------------------------------------------------------------------- +// +// Method: CDdeObject::Create +// +// Synopsis: Creates a CDdeObject +// +// Effects: +// +// Arguments: [pUnkOuter] -- Controlling IUnknown +// [clsid] -- OLE1 ClassID +// [ulObjType] -- Object type. Optional: def to OT_EMBEDDED +// [aTopic] -- Atom of link. Optional: def to NULL +// [szItem] -- String for link object (def to NULL) +// [ppdde] -- Output pointer to CDdeObject (def to NULL) +// [fAllowNullClsid] -- Is NULL clsid OK? Default: false +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL_(LPUNKNOWN) CDdeObject::Create + (IUnknown * pUnkOuter, + REFCLSID clsid, + ULONG ulObjType,// optional, default OT_EMBEDDED + ATOM aTopic, // optional, only relevant if ulObjType==OT_LINK + LPOLESTR szItem, // optional, only relevant if ulObjType==OT_LINK + CDdeObject * * ppdde, // optional, thing created + BOOL fAllowNullClsid) // default FALSE +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::Create(%x,ulObjType=%x)\n", + pUnkOuter, + ulObjType)); + + CDdeObject * pDdeObject; + static int iTopic=1; // used to make topic names unique + WCHAR szTopic[30]; + Assert (ulObjType==OT_LINK || ulObjType==OT_EMBEDDED); + + Assert (ulObjType != OT_LINK || wIsValidAtom(aTopic)); + if (ppdde) + *ppdde = NULL; + + if (NULL==(pDdeObject = new CDdeObject (pUnkOuter)) + || NULL == pDdeObject->m_pDataAdvHolder + || NULL == pDdeObject->m_pOleAdvHolder) + { + Assert (!"new CDdeObject failed"); + return NULL; + } + + pDdeObject->m_refs = 1; + pDdeObject->m_clsid = clsid; + pDdeObject->m_aClass = wAtomFromCLSID(clsid); + +#ifdef OLE1INTEROP + + pDdeObject->m_fOle1interop = TRUE; + +#endif + + if (ulObjType==OT_LINK) + { + + pDdeObject->m_aTopic = wDupAtom (aTopic); + pDdeObject->m_aItem = wGlobalAddAtom (szItem); + // Never close a linked document + pDdeObject->m_fNoStdCloseDoc = TRUE; + } + else + { + // This string may actually be visible in the Window Title Bar for a sec. + InterlockedIncrement((long *)&iTopic); + wsprintf (szTopic,OLESTR("Embedded Object #%u"), iTopic); + Assert (lstrlenW(szTopic) < 30); + pDdeObject->m_aItem = NULL; + pDdeObject->m_aTopic = wGlobalAddAtom (szTopic); + } + pDdeObject->m_bOldSvr = wIsOldServer (pDdeObject->m_aClass); + pDdeObject->m_ulObjType = ulObjType; + + // we can only run if we have a MFI + pDdeObject->m_aExeName = wGetExeNameAtom(clsid); + + intrDebugOut((DEB_ITRACE, + "::Create(%x,aTopic=%x,aItem=%x,szItem=%ws,aExeName=%x)\n", + pDdeObject, + pDdeObject->m_aTopic, + pDdeObject->m_aItem, + szItem?szItem:L"<NULL>", + pDdeObject->m_aExeName)); + + if (ppdde) + *ppdde = pDdeObject; + return &pDdeObject->m_Unknown; +} + + + +// Constructor +CDdeObject::CDdeObject (IUnknown * pUnkOuter) : + m_Unknown(this), + CONSTRUCT_DEBUG + m_Data(this), + m_Ole(this), + m_PersistStg(this), + m_ProxyMgr(this), + m_OleItemContainer(this) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::CDdeObject(%x)\n",this)); + if (!pUnkOuter) + pUnkOuter = &m_Unknown; + + m_pUnkOuter = pUnkOuter; + m_bRunning = FALSE; + m_pOleClientSite = NULL; + m_pstg = NULL; + m_pSysChannel = NULL; + m_pDocChannel = NULL; + m_bInitNew = NULL; + m_hNative = NULL; + m_hPict = NULL; + m_hExtra = NULL; + m_cfExtra = NULL; + m_cfPict = 0; + m_aItem = NULL; + m_iAdvSave = 0; + m_iAdvClose = 0; + m_iAdvChange = 0; + m_fDidAdvNative = FALSE; + m_pOleAdvHolder = NULL; + m_pDataAdvHolder = NULL; + m_fDidSendOnClose = FALSE; + m_fNoStdCloseDoc = FALSE; + m_fDidStdCloseDoc = FALSE; + m_fDidStdOpenDoc = FALSE; + m_fDidGetObject = FALSE; + m_fDidLaunchApp = FALSE; + m_fUpdateOnSave = TRUE; + m_fVisible = FALSE; + m_fWasEverVisible = FALSE; + m_fCalledOnShow = FALSE; + m_fGotCloseData = FALSE; + m_cLocks = 1; // connections are initially locked + m_chk = chkDdeObj; + m_ptd = NULL; + m_fDoingSendOnDataChange = FALSE; +#ifdef _CHICAGO_ + //Note:POSTPPC + _DelayDelete = NoDelay; +#endif // _CHICAGO_ + + CreateOleAdviseHolder (&m_pOleAdvHolder); + Assert (m_pOleAdvHolder); + CreateDataAdviseHolder (&m_pDataAdvHolder); + Assert (m_pDataAdvHolder); + +#ifdef OLD + m_cxContentExtent = 2000; // 2 centimeters , totally random default + m_cyContentExtent = 2000; +#endif + + m_wTerminate = Terminate_None; + + DebugOnly (v_cDdeObjects++;) + Putsi (v_cDdeObjects); +} + + + +CDdeObject::~CDdeObject + (void) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::~CDdeObject(%x)\n",this)); + + if (m_pDocChannel) + { + intrDebugOut((DEB_IWARN , "Abnormal situation: Doc Channel not deleted. Server died?")); + delete m_pDocChannel; + } + if (m_pSysChannel) + { + Warn ("Abnormal situation: Sys Channel not deleted. Server died?"); + delete m_pSysChannel; + } + if (m_hNative) + { + GlobalFree(m_hNative); + } + + if (m_hPict) + { + wFreeData (m_hPict, m_cfPict, TRUE); + } + + if (m_hExtra) + { + wFreeData (m_hExtra, m_cfExtra, TRUE); + } + + // release all the pointers that we remember + + if (m_pOleClientSite) + { + DeclareVisibility (FALSE); + m_pOleClientSite->Release(); + } + + if (m_pDataAdvHolder) + m_pDataAdvHolder->Release(); + + if (m_pOleAdvHolder) + m_pOleAdvHolder->Release(); + + if (m_pstg) + m_pstg->Release(); + + if (m_aExeName) + GlobalDeleteAtom (m_aExeName); + + if (m_aClass) + GlobalDeleteAtom (m_aClass); + + if (m_aTopic) + GlobalDeleteAtom (m_aTopic); + + if (m_aItem) + GlobalDeleteAtom (m_aItem); + + if (m_ptd) + delete m_ptd; + + m_chk = 0; + DebugOnly (v_cDdeObjects--;) + Putsi (v_cDdeObjects); +} + + + + +// Handles WM_DDE_ACKs received while in initiate state. If this is the first +// reply, save its window handle. If multiple replies are received, take the +// one with the prefered instance, if there is one. Keep a count of +// WM_DDE_TERMINATEs we send so that we don't shut the window until we get +// all of the responses for WM_DDE_TERMINATEs. + + +INTERNAL_(void) CDdeObject::OnInitAck (LPDDE_CHANNEL pChannel, HWND hwndSvr) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::OnInitAck(%x,hwndSvr=%x)\n",this,hwndSvr)); +#ifdef _MAC +#else + if (!IsWindow (hwndSvr)) + { + Assert (0); + return; + } + if (pChannel->hwndSvr) { // if we already have a handle + intrDebugOut((DEB_ITRACE, + "CDdeObject::OnInitAck(%x,hwndSvr=%x) Already have hwndSvr=%x\n", + this, + hwndSvr, + pChannel->hwndSvr)); + // just take the very first one. Direct post is OK + MPostWM_DDE_TERMINATE(hwndSvr,pChannel->hwndCli); + // Expect an extra WM_DDE_TERMINATE + ++pChannel->iExtraTerms; + } else { + // this is the server we want + pChannel->hwndSvr = hwndSvr; + pChannel->iExtraTerms = NULL; + + intrDebugOut((DEB_ITRACE, + "CDdeObject::OnInitAck(%x,hwndSvr=%x) Established Connection\n", + this, + hwndSvr, + pChannel->hwndSvr)); + } +#endif _MAC +} + +INTERNAL_(BOOL) CDdeObject::OnAck (LPDDE_CHANNEL pChannel, LONG lParam) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::OnAck(%x,lParam=%x)\n",this,lParam)); + + BOOL retval = TRUE; + ATOM aItem; + WORD wStatus; + HANDLE hData; + + if( pChannel->iAwaitAck == AA_EXECUTE) + { + wStatus = GET_WM_DDE_EXECACK_STATUS( NULL, lParam ); + hData = GET_WM_DDE_EXECACK_HDATA( NULL, lParam ); + } + else + { + wStatus = GET_WM_DDE_ACK_STATUS( NULL, lParam ); + aItem = GET_WM_DDE_ACK_ITEM( NULL, lParam ); + } + + + // check for busy bit + if (wStatus & 0x4000) + { + // we got busy from the server. + pChannel->fRejected = TRUE; + // tell the wait loop that we got a busy ack + //CoSetAckState(pChannel->pCI , FALSE,TRUE, SERVERCALLEX_RETRYLATER); + intrDebugOut((DEB_ITRACE,"::OnAck(%x) Busy SetCallState(SERVERCALLEX_RETRYLATER)\n",this)); + pChannel->pCallCont->SetCallState(pChannel->pCD, SERVERCALLEX_RETRYLATER, NOERROR); + return TRUE; + } + + // just reset the flag always + m_wTerminate = Terminate_None; + + intrDebugOut((DEB_ITRACE, + "::OnAck(%x)aItem=%x(%ws) wStatus=\n", + this, + aItem, + wAtomName(aItem), + wStatus)); + + if (pChannel->iAwaitAck == AA_EXECUTE) + { + GlobalFree (hData); + pChannel->hCommands = NULL; + } + else + { + if (hData) + GlobalDeleteAtom ((ATOM)hData); + } + + + // even if the client got terminate we have to go thru this path. + + if (pChannel->wTimer) { + KillTimer (pChannel->hwndCli, 1); + pChannel->wTimer = 0; + } + + + if (pChannel->iAwaitAck == AA_POKE) + // We have to free the data first. OnAck can trigger + // another Poke (like pokehostnames) + wFreePokeData (pChannel, (m_bOldSvr && m_aClass==aMSDraw)); + + + if (!(wStatus & POSITIVE_ACK)) + { + intrDebugOut((DEB_ITRACE,"::OnAck(%x) OnAck got an ack with fAck==FALSE.\n",this)); + + // A negative ack is OK when doing a temporary advise from + // IsFormatAvailable(). Also, apps don't seem to positively + // ack all unadvises. + + // review: johannp : this is the case were have to inform the reply rejected call + + retval = FALSE; + // we got the ack and can leave the wait loop + //CoSetAckState(pChannel->pCI, FALSE); + + intrDebugOut((DEB_ITRACE, + "::OnAck(%x) ***_ NACK _*** SetCallState(ISHANDLED,RPC_E_DDE_NACK)\n", + this)); + + pChannel->pCallCont->SetCallState(pChannel->pCD, SERVERCALLEX_ISHANDLED, RPC_E_DDE_NACK); + + // MSDraw frees hOptions even on a NACK, despite official DDE rules. + if (pChannel->iAwaitAck == AA_ADVISE && m_clsid != CLSID_MSDraw) + GlobalFree (pChannel->hopt); + } + else + { + // we got the ack and can leave the wait loop + // CoSetAckState(pChannel->pCI, FALSE); + intrDebugOut((DEB_ITRACE, + "::OnAck(%x) POSITIVE_ACK SetCallState(SERVERCALLEX_ISHANDLED)\n", + this)); + pChannel->pCallCont->SetCallState(pChannel->pCD, SERVERCALLEX_ISHANDLED, NOERROR); + } + + pChannel->hopt = NULL; + pChannel->iAwaitAck = NULL; + return retval; + +} + + + + + +INTERNAL_(void) CDdeObject::OnTimer (LPDDE_CHANNEL pChannel) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::OnTimer(%x)\n",this)); + // Since there is only one timer for each client, just + // repost the message and delete the timer. +#ifdef _MAC +#else + KillTimer (pChannel->hwndCli, 1); + pChannel->wTimer = 0; + + if (wPostMessageToServer(pChannel, pChannel->wMsg, pChannel->lParam,FALSE)) + return ; + + // Postmessage failed. We need to getback to the main stream of + // commands for the object. + OnAck (pChannel, pChannel->lParam); +#endif _MAC +} + + + +// Called when we get a WM_DDE_DATA message in reponse to +// a DDE_REQUEST we sent to check if a format is available. +// +INTERNAL CDdeObject::OnDataAvailable + (LPDDE_CHANNEL pChannel, + HANDLE hDdeData, + ATOM aItem) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::OnDataAvailable(%x)\n",this)); + CLIPFORMAT cf; + Assert (AA_REQUESTAVAILABLE == pChannel->iAwaitAck); + intrAssert( wIsValidAtom(aItem)); + + DDEDATA * pDdeData = (DDEDATA *) GlobalLock (hDdeData); + RetZS (pDdeData, E_OUTOFMEMORY); + if (!pDdeData->fAckReq && aItem) + { + GlobalDeleteAtom (aItem); + } + cf = pDdeData->cfFormat; + GlobalUnlock (hDdeData); + wFreeData (wHandleFromDdeData (hDdeData), cf); + return NOERROR; +} + + + +// Called for WM_DDE_DATA message. If data is from an ADVISE-ON-CLOSE and this +// is there are no more outstanding ADVISE-ON-CLOSE requests, close the +// document and end the conversation. + + +//+--------------------------------------------------------------------------- +// +// Method: CDdeObject::OnData +// +// Synopsis: Called when a WM_DDE_DATA message is recieved. If the data +// is from an ADVISE_ON_CLOSE, and there are no more +// outstanding ADVISE_ON_CLOSE request, close the document +// and end the conversation. +// +// Effects: The effects of this routine are complex. +// +// Wow! What else can be said. This routine does alot of stuff in response +// to an incoming WM_DDE_DATA message. There are basically two flavors of +// response here. First is when we were expecting to get this result, +// in which case we know what we wanted to do with the data. Second is +// when the data just arrives, but we didn't expect it. These cases could +// indicate that the server is shutting down. +// +// +// Arguments: [pChannel] -- The DDE channel recieving the message +// [hDdeData] -- Handle to the data +// [aItem] -- Atom to the item +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 5-16-94 kevinro Restructured and commented +// +// Notes: +// +// +// Be extra careful you change this routine. +// This is especially neccesary if you are going to exit early. The +// way that hDdeData is free'd or kept should be understood before +// changing. +// +// +//---------------------------------------------------------------------------- +INTERNAL CDdeObject::OnData + (LPDDE_CHANNEL pChannel, + HANDLE hDdeData, + ATOM aItem) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::OnData(%x,pChannel=%x,hDdeData=%x,aItem=%x(%s)iAwaitAck=%x\n", + this, + pChannel, + hDdeData, + aItem, + wAtomNameA(aItem), + pChannel->iAwaitAck)); +#ifdef _MAC +#else + DDEDATA * lpDdeData = NULL; + BOOL fAck = TRUE; + int iAdvOpt; + BOOL fCallBack; + HRESULT hresult = NOERROR; + + ICallControl *lpCallCont = pChannel->pCallCont; + intrAssert(lpCallCont != NULL); + BOOL fRequested = FALSE; + + intrAssert(wIsValidAtom(aItem)); + + int iAwaitAck = pChannel->iAwaitAck; + + // + // If we were waiting for this data, then we are sitting in the + // modal loop. Set the call state on the call control interface + // to indicate that a response was recieved. Pass NOERROR to indicate + // that there was success. If an error is determined later, then + // the state will be set a second time. + // + + if ((AA_REQUEST == iAwaitAck) || (AA_REQUESTAVAILABLE == iAwaitAck)) + { + intrDebugOut((DEB_ITRACE, + "::OnData(%x) AA_REQUEST/AVAILABLE pCD->id=%x\n", + this, + pChannel->pCD?pChannel->pCD->id:0xBAD)); + + // + // Regardless of the outcome of this call, we have recieved a + // response. Set the Awaiting Ack state to nothing. + // + pChannel->iAwaitAck = AA_NONE; + + // + // Determine if this channels call data is valid, and is in use. + // If the channel is in use, then then its id will not be + // CALLDATAID_UNUSED. If the call data isn't valid, then something + // is wrong, but there isn't a good way to recover. + // + + if (pChannel->pCD && (pChannel->pCD->id != CALLDATAID_UNUSED)) + { + // call only if there is a call id + //CoSetAckState(pChannel->pCI, FALSE); // clear waiting flag + intrDebugOut((DEB_ITRACE,"::OnData(%x) SetCallState(SERVERCALLEX_ISHANDLED)\n",this)); + pChannel->pCallCont->SetCallState(pChannel->pCD, + SERVERCALLEX_ISHANDLED, + NOERROR); + } + } + + + // + // Check the string for aItem, looking for advise options. The variable + // iAdvOpt will be set to indicate what type of data we just got, such + // as ON_CHANGE, etc. If the option is invalid, then we won't know + // what to do with it. + // + + if ((hresult=wScanItemOptions (aItem, (int *) &iAdvOpt)) != NOERROR) + { + intrAssert(!"Item found with unknown advise option\n"); + LPARAM lp; + if(!wPostMessageToServer (pChannel, + WM_DDE_ACK, + lp = MAKE_DDE_LPARAM (WM_DDE_ACK,NEGATIVE_ACK, aItem),TRUE)) + { + hresult = RPC_E_SERVER_DIED; + + } + + // + // Did we need to free hDdeData here? No, according to the DDE spec, if the + // receiever responds with a NACK, then the sender is responsible for + // freeing the data. + // + return hresult; + } + + // + // If the server sent no data, there ain't much we can do about it. + // + + if (hDdeData == NULL) + { + intrDebugOut((DEB_IERROR, + "::OnData(%x)hDdeData is NULL!\n", + this)); + + return(RPC_E_INVALID_PARAMETER); + } + + // + // Lock the data into memory so we can use it. Be careful, the way + // this routine was written originally, there are places that free + // and realloc hDdeData. Specifically, the call to KeepData. Carefully + // evaluate each place where you are returning, to insure the memory + // isn't leaked. (if you have time, please restructure this routine + // so it is easier to understand. + // + if (!(lpDdeData = (DDEDATA FAR *) GlobalLock(hDdeData))) + { + intrDebugOut((DEB_IERROR, + "::OnData(%x)GlobalLock on lpDdeData failed\n", + this)); + // + // BUGBUG: (KevinRo)Did we need to free hDdeData here? I think + // we should have if the fRelease flag was set. The old code + // didn't. Need to research this further (ie you figure it out!) + // + return ResultFromScode (E_OUTOFMEMORY); + } + + intrDebugOut((INTR_DDE, + "::OnData(%x) lpDdeData->cfFormat=%x\n", + this, + (UINT)lpDdeData->cfFormat)); + + // + // The server will set fAckReq if it wants a response. + // don't call HIC for call where not acknoewledge is requested + // + fAck = lpDdeData->fAckReq; + + if (pChannel->bTerminating) { + intrDebugOut((INTR_DDE,"::OnData(%x) Got DDE_DATA in terminate sequence\n",this)); + // + // BUGBUG: this is very dangerous since the pointer on the + // hDocWnd does not get deleted and a further will + // DDE message will GPF - we need to fix this!!! + // + GlobalUnlock (hDdeData); + GlobalFree (hDdeData); + goto exitRtn; + } + + // + // (KevinRo) Found this comment: + // + // important that we post the acknowledge first. Otherwise the + // messages are not in sync. + // + // The above comment might be intended to mean that the acknowledge needs to be + // send now, because we may call one of the advise functions below, which in + // turn may send another message to the OLE 1.0 server. Therefore, we ACK now, + // so the messages to the OLE 1.0 server are in the correct order. + // + if (fAck) + { + LPARAM lp; + if(!wPostMessageToServer (pChannel, + WM_DDE_ACK, + lp=MAKE_DDE_LPARAM(WM_DDE_ACK,POSITIVE_ACK, aItem),TRUE)) + { + return(RPC_E_SERVER_DIED); + } + } + + // + // this call is now an async call and can not be rejected be HandleIncomingMessage + // + + if ((AA_REQUESTAVAILABLE == pChannel->iAwaitAck) && (lpDdeData->fResponse)) + { + // + // For some reasons, OnDataAvailable will be the one to delete this data. + // I don't understand it, but lets roll with it. (KevinRo) + // + GlobalUnlock (hDdeData); + return OnDataAvailable (pChannel, hDdeData, aItem); + } + + // + // If the clipboard format is binary, and the topic is aStdDocName, then this + // OnData is a RENAME + // + if (lpDdeData->cfFormat == (short)g_cfBinary && aItem== aStdDocName) + { + // ON_RENAME + // + // The data should be the new name, in ANSI. + // + ChangeTopic ((LPSTR)lpDdeData->Value); + GlobalUnlock (hDdeData); + GlobalFree (hDdeData); + return(NOERROR); + } + + // + // Based on iAdvOpt, determine if we can callback. This one is a little + // hard to understand. I don't either. CanCallBack appears to return + // true if the count is 0,1, or 3, but returns FALSE if its 2 or + // greater than 3. There are no comments in the old code as to why + // this is. I am leaving it, since it must have been put there for + // a reason. See CanCallBack in ddeworker.cxx for futher (ie no) details + // + switch (iAdvOpt) + { + case ON_SAVE: + fCallBack = CanCallBack(&m_iAdvSave); + intrDebugOut((INTR_DDE, + "::OnData(%x)ON_SAVE m_iAdvSave=%x\n", + this, + m_iAdvSave)); + + break; + case ON_CLOSE: + fCallBack = CanCallBack(&m_iAdvClose); + intrDebugOut((INTR_DDE, + "::OnData(%x)ON_CLOSE m_iAdvClose=%x\n", + this, + m_iAdvClose)); + break; + case ON_CHANGE: + fCallBack = TRUE; + intrDebugOut((INTR_DDE, + "::OnData(%x)ON_CHANGE m_iAdvClose=%x\n", + this, + m_iAdvClose)); + break; + default: + intrAssert( !"Unknown iAdvOpt: Somethings really broke"); + } + + // Keep the data in a cache for a future GetData call + // which may be triggered a few lines later by the + // SendOnDataChange(). + + fRequested = lpDdeData->fResponse; + + + // The call to KeepData will change hDdeData and + // invalidate lpDdeData. Check out KeepData for details. The net + // result is that hDdeData is no longer valid + + GlobalUnlock (hDdeData); + lpDdeData=NULL; + + hresult = KeepData (pChannel, hDdeData); + + // + // This is unpleasant, but if KeepData fails, we need to + // call SetCallState again, resetting the error code. This + // code is such a mess that rearranging it to do + // it in a rational way is going to be too much work given + // the amount of time I have until shipping. + // + // If you have time, please simplify this code. Thanks + // + if (hresult != NOERROR) + { + // + // At this point, hDdeData has been unlocked, and deleted by + // the KeepData routine. Therefore, the return here doesn't + // need to be concerned with cleaning up after hDdeData + // + intrDebugOut((DEB_ITRACE, + "::OnData(%x) KeepData failed %x\n", + this, + hresult)); + // + // Reset the error code on the call control + // + if ((AA_REQUEST == iAwaitAck) || (AA_REQUESTAVAILABLE == iAwaitAck)) + { + if (pChannel->pCD && (pChannel->pCD->id != CALLDATAID_UNUSED)) + { + pChannel->pCallCont->SetCallState(pChannel->pCD, + SERVERCALLEX_ISHANDLED, + hresult); + } + } + goto exitRtn; + } + + if (fRequested) + { + // We REQUESTed the data. So, we are no longer waiting. + // Do NOT call SendOnDataChange because the data hasn't + // really changed again, we just requested it to satisfy + // a call to GetData, which was probably called by the + // real SendOnDataChange. + intrDebugOut((INTR_DDE, + "::OnData(%x) fRequested DATA\n", + this)); + + iAwaitAck = NULL; + hresult = NOERROR; + goto exitRtn; + + } + + // + // Now we have decided this is data we had not asked for. This makes + // it a change/close/saved notificiation. + // + intrDebugOut((INTR_DDE,"::OnData(%x) Non requested DATA\n",this)); + pChannel->AddReference(); + if (fCallBack && iAdvOpt != ON_CHANGE) + { + // ON_CHANGE will be handled by OleCallback, below + + intrDebugOut((INTR_DDE, + "::OnData(%x)Dispatching SendOnDataChange\n", + this)); + + + // + // There are a couple of things to note about the following. First, + // the iid of the call doesn't matter. Since OLE 1.0 servers don't + // do nested calls, the original LID (Logical ID) can be any random + // value. Therefore, we don't initalize it. + // + // According to JohannP, the calltype of these calls is supposed + // to be CALLTYPE_SYNC. I don't fully understand why they are. + // I am taking is decision on faith. + // + // Using the new call control interfaces, we do the following. + // + IID iid; + + DDEDISPATCHDATA ddedispdata; + DISPATCHDATA dispatchdata; + INTERFACEINFO32 ifInfo; + + ifInfo.pUnk = m_pDataAdvHolder; + ifInfo.iid = IID_IDataAdviseHolder; + // + // We are about to call method #6 in the interface, + // which is SendOnDataChange + // + ifInfo.wMethod = 6; + ifInfo.callcat = CALLCAT_SYNCHRONOUS; + + //dispatchdata.scode = S_OK; + dispatchdata.pData = (LPVOID) &ddedispdata; + + ddedispdata.pCDdeObject = this; + ddedispdata.wDispFunc = DDE_DISP_SENDONDATACHANGE; + ddedispdata.iArg = iAdvOpt; + + lpCallCont->HandleDispatchCall((DWORD)GetWindowTask(pChannel->hwndSvr), + iid, + &ifInfo, + &dispatchdata); + + } + if (fCallBack && (pChannel->pCallCont != NULL)) + { + // in 1.0 ON_CLOSE comes with data + if (iAdvOpt==ON_CLOSE) + { + + intrDebugOut((INTR_DDE, + "::OnData(%x) iAdvOpt == ON_CLOSE, send ON_SAVE\n", + this)); + + m_fGotCloseData = TRUE; + + hresult = OleCallBack(ON_SAVE,pChannel); + if (hresult != NOERROR) + { + goto errRel; + } + + //ErrRtnH (DdeHandleIncomingCall(pChannel->hwndSvr, CALLTYPE_TOPLEVEL) ); + //ErrRtnH (OleCallBack (ON_SAVE)); + } + + // check if app can handle this call + // we do not need to call HIC for SendOnClose + + hresult = OleCallBack (iAdvOpt,pChannel); + } + +errRel: + // Don't use pChannel after this. It can get deleted. (srinik) + if (pChannel->ReleaseReference() == 0) + { + m_pDocChannel = NULL; + } + +exitRtn: + if (!fAck && aItem) + { + GlobalDeleteAtom (aItem); + } + return hresult; +#endif _MAC +} + +//+--------------------------------------------------------------------------- +// +// Method: CDdeObject::OleCallBack +// +// Synopsis: Send all the right notifications whan a Save or Close happens. +// +// Effects: OleCallBack is a double duty function. It is called in two +// different cases. +// +// First, is to setup the callback, and call HandleIncomingCall. +// Second is from DispatchCall() in the CDdeChannelControl. +// +// The reason for doing it this way is we localize the setup +// and processing of these calls to one routine. Therefore, +// we can go to one spot in the code to find all of the call +// back information. +// +// Arguments: [iAdvOpt] -- Which Advise operation to perform +// [pChannel] -- Which channel is being called back +// +// Requires: pChannel == NULL, and the AdviseHolders are called. +// pChannel != NULL, and the call is setup, and HandleIncomingCall +// is setup. +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 5-23-94 kevinro Created +// +// Notes: +// +// WARNING: This code sucks completely. One of the major problems you need +// to know about is that the CDdeObject may go away as part of the normal +// processing of some of the below. Be very careful about any processing +// that might occur after an ON_CLOSE +// +//---------------------------------------------------------------------------- +INTERNAL CDdeObject::OleCallBack (int iAdvOpt, LPDDE_CHANNEL pChannel) +{ + HRESULT hresult = NOERROR; + IID iid; + DDEDISPATCHDATA ddedispdata; + DISPATCHDATA dispatchdata; + INTERFACEINFO32 ifInfo; + ICallControl *lpCallCont = NULL; + + // + // If the channel isn't NULL, then setup the data structures for calling + // off to the call control. + // + if (pChannel != NULL) + { + lpCallCont = pChannel->pCallCont; + + if (lpCallCont == NULL) + { + return(E_UNEXPECTED); + } + // + // Only do this work if we really have to + // + + dispatchdata.scode = S_OK; + dispatchdata.pData = (LPVOID) &ddedispdata; + ddedispdata.pCDdeObject = this; + ddedispdata.wDispFunc = DDE_DISP_OLECALLBACK; + ddedispdata.iArg = iAdvOpt; + + } + + intrDebugOut((DEB_ITRACE, + "CDdeObject::OleCallBack(%x,iAdvOpt=%x,pChannel=%x,lpCallCont=%x)\n", + this, + iAdvOpt, + pChannel, + lpCallCont)); + + // + // Determine what needs to be done, based on the iAdvOpt. This should be + // one of the handled cases below, otherwise its an error. + // + switch (iAdvOpt) + { + case ON_CLOSE: + if (pChannel != NULL) + { + intrDebugOut((DEB_ITRACE, + "::OleCallBack(%x) setup for ON_CLOSE\n", + this)); + + ifInfo.pUnk = m_pOleAdvHolder; + ifInfo.iid = IID_IOleAdviseHolder; + // IOleAdviseHolder::SendOnClose is method 8 + ifInfo.wMethod = 8; + ifInfo.callcat = CALLCAT_SYNCHRONOUS; + } + else + { + intrDebugOut((DEB_ITRACE,"::OleCallBack(%x) ON_CLOSE\n",this)); + DeclareVisibility (FALSE); + RetZ (!m_fDidSendOnClose); // This SendOnClose should happen 1st + // Don't let OnTerminate() do it too + hresult = SendOnClose(); + + // + // WARNING WARNING WARNING: SendOnClose() may have caused the + // destruction of this CDdeObject. Touch nothing on the way + // out. Actually, if you have time, which I currently don't, + // see what you can do with reference counting tricks to + // insure this object doesn't die during this callback. + // Its a tricky problem, and we are shipping in 2 weeks. + // (KevinRo 8/6/94) + // + } + break; + + case ON_SAVE: + if (pChannel != NULL) + { + intrDebugOut((DEB_ITRACE, + "::OleCallBack(%x) setup for ON_SAVE\n", + this)); + + if (m_pOleClientSite == NULL) + { + ifInfo.pUnk = m_pOleClientSite; + ifInfo.iid = IID_IOleClientSite; + // IOleClientSite::SaveObject method 7 + ifInfo.wMethod = 7; + ifInfo.callcat = CALLCAT_SYNCHRONOUS; + } + else + { + // Going to call the IOleAdviseHolder + + ifInfo.pUnk = m_pOleAdvHolder; + ifInfo.iid = IID_IOleAdviseHolder; + // IOleAdviseHolder::SendOnSave method 7 + // (Yes, same ordinal as above, I double checked) + ifInfo.wMethod = 7; + ifInfo.callcat = CALLCAT_SYNCHRONOUS; + } + } + else + { + + intrDebugOut((DEB_ITRACE,"::OleCallBack(%x) ON_SAVE\n",this)); + if (m_pOleClientSite) + { + // We just got data from the server, so we don't want to + // ask him for it again when the container does a save. + m_fUpdateOnSave = FALSE; + m_pOleClientSite->SaveObject(); + // SendOnSave is called in PS::SaveCompleted + m_fUpdateOnSave = TRUE; + } + else + { + // Link case + RetZS (m_pOleAdvHolder, E_OUTOFMEMORY); + m_pOleAdvHolder->SendOnSave(); + } + } + break; + + case ON_CHANGE: + if (pChannel != NULL) + { + // Going to call the IDataAdviseHolder + + ifInfo.pUnk = m_pDataAdvHolder; + ifInfo.iid = IID_IDataAdviseHolder; + // IDataAdviseHolder::SendOnDataChange method 6 + ifInfo.wMethod = 6; + ifInfo.callcat = CALLCAT_SYNCHRONOUS; + + } + else + { + RetZS (m_pDataAdvHolder, E_OUTOFMEMORY); + intrDebugOut((DEB_ITRACE,"::OleCallBack(%x) ON_CHANGE\n",this)); + hresult = SendOnDataChange (ON_CHANGE); + } + break; + + default: + + + intrDebugOut((DEB_ITRACE, + "CDdeObject::OleCallBack(%x,iAdvOpt=%x) UNKNOWN iAdvOpt\n", + this, + iAdvOpt)); + intrAssert(!"Unexpected iAdvOpt"); + return(E_UNEXPECTED); + break; + } + + // + // There are a couple of things to note about the following. First, + // the iid of the call doesn't matter. Since OLE 1.0 servers don't + // do nested calls, the original LID (Logical ID) can be any random + // value. Therefore, we don't initalize it. + // + // According to JohannP, the calltype of these calls is supposed + // to be CALLTYPE_SYNCHRONOUS. I don't fully understand why they are. + // I am taking is decision on faith. + // + // + // Its possible that during the handling of this call that this object + // will get deleted. This is a pain in the butt. This means that anything + // used after this call MUST be protected. lpCallCont happens to be one of + // these. We have been having problems with lpCallCont being released as + // part of the object cleanup. The call control code will access member + // variables on its way out of the HandleDispatch. We need to bracket + // the call below so this doesn't happen. + // + if (pChannel != NULL) + { + // + // We normally keep a per thread copy of the call control interface. + // When the reference count for that copy goes to zero, we need to + // flush that copy. We can do the addref here, because the current + // reference is the same value that would be returned by + // GetDdeCallControlInterface. The balancing call, however, needs + // to be ReleaseDdeCallControlInterface, since it may need to flush + // the TLS value. + // + + lpCallCont->AddRef(); + + hresult = lpCallCont->HandleDispatchCall((DWORD)GetWindowTask(pChannel->hwndSvr), + iid, + &ifInfo, + &dispatchdata); + + ReleaseDdeCallControlInterface(); + } + + return hresult; +} + + +INTERNAL CDdeObject::SendOnDataChange + (int iAdvOpt) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::SendOnDataChange(%x)\n",this)); + HRESULT hresult; + RetZS (m_pDataAdvHolder, E_OUTOFMEMORY); + m_fDoingSendOnDataChange = TRUE; + hresult = m_pDataAdvHolder->SendOnDataChange (&m_Data, + DVASPECT_CONTENT, + 0); + if (ON_CLOSE==iAdvOpt) + { + hresult = m_pDataAdvHolder->SendOnDataChange (&m_Data, + DVASPECT_CONTENT, + ADVF_DATAONSTOP); + } + m_fDoingSendOnDataChange = FALSE; + return hresult; +} + + + + +INTERNAL CDdeObject::SendOnClose + (void) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::SendOnClose(%x)\n",this)); + RetZS (m_pOleAdvHolder, E_OUTOFMEMORY); + m_fDidSendOnClose = TRUE; + RetErr (m_pOleAdvHolder->SendOnClose() ); + return NOERROR; +} + + + + +INTERNAL CDdeObject::OnTerminate + (LPDDE_CHANNEL pChannel, + HWND hwndPost) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::OnTerminate(%x,pChannel=%x,hwndPost=%x)\n", + this, + pChannel, + hwndPost)); + + // + // If the hwndPost and hwndSvr are different, then it is one of two + // cases. We could have recieved more than one Acknowlege during our + // initiate, in which case the count iExtraTerms would have been + // incremented, and this terminate is accounted for iExtraTerms. + // + // The other case is that we were terminated by a window that was + // NOT the window we were conversing with. + // + if (pChannel->hwndSvr != hwndPost) + { + intrDebugOut((DEB_ITRACE, + "::OnTerminate(%x) Extra terms is 0x%x \n", + this, + pChannel->iExtraTerms)); + + // + // iExtraTerms shouldn't go below zero. If it does, something + // has gone wrong. We have been seeing some problems with the + // HWND mapping layer in the past. If the following condition + // ever trips, then it is possible that another mapping + // problem has been seen. + // +#if DBG == 1 + if((pChannel->iExtraTerms == 0 ) && + (((DWORD)pChannel->hwndSvr) & (0xffff)) == ((DWORD)hwndPost & (0xffff))) + { + intrDebugOut((DEB_ERROR, + "*** OnTerminate expected hwnd=%x got hwnd=%x ***\n", + pChannel->hwndSvr,hwndPost)); + + intrDebugOut((DEB_ERROR, + "\n*** Call KevinRo or SanfordS ***\n\n", + pChannel->hwndSvr,hwndPost)); + + } +#endif + --pChannel->iExtraTerms; + + intrAssert((pChannel->iExtraTerms >= 0) && "Call KevinRo or SanfordS"); + return NOERROR; + } + if (m_wTerminate == Terminate_Detect) { + // we should only detect the call but not execute the code + // set the state to Received + m_wTerminate = Terminate_Received; + pChannel->iAwaitAck = NULL; + // Since Excel incorrectly did not send an ACK, we need to + // delete the handle in the DDE message ourselves. + if (pChannel->hCommands) + { + GlobalFree (pChannel->hCommands); + pChannel->hCommands = NULL; + } + //CoSetAckState(pChannel->pCI, FALSE); + intrDebugOut((DEB_ITRACE, + "::OnTerminate(%x) Terminate_Detect SERVERCALLEX_ISHANDLED\n", + this)); + pChannel->pCallCont->SetCallState(pChannel->pCD, SERVERCALLEX_ISHANDLED, RPC_E_SERVER_DIED); + return NOERROR; + } + + RetZ (pChannel); + ChkDR (this); + + if (!pChannel->bTerminating) + { + // Got unprompted terminate + BOOL bBusy; + + // Necessary safety bracket + m_pUnkOuter->AddRef(); + + bBusy = wClearWaitState (pChannel); + + if (pChannel->iAwaitAck || bBusy) + { + pChannel->iAwaitAck = NULL; + //CoSetAckState(pChannel->pCI, FALSE); + intrDebugOut((DEB_ITRACE,"::OnTerminate(%x) !bTerminating SERVERCALLEX_ISHANDLED,RPC_E_DDE_UNEXP_MSG\n",this)); + pChannel->pCallCont->SetCallState(pChannel->pCD, SERVERCALLEX_ISHANDLED, RPC_E_DDE_UNEXP_MSG); + } + + if (!m_fDidSendOnClose) + { + intrDebugOut((DEB_ITRACE, + "::OnTerminate(%x) SendOnClose from terminate\n", + this)); + + BOOL f= m_fNoStdCloseDoc; + m_fNoStdCloseDoc = TRUE; + + DeclareVisibility (FALSE); + SendOnClose(); + + m_fNoStdCloseDoc = f; + } + else + { + intrDebugOut((DEB_ITRACE, + "::OnTerminate(%x) Already did SendOnClose\n", + this)); + Puts ("Already did SendOnClose\n"); + } + intrDebugOut((DEB_ITRACE, + "::OnTerminate(%x) Posting DDE_TERMINATE as reply\n", + this)); + + wPostMessageToServer (pChannel, WM_DDE_TERMINATE, NULL,FALSE); + + // The terminate that we are sending itself is a reply, so we don't + // need to do WaitForReply. + DeleteChannel (pChannel); + + // Necessary safety bracket + m_pUnkOuter->Release(); + } + else + { + intrDebugOut((DEB_ITRACE, + "::OnTerminate(%x) Received DDE_TERMINATE in reply\n", + this)); + + // We sent the WM_DDE_TERMINATE and we got the acknowledge for it + pChannel->hwndSvr = NULL; + pChannel->iExtraTerms == NULL; + pChannel->iAwaitAck = NULL; + //CoSetAckState(pChannel->pCI, FALSE); + intrDebugOut((DEB_ITRACE,"::OnTerminate(%x) bTerminating SERVERCALLEX_ISHANDLED\n",this)); + pChannel->pCallCont->SetCallState(pChannel->pCD, SERVERCALLEX_ISHANDLED, NOERROR); + } + Puts ("OnTerminate() done.\n"); + return NOERROR; +} + + + + +INTERNAL_(BOOL) CDdeObject::AllocDdeChannel + (LPDDE_CHANNEL * lplpChannel, LPSTR lpszWndClass) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::AllocDdeChannel(%x,WndClass=%s)\n", + this, + lpszWndClass)); + + // + // Try to get the global call control interface + // + + PCALLCONTROL pCallCont = GetDdeCallControlInterface(); + + if (pCallCont == NULL) + { + // + // Couldn't allocate a CallControl. Fail. + // + + intrAssert(pCallCont != NULL); + return(FALSE); + } + + // + // Now try to allocate a channel + // + + if (!(*lplpChannel = (LPDDE_CHANNEL) new DDE_CHANNEL )) + { + // + // This failed, so give back the CallControl + // + intrAssert(*lplpChannel != NULL); + ReleaseDdeCallControlInterface(); + return FALSE; + } + + (*lplpChannel)->m_cRefs = 1; + (*lplpChannel)->hwndSvr = NULL; + (*lplpChannel)->bTerminating = FALSE; + (*lplpChannel)->wTimer = NULL; + (*lplpChannel)->hDdePoke = NULL; + (*lplpChannel)->hCommands = NULL; + (*lplpChannel)->hopt = NULL; + (*lplpChannel)->dwStartTickCount= 0; + (*lplpChannel)->msgFirst = 0; + (*lplpChannel)->msgLast = 0; + (*lplpChannel)->fRejected = FALSE; + (*lplpChannel)->wChannelDeleted = 0; + //(*lplpChannel)->pCI = NULL; + (*lplpChannel)->pCD = NULL; + (*lplpChannel)->pCallCont = pCallCont; + (*lplpChannel)->pChanCont = &g_CDdeChannelControl; + + if (!((*lplpChannel)->hwndCli = SSCreateWindowExA(0, + lpszWndClass, + "DDE Channel", + WS_CHILD, + 0,0,0,0, + (HWND)TLSGetDdeClientWindow(), + NULL, + hinstSO, + NULL))) + { + intrAssert (!"Could not create AllocDdeChannel window"); + + // + // DeleteChannel will give back the CallControl + // + + DeleteChannel(*lplpChannel); + *lplpChannel = NULL; + return FALSE; + } + + SetWindowLong ((*lplpChannel)->hwndCli, 0, (LONG) this); + return TRUE; +} + + + +INTERNAL_(BOOL) CDdeObject::InitSysConv() +{ + DWORD dwResult; + intrDebugOut((DEB_ITRACE,"CDdeObject::InitSysConv(%x)\n",this)); + + dwResult = wInitiate (m_pSysChannel, m_aClass, aOLE); + if (!dwResult) + { + intrDebugOut((DEB_ITRACE,"\t::InitSysConv(%x) Try aSysTopic\n",this)); + dwResult = wInitiate (m_pSysChannel, m_aClass, aSysTopic); + } + + if (!dwResult) + { + intrDebugOut((DEB_ITRACE,"\t::InitSysConv(%x) is failing\n",this)); + } + return(dwResult); +} + + + +INTERNAL_(void) CDdeObject::SetTopic(ATOM aTopic) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::SetTopic(%x)\n",this)); + intrAssert(wIsValidAtom(aTopic)); + if (m_aTopic) + GlobalDeleteAtom (m_aTopic); + + m_aTopic = aTopic; +} + + + +INTERNAL CDdeObject::TermConv + (LPDDE_CHANNEL pChannel, + BOOL fWait) // Default==TRUE. FALSE only in ProxyManager::Disconnect +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::TermConv(%x,pChannel=%x)\n", + this, + pChannel)); + + HRESULT hres; + if (!pChannel) + { + return NOERROR; + } + + if (!wPostMessageToServer (pChannel, WM_DDE_TERMINATE, 0,FALSE)) + { + intrDebugOut((DEB_ITRACE, + "CDdeObject::TermConv(%x) Server Probably Died\n", + this)); + hres = RPC_E_SERVER_DIED; + } + else + { + pChannel->bTerminating = TRUE; + Putsi (fWait); + hres = fWait ? WaitForReply (pChannel, + AA_TERMINATE, + /*fStdCloseDoc*/FALSE, + /*fDetectTerminate*/ FALSE) : NOERROR; + if (pChannel==m_pDocChannel) + { + DeclareVisibility (FALSE); + if (!m_fDidSendOnClose) + { + SendOnClose(); + } + } + } + + DeleteChannel (pChannel); + intrDebugOut((DEB_ITRACE,"::TermConv(%x) returns %x\n",this,hres)); + return hres; +} + + + + +INTERNAL_(void) CDdeObject::DeleteChannel (LPDDE_CHANNEL pChannel) +{ + BOOL fDocChannel = FALSE; + intrDebugOut((DEB_ITRACE, + "CDdeObject::DeleteChannel(%x,pChannel=%x)\n", + this, + pChannel)); + + if (pChannel == NULL) + { + return; + } + + if (pChannel == m_pDocChannel) + fDocChannel = TRUE; + + + + // delete any data if we were in busy mode. + wClearWaitState (pChannel); + + if (pChannel == m_pDocChannel) + { + intrDebugOut((DEB_ITRACE, + "::DeleteChannel(%x)Clean up pDocChannel\n", + this)); + + // Cleanup per-conversation information + m_fDidSendOnClose = FALSE; + m_fDidStdCloseDoc = FALSE; + m_ConnectionTable.Erase(); + m_iAdvSave = 0; + m_iAdvClose= 0; + m_fWasEverVisible = FALSE; + m_fGotCloseData = FALSE; + if (m_ptd) + { + delete m_ptd; + m_ptd = NULL; + } + if (m_pstg) + { + m_pstg->Release(); + m_pstg = NULL; + } + if (m_pDataAdvHolder) + { + Verify (0==m_pDataAdvHolder->Release()); + } + CreateDataAdviseHolder (&m_pDataAdvHolder); + if (m_pOleAdvHolder) + { + m_pOleAdvHolder->Release(); // may not return 0 if we are + // in a SendOnClose + } + CreateOleAdviseHolder (&m_pOleAdvHolder); + } + + if (pChannel->hwndCli) + { + intrDebugOut((DEB_ITRACE, + "::DeleteChannel(%x)Destroy hwndCli(%x)\n", + this, + pChannel->hwndCli)); + + Assert (IsWindow (pChannel->hwndCli)); + Assert (this==(CDdeObject *)GetWindowLong (pChannel->hwndCli, 0)); + Verify (SSDestroyWindow (pChannel->hwndCli)); + } + + if (pChannel == m_pDocChannel) + { + m_pDocChannel = NULL; + } + else + { + intrAssert(pChannel == m_pSysChannel); + m_pSysChannel = NULL; + } + + + if (pChannel->pCallCont != NULL) + { + ReleaseDdeCallControlInterface(); + pChannel->pCallCont = NULL; + } + + // Channel will be deleted in the modallp.cpp + // if flag is on. + + if (pChannel->wChannelDeleted == Channel_InModalloop) + { + intrDebugOut((DEB_ITRACE, + "::DeleteChannel(%x) Channel(%x) in Modal Loop\n", + this,pChannel)); + + pChannel->wChannelDeleted = Channel_DeleteNow; + } + else + { + if (pChannel->ReleaseReference() == 0) + pChannel = NULL; + } + + if (fDocChannel) + m_pDocChannel = pChannel; +} + +const WCHAR EMB_STR[]= OLESTR(" -Embedding ") ; + +INTERNAL_(BOOL) CDdeObject::LaunchApp (void) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::LaunchApp(%x)\n",this)); + + STARTUPINFO startInfo; + PROCESS_INFORMATION procInfo; + BOOL fProcStarted; + WCHAR cmdline[MAX_PATH + sizeof(EMB_STR)]; + WCHAR exeName[MAX_PATH + sizeof(cmdline)]; + // + // Init all fields of startInfo to zero + // + memset((void *)&startInfo,0,sizeof(startInfo)); + + // + // The normal startup is set here. + // + startInfo.wShowWindow = SW_NORMAL; + startInfo.dwFlags = STARTF_USESHOWWINDOW; + + m_fDidLaunchApp = FALSE; + + + DWORD dw; + + // + // Do our best to find the path + // + intrAssert(wIsValidAtom(m_aExeName)); + + if (m_aExeName == 0) + { + // + // There is no exe name to execute. Can't start it. + // + return(FALSE); + } + + dw = SearchPath(NULL,wAtomName(m_aExeName),NULL,MAX_PATH,exeName, NULL); + + if ((dw == 0) || (dw > MAX_PATH)) + { + intrDebugOut((DEB_ITRACE, + "::LaunchApp(%x) SearchPath failed. Do Default",this)); + // + // SearchPath failed. Use the default + // + GlobalGetAtomName (m_aExeName, exeName, MAX_PATH); + } + + memcpy(cmdline, EMB_STR,sizeof(EMB_STR)); + + if (m_ulObjType == OT_LINK) + { + intrAssert(wIsValidAtom(m_aTopic)); + // File name + Assert (wAtomName (m_aTopic)); + + lstrcatW (cmdline, wAtomName (m_aTopic)); + } + + if (m_clsid == CLSID_ExcelWorksheet // Stupid apps that show themselves + || m_clsid == CLSID_ExcelMacrosheet // when they're not supposed to + || m_clsid == CLSID_ExcelChart + || m_clsid == CLSID_PBrush) + { + startInfo.wShowWindow = SW_SHOWMINNOACTIVE; + } + + // + // According to the spec, the most robust way to start the app is to + // only use a cmdline that consists of the exe name, followed by the + // command line arguments. + // + + lstrcatW(exeName,cmdline); + + Assert((lstrlenW(exeName)+1) < sizeof(exeName)); + + intrDebugOut((DEB_ITRACE, + "CDdeObject::LaunchApp(%x) Starting '%ws' \n", + this, + exeName)); + + if (IsWOWThreadCallable()) + { + HRESULT hr; + + hr = g_pOleThunkWOW->WinExec16(exeName, startInfo.wShowWindow); + + fProcStarted = SUCCEEDED(hr); + +#if DBG==1 + if (!fProcStarted) + { + intrDebugOut((DEB_ITRACE, + "::LaunchApp(%x) in Wow FAILED(%x) TO START %ws \n", + this, + hr, + exeName)); + } +#endif + } + else + { + fProcStarted = CreateProcess(NULL, + exeName, + NULL, + NULL, + FALSE, + 0, + NULL, + NULL, + &startInfo, + &procInfo); + if (fProcStarted) + { + // + // Let's give the server a chance to register itself. On NT, + // CreateProcess gets the other process going, but returns + // to let it run asynchronously. This isn't good, since we + // need some way of knowing when it has started, so we can + // send the DDE_INITIATES 'after' they create their DDE + // window. + // + // Maximum timeout we want here shall be set at 30 seconds. + // This should give enough time for even a 16bit WOW app to + // start. This number was picked by trial and error. Normal + // apps that go into an InputIdle state will return as soon + // as they are ready. Therefore, we normally won't wait + // the full duration. + // + + ULONG ulTimeoutDuration = 30000L; + + // + // Now modify this start time to handle classes + // that have known problems. This list includes: + // + + switch(WaitForInputIdle(procInfo.hProcess, ulTimeoutDuration)) + { + case 0: + intrDebugOut((DEB_ITRACE, + "::LaunchApp, %ws started\n", + exeName)); + break; + case WAIT_TIMEOUT: + intrDebugOut((DEB_ITRACE, + "::LaunchApp, %ws wait timeout at %u (dec) ms. Go Anyway\n", + exeName, + ulTimeoutDuration)); + break; + default: + intrDebugOut((DEB_ITRACE, + "::LaunchApp, %ws unknown condition (%x)\n", + exeName, + GetLastError())); + } + // + // We are already done with the Process and Thread handles + // + CloseHandle(procInfo.hProcess); + CloseHandle(procInfo.hThread); + } + else + { + intrDebugOut((DEB_ITRACE, + "::LaunchApp(%x) FAILED(%x) TO START %ws \n", + this, + GetLastError(), + exeName)); + } + } + + if (fProcStarted) + { + // If we ran the server, it should not be visible yet. + DeclareVisibility (FALSE); + m_fDidLaunchApp = TRUE; + } + + return fProcStarted; +} + + +INTERNAL CDdeObject::MaybeUnlaunchApp (void) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::MaybeUnlaunchApp(%x)\n",this)); + if (m_fDidLaunchApp + && !m_fDidGetObject + && (m_clsid == CLSID_ExcelWorksheet + || m_clsid == CLSID_ExcelMacrosheet + || m_clsid == CLSID_ExcelChart)) + { + return UnlaunchApp(); + } + return NOERROR; +} + + + + +INTERNAL CDdeObject::UnlaunchApp (void) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::UnlaunchApp(%x)\n",this)); + HANDLE hCommands; + HRESULT hresult = NOERROR; + RetZS (AllocDdeChannel (&m_pSysChannel, SYS_CLASSA), E_OUTOFMEMORY); + ErrZS (InitSysConv(), E_UNEXPECTED); + ErrRtnH (PostSysCommand (m_pSysChannel,(LPSTR) &achStdExit, /*bStdNew*/FALSE, + /*fWait*/FALSE)); + hCommands = m_pSysChannel->hCommands; + hresult = TermConv (m_pSysChannel); + + // Since Excel incorrectly did not send an ACK, we need to + // delete the handle ("[StdExit]") in the DDE message ourselves. + if (hCommands) + GlobalFree (hCommands); + + return hresult; + + errRtn: + DeleteChannel (m_pSysChannel); + return hresult; +} + + + + +INTERNAL CDdeObject::Execute + (LPDDE_CHANNEL pChannel, + HANDLE hdata, + BOOL fStdCloseDoc, + BOOL fWait, + BOOL fDetectTerminate) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::Execute(%x,hdata=%x)\n",this,hdata)); + + LPARAM lp; + +#ifdef _CHICAGO_ + //POSTPPC + if (fWait && (CanMakeOutCall(pChannel) == FALSE)) + { + intrDebugOut((DEB_ERROR, "::Execute(%x) can not call out\n", this)); + GlobalFree (hdata); + return ResultFromScode (E_UNEXPECTED); + } +#endif + + if (wPostMessageToServer (pChannel, + WM_DDE_EXECUTE, + lp=MAKE_DDE_LPARAM(WM_DDE_EXECUTE,0, hdata),TRUE)) + { + if (fStdCloseDoc) + { + // Prepare to free the handle if Excel does not send an Ack + pChannel->hCommands = hdata; + } + return fWait ? WaitForReply (pChannel, AA_EXECUTE, fStdCloseDoc, + fDetectTerminate) + : NOERROR ; + } + GlobalFree (hdata); + return ReportResult(0, RPC_E_DDE_POST, 0, 0); +} + + + + +INTERNAL_(HRESULT) CDdeObject::AdviseOn (CLIPFORMAT cfFormat, int iAdvOn) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::AdviseOn(%x,cfFormat=%x,iAdvOn=%x)\n", + this, + cfFormat, + iAdvOn)); + + HANDLE hopt=NULL; + DDEADVISE * lpopt=NULL; + ATOM aItem=(ATOM)0; + HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0); + + RetZ (m_pDocChannel); + + if (NOERROR == m_ConnectionTable.Lookup (cfFormat, NULL)) + { + // We already got a call to DataObject::Advise on this format. + intrDebugOut((DEB_ITRACE, + "::AdviseOn(%x) Advise had been done on cfFormat=%x\n", + this, + cfFormat)); + return NOERROR; + } + + UpdateAdviseCounts (cfFormat, iAdvOn, +1); + + if (m_fDidSendOnClose) + { + intrDebugOut((DEB_ITRACE,"::AdviseOn(%x)Ignoring Advise because we are closing\n",this)); + return NOERROR; + } + + if (!(hopt = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, sizeof(DDEADVISE)))) + { + intrDebugOut((DEB_ITRACE,"::AdviseOn(%x)GlobalAlloc returned NULL\n",this)); + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + } + + + if (!(lpopt = (DDEADVISE FAR *) GlobalLock (hopt))) + { + intrDebugOut((DEB_ITRACE,"::AdviseOn(%x)GlobalLock returned NULL\n",this)); + GlobalFree (hopt); + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + } + + lpopt->fAckReq = TRUE; + lpopt->fDeferUpd = FALSE; + lpopt->cfFormat = cfFormat; + m_pDocChannel->hopt = hopt; + + if (iAdvOn == ON_RENAME) + { + aItem = wDupAtom (aStdDocName); + intrAssert(wIsValidAtom(aItem)); + } + else + { + intrAssert(wIsValidAtom(m_aItem)); + aItem = wExtendAtom (m_aItem, iAdvOn); + intrAssert(wIsValidAtom(aItem)); + } + + intrDebugOut((DEB_ITRACE, + "::AdviseOn(%x) lpopt->cfFormat = %x, aItem=%x (%ws)\n", + this, + lpopt->cfFormat, + aItem, + wAtomName(aItem))); + + GlobalUnlock (hopt); + + LPARAM lp; + if (FALSE==wPostMessageToServer (m_pDocChannel, WM_DDE_ADVISE, + lp=MAKE_DDE_LPARAM(WM_DDE_ADVISE,hopt,aItem),TRUE)) + { + intrDebugOut((DEB_ITRACE,"::AdviseOn(%x)wPostMessageToServer failed\n",this)); + if (aItem) + GlobalDeleteAtom (aItem); + if (hopt) + GlobalFree (hopt); + return ResultFromScode (RPC_E_DDE_POST); + } + ErrRtnH (WaitForReply (m_pDocChannel, AA_ADVISE)); + + return NOERROR; + +errRtn: + hresult = (RPC_E_DDE_NACK == hresult) ? DV_E_CLIPFORMAT : hresult; + intrDebugOut((DEB_ITRACE, + "::AdviseOn(%x) errRet, AdviseRejected, returning %x\n", + this,hresult)); + return hresult; +} + +INTERNAL CDdeObject::UpdateAdviseCounts + (CLIPFORMAT cf, + int iAdvOn, + signed int cDelta) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::UpdateAdviseCounts(%x)\n",this)); + if (cf==g_cfBinary) + return NOERROR; + + // Update m_iAdv* flags + #define macro(Notif, NOTIF) \ + if (iAdvOn == ON_##NOTIF) \ + m_iAdv##Notif += cDelta; \ + if (m_iAdv##Notif < 0) \ + m_iAdv##Notif = 0; \ + else if (m_iAdv##Notif > 2) \ + m_iAdv##Notif = 2; + + macro (Close, CLOSE) + macro (Save, SAVE) + macro (Change,CHANGE) + #undef macro + + Assert (m_iAdvClose < 3 && m_iAdvSave < 3 && m_iAdvChange < 3); + Assert (m_iAdvClose >= 0 && m_iAdvSave >= 0 && m_iAdvChange >= 0); + + if (cf == g_cfNative) + { + if (iAdvOn != ON_CHANGE) + m_fDidAdvNative = (cDelta > 0); + else + intrDebugOut((DEB_ITRACE, + "::UpdateAdviseCounts(%x)Asked advise on cfNative\n", + this)); + } + + return NOERROR; +} + + + + +INTERNAL CDdeObject::UnAdviseOn (CLIPFORMAT cfFormat, int iAdvOn) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::UnAdviseOn(%x,cfFormat=%x,iAdvOn=%x)\n", + this,cfFormat,iAdvOn)); + HRESULT hr; + ATOM aItem= (ATOM)0; + + RetZ (m_pDocChannel); + UpdateAdviseCounts (cfFormat, iAdvOn, -1); + if (m_fDidSendOnClose) + { + intrDebugOut((DEB_ITRACE, + "CDdeObject::UnAdviseOn(%x) Ignored because closing\n", + this)); + return NOERROR; + } + if (wTerminateIsComing (m_pDocChannel)) + { + // We already did a StdCloseDocument, so the server is not willing + // to do an unadvise even though the default hanlder asked us to. + intrDebugOut((DEB_ITRACE, + "CDdeObject::UnAdviseOn(%x) Terminate coming\n", + this)); + return NOERROR; + } + + if (iAdvOn == ON_RENAME) + { + aItem = wDupAtom (aStdDocName); + intrAssert(wIsValidAtom(aItem)); + } + else + { + intrAssert(wIsValidAtom(m_aItem)); + aItem = wExtendAtom (m_aItem, iAdvOn); + intrAssert(wIsValidAtom(aItem)); + } + + + if (!wPostMessageToServer(m_pDocChannel, WM_DDE_UNADVISE, + MAKE_DDE_LPARAM (WM_DDE_UNADVISE,cfFormat,aItem),FALSE)) + { + if (aItem) + GlobalDeleteAtom (aItem); + intrDebugOut((DEB_ITRACE, + "CDdeObject::UnAdviseOn(%x) wPostMessage failed\n", + this)); + return RPC_E_DDE_POST; + } + + // Wait For Reply + hr = WaitForReply (m_pDocChannel, AA_UNADVISE, FALSE); + if (hr != NOERROR && hr != RPC_E_DDE_NACK) + { + intrDebugOut((DEB_ITRACE, + "::UnAdviseOn(%x)WaitForReply returns %x\n", + this)); + return hr; + } + + + if (cfFormat==m_cfPict) + { + if (m_hPict) + { + // Invalidate the cache so when someone explicitly asks for + // the data, they will get fresh data. + wFreeData (m_hPict, m_cfPict, TRUE); + m_hPict = (HANDLE)0; + m_cfPict = 0; + } + } + + // Due to a bug in the OLE1 libraries, unadvising on a presentation + // format effectively unadvises on native. + if (cfFormat != g_cfNative && m_fDidAdvNative) + { + if (iAdvOn == ON_SAVE) + { + // to reflect the fact that the native advise connection was lost + m_iAdvSave--; + m_fDidAdvNative = FALSE; + RetErr (AdviseOn (g_cfNative, ON_SAVE)); // re-establish + } + else if (iAdvOn == ON_CLOSE) + { + // to reflect the fact that the native advise connection was lost + m_iAdvClose--; + m_fDidAdvNative = FALSE; + RetErr (AdviseOn (g_cfNative, ON_CLOSE)); + } + } + + return NOERROR; +} + + +// +// Post a message to a 1.0 server (callee) and wait for the acknowledge +// + + +INTERNAL CDdeObject::Poke + (ATOM aItem, HANDLE hDdePoke) +{ + HRESULT hr; + + intrDebugOut((DEB_ITRACE,"CDdeObject::Poke(%x)\n",this)); + + ATOM aTmpItem; + + intrAssert(wIsValidAtom(aItem)); + + aTmpItem = wDupAtom (aItem); + + intrAssert(wIsValidAtom(aTmpItem)); + + m_pDocChannel->hDdePoke = hDdePoke; + + LPARAM lp; + if (hr = wPostMessageToServer (m_pDocChannel, + WM_DDE_POKE, + lp=MAKE_DDE_LPARAM(WM_DDE_POKE,hDdePoke,aTmpItem),TRUE)) + { + hr = WaitForReply (m_pDocChannel, AA_POKE); + intrDebugOut((DEB_ITRACE,"::Poke(%x) returning %x\n",this,hr)); + return hr; + } + + intrDebugOut((DEB_ITRACE,"::Poke(%x)wPostMessage failed %x\n",this,hr)); + // Error case + if (aTmpItem) + GlobalDeleteAtom (aTmpItem); + wFreePokeData (m_pDocChannel, m_bOldSvr && m_aClass==aMSDraw); + hr = RPC_E_DDE_POST; + intrDebugOut((DEB_ITRACE,"::Poke(%x)wPostMessage returns %x\n",this,hr)); + return hr; + +} + +INTERNAL CDdeObject::PostSysCommand + (LPDDE_CHANNEL pChannel, + LPCSTR szCmd, + BOOL fStdNew, + BOOL fWait) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::PostSysCommand(%x,szCmd=%s,fStdNew=%x,fWait=%x)\n", + this, + szCmd, + fStdNew, + fWait)); + + ULONG size; + WORD len; + LPSTR lpdata= NULL; + HANDLE hdata = NULL; + HRESULT hresult; + + + #define LN_FUDGE 16 // [],(), 3 * 3 (2 double quotes and comma) + + len = strlen (szCmd); + + // for StdNewDocument command add class name + if (fStdNew) + len += wAtomLenA (m_aClass); + + // Now add the document length. + len += wAtomLenA (m_aTopic); + + // now add the fudge factor for the Quotes etc. + len += LN_FUDGE; + + // allocate the buffer and set the command. + if (!(hdata = GlobalAlloc (GMEM_DDESHARE, size = len))) + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + + if (!(lpdata = (LPSTR)GlobalLock (hdata))) { + Assert (0); + GlobalFree (hdata); + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + } + + strcpy (lpdata, (LPSTR)"["); // [ + strcat (lpdata, szCmd); // [StdCmd + if (strcmp (szCmd, "StdExit")) + { + strcat (lpdata, "(\""); // [StdCmd(" + + if (fStdNew) + { + len = strlen (lpdata); + GlobalGetAtomNameA (m_aClass, (LPSTR)lpdata + len, size-len); + // [StdCmd("class + strcat (lpdata, "\",\""); // [StdCmd("class"," + } + + len = strlen (lpdata); + // now get the topic name. + GlobalGetAtomNameA (m_aTopic, lpdata + len, (WORD)size - len); + // [StdCmd("class","topic + strcat (lpdata, "\")"); // [StdCmd("class","topic") + } + strcat (lpdata, "]"); + Assert (strlen(lpdata) < size); + intrDebugOut((DEB_ITRACE,"::PostSysCommand(%x) hData(%s)\n",this,lpdata)); + GlobalUnlock (hdata); + + // return Execute (m_pSysChannel, hdata, /*fStdClose*/FALSE, fWait); + // REVIEW: this fixed bug 1856 (johannp) + // JasonFul - does it break something else? + + hresult = Execute (m_pSysChannel, + hdata, + /*fStdClose*/FALSE, + fWait, + /*fDetectTerminate*/ TRUE); + + intrDebugOut((DEB_ITRACE,"::PostSysCommand(%x) returns \n",this,hresult)); + return hresult; + +} + +//+--------------------------------------------------------------------------- +// +// Method: CDdeObject::KeepData +// +// Synopsis: Given the DDEDATA structure from a WM_DDE_DATA message, extract +// the real data and keep it till GetData or Save is done. +// +// +// Effects: +// +// Arguments: [pChannel] -- +// [hDdeData] -- +// +// Requires: +// +// Returns: E_OUTOFMEMORY or E_HANDLE if failure, NOERROR if success +// +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 5-14-94 kevinro Commented +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL CDdeObject::KeepData + (LPDDE_CHANNEL pChannel, HANDLE hDdeData) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::KeepData(%x)\n",this)); + + DDEDATA * lpDdeData = NULL; + HANDLE hData; + CLIPFORMAT cfFormat; + + + + if (!(lpDdeData = (DDEDATA *) (GlobalLock (hDdeData)))) + { + return E_OUTOFMEMORY;; + } + + + cfFormat = lpDdeData->cfFormat; + intrDebugOut((DEB_ITRACE, + "::KeepData(%x) Keeping cfFormat=%x\n", + this, + cfFormat)); + + GlobalUnlock (hDdeData); + + // Possible Side effect of wHandleFromDdeData() is the freeing of hDdeData + if (!(hData = wHandleFromDdeData (hDdeData)) + || !wIsValidHandle (hData, cfFormat) ) + { + Assert(0); + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + } + + if (cfFormat == g_cfNative) { + if (m_hNative) + GlobalFree (m_hNative); + // Keep the native data + RetErr (wTransferHandle (&m_hNative, &hData, cfFormat)); + } + else if (cfFormat == CF_METAFILEPICT || + cfFormat == CF_BITMAP || + cfFormat == CF_DIB) + { + if (m_hPict) + wFreeData (m_hPict, m_cfPict, TRUE); + m_cfPict = cfFormat; + // Keep the presentation data + RetErr (wTransferHandle (&m_hPict, &hData, cfFormat)); + +#ifdef OLD + // Remember size of picture so we can return + // a reasonable answer for GetExtent + if (cfFormat == CF_METAFILEPICT) + { + LPMETAFILEPICT lpMfp = (LPMETAFILEPICT) GlobalLock (m_hPict); + if (NULL==lpMfp) + return E_HANDLE; + UpdateExtent (m_cxContentExtent, lpMfp->xExt); + UpdateExtent (m_cyContentExtent, lpMfp->yExt); + GlobalUnlock (m_hPict); + } + else if (cfFormat==CF_BITMAP) + { + BITMAP bm; + if (0==GetObject (m_hPict, sizeof(BITMAP), (LPVOID) &bm)) + return E_HANDLE; + UpdateExtent (m_cxContentExtent, + wPixelsToHiMetric (bm.bmWidth, giPpliX)); + UpdateExtent (m_cyContentExtent, + wPixelsToHiMetric (bm.bmHeight,giPpliY)); + } + else if (cfFormat==CF_DIB) + { + BITMAPINFOHEADER * pbminfohdr; + pbminfohdr = (BITMAPINFOHEADER *) GlobalLock (m_hPict); + if (NULL==pbminfohdr) + return E_HANDLE; + UpdateExtent (m_cxContentExtent, + wPixelsToHiMetric (pbminfohdr->biWidth, giPpliX)); + UpdateExtent (m_cyContentExtent, + wPixelsToHiMetric (pbminfohdr->biHeight,giPpliY)); + GlobalUnlock (m_hPict); + } +#endif + + } + else + { + if (m_hExtra) + wFreeData (m_hExtra, m_cfExtra, TRUE); + m_cfExtra = cfFormat; + wTransferHandle (&m_hExtra, &hData, cfFormat); + } + + return NOERROR; +} + + +// IsFormatAvailable +// +// Does a temporary DDE_REQUEST to see if server supports a format +// Returns NOERROR if format is available. +// + + +INTERNAL CDdeObject::IsFormatAvailable + (LPFORMATETC pformatetc) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::IsFormatAvailable(%x)\n",this)); + ATOM aItem=(ATOM)0; + HRESULT hresult; + + Puts ("DdeObject::IsFormatAvailable\n"); + + if (!HasValidLINDEX(pformatetc)) + { + intrDebugOut((DEB_IERROR, "\t!HasValidLINDEX(pformatetc)\n")); + return(DV_E_LINDEX); + } + + if (0==pformatetc->cfFormat) + return ResultFromScode (E_INVALIDARG); + + if (pformatetc->dwAspect & DVASPECT_ICON) + { + if (pformatetc->cfFormat==CF_METAFILEPICT) + { + // This is always available. we get it from the exe. + return NOERROR; + } + // an icon must be a metafile + return ResultFromScode (S_FALSE); + } + if (!(pformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_DOCPRINT))) + { + // 1.0 does not support Thumb. + return ReportResult(0, S_FALSE, 0, 0); + } + + if (NOERROR == (hresult=m_ConnectionTable.Lookup (pformatetc->cfFormat, NULL))) + { + // We already got a call to DataObject::Advise on this format, + // so it must be available. + Puts ("DataObject::Advise had been done on this format.\n"); + return NOERROR; + } + else + { + // Lookup () didn't find this format. + ErrZ (GetScode(hresult)==S_FALSE); + } + + intrAssert(wIsValidAtom(m_aItem)); + aItem = wDupAtom (m_aItem); + intrAssert(wIsValidAtom(aItem)); + + LPARAM lp; + if(!wPostMessageToServer (m_pDocChannel, WM_DDE_REQUEST, + lp = MAKE_DDE_LPARAM (WM_DDE_REQUEST,pformatetc->cfFormat,aItem),TRUE)) + { + + return(RPC_E_DDE_POST); + } + + if (NOERROR==WaitForReply (m_pDocChannel, AA_REQUESTAVAILABLE)) + return NOERROR; + + // Last ditch effort: Advise + if (NOERROR== AdviseOn (pformatetc->cfFormat, ON_SAVE)) + { + // We cannot Unadvise because an OLE 1.0 bug + // terminates DDE advise connections for ALL formats. + //// UnAdviseOn (pformatetc->cfFormat, ON_SAVE); + // Instead, just remember we did this advise. + m_ConnectionTable.Add (0, pformatetc->cfFormat, ADVFDDE_ONSAVE); + return NOERROR; + } + return ResultFromScode (S_FALSE); + +errRtn: + AssertSz (0, "Error in CDdeObject::IsFormatAvailable"); + Puth (hresult); Putn(); + if (aItem) + GlobalDeleteAtom (aItem); + + return hresult; +} + + + + +INTERNAL CDdeObject::ChangeTopic + (LPSTR lpszTopic) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::ChangeTopic(%x,lpszTopic=%s)\n",this,lpszTopic)); + HRESULT hresult; + LPMONIKER pmkFile=NULL; + LPMONIKER pmkItem=NULL; + LPMONIKER pmkComp=NULL; + LPMONIKER pmkNewName=NULL; + ATOM aTopic = wGlobalAddAtomA (lpszTopic); + intrAssert(wIsValidAtom(aTopic)); + + // Yet-Another-Excel-Hack + // Excel 4.0 sends StdDocumentName every time it saves, + // whether or not the file name has actually changed. Bug 2957 + if (aTopic != m_aTopic) + { + ErrRtnH (CreateOle1FileMoniker (wAtomName(aTopic), m_clsid, &pmkFile)); + if (m_aItem) + { + intrAssert (wIsValidAtom (m_aItem)); + ErrRtnH (CreateItemMoniker (OLESTR("!"), wAtomName (m_aItem), &pmkItem)); + ErrRtnH (CreateGenericComposite (pmkFile, pmkItem, &pmkComp)); + (pmkNewName = pmkComp)->AddRef(); + } + else + { + (pmkNewName = pmkFile)->AddRef(); + } + RetZS (m_pOleAdvHolder, E_OUTOFMEMORY); + RetZ (pmkNewName); + ErrRtnH (m_pOleAdvHolder->SendOnRename (pmkNewName)); + } + SetTopic (aTopic); + hresult = NOERROR; + + errRtn: + if (pmkFile) + pmkFile->Release(); + if (pmkItem) + pmkItem->Release(); + if (pmkComp) + pmkComp->Release(); + if (pmkNewName) + pmkNewName->Release(); + return hresult; +} + + +//+--------------------------------------------------------------------------- +// +// Method: CDdeObject::ChangeItem +// +// Synopsis: Changes the m_aItem atom, using an Ansi string +// +// Effects: +// +// Arguments: [szItem] -- Ansi string for the new item +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 5-12-94 kevinro Created +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL_(void) CDdeObject::ChangeItem + (LPSTR szItem) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::ChangeItem(%x,szItem=%s)\n",this,szItem)); + intrAssert(wIsValidAtom(m_aItem)); + if (m_aItem) + GlobalDeleteAtom (m_aItem); + m_aItem = wGlobalAddAtomA (szItem); + intrAssert(wIsValidAtom(m_aItem)); +} + + + + +INTERNAL CDdeObject::DeclareVisibility + (BOOL f, + BOOL fCallOnShowIfNec) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::DelcareVisibility(%x)\n",this)); + if (f) + m_fWasEverVisible = TRUE; + if ((f && (!m_fVisible || !m_fCalledOnShow)) || + (!f && m_fVisible)) + { + if (m_pOleClientSite && fCallOnShowIfNec && m_clsid != CLSID_Package) + { + m_pOleClientSite->OnShowWindow (f); + m_fCalledOnShow = f; + } + m_fVisible = f; + } + return NOERROR; +} + + + +INTERNAL CDdeObject::Update + (BOOL fRequirePresentation) +{ + intrDebugOut((DEB_ITRACE, + "CDdeObject::Update(%x,fRequiredPresentation=%x)\n", + this, + fRequirePresentation)); + // Get latest data + // OLE 1.0 spec says servers must supply metafile format. + HRESULT hresult = RequestData (m_cfPict ? m_cfPict : CF_METAFILEPICT); + if (fRequirePresentation && hresult!=NOERROR) + return hresult; + RetErr (RequestData (g_cfNative)); + SendOnDataChange (ON_CHANGE); + return NOERROR; +} + + + +INTERNAL CDdeObject::Save + (LPSTORAGE pstg) +{ + intrDebugOut((DEB_ITRACE,"CDdeObject::Save(%x)\n",this)); + VDATEIFACE (pstg); +#ifdef OLE1INTEROP + RetErr (StSave10NativeData (pstg, m_hNative, m_fOle1interop)); +#else + RetErr (StSave10NativeData (pstg, m_hNative, FALSE)); +#endif + if (m_aItem) + { + intrAssert(wIsValidAtom(m_aItem)); + RetErr (StSave10ItemName (pstg, wAtomNameA (m_aItem))); + } + RetErr (wWriteFmtUserType (pstg, m_clsid)); + return NOERROR; +} + +/* + * IMPLEMENTATION of CUnknownImpl + * + */ + + + +STDMETHODIMP_(ULONG) NC(CDdeObject,CUnknownImpl)::AddRef() +{ + ChkD(m_pDdeObject); + + return InterlockedAddRef(&(m_pDdeObject->m_refs)); +} + + +STDMETHODIMP_(ULONG) NC(CDdeObject,CUnknownImpl)::Release() +{ + ChkD(m_pDdeObject); + Assert (m_pDdeObject->m_refs != 0); + ULONG ul; + + if ((ul=InterlockedRelease(&(m_pDdeObject->m_refs))) == 0) { + m_pDdeObject->m_ProxyMgr.Disconnect(); + +#ifdef _CHICAGO_ + //Note:POSTPPC + // the object can not be delete if guarded + // which is the case if DelayDelete state is 'DelayIt' + // + if (m_pDdeObject->_DelayDelete == DelayIt) + { + // set the state to ReadyToDelete and + // the object will be deleted at the + // UnGuard call + m_pDdeObject->_DelayDelete = ReadyToDelete; + intrDebugOut((DEB_IWARN ,"Can not release CDdeObject\n")); + return 1; + } +#endif //_CHICAGO_ + delete m_pDdeObject; + return 0; + } + return ul; +} + + + + +STDMETHODIMP NC(CDdeObject,CUnknownImpl)::QueryInterface(REFIID iid, LPLPVOID ppv) +{ + ChkD(m_pDdeObject); + if (iid == IID_IUnknown) { + *ppv = (void FAR *)&m_pDdeObject->m_Unknown; + AddRef(); + return NOERROR; + } + else if (iid == IID_IOleObject) + *ppv = (void FAR *) &(m_pDdeObject->m_Ole); + else if (iid == IID_IDataObject) + *ppv = (void FAR *) &(m_pDdeObject->m_Data); + else if (iid == IID_IPersist || iid == IID_IPersistStorage) + *ppv = (void FAR *) &(m_pDdeObject->m_PersistStg); + else if (iid == IID_IProxyManager) + *ppv = (void FAR *) &(m_pDdeObject->m_ProxyMgr); + else if (iid == IID_IOleItemContainer + || iid == IID_IOleContainer + || iid == IID_IParseDisplayName) + *ppv = (void FAR *) &(m_pDdeObject->m_OleItemContainer); + else { + Puts ("INTERFACE NOT FOUND \r\n"); + *ppv = NULL; + return ReportResult(0, E_NOINTERFACE, 0, 0); + } + + m_pDdeObject->m_pUnkOuter->AddRef(); + return NOERROR; +} + diff --git a/private/ole32/com/remote/dde/client/ddeproxy.h b/private/ole32/com/remote/dde/client/ddeproxy.h new file mode 100644 index 000000000..8f55b6dd2 --- /dev/null +++ b/private/ole32/com/remote/dde/client/ddeproxy.h @@ -0,0 +1,608 @@ +/* ddeproxy.h + + Used by ddeproxy.cpp ddeDO.cpp ddeOO.cpp + + Author: Jason Fuller jasonful 24-July-1992 + +*/ +#ifndef fDdeProxy_h +#define fDdeProxy_h + +// +// One of the oleint.h routines redefines GlobalAlloc and friends +// to perform some memory tracking functions. +// +// This doesn't work in these files, since the tracking functions +// add tail checking, and size to the data structures. GlobalSize +// is a common function to use to determine how much data to +// serialize, plus it turns out that the other side of a DDE +// connection will often be the caller to free the memory. +// +// Therefore, OLE_DDE_NO_GLOBAL_TRACKING is used to disable this in the +// global header file ih\memapi.hxx. Check to insure this +// flag is set on the compile line +// +#if !defined(OLE_DDE_NO_GLOBAL_TRACKING) +error OLE_DDE_OLE_DDE_NO_GLOBAL_TRACKING must be defined to build this directory +#endif + + +#include <ole2int.h> +#include <callcont.hxx> +#include <ddeint.h> +#include <dde.h> +#include <olerem.h> +#include <ole1cls.h> +#include <limits.h> +// For fDdeCodeInOle2Dll flag +#include <ddeatoms.h> +#include <ddepack.h> +#include <ddedebug.h> + +#ifdef OLE_DEBUG_EXT +#include <ntsdexts.h> +#endif OLE_DEBUG_EXT + +#include "ddechc.hxx" +#define LPCALLINFO LPVOID +#include "ddeerr.h" +#include "cnct_tbl.h" + +#define MAX_STR 256 + +// number of .01 mm per inch +#define HIMETRIC_PER_INCH 2540 + +//#define fDebugOutput + +// callback notifications +#define ON_CHANGE 0 +#define ON_SAVE 1 +#define ON_CLOSE 2 +#define ON_RENAME 3 + +// AwaitAck values +#define AA_NONE 0 +#define AA_REQUEST 1 +#define AA_ADVISE 2 +#define AA_POKE 3 +#define AA_EXECUTE 4 +#define AA_UNADVISE 5 +#define AA_INITIATE 6 +#define AA_TERMINATE 7 +// A DDE_REQUEST to see if a format is available, not to keep the data. +#define AA_REQUESTAVAILABLE 8 + +// Bits for Positive WM_DDE_ACK +//#define POSITIVE_ACK 0x8000 +//#define NEGATIVE_ACK 0x0000 + + + +typedef DWORD CHK; +const DWORD chkDdeObj = 0xab01; // magic cookie + + +typedef struct tagDDE_CHANNEL : public CPrivAlloc { + ULONG AddReference() + { + return ++m_cRefs; + } + ULONG ReleaseReference() + { + if (--m_cRefs == 0) + { + delete this; + return(0); + } + return(m_cRefs); + } + ULONG m_cRefs; + HWND hwndCli; + HWND hwndSvr; + BOOL bTerminating; + int iExtraTerms; + WORD wTimer; + DWORD dwStartTickCount; + WORD msgFirst; + WORD msgLast; + HWND msghwnd; // + BOOL fRejected; // because fBusy flag set in DDE_ACK + WORD wMsg; + LONG lParam; + int iAwaitAck; + HRESULT hres; + HANDLE hopt; // Memory blocks I may have to free for DDE_ADVISE + HANDLE hDdePoke; // for DDE_POKE + HANDLE hCommands; // for DDE_EXECUTE + WORD wChannelDeleted; + PCALLDATA pCD; + PCALLCONTROL pCallCont; + CDdeChannelControl *pChanCont; +} DDE_CHANNEL; + + +#define Channel_InModalloop 1 +#define Channel_DeleteNow 2 + + +typedef DDE_CHANNEL * LPDDE_CHANNEL; +extern BOOL bWndClassesRegistered; + +#define hinstSO g_hmodOLE2 +extern HMODULE g_hmodOLE2; + +extern INTERNAL_(BOOL) wRegisterClasses (void); + +#ifndef _MAC +extern CLIPFORMAT g_cfNative; +extern CLIPFORMAT g_cfBinary; +#endif + +#ifdef _CHICAGO_ +//Note:POSTPPC +// +// DelayDelete is used to delay deleting the CDdeObject +// Guard will set it to DelayIt +// UnGuard will reset it to NoDelay or delete the object +// if state is ReadyToDelete +// +typedef enum +{ + NoDelay = 0, // normal state + DelayIt = 1, // object is protected and deleting will be delayed + ReadyToDelete = 2 // object was is DelayIt state and can be deleted +} DelayDelete; + +#endif // _CHICAGO_ + +/* + * Definition of CDdeObject + * + */ +class CMsgFilterInfo; +class CDdeObject; + +class CDdeObject : public CPrivAlloc +{ +public: + + static INTERNAL_(LPUNKNOWN) Create (IUnknown * pUnkOuter, + REFCLSID clsidClass, + ULONG ulObjType = OT_EMBEDDED, + ATOM aTopic = NULL, + LPOLESTR szItem = NULL, + CDdeObject * * ppdde = NULL, + BOOL fAllowNullClsid = FALSE); + + INTERNAL_(void) OnInitAck (LPDDE_CHANNEL pChannel, HWND hwndSvr); + INTERNAL_(BOOL) OnAck (LPDDE_CHANNEL pChannel, LONG lParam); + INTERNAL_(void) OnTimer (LPDDE_CHANNEL pChannel); + INTERNAL OnData (LPDDE_CHANNEL pChannel, HANDLE hData,ATOM aItem); + INTERNAL OnDataAvailable (LPDDE_CHANNEL pChannel, HANDLE hData,ATOM aItem); + INTERNAL OnTerminate (LPDDE_CHANNEL pChannel, HWND hwndPost); + + INTERNAL_(LPDDE_CHANNEL) GetSysChannel(void) + { return m_pSysChannel; } + + INTERNAL_(LPDDE_CHANNEL) GetDocChannel(void) + { return m_pDocChannel; } + + INTERNAL_(BOOL) AllocDdeChannel(LPDDE_CHANNEL * lpChannel, LPSTR lpszWndClass); + INTERNAL_(BOOL) InitSysConv (void); + INTERNAL_(void) SetTopic (ATOM aTopic); + + INTERNAL SendOnDataChange (int iAdvOpt); + INTERNAL OleCallBack (int iAdvOpt,LPDDE_CHANNEL pChannel); +#ifdef _CHICAGO_ + //Note:POSTPPC + INTERNAL_(void) Guard() + { + intrDebugOut((DEB_IWARN ,"CDdeObject: %x DelayDelete is set to 'DelayIt'\n", this)); + _DelayDelete = DelayIt; + } + INTERNAL_(BOOL) UnGuard() + { + if (_DelayDelete == ReadyToDelete) + { + intrDebugOut((DEB_IWARN ,"CDdeObject: %x DelayDelete it set 'ReadyToDelete'\n", this)); + delete this; + intrDebugOut((DEB_IWARN ,"CDdeObject: %x was deleted\n", this)); + return TRUE; + } + else + { + intrDebugOut((DEB_IWARN ,"CDdeObject: %x DelayDelete set to 'NoDelay'\n", this)); + _DelayDelete = NoDelay; + } + + return FALSE; + } +#endif // _CHICAGO_ + + BOOL m_fDoingSendOnDataChange; + ULONG m_cRefCount; + +private: + + CDdeObject (IUnknown * pUnkOuter); + ~CDdeObject (void); + INTERNAL TermConv (LPDDE_CHANNEL pChannel, BOOL fWait=TRUE); + INTERNAL_(void) DeleteChannel (LPDDE_CHANNEL pChannel); + INTERNAL_(BOOL) LaunchApp (void); + INTERNAL MaybeUnlaunchApp (void); + INTERNAL UnlaunchApp (void); + INTERNAL Execute (LPDDE_CHANNEL pChannel, + HANDLE hdata, + BOOL fStdCloseDoc=FALSE, + BOOL fWait=TRUE, + BOOL fDetectTerminate = TRUE); + INTERNAL Advise(void); + INTERNAL AdviseOn (CLIPFORMAT cfFormat, int iAdvOn); + INTERNAL UnAdviseOn (CLIPFORMAT cfFormat, int iAdvOn); + INTERNAL Poke (ATOM aItem, HANDLE hDdePoke); + INTERNAL PostSysCommand (LPDDE_CHANNEL pChannel, + LPCSTR szCmd, + BOOL bStdNew=FALSE, + BOOL fWait=TRUE); + +#ifdef _CHICAGO_ + //POSTPPC + INTERNAL_(BOOL) CanMakeOutCall(LPDDE_CHANNEL pChannel); +#endif + + INTERNAL WaitForReply (LPDDE_CHANNEL pChannel, + int iAwaitAck, + BOOL fStdCloseDoc = FALSE, + BOOL fDetectTerminate = TRUE); + INTERNAL KeepData (LPDDE_CHANNEL pChannel, HANDLE hDdeData); + INTERNAL ChangeTopic (LPSTR lpszTopic); + INTERNAL_(void) ChangeItem (LPSTR lpszItem); + INTERNAL IsFormatAvailable (LPFORMATETC); + INTERNAL_(BOOL) CanCallBack(LPINT); + INTERNAL RequestData (CLIPFORMAT); + INTERNAL SetTargetDevice (const DVTARGETDEVICE *); + INTERNAL DocumentLevelConnect (LPBINDCTX pbc); + INTERNAL SendOnClose (void); + INTERNAL UpdateAdviseCounts (CLIPFORMAT cf, + int iAdvOn, + signed int cDelta); + INTERNAL DeclareVisibility (BOOL fVisible, + BOOL fCallOnShowIfNec=TRUE); + INTERNAL Save (LPSTORAGE); + INTERNAL Update (BOOL fRequirePresentation); + +implementations: + + STDUNKDECL(CDdeObject,DdeObject) + STDDEBDECL(CDdeObject,DdeObject) + + + implement COleObjectImpl : IOleObject + { + public: + COleObjectImpl (CDdeObject * pDdeObject) + { m_pDdeObject = pDdeObject; } + + // *** IUnknown methods *** + STDMETHOD(QueryInterface) ( REFIID riid, LPVOID * ppvObj); + STDMETHOD_(ULONG,AddRef) (); + STDMETHOD_(ULONG,Release) (); + + // *** IOleObject methods *** + STDMETHOD(SetClientSite) ( LPOLECLIENTSITE pClientSite); + STDMETHOD(GetClientSite) ( LPOLECLIENTSITE * ppClientSite); + STDMETHOD(SetHostNames) ( LPCOLESTR szContainerApp, LPCOLESTR szContainerObj); + STDMETHOD(Close) ( DWORD reserved); + STDMETHOD(SetMoniker) ( DWORD dwWhichMoniker, LPMONIKER pmk); + STDMETHOD(GetMoniker) ( DWORD dwAssign, DWORD dwWhichMoniker,LPMONIKER * ppmk); + STDMETHOD(InitFromData) ( LPDATAOBJECT pDataObject,BOOL fCreation,DWORD dwReserved); + STDMETHOD(GetClipboardData) ( DWORD dwReserved,LPDATAOBJECT * ppDataObject); + + STDMETHOD(DoVerb) ( LONG iVerb, + LPMSG lpmsg, + LPOLECLIENTSITE pActiveSite, + LONG lindex, + HWND hwndParent, + const RECT * lprcPosRect); + + STDMETHOD(EnumVerbs) ( IEnumOLEVERB * * ppenumOleVerb); + STDMETHOD(Update) (); + STDMETHOD(IsUpToDate) (); + STDMETHOD(GetUserClassID) ( CLSID * pClsid); + STDMETHOD(GetUserType) ( DWORD dwFormOfType, LPOLESTR * pszUserType); + STDMETHOD(SetExtent) ( DWORD dwDrawAspect, LPSIZEL lpsizel); + STDMETHOD(GetExtent) ( DWORD dwDrawAspect, LPSIZEL lpsizel); + STDMETHOD(Advise)( IAdviseSink * pAdvSink, DWORD * pdwConnection) ; + STDMETHOD(Unadvise) ( DWORD dwConnection); + STDMETHOD(EnumAdvise) ( LPENUMSTATDATA * ppenumAdvise); + STDMETHOD(GetMiscStatus) ( DWORD dwAspect, DWORD * pdwStatus); + STDMETHOD(SetColorScheme) ( LPLOGPALETTE lpLogpal); + + private: + CDdeObject * m_pDdeObject; + }; + + + implement CDataObjectImpl : IDataObject + { + public: + CDataObjectImpl (CDdeObject * pDdeObject) + { m_pDdeObject = pDdeObject; } + // *** IUnknown methods *** + STDMETHOD(QueryInterface) ( REFIID riid, LPVOID * ppvObj); + STDMETHOD_(ULONG,AddRef) () ; + STDMETHOD_(ULONG,Release) (); + + STDMETHOD(GetData) ( LPFORMATETC pformatetcIn,LPSTGMEDIUM pmedium ); + STDMETHOD(GetDataHere) ( LPFORMATETC pformatetc,LPSTGMEDIUM pmedium ); + STDMETHOD(QueryGetData) ( LPFORMATETC pformatetc ); + STDMETHOD(GetCanonicalFormatEtc) ( LPFORMATETC pformatetc,LPFORMATETC pformatetcOut); + STDMETHOD(SetData) ( LPFORMATETC pformatetc, STGMEDIUM * pmedium, BOOL fRelease); + STDMETHOD(EnumFormatEtc) ( DWORD dwDirection, LPENUMFORMATETC * ppenumFormatEtc); + STDMETHOD(DAdvise) ( FORMATETC * pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD * pdwConnection) ; + STDMETHOD(DUnadvise) ( DWORD dwConnection) ; + STDMETHOD(EnumDAdvise) ( LPENUMSTATDATA * ppenumAdvise) ; + + private: + CDdeObject * m_pDdeObject; + }; + + + implement CPersistStgImpl : IPersistStorage + { + public: + CPersistStgImpl (CDdeObject * pDdeObject) + { m_pDdeObject = pDdeObject; } + + STDMETHOD(QueryInterface) ( REFIID iid, LPVOID * ppvObj); + STDMETHOD_(ULONG,AddRef) (); + STDMETHOD_(ULONG,Release) (); + STDMETHOD(GetClassID) ( LPCLSID pClassID); + STDMETHOD(IsDirty) (void); + STDMETHOD(InitNew) ( LPSTORAGE pstg); + STDMETHOD(Load) ( LPSTORAGE pstg); + STDMETHOD(Save) ( LPSTORAGE pstgSave, BOOL fSameAsLoad); + STDMETHOD(SaveCompleted) ( LPSTORAGE pstgNew); + STDMETHOD(HandsOffStorage) (void); + + private: + CDdeObject * m_pDdeObject; + }; + + + implement CProxyManagerImpl : IProxyManager + { + public: + CProxyManagerImpl (CDdeObject * pDdeObject) + { m_pDdeObject = pDdeObject; } + + STDMETHOD(QueryInterface) ( REFIID iid, LPVOID * ppvObj); + STDMETHOD_(ULONG,AddRef) (); + STDMETHOD_(ULONG,Release) (); + + STDMETHOD(CreateServer)(REFCLSID rclsid, DWORD clsctx, void *pv); + STDMETHOD_(BOOL, IsConnected)(void); + STDMETHOD(LockConnection)(BOOL fLock, BOOL fLastUnlockReleases); + STDMETHOD_(void, Disconnect)(); + + + STDMETHOD(Connect)(OID oid, REFCLSID rclsid); + STDMETHOD(EstablishIID)(REFIID iid, LPVOID FAR* ppv); + + STDMETHOD(CreateServerWithHandler)(REFCLSID rclsid, DWORD clsctx, void *pv, + REFCLSID rclsidHandler, IID iidSrv, void **ppv, + IID iidClnt, void *pClientSiteInterface); + + private: + CDdeObject * m_pDdeObject; + }; + + + implement COleItemContainerImpl : IOleItemContainer + { + public: + COleItemContainerImpl (CDdeObject * pDdeObject) + { m_pDdeObject = pDdeObject; } + + STDMETHOD(QueryInterface) ( REFIID iid, LPVOID * ppvObj); + STDMETHOD_(ULONG,AddRef) (); + STDMETHOD_(ULONG,Release) (); + + // IParseDisplayName method + STDMETHOD(ParseDisplayName) ( LPBC pbc, + LPOLESTR lpszDisplayName, + ULONG * pchEaten, + LPMONIKER * ppmkOut) ; + + // IOleContainer methods + STDMETHOD(EnumObjects) ( DWORD grfFlags,LPENUMUNKNOWN * ppenumUnk); + + STDMETHOD(LockContainer) (BOOL fLock); + + // IOleItemContainer methods + STDMETHOD(GetObject) ( LPOLESTR lpszItem, + DWORD dwSpeedNeeded, + LPBINDCTX pbc, + REFIID riid, + LPVOID * ppvObject) ; + STDMETHOD(GetObjectStorage) ( LPOLESTR lpszItem, + LPBINDCTX pbc, + REFIID riid, + LPVOID * ppvStorage) ; + + STDMETHOD(IsRunning) ( LPOLESTR lpszItem) ; + + private: + CDdeObject * m_pDdeObject; + }; + + + + DECLARE_NC(CDdeObject, COleObjectImpl) + DECLARE_NC(CDdeObject, CDataObjectImpl) + DECLARE_NC(CDdeObject, CPersistStgImpl) + DECLARE_NC(CDdeObject, CProxyManagerImpl) + DECLARE_NC(CDdeObject, COleItemContainerImpl) + + COleObjectImpl m_Ole; + CDataObjectImpl m_Data; + CPersistStgImpl m_PersistStg; + CProxyManagerImpl m_ProxyMgr; + COleItemContainerImpl m_OleItemContainer; + +shared_state: + ULONG m_refs; +#ifdef _CHICAGO_ + //Note:POSTPPC + DelayDelete _DelayDelete; +#endif // _CHICAGO_ + ULONG m_ulObjType; + CLSID m_clsid; + ATOM m_aClass; + ATOM m_aExeName; + ATOM m_aTopic; + ATOM m_aItem; + BOOL m_bRunning; + IUnknown * m_pUnkOuter; + IOleClientSite * m_pOleClientSite; + LPSTORAGE m_pstg; + BOOL m_bInitNew; + BOOL m_bOldSvr; + HANDLE m_hNative; + HANDLE m_hPict; + HANDLE m_hExtra; + CLIPFORMAT m_cfPict; + CLIPFORMAT m_cfExtra; + + BOOL m_fDidSendOnClose; + BOOL m_fNoStdCloseDoc; + BOOL m_fDidStdCloseDoc; + BOOL m_fDidStdOpenDoc; + BOOL m_fDidGetObject; + BOOL m_fDidLaunchApp; + BOOL m_fUpdateOnSave; + BOOL m_fGotCloseData; + +#ifdef OLE1INTEROP + BOOL m_fOle1interop; +#endif + + // Invisible update stuff + ULONG m_cLocks; // PM::LockConnection lock count (init 1) + BOOL m_fVisible; // is server visible (as best we know)? + BOOL m_fWasEverVisible; + BOOL m_fCalledOnShow; // Did we call IOleClientSite::OnShow + + CHK m_chk; + DVTARGETDEVICE * m_ptd; + + // m_iAdvClose and m_iAdvSave are counts (1 or 2) of the number of formats + // that have advise connections of a given type (Save or Close) + int m_iAdvClose; + int m_iAdvSave; + int m_iAdvChange; + + BOOL m_fDidAdvNative; + + // Extent info +#ifdef OLD + long m_cxContentExtent; + long m_cyContentExtent; +#endif + + // terminate info - only used to detect a premature WM_DDE_TERMINATE + WORD m_wTerminate; + + IDataAdviseHolder * m_pDataAdvHolder; + IOleAdviseHolder * m_pOleAdvHolder; + CDdeConnectionTable m_ConnectionTable; + + + // DDE window related stuff + LPDDE_CHANNEL m_pSysChannel; + LPDDE_CHANNEL m_pDocChannel; + + friend INTERNAL DdeBindToObject + (LPCOLESTR szFile, + REFCLSID clsid, + BOOL fPackageLink, + REFIID iid, + LPLPVOID ppv); + + friend INTERNAL DdeIsRunning + (CLSID clsid, + LPCOLESTR szFile, + LPBC pbc, + LPMONIKER pmkToLeft, + LPMONIKER pmkNewlyRunning); +#ifdef OLE_DEBUG_EXT + +#endif OLE_DEBUG_EXT +}; +// +// Note: WM_DDE_TERMINATE +// A state machine is used to delay the executing of a premature WM_DDE_TERMINTE +// message, which is send by some apps instead of WM_DDE_ACK (or alike). +// The code is in WaitForReply() and in OnTerminate() +typedef enum { + Terminate_None = 0, // default state - terminate code is executed + Terminate_Detect = 1, // window proc will NOT execute terminate code + Terminate_Received = 2 // wait loop does not need to run, execute terminate code now +} TERMINATE_DOCUMENT; + + + +INTERNAL_(BOOL) wPostMessageToServer(LPDDE_CHANNEL pChannel, + WORD wMsg, + LONG lParam, + BOOL fFreeOnError); + +INTERNAL_(ATOM) wAtomFromCLSID(REFCLSID rclsid); +INTERNAL_(ATOM) wGetExeNameAtom (REFCLSID rclsid); +INTERNAL_(BOOL) wIsWindowValid (HWND hwnd); +INTERNAL_(void) wFreeData (HANDLE hData, CLIPFORMAT cfFormat, + BOOL fFreeNonGdiHandle=TRUE); +INTERNAL_(BOOL) wInitiate (LPDDE_CHANNEL pChannel, ATOM aLow, ATOM aHigh); +INTERNAL wScanItemOptions (ATOM aItem, int * lpoptions); +INTERNAL_(BOOL) wClearWaitState (LPDDE_CHANNEL pChannel); +INTERNAL_(HANDLE) wStdCloseDocumentHandle (void); +INTERNAL_(ATOM) wExtendAtom (ATOM aIitem, int iAdvOn); +INTERNAL_(int) wAtomLen (ATOM atom); +INTERNAL_(int) wAtomLenA (ATOM atom); +INTERNAL_(LPDDE_CHANNEL) wAllocDdeChannel(void); +INTERNAL_(HANDLE) wHandleFromDdeData(HANDLE hDdeData); +INTERNAL_(BOOL) wIsOldServer (ATOM aClass); +INTERNAL_(LPSTR) wAllocDdePokeBlock (DWORD dwSize, CLIPFORMAT cfFormat,LPHANDLE phDdePoke); +INTERNAL_(void) wFreePokeData (LPDDE_CHANNEL pChannel, BOOL fMSDrawBug); +INTERNAL_(HANDLE) wPreparePokeBlock (HANDLE hData, CLIPFORMAT cfFormat, + ATOM aClass, BOOL bOldSvr); +INTERNAL_(HANDLE) wNewHandle (LPSTR lpstr, DWORD cb); +INTERNAL wDupData (LPHANDLE ph, HANDLE h, CLIPFORMAT cf); +INTERNAL wHandleCopy (HANDLE hDst, HANDLE hSrc); +INTERNAL wGetRequestResponse (LPDDE_CHANNEL pChannel, CLIPFORMAT cf, ATOM aItem); +INTERNAL wGetItemFromClipboard (ATOM * paItem); +INTERNAL GetDefaultIcon (REFCLSID clsidIn, LPCOLESTR szFile, HANDLE * phmfp); +INTERNAL_(BOOL) wTerminateIsComing (LPDDE_CHANNEL); +INTERNAL wTimedGetMessage (LPMSG pmsg, HWND hwnd, WORD wFirst, WORD wLast); + +INTERNAL_(ATOM) wGlobalAddAtom(LPCOLESTR sz); +INTERNAL_(ATOM) wGlobalAddAtomA(LPCSTR sz); + +INTERNAL wVerifyFormatEtc (LPFORMATETC pformatetc); +INTERNAL wNormalize (LPFORMATETC pfetc, LPFORMATETC pfetcOut); +INTERNAL wTransferHandle (LPHANDLE phDst, LPHANDLE phSrc, CLIPFORMAT cf); +INTERNAL wClassesMatch (REFCLSID clsidIn, LPOLESTR szFile); + +#if DBG == 1 +INTERNAL_(BOOL) wIsValidHandle (HANDLE h, CLIPFORMAT cf); +INTERNAL_(BOOL) wIsValidAtom (ATOM a); +#endif + +const char achStdCloseDocument[]="[StdCloseDocument]"; +const char achStdOpenDocument[]="StdOpenDocument"; +const char achStdExit[]="StdExit"; +const char achStdNewDocument[]="StdNewDocument"; +const char achStdEditDocument[]="StdEditDocument"; + +#endif // ddeproxy.h diff --git a/private/ole32/com/remote/dde/client/ddestg.cxx b/private/ole32/com/remote/dde/client/ddestg.cxx new file mode 100644 index 000000000..657b9c2fe --- /dev/null +++ b/private/ole32/com/remote/dde/client/ddestg.cxx @@ -0,0 +1,535 @@ +/* + +copyright (c) 1992 Microsoft Corporation + +Module Name: + + ddeStg.cpp + +Abstract: + + This module contains the DdeObject::PersistStg and + DdeObject::ProxyManager methods + +Author: + + Srini Koppolu (srinik) 22-June-1992 + Jason Fuller (jasonful) 24-July-1992 + +*/ + +#include "ddeproxy.h" +ASSERTDATA + + +/* + * IMPLEMENTATION of CPersistStgImpl methods + * + */ + + +STDUNKIMPL_FORDERIVED(DdeObject, PersistStgImpl) + + +#pragma SEG(CDdeObject_CPersistStgImpl_GetClassID) +STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::GetClassID (CLSID FAR* pClassID) +{ + *pClassID = m_pDdeObject->m_clsid; + return NOERROR; +} + + +#pragma SEG(CDdeObject_CPersistStgImpl_IsDirty) +STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::IsDirty () +{ + return NOERROR; +} + + + +#pragma SEG(CDdeObject_CPersistStgImpl_InitNew) +STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::InitNew + (IStorage FAR* pstg) +{ + HRESULT hres; + intrDebugOut((DEB_ITRACE, + "DdeObejct::InitNew(%x,pstg=%x)\n", + this, + pstg)); + + if (hres = m_pDdeObject->PostSysCommand (m_pDdeObject->m_pSysChannel, + (LPSTR)&achStdNewDocument, + TRUE)) + return hres; + + if (hres = m_pDdeObject->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL)) + return hres; + + RetErr (m_pDdeObject->TermConv (m_pDdeObject->m_pSysChannel)); + if (m_pDdeObject->m_pstg) + { + m_pDdeObject->m_pstg->Release(); + } + m_pDdeObject->m_pstg = pstg; + pstg->AddRef(); + return hres; +} + + + +#pragma SEG(CDdeObject_CPersistStgImpl_Load) +STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::Load (IStorage FAR* pstg) +{ + LPSTR lpBuf=NULL; + HANDLE hDdePoke = NULL; + DWORD dwSize; + CStmBufRead StmRead; + CStmBufRead StmReadItem; + HRESULT hresult; + + intrDebugOut((DEB_ITRACE,"CDdeObject::Load(%x,pstg=%x)\n",this,pstg)); + + { + + if (hresult = StmRead.OpenStream(pstg, OLE10_NATIVE_STREAM)) + { + intrDebugOut((DEB_ITRACE, + "::Load(%x) OpenStream failed(%x)\n", + this, + hresult)); + return hresult; + } + + + if (hresult = StmRead.Read(&dwSize, sizeof(DWORD))) + { + intrDebugOut((DEB_ITRACE, + "::Load(%x) StRead failed(%x)\n", + this, + hresult)); + + goto errRtn; + } + + + lpBuf = wAllocDdePokeBlock (dwSize, g_cfNative, &hDdePoke); + + if (lpBuf == NULL) + { + intrDebugOut((DEB_ITRACE, + "::Load(%x) wAllocDdePokeBlock failed(%x)\n", + this, + hresult)); + + hresult = E_OUTOFMEMORY; + goto errRtn; + } + + if (hresult = StmRead.Read(lpBuf, dwSize)) + { + intrDebugOut((DEB_ITRACE, + "::Load(%x) StRead of cfNative failed(%x)\n", + this, + hresult)); + goto errRtn; + } + + if (m_pDdeObject->m_hNative) + { + GlobalFree (m_pDdeObject->m_hNative); + } + m_pDdeObject->m_hNative = wNewHandle (lpBuf, dwSize); + + if (m_pDdeObject->m_hNative == NULL) + { + intrDebugOut((DEB_ITRACE, + "::Load(%x) m_hNative NULL\n", + this)); + } + } + + GlobalUnlock (hDdePoke); // done with lpBuf + + if (hresult = m_pDdeObject->PostSysCommand (m_pDdeObject->m_pSysChannel, + (LPSTR)&achStdEditDocument, + FALSE)) + { + intrDebugOut((DEB_ITRACE, + "::Load(%x) PostSysCommand %s failed (%x)\n", + this, + &achStdEditDocument, + hresult)); + goto errRtn; + } + + + // Read Item Name, if there is one + if (NOERROR == StmReadItem.OpenStream(pstg, OLE10_ITEMNAME_STREAM)) + { + LPSTR szItemName = NULL; + + ErrRtnH (ReadStringStreamA (StmReadItem, &szItemName)); + m_pDdeObject->ChangeItem (szItemName); + PubMemFree(szItemName); + } + + if (hresult = m_pDdeObject->m_ProxyMgr.Connect (IID_NULL, CLSID_NULL)) + { + intrDebugOut((DEB_ITRACE, + "::Load(%x) ProxyMgr.Connect failed(%x)\n", + this, + hresult)); + goto errRtn; + } + + + if ((hresult = m_pDdeObject->Poke(m_pDdeObject->m_aItem, hDdePoke)) + != NOERROR) + { + intrDebugOut((DEB_ITRACE, + "::Load(%x) Poke failed(%x)\n", + this, + hresult)); + + // the Poke calls frees the Poke data even in case of failure. +#ifdef LATER + + if (hresult = m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel, + wNewHandle ((LPSTR)achStdCloseDocument,sizeof(achStdCloseDocument))); + goto errDoc; +#elseif + goto errDoc; +#endif + } + + hresult = m_pDdeObject->TermConv (m_pDdeObject->m_pSysChannel); + if (hresult != NOERROR) + { + intrDebugOut((DEB_ITRACE, + "::Load(%x) TermConv on SysChannel failed(%x)\n", + this, + hresult)); + goto errRtn; + } + + + if (m_pDdeObject->m_pstg) + { + m_pDdeObject->m_pstg->Release(); + } + + m_pDdeObject->m_pstg = pstg; + pstg->AddRef(); + goto LExit; + +errRtn: + if (hDdePoke) + GlobalFree (hDdePoke); + if (m_pDdeObject->m_pDocChannel) + m_pDdeObject->TermConv (m_pDdeObject->m_pDocChannel); +LExit: + StmReadItem.Release(); + StmRead.Release(); + + intrDebugOut((DEB_ITRACE,"::Load(%x) returning (%x)\n",this,hresult)); + return hresult; +} + + +#pragma SEG(CDdeObject_CPersistStgImpl_Save) +STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::Save + (IStorage FAR* pstgSave, BOOL fSameAsLoad) +{ + intrDebugOut((DEB_ITRACE, + "DdeObject::Save(%x,pstgSave=%x)\n", + this, + pstgSave)); + + + HRESULT hresult=NOERROR; + + if (m_pDdeObject->m_fUpdateOnSave + && (m_pDdeObject->m_clsid != CLSID_Package + || m_pDdeObject->m_hNative == NULL)) + { + // Get latest data from server, if it is not shutting down + // or telling us to Save, in which case it just gave us data. + // (If it is shutting down, it probably won't respond. + // Draw does respond, but gives bad data.) + // Packager gives truncated native data (header info with no + // actual embedded file) if you DDE_REQUEST it. Bug 3103 + m_pDdeObject->Update (FALSE); + } + + if (m_pDdeObject->m_hNative == NULL) + { + // we still have nothing to save + return ResultFromScode (E_BLANK); + } + + hresult = m_pDdeObject->Save (pstgSave); + + Puts ("PersistStg::Save done\n"); + return hresult; +} + + +#pragma SEG(CDdeObject_CPersistStgImpl_SaveCompleted) +STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::SaveCompleted + (IStorage FAR* pstgNew) +{ + intrDebugOut((DEB_ITRACE, + "DdeObejct::SaveCompleted(%x,pstgNew=%x)\n", + this, + pstgNew)); + + RetZ (m_pDdeObject->m_pOleAdvHolder); + m_pDdeObject->m_pOleAdvHolder->SendOnSave(); + if (pstgNew) + { + if (m_pDdeObject->m_pstg) + m_pDdeObject->m_pstg->Release(); + m_pDdeObject->m_pstg = pstgNew; + pstgNew->AddRef(); + } + return NOERROR; +} + + +#pragma SEG(CDdeObject_CPersistStgImpl_HandsOffStorage) +STDMETHODIMP NC(CDdeObject,CPersistStgImpl)::HandsOffStorage(void) +{ + intrDebugOut((DEB_ITRACE,"DdeObejct::HandsOffStorage(%x)\n",this)); + if (m_pDdeObject->m_pstg) + { + m_pDdeObject->m_pstg->Release(); + m_pDdeObject->m_pstg = NULL; + } + return NOERROR; +} + + +/* + * IMPLEMENTATION of CProxyManagerImpl methods + * + */ + + +STDUNKIMPL_FORDERIVED(DdeObject, ProxyManagerImpl) + + + +#pragma SEG(CDdeObject_CProxyManagerImpl_CreateServer) +STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::CreateServer(REFCLSID rclsid, + DWORD clsctx, + void *pv) +{ + intrDebugOut((DEB_ITRACE,"DdeObejct::CreateServer(%x)\n",this)); + HRESULT hresult = NOERROR; + + if (m_pDdeObject->m_pSysChannel) + { + intrDebugOut((DEB_ITRACE, + "::CreateServer(%x)m_pSysChannel exists\n", + this)); + return NOERROR; + } + + if (m_pDdeObject->m_aExeName == NULL) + { + intrDebugOut((DEB_ITRACE, + "::CreateServer(%x) Class Not Registered\n", + this)); + return(REGDB_E_CLASSNOTREG); + } + + + if (!m_pDdeObject->AllocDdeChannel(&m_pDdeObject->m_pSysChannel,SYS_CLASSA)) + { + intrDebugOut((DEB_ITRACE, + "::CreateServer(%x)AllocDdeChannel is failing\n", + this)); + return ReportResult(0, E_OUTOFMEMORY,0,0); + } + + if (!m_pDdeObject->InitSysConv()) + { + if (!(m_pDdeObject->LaunchApp())) + { + intrDebugOut((DEB_IERROR,"::CreateServer Could not launch app\n")); + hresult = ResultFromScode (CO_E_APPNOTFOUND); + goto errRtn; + } + + if (!m_pDdeObject->InitSysConv()) + { + intrDebugOut((DEB_IERROR,"::CreateServer Second init failed\n")); + hresult = ResultFromScode (CO_E_APPDIDNTREG); + goto errRtn; + } + } + + return NOERROR; + +errRtn: + intrDebugOut((DEB_ITRACE,"DdeObejct::CreateServer(%x) is failing(%x)\n",this,hresult)); + m_pDdeObject->DeleteChannel (m_pDdeObject->m_pSysChannel); + Assert (hresult != NOERROR); // This is an error path + return hresult; + +} + + +#pragma SEG(CDdeObject_CProxyManagerImpl_Connect) +STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::Connect(OID oid, REFCLSID rclsid) +{ + intrDebugOut((DEB_ITRACE,"DdeObject::Connect(%x)\n",this)); + + if (m_pDdeObject->m_pDocChannel) + return NOERROR; + + if (!m_pDdeObject->AllocDdeChannel (&m_pDdeObject->m_pDocChannel,CLIENT_CLASSA)) + { + intrDebugOut((DEB_ITRACE, + "::Connect(%x) AllocDdeChannel failed, return E_OUTOFMEMORY\n", + this)); + return ReportResult(0, E_OUTOFMEMORY,0,0); + } + + // Bug 3701 + m_pDdeObject->m_fDidSendOnClose = FALSE; + if (wInitiate (m_pDdeObject->m_pDocChannel, m_pDdeObject->m_aClass, + m_pDdeObject->m_aTopic)) + { + return NOERROR; + } + + intrDebugOut((DEB_ITRACE,"::Connect(%x) wInitiate failed\n",this)); + m_pDdeObject->DeleteChannel (m_pDdeObject->m_pDocChannel); + return ResultFromScode (E_FAIL); +} + + +#pragma SEG(CDdeObject_CProxyManagerImpl_LockConnection) +STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::LockConnection(BOOL fLock, BOOL fLastUnlockReleases) +{ + intrDebugOut((DEB_ITRACE, + "DdeObject::LockConnection(%x,fLock=%x,fLastUnlockReleases=%x)\n", + this, + fLock, + fLastUnlockReleases)); + + if (fLock) + m_pDdeObject->m_cLocks++; + else + { + if (m_pDdeObject->m_cLocks!=0 && 0 == --m_pDdeObject->m_cLocks && + fLastUnlockReleases && !m_pDdeObject->m_fVisible) + (void)m_pDdeObject->m_Ole.Close (OLECLOSE_SAVEIFDIRTY); + } + return NOERROR; +} + + +#ifdef NOTNEEDED +#pragma SEG(CDdeObject_CProxyManagerImpl_GetClassID) +STDMETHODIMP_(void) NC(CDdeObject, CProxyManagerImpl)::GetClassID(CLSID FAR* pClsid) +{ + *pClsid = m_pDdeObject->m_clsid; +} + + +#pragma SEG(CDdeObject_CProxyManagerImpl_GetOID) +STDMETHODIMP_(OID) NC(CDdeObject, CProxyManagerImpl)::GetOID() +{ + if (m_pDdeObject->m_pSysChannel) + return (OID) m_pDdeObject->m_pSysChannel; + + if (m_pDdeObject->m_pDocChannel) + return (OID) m_pDdeObject->m_pDocChannel; + + return NULL; +} +#endif + +#pragma SEG(CDdeObject_CProxyManagerImpl_IsConnected) +STDMETHODIMP_(BOOL) NC(CDdeObject, CProxyManagerImpl)::IsConnected(void) +{ + return m_pDdeObject->m_pDocChannel != NULL; +} + + +#pragma SEG(CDdeObject_CProxyManagerImpl_EstablishIID) +STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::EstablishIID(REFIID iid, LPVOID FAR* ppv) +{ + // REVIEW: this is correct, but can we be smarter like in the real PM? + return QueryInterface(iid, ppv); +} + + +#pragma SEG(wTerminateIsComing) +INTERNAL_(BOOL) wTerminateIsComing (LPDDE_CHANNEL pChannel) +{ + MSG msg; + return SSPeekMessage (&msg, pChannel->hwndCli, 0, 0, PM_NOREMOVE) + && msg.message == WM_DDE_TERMINATE + && (HWND)msg.wParam==pChannel->hwndSvr; +} + + +#pragma SEG(CDdeObject_CProxyManagerImpl_Disconnect) +STDMETHODIMP_(void) NC(CDdeObject, CProxyManagerImpl)::Disconnect() +{ + intrDebugOut((DEB_ITRACE,"DdeObject::Disonnect(%x)\n",this)); + #define p m_pDdeObject + if (m_pDdeObject->m_pDocChannel) + { + BOOL fTermComing = wTerminateIsComing (m_pDdeObject->m_pDocChannel); + if ((!m_pDdeObject->m_fNoStdCloseDoc + || (!m_pDdeObject->m_fWasEverVisible // invisible update or + && !m_pDdeObject->m_fDidGetObject // link from file case. + && m_pDdeObject->m_fDidStdOpenDoc)) // only do StdClose if did StdOpen + && !m_pDdeObject->m_fDidStdCloseDoc + && !fTermComing) + { + m_pDdeObject->Execute (m_pDdeObject->m_pDocChannel, + wNewHandle ((LPSTR)&achStdCloseDocument,sizeof(achStdCloseDocument)), + /*fStdClose*/TRUE, + /*fWait*/TRUE, + /*fDetectTerminate*/TRUE); + + m_pDdeObject->m_fDidStdCloseDoc = TRUE; + } + if (!m_pDdeObject->m_fDidSendOnClose /*|| fTermComing*/) + { + // if we did not call SendOnClose() then Disconnect() was called + // by a Release method, not by SendOnClose(). + // This happens when user deletes object in container. + BOOL fVisible = m_pDdeObject->m_fWasEverVisible; // TermConv clears this flag + m_pDdeObject->TermConv (m_pDdeObject->m_pDocChannel); + if (!fVisible) + m_pDdeObject->MaybeUnlaunchApp(); + } + } + + if (m_pDdeObject->m_pSysChannel) + { + intrDebugOut((DEB_IWARN,"Terminating system conversation in Disconnect()\n")); + // This should never happen, I think. + m_pDdeObject->TermConv (m_pDdeObject->m_pSysChannel); + } + #undef p +} + +// +// There is no ServerHandler with DDE servers. Therefore, this function returns E_NOTIMPL +// back to the handler. +// +STDMETHODIMP NC(CDdeObject, CProxyManagerImpl)::CreateServerWithHandler (REFCLSID rclsid, DWORD clsctx, void *pv, + REFCLSID rclsidHandler, IID iidSrv, void **ppv, + IID iidClnt, void *pClientSiteInterface) +{ + return E_NOTIMPL; +} + + diff --git a/private/ole32/com/remote/dde/client/ddewnd.cxx b/private/ole32/com/remote/dde/client/ddewnd.cxx new file mode 100644 index 000000000..a3a6725a0 --- /dev/null +++ b/private/ole32/com/remote/dde/client/ddewnd.cxx @@ -0,0 +1,363 @@ +/*++ + +copyright (c) 1992 Microsoft Corporation + +Module Name: + + ddewnd.cpp + +Abstract: + + This module contains the code for the dde window procs + +Author: + + Srini Koppolu (srinik) 20-June-1992 + +Revision History: + +--*/ +#include "ddeproxy.h" + + + +#define SYS_MSG 0 +#define DOC_MSG 1 + +// SysWndProc: Window Procedure for System Topic DDE conversations +// wndproc for system topic + + +STDAPI_(LRESULT) SysWndProc ( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + StackAssert(SSOnSmallStack()); + CDdeObject FAR* pDdeObj = NULL; + LPDDE_CHANNEL pChannel = NULL; + + if (message>=WM_DDE_FIRST && message <= WM_DDE_LAST) + { + if (pDdeObj = (CDdeObject FAR*) GetWindowLong (hwnd, 0)) + { + pChannel = pDdeObj->GetSysChannel(); + } + + if (pChannel == NULL) + { + intrAssert(pChannel != NULL); + return SSDefWindowProc (hwnd, message, wParam, lParam); + } + } + if ( pChannel + && ( pChannel->iAwaitAck == AA_EXECUTE + || pChannel->iAwaitAck == AA_INITIATE) ) + { + MSG msg; + BOOL fDisp = FALSE; + while (SSPeekMessage(&msg, hwnd, WM_DDE_ACK, WM_DDE_ACK, PM_REMOVE | PM_NOYIELD) ) + { + intrDebugOut((DEB_WARN, "DDE SysWndProc: dispatching WM_DDE_ACK message (%x)\n",pChannel)); + SSDispatchMessage(&msg); + fDisp = TRUE; + } + if (fDisp && (pDdeObj = (CDdeObject FAR*) GetWindowLong (hwnd, 0))) + { + pChannel = pDdeObj->GetSysChannel(); + } + + if (pChannel == NULL) + { + intrAssert(pChannel != NULL); + return SSDefWindowProc (hwnd, message, wParam, lParam); + } + } + + switch (message){ + case WM_DDE_ACK: + intrDebugOut((DEB_ITRACE, + "SWP: WM_DDE_ACK pChannel(%x)\n",pChannel)); + if (pChannel->bTerminating) + { + intrDebugOut((DEB_ITRACE, + "SWP: pChannel->bTerminating: no action\n")); + + break; + } + + switch (pChannel->iAwaitAck) { + case AA_INITIATE: + pDdeObj->OnInitAck (pChannel, (HWND)wParam); + if (LOWORD(lParam)) + GlobalDeleteAtom (LOWORD(lParam)); + if (HIWORD(lParam)) + GlobalDeleteAtom (HIWORD(lParam)); + break; + + case AA_EXECUTE: + pDdeObj->OnAck (pChannel, lParam); + break; + + default: + intrDebugOut((DEB_ITRACE, + "SWP: WM_DDE_ACK UnhandledpChannel(%x)\n",pChannel)); + break; + } + break; + + case WM_TIMER: + pDdeObj->OnTimer (pChannel); + break; + + case WM_DDE_TERMINATE: + intrDebugOut((DEB_ITRACE, + "SWP: WM_DDE_TERMINATE pChannel(%x)\n",pChannel)); + pDdeObj->OnTerminate (pChannel, (HWND)wParam); + break; + + default: + return SSDefWindowProc (hwnd, message, wParam, lParam); + } + + return 0L; +} + + +// ClientDocWndProc: Window procedure used to document DDE conversations +STDAPI_(LRESULT) ClientDocWndProc ( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + StackAssert(SSOnSmallStack()); + CDdeObject FAR* pDdeObj = NULL; + LPDDE_CHANNEL pChannel = NULL; + HANDLE hData; + ATOM aItem; + + if (message>=WM_DDE_FIRST && message <= WM_DDE_LAST) + { + + if (pDdeObj = (CDdeObject FAR*) GetWindowLong (hwnd, 0)) + pChannel = pDdeObj->GetDocChannel(); + + if (pChannel == NULL) + { + // + // pChannel == NULL. Something is very wrong! But, lets + // not fault on it. + // + //intrAssert(pChannel != NULL); + return SSDefWindowProc (hwnd, message, wParam, lParam); + } + + } + if ( pChannel + && ( pChannel->iAwaitAck == AA_EXECUTE + || pChannel->iAwaitAck == AA_INITIATE + || pChannel->iAwaitAck == AA_REQUESTAVAILABLE + || pChannel->iAwaitAck == AA_REQUEST + || pChannel->iAwaitAck == AA_UNADVISE + || pChannel->iAwaitAck == AA_EXECUTE + || pChannel->iAwaitAck == AA_ADVISE + || pChannel->iAwaitAck == AA_POKE) ) + { + MSG msg; + BOOL fDisp = FALSE; + while (SSPeekMessage(&msg, hwnd, WM_DDE_ACK, WM_DDE_ACK, PM_REMOVE | PM_NOYIELD) ) + { + intrDebugOut((DEB_WARN, "DDE DocWndProc: dispatching WM_DDE_ACK message (%x)\n",pChannel)); + SSDispatchMessage(&msg); + fDisp = TRUE; + } + + if (fDisp && (pDdeObj = (CDdeObject FAR*) GetWindowLong (hwnd, 0))) + { + pChannel = pDdeObj->GetDocChannel(); + } + + if (pChannel == NULL) + { + intrAssert(pChannel != NULL); + return SSDefWindowProc (hwnd, message, wParam, lParam); + } + } + + switch (message) + { + case WM_DDE_ACK: + + intrDebugOut((DEB_ITRACE, + "ClientWndProc: WM_DDE_ACK pChannel(%x)\n", + pChannel)); + if (pChannel->bTerminating){ + // ### this error recovery may not be correct. + DEBUG_OUT ("No action due to termination process",0) + break; + } + + switch(pChannel->iAwaitAck){ + case AA_INITIATE: + pDdeObj->OnInitAck (pChannel, (HWND)wParam); + if (LOWORD(lParam)) + GlobalDeleteAtom (LOWORD(lParam)); + if (HIWORD(lParam)) + GlobalDeleteAtom (HIWORD(lParam)); + break; + + case AA_REQUESTAVAILABLE: + case AA_REQUEST: + case AA_UNADVISE: + case AA_EXECUTE: + case AA_ADVISE: + pDdeObj->OnAck (pChannel, lParam); + break; + + case AA_POKE: + // freeing pokedata is done in handleack + pDdeObj->OnAck (pChannel, lParam); + break; + + default: + intrDebugOut((DEB_IERROR, + "ClientWndProc: WM_DDE_ACK unhandled\n")); + break; + + } // end of switch + break; + + case WM_DDE_DATA: +#ifdef _CHICAGO_ + //Note:POSTPPC + pDdeObj->Guard(); +#endif // _CHICAGO_ + hData = GET_WM_DDE_DATA_HDATA(wParam,lParam); + aItem = GET_WM_DDE_DATA_ITEM(wParam,lParam); + intrDebugOut((DEB_ITRACE, + "CWP: WM_DDE_DATA pChannel(%x) hData(%x) aItem(%x)\n", + pChannel,hData,aItem)); + pDdeObj->OnData (pChannel, hData, aItem); +#ifdef _CHICAGO_ + //Note:POSTPPC + if (pDdeObj->UnGuard()) + { + SetWindowLong(hwnd, 0, (LONG)0); + intrDebugOut((DEB_IWARN, "DDE ClientDocWndProc Release on pUnkOuter == 0 (this:%x, hwnd:%x\n",pDdeObj, hwnd )); + } +#endif // _CHICAGO_ + + break; + + case WM_DDE_TERMINATE: +#ifdef _CHICAGO_ + //Note:POSTPPC + pDdeObj->Guard(); +#endif // _CHICAGO_ + intrDebugOut((DEB_ITRACE, + "CWP: WM_DDE_TERMINATE pChannel(%x)\n",pChannel)); + + + if (pDdeObj->m_fDoingSendOnDataChange) + { +#ifdef _CHICAGO_ + //Note:POSTPPC + BOOL fPostMsg = TRUE; +#endif + // + // Cheese alert! This protocol is very bad. The original + // 16 bit code something even more worse, so we are stuck + // to do something roughly compatible. + // + // If fDoingSendOnDataChange, the client may be asking for + // additional information from the server. The way the code + // is structured, it doesn't handle OnTerminate gracefully + // in this case. + // + // To fix this, we first tell the call control that + // the server has died. Then we repost the terminate + // message so we can handle it later. + // + // The old code did a + // pDdeObj->QueueMsg (hwnd, message, wParam, lParam); + // + // and the old SendOnDataChange removed the message. + // This probably didn't work either, but was never + // actually encountered. + // + + intrDebugOut((DEB_ITRACE, + "CWP: term doing SendOnDataChange \n")); + // + // If we got here, there should be a CallData assigned + // to the channel. + // + if ((pChannel->pCD) && (pChannel->pCallCont)) + { + intrDebugOut((DEB_ITRACE,"CWP: Setting call state\n")); + + pChannel->pCallCont->SetCallState(pChannel->pCD, + SERVERCALLEX_ISHANDLED, + RPC_E_SERVER_DIED); + + } + else + { + // + // If there is no call data, then we aren't waiting in + // the channel. Terminate the conversation. + // + + intrDebugOut((DEB_ERROR,"CWP: No call state exists\n")); + pDdeObj->OnTerminate (pChannel, (HWND)wParam); +#ifdef _CHICAGO_ + //Note:POSTPPC + fPostMsg = FALSE; +#else + break; +#endif // + } + +#ifdef _CHICAGO_ + //Note:POSTPPC + if (fPostMsg) + { +#endif + // + // Repost the message and try again. + // + intrDebugOut((DEB_ITRACE,"CWP: Reposting WM_DDE_TERMINATE\n")); + PostMessage(hwnd,message,wParam,lParam); +#ifdef _CHICAGO_ + //Note:POSTPPC + } +#else + break; +#endif + + } + else + { + pDdeObj->OnTerminate (pChannel, (HWND)wParam); + } +#ifdef _CHICAGO_ + //Note:POSTPPC + if (pDdeObj->UnGuard()) + { + SetWindowLong(hwnd, 0, (LONG)0); + intrDebugOut((DEB_IWARN, "DDE ClientDocWndProc Release on pUnkOuter == 0 (this:%x, hwnd:%x\n",pDdeObj, hwnd )); + } +#endif // _CHICAGO_ + break; + + default: + return SSDefWindowProc (hwnd, message, wParam, lParam); + + } + + return 0L; +} diff --git a/private/ole32/com/remote/dde/client/ddeworkr.cxx b/private/ole32/com/remote/dde/client/ddeworkr.cxx new file mode 100644 index 000000000..9d117db18 --- /dev/null +++ b/private/ole32/com/remote/dde/client/ddeworkr.cxx @@ -0,0 +1,1331 @@ +/*++ + +copyright (c) 1992 Microsoft Corporation + +Module Name: + + ddeworkr.cpp + +Abstract: + + This module contains the code for the worker routines + +Author: + + Srini Koppolu (srinik) 22-June-1992 + Jason Fuller (jasonful) 24-July-1992 + +Revision History: + Kevin Ross (KevinRo) 10-May-1994 + Mostly added comments, and attempted to clean + it up. + +--*/ +#include "ddeproxy.h" + +ASSERTDATA + +/* + * WORKER ROUTINES + * + */ + + +INTERNAL_(BOOL) wPostMessageToServer(LPDDE_CHANNEL pChannel, + WORD wMsg, + LONG lParam, + BOOL fFreeOnError) +{ + int c=0; + intrDebugOut((DEB_ITRACE, + "wPostMessageToServer(pChannel=%x,wMsg=%x,lParam=%x,fFreeOnError=%x\n", + pChannel, + wMsg, + lParam, + fFreeOnError)); + if (NULL==pChannel) + { + AssertSz (0, "Channel missing"); + return FALSE; + } + pChannel->wMsg = wMsg; + pChannel->lParam = lParam; + pChannel->hres = NOERROR; + + while (TRUE && c<10 ) + { + if (!IsWindow (pChannel->hwndSvr)) + { + intrDebugOut((DEB_IWARN, + "wPostMessageToServer: invalid window %x\n", + pChannel->hwndSvr)); + goto errRet; + } + if (wTerminateIsComing (pChannel) + && wMsg != WM_DDE_ACK + && wMsg != WM_DDE_TERMINATE) + { + intrDebugOut((DEB_IWARN,"Server sent terminate, cannot post\n")); + goto errRet; + } + if (!PostMessage (pChannel->hwndSvr, wMsg, (WPARAM) pChannel->hwndCli, lParam)) + { + intrDebugOut((DEB_IWARN, + "wPostMessageToServer: PostMessageFailed, yielding\n")); + Yield (); + c++; + } + else + return TRUE; + } + AssertSz (0, "PostMessage failed"); + +errRet: + intrDebugOut((DEB_IWARN,"wPostMessageToServer returns FALSE\n")); + if (fFreeOnError) + { + DDEFREE(wMsg,lParam); + } + + return FALSE; +} + + +// call Ole1ClassFromCLSID then global add atom; returns NULL if error. +INTERNAL_(ATOM) wAtomFromCLSID(REFCLSID rclsid) +{ + WCHAR szClass[MAX_STR]; + ATOM aCls; + + if (Ole1ClassFromCLSID2(rclsid, szClass, sizeof(szClass)) == 0) + return NULL; + aCls = wGlobalAddAtom(szClass); + intrAssert(wIsValidAtom(aCls)); + return aCls; +} + +INTERNAL_(ATOM) wGlobalAddAtom(LPCOLESTR sz) +{ + if (sz==NULL || sz[0] == '\0') + { + return NULL; + } + + ATOM a = GlobalAddAtom(sz); + intrAssert(wIsValidAtom(a)); + return a; +} + +INTERNAL_(ATOM) wGlobalAddAtomA(LPCSTR sz) +{ + if (sz==NULL || sz[0] == '\0') + return NULL; + ATOM a = GlobalAddAtomA(sz); + intrAssert(wIsValidAtom(a)); + return a; +} + + +INTERNAL_(ATOM) wGetExeNameAtom (REFCLSID rclsid) +{ + LONG cb = MAX_STR; + WCHAR key[MAX_STR]; + ATOM a; + + if (Ole1ClassFromCLSID2(rclsid, key, sizeof(key)) == 0) + return NULL; + + lstrcatW (key, OLESTR("\\protocol\\StdFileEditing\\server")); + + if (RegQueryValue (HKEY_CLASSES_ROOT, key, key, &cb)) + { + Puts ("ERROR: wGetExeNameAtom failed\n"); + return NULL; + } + a = wGlobalAddAtom (key); + intrAssert(wIsValidAtom(a)); + return a; +} + +INTERNAL_(void) wFreeData (HANDLE hData, CLIPFORMAT cfFormat, + BOOL fFreeNonGdiHandle) +{ + intrDebugOut((DEB_ITRACE, + "wFreeData(hData=%x,cfFormat=%x,FreeNonGDIHandle=%x\n", + hData, + (USHORT)cfFormat, + fFreeNonGdiHandle)); + + AssertSz (hData != NULL, "Trying to free NULL handle"); + AssertSz (hData != (HANDLE) 0xcccccccc, "Trying to free handle from a deleted object"); + + switch (cfFormat) { + case CF_METAFILEPICT: + LPMETAFILEPICT lpMfp; + + if (lpMfp = (LPMETAFILEPICT) GlobalLock (hData)) + { + intrDebugOut((DEB_ITRACE, + "wFreeData freeing metafile %x\n", + lpMfp->hMF)); + + OleDdeDeleteMetaFile(lpMfp->hMF); + GlobalUnlock (hData); + } + GlobalFree (hData); + break; + + case CF_BITMAP: + case CF_PALETTE: + Verify(DeleteObject (hData)); + break; + + case CF_DIB: + GlobalFree (hData); + break; + + default: + if (fFreeNonGdiHandle) + GlobalFree (hData); + break; + } +} + + + +INTERNAL_(BOOL) wInitiate (LPDDE_CHANNEL pChannel, ATOM aLow, ATOM aHigh) +{ + intrDebugOut((DEB_ITRACE,"wInitiate(pChannel=%x,aLow=%x,aHigh=%x)\n", + pChannel, aLow, aHigh)); + + intrAssert(wIsValidAtom(aLow)); + if (aLow == (ATOM)0) + { + intrDebugOut((DEB_IERROR,"wInitiate Failed, aLow == 0\n")); + return FALSE; + } + + pChannel->iAwaitAck = AA_INITIATE; + + SSSendMessage ((HWND)-1, WM_DDE_INITIATE, (WPARAM) pChannel->hwndCli, + MAKE_DDE_LPARAM (WM_DDE_INITIATE, aLow, aHigh)); + + pChannel->iAwaitAck = NULL; + + intrDebugOut((DEB_ITRACE, + "wInitiate pChannel->hwndSrvr = %x\n", + pChannel->hwndSvr)); + + return (pChannel->hwndSvr != NULL); +} + + + +INTERNAL_(HRESULT) wScanItemOptions (ATOM aItem, int FAR* lpoptions) +{ + ATOM aModifier; + LPOLESTR lpbuf; + WCHAR buf[MAX_STR]; + + *lpoptions = ON_CHANGE; // default + + if (!aItem) { + // NULL item with no modifier means ON_CHANGE for NULL item + return NOERROR; + } + + intrAssert(wIsValidAtom(aItem)); + GlobalGetAtomName (aItem, buf, MAX_STR); + lpbuf = buf; + + while ( *lpbuf && *lpbuf != '/') + IncLpch (lpbuf); + + // no modifier same as /change + + if (*lpbuf == NULL) + return NOERROR; + + *lpbuf++ = NULL; // seperate out the item string + // We are using this in the caller. + + if (!(aModifier = GlobalFindAtom (lpbuf))) + { + Puts ("ERROR: wScanItemOptions found non-atom modifier\n"); + return ReportResult(0, RPC_E_DDE_SYNTAX_ITEM, 0, 0); + } + + intrAssert(wIsValidAtom(aModifier)); + + if (aModifier == aChange) + return NOERROR; + + // Is it a save? + if (aModifier == aSave){ + *lpoptions = ON_SAVE; + return NOERROR; + } + // Is it a Close? + if (aModifier == aClose){ + *lpoptions = ON_CLOSE; + return NOERROR; + } + + // unknown modifier + Puts ("ERROR: wScanItemOptions found bad modifier\n"); + return ReportResult(0, RPC_E_DDE_SYNTAX_ITEM, 0, 0); +} + + +INTERNAL_(BOOL) wClearWaitState (LPDDE_CHANNEL pChannel) +{ + Assert (pChannel); + // kill if any timer active. + if (pChannel->wTimer) { + KillTimer (pChannel->hwndCli, 1); + pChannel->wTimer = 0; + + if (pChannel->hDdePoke) { + GlobalFree (pChannel->hDdePoke); + pChannel->hDdePoke = NULL; + } + + if (pChannel->hopt) { + GlobalFree (pChannel->hopt); + pChannel->hopt = NULL; + } + + // + // If the channel is waiting on an Ack, and there is an + // lParam, then we may need to cleanup the data. + + if (pChannel->iAwaitAck && (pChannel->lParam)) { + if (pChannel->iAwaitAck == AA_EXECUTE) + { + // + // KevinRo: Found the following comment in the code. + // ; // BUGBUG32 - get hData from GET_WM_DDE_EXECUTE_HADATA ?? + // It appears, by looking at what the 16-bit code does, + // that the goal is to free the handle that was passed as + // part of the EXECUTE message. Judging by what the 16-bit + // code did, I have determined that this is correct. + // + // The macro used below wanted two parameters. The first was + // the WPARAM, the second the LPARAM. We don't have the WPARAM. + // However, it isn't actually used by the macro, so I have + // cheated and provided 0 as a default + // + GlobalFree(GET_WM_DDE_EXECUTE_HDATA(0,pChannel->lParam)); + +#ifdef KEVINRO_HERE_IS_THE_16_BIT_CODE + GlobalFree (HIWORD (pChannel->lParam)); +#endif + } + else + { + // + // All of the other DDE messages pass an Atom in the high word. + // Therefore, we should delete the atom. + // + // + ATOM aTmp; + + aTmp = MGetDDElParamHi(pChannel->wMsg,pChannel->lParam); + + intrAssert(wIsValidAtom(aTmp)); + if (aTmp) + { + GlobalDeleteAtom (aTmp); + } + } + DDEFREE(pChannel->wMsg,pChannel->lParam); + + // we want to wipe out the lParam + pChannel->lParam = 0x0; + } + + return TRUE; + } + + return FALSE; +} + + + +// wNewHandle (LPSTR, DWORD) +// +// Copy cb bytes from lpstr into a new memory block and return a handle to it. +// If lpstr is an ASCIIZ string, cb must include 1 for the null terminator. +// + +INTERNAL_(HANDLE) wNewHandle (LPSTR lpstr, DWORD cb) +{ + + HANDLE hdata = NULL; + LPSTR lpdata = NULL; + + hdata = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, cb); + if (hdata == NULL || (lpdata = (LPSTR) GlobalLock (hdata)) == NULL) + goto errRtn; + + memcpy (lpdata, lpstr, cb); + GlobalUnlock (hdata); + return hdata; + +errRtn: + Puts ("ERROR: wNewHandle\n"); + Assert (0); + if (lpdata) + GlobalUnlock (hdata); + + if (hdata) + GlobalFree (hdata); + return NULL; +} + + + +// wDupData +// +// Copy data from handle h into a new handle which is returned as *ph. +// + +INTERNAL wDupData (LPHANDLE ph, HANDLE h, CLIPFORMAT cf) +{ + Assert (ph); + RetZ (wIsValidHandle(h, cf)); + *ph = OleDuplicateData (h, cf, GMEM_DDESHARE | GMEM_MOVEABLE); + RetZ (wIsValidHandle (*ph, cf)); + return NOERROR; +} + + +// wTransferHandle +// +// +INTERNAL wTransferHandle + (LPHANDLE phDst, + LPHANDLE phSrc, + CLIPFORMAT cf) +{ + RetErr (wDupData (phDst, *phSrc, cf)); + wFreeData (*phSrc, cf, TRUE); + *phSrc = (HANDLE)0; + return NOERROR; +} + + +// wHandleCopy +// +// copy data from hSrc to hDst. +// Both handles must already have memory allocated to them. +// + +INTERNAL wHandleCopy (HANDLE hDst, HANDLE hSrc) +{ + LPSTR lpDst, lpSrc; + DWORD dwSrc; + + if (NULL==hDst || NULL==hSrc) + return ResultFromScode (E_INVALIDARG); + if (GlobalSize(hDst) < (dwSrc=GlobalSize(hSrc))) + { + HANDLE hDstNew = GlobalReAlloc (hDst, dwSrc, GMEM_DDESHARE | GMEM_MOVEABLE); + if (hDstNew != hDst) + return ResultFromScode (E_OUTOFMEMORY); + } + if (!(lpDst = (LPSTR) GlobalLock(hDst))) + { + intrAssert(!"ERROR: wHandleCopy hDst"); + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + } + if (!(lpSrc = (LPSTR) GlobalLock(hSrc))) + { + GlobalUnlock(hDst); + intrAssert (!"ERROR: wHandleCopy hSrc"); + return ReportResult(0, E_OUTOFMEMORY, 0, 0); + } + memcpy (lpDst, lpSrc, dwSrc); + GlobalUnlock(hDst); + GlobalUnlock(hSrc); + return NOERROR; +} + + +// ExtendAtom: Create a new atom, which is the old one plus extension + +INTERNAL_(ATOM) wExtendAtom (ATOM aItem, int iAdvOn) +{ + WCHAR buffer[MAX_STR+1]; + LPOLESTR lpext; + + buffer[0] = 0; + // aItem==NULL for embedded objects. + // If so, there is no item name before the slash. + if (aItem) + GlobalGetAtomName (aItem, buffer, MAX_STR); + + switch (iAdvOn) { + case ON_CHANGE: + lpext = OLESTR(""); + break; + + case ON_SAVE: + lpext = OLESTR("/Save"); + break; + + case ON_CLOSE: + lpext = OLESTR("/Close"); + break; + + default: + AssertSz (FALSE, "Unknown Advise option"); + break; + + } + + lstrcatW (buffer, lpext); + if (buffer[0]) + return wGlobalAddAtom (buffer); + else + return NULL; + // not an error. For embedded object on-change, aItem==NULL +} + + + + +INTERNAL_(ATOM) wDupAtom (ATOM a) +{ + WCHAR sz[MAX_STR]; + + if (!a) + return NULL; + + Assert (wIsValidAtom (a)); + GlobalGetAtomName (a, sz, MAX_STR); + return wGlobalAddAtom (sz); +} + + + +//+--------------------------------------------------------------------------- +// +// Function: wAtomLen +// +// Synopsis: Return the length, in characters, of the atom name. +// The length includes the NULL. This function returns the +// length of the UNICODE version of the atom. +// +// Effects: +// +// Arguments: [atom] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-12-94 kevinro Created +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL_(int) wAtomLen (ATOM atom) +{ + WCHAR buf[MAX_STR]; + + if (!atom) + return NULL; + + return (GlobalGetAtomName (atom, buf, MAX_STR)); +} + +//+--------------------------------------------------------------------------- +// +// Function: wAtomLenA +// +// Synopsis: Return the length, in characters, of the atom name. +// The length includes the NULL This function returns the +// length of the ANSI version of the atom, +// +// Effects: +// +// Arguments: [atom] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-12-94 kevinro Created +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL_(int) wAtomLenA (ATOM atom) +{ + char buf[MAX_STR]; + + if (!atom) + return NULL; + + return (GlobalGetAtomNameA (atom, (LPSTR)buf, MAX_STR)); +} + + + +// NOTE: returns address of static buffer. Use return value immediately. +// + + +//+--------------------------------------------------------------------------- +// +// Function: wAtomName +// +// Synopsis: Returns a STATIC BUFFER that holds the string name of the +// atom. +// +// Effects: +// +// Arguments: [atom] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-12-94 kevinro Commented +// +// Notes: +// +// WARNING: This uses a static buffer, so don't depend on the pointer for +// very long. +// +//---------------------------------------------------------------------------- +INTERNAL_(LPOLESTR) wAtomName (ATOM atom) +{ + static WCHAR buf[MAX_STR]; + + if (!atom) + return NULL; + + if (0==GlobalGetAtomName (atom, buf, MAX_STR)) + return NULL; + + return buf; +} + +//+--------------------------------------------------------------------------- +// +// Function: wAtomName +// +// Synopsis: Returns a STATIC BUFFER that holds the string name of the +// atom. +// +// Effects: +// +// Arguments: [atom] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-12-94 kevinro Commented +// +// Notes: +// +// WARNING: This uses a static buffer, so don't depend on the pointer for +// very long. +// +//---------------------------------------------------------------------------- +INTERNAL_(LPSTR) wAtomNameA (ATOM atom) +{ + static char buf[MAX_STR]; + + if (!atom) + return NULL; + + if (0==GlobalGetAtomNameA (atom, (LPSTR)buf, MAX_STR)) + return NULL; + + return buf; +} + + + + +//+--------------------------------------------------------------------------- +// +// Function: wHandleFromDdeData +// +// Synopsis: Return a handle from the DDEDATA passed in. +// +// Effects: This function will return the correct data from the +// DDEDATA that is referenced by the handle passed in. +// +// DDEDATA is a small structure that is used in DDE to +// specify the data type of the buffer, its release +// semantics, and the actual data. +// +// In the case of a known format, the handle to the +// data is extracted from the DDEDATA structure, and +// the hDdeData is released. +// +// If its a Native format, the data is either moved +// within the memory block allocated, or is copied to +// another block, depending on the fRelease flag in +// the hDdeData. +// +// Arguments: [hDdeData] -- Handle to DDEDATA +// +// Requires: +// +// Returns: A handle to the data. hDdeData will be invalidated +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-13-94 kevinro Commented +// +// Notes: +// +// hDdeData is invalid after calling this function +// +//---------------------------------------------------------------------------- + + +INTERNAL_(HANDLE) wHandleFromDdeData + (HANDLE hDdeData) +{ + intrDebugOut((DEB_ITRACE,"wHandleFromDdeData(%x)\n",hDdeData)); + BOOL fRelease; + HGLOBAL h = NULL; // return value + + DDEDATA FAR* lpDdeData = (DDEDATA FAR *) GlobalLock (hDdeData); + + // + // If the handle is invalid, then the lpDdeData will be NULL + // + if (!lpDdeData) + { + intrDebugOut((DEB_ITRACE, + "\twHandleFromDdeData(%x) invalid handle\n", + hDdeData)); + return NULL; + } + + + // + // The header section of a DDEDATA consists of 2 shorts. + // That makes it 4 bytes. Due to the new packing values, + // it turns out that doing a sizeof(DDEDATA) won't work, + // because the size gets rounded up to a multple of 2 + // + // We will just hard code the 4 here, since it cannot change + // for all time anyway. + // + #define cbHeader 4 + Assert (cbHeader==4); + + // + // If the cfFormat is BITMAP or METAFILEPICT, then the + // handle will be retrieved from the first DWORD of the + // buffer + // + if (lpDdeData->cfFormat == CF_BITMAP || + lpDdeData->cfFormat == CF_METAFILEPICT) + { + // + // The alignment here should be fine, since the Value + // field is DWORD aligned. So, we trust this cast + // + h = *(LPHANDLE)lpDdeData->Value; + Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE); + fRelease = lpDdeData->fRelease; + GlobalUnlock (hDdeData); + if (fRelease) + { + GlobalFree (hDdeData); + } + + return h; + } + else if (lpDdeData->cfFormat == CF_DIB) + { + // + // The alignment here should be fine, since the Value + // field is DWORD aligned. + // + // This changes the memory from fixed to moveable. + // + h = GlobalReAlloc (*(LPHANDLE)lpDdeData->Value, 0L, + GMEM_MODIFY|GMEM_MOVEABLE); + Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE); + fRelease = lpDdeData->fRelease; + GlobalUnlock (hDdeData); + if (fRelease) + GlobalFree (hDdeData); + return h; + } + + + // Native and other data case + // dwSize = size of Value array, ie, size of the data itself + const DWORD dwSize = GlobalSize (hDdeData) - cbHeader; + + if (lpDdeData->fRelease) + { + // Move the Value data up over the DDE_DATA header flags. + memcpy ((LPSTR)lpDdeData, ((LPSTR)lpDdeData)+cbHeader, dwSize); + GlobalUnlock (hDdeData); + h = GlobalReAlloc (hDdeData, dwSize, GMEM_MOVEABLE); + Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE); + return h; + } + else + { + // Duplicate the data because the server will free the original. + h = wNewHandle (((LPSTR)lpDdeData)+cbHeader, dwSize); + Assert (GlobalFlags(h) != GMEM_INVALID_HANDLE); + GlobalUnlock (hDdeData); + return h; + } +} + + + + + +//+--------------------------------------------------------------------------- +// +// Method: CDdeObject::CanCallBack +// +// Synopsis: This routine apparently was supposed to determine if a +// call back could be made. However, the PeekMessage stuff +// was commented out. +// +// So, it returns TRUE if 0 or 1, FALSE but increments lpCount +// if 2, returns true but decrements lpCount if > 3. Why? +// Dunno. Need to ask JasonFul +// +// Effects: +// +// Arguments: [lpCount] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 5-16-94 kevinro Commented, confused, and disgusted +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL_(BOOL) CDdeObject::CanCallBack (LPINT lpCount) +{ + switch (*lpCount) { + case 0: + case 1: + return TRUE; + + case 2: + { +// MSG msg; + if (0) + //!PeekMessage (&msg, m_pDocChannel->hwndCli,0,0, PM_NOREMOVE) || + // msg.message != WM_DDE_DATA) + { + Puts ("Server only sent one format (hopefully presentation)\n"); + return TRUE; + } + else + { + ++(*lpCount); + return FALSE; + } + } + + case 3: + --(*lpCount); + return TRUE; + + default: + AssertSz (FALSE, "012345" + *lpCount); + return FALSE; + } +} + + +INTERNAL_(BOOL) wIsOldServer (ATOM aClass) +{ + LONG cb = MAX_STR; + WCHAR key[MAX_STR]; + int len; + + if (aClass==(ATOM)0) + return FALSE; + + if (!GlobalGetAtomName (aClass, key, sizeof(key))) + return TRUE; + + lstrcatW (key, OLESTR("\\protocol\\StdFileEditing\\verb\\")); + len = lstrlenW (key); + key [len++] = (char) ('0'); + key [len++] = 0; + + if (RegQueryValue (HKEY_CLASSES_ROOT, key, key, &cb)) + return TRUE; // no verbs registered + + return FALSE; +} + + + + +INTERNAL_(void) wFreePokeData + (LPDDE_CHANNEL pChannel, + BOOL fMSDrawBug) +{ + DDEPOKE FAR * lpdde; + + if (!pChannel ) + return; + + if (!pChannel->hDdePoke) + return; + + if (lpdde = (DDEPOKE FAR *) GlobalLock (pChannel->hDdePoke)) { + + // The old version of MSDraw expects the _contents_ of METAFILEPICT + // structure, rather than the handle to it, to be part of DDEPOKE. + + if (fMSDrawBug && lpdde->cfFormat==CF_METAFILEPICT) { + intrDebugOut((DEB_ITRACE, + "wFreePokeData is accomodating MSDraw bug\n")); + // + // This meta file was created in 32-bits, and was not passed + // into us by DDE. Therefore, this metafile should not need to + // call WOW to be free'd. + // + DeleteMetaFile (((LPMETAFILEPICT) ((LPVOID) &lpdde->Value))->hMF); + } + // If there is a normal metafile handle in the Value field, + // it will be freed (if necessary) by the ReleaseStgMedium() + // in DO::SetData + GlobalUnlock (pChannel->hDdePoke); + } + GlobalFree (pChannel->hDdePoke); + pChannel->hDdePoke = NULL; +} + + + + +INTERNAL_(HANDLE) wPreparePokeBlock + (HANDLE hData, CLIPFORMAT cfFormat, ATOM aClass, BOOL bOldSvr) +{ + HANDLE hDdePoke; + LPSTR lpBuf; + + if (!hData) + return NULL; + + // The old version of MSDraw expects the contents of METAFILEPICT + // structure to be part of DDEPOKE, rather than the handle to it. + if ((cfFormat==CF_METAFILEPICT && !(aClass==aMSDraw && bOldSvr)) + || (cfFormat == CF_DIB) + || (cfFormat == CF_BITMAP)) { + + Verify (lpBuf = wAllocDdePokeBlock (4, cfFormat, &hDdePoke)); + *((HANDLE FAR*)lpBuf) = hData; + + } + else { + // Handle the non-metafile case and the MS-Draw bug + DWORD dwSize = GlobalSize (hData); + + if ((aClass == aMSDraw) && bOldSvr) + { + intrDebugOut((DEB_ITRACE, + "wPreparePokeBlock is accomodating MSDraw bug\n")); + } + + if (lpBuf = wAllocDdePokeBlock (dwSize, cfFormat, &hDdePoke)) { + memcpy (lpBuf, GlobalLock(hData), dwSize); + GlobalUnlock (hData); + } + } + GlobalUnlock (hDdePoke); + return hDdePoke; +} + + +// wAllocDdePokeBlock +// The caller must unlock *phDdePoke when it is done using the return value +// of this function but before a DDe message is sent using *phDdePoke. +// + +INTERNAL_(LPSTR) wAllocDdePokeBlock + (DWORD dwSize, CLIPFORMAT cfFormat, LPHANDLE phDdePoke) +{ + HANDLE hdde = NULL; + DDEPOKE FAR * lpdde = NULL; + + if (!(hdde = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, + (dwSize + sizeof(DDEPOKE) - sizeof(BYTE) )))) + return NULL; + + if (!(lpdde = (DDEPOKE FAR*)GlobalLock (hdde))) { + GlobalFree (hdde); + return NULL; + } + // hdde will be UnLock'ed in wPreparePokeBlock and Free'd in wFreePokeData + lpdde->fRelease = FALSE; + lpdde->cfFormat = cfFormat; + *phDdePoke = hdde; + return (LPSTR) &(lpdde->Value); +} + + +#ifdef OLD +INTERNAL_(ULONG) wPixelsToHiMetric + (ULONG cPixels, + ULONG cPixelsPerInch) +{ + return cPixels * HIMETRIC_PER_INCH / cPixelsPerInch; +} +#endif + +// Can ask for icon based on either CLSID or filename +// + +INTERNAL GetDefaultIcon (REFCLSID clsidIn, LPCOLESTR szFile, HANDLE FAR* phmfp) +{ + if (!(*phmfp = OleGetIconOfClass(clsidIn, NULL, TRUE))) + return ResultFromScode(E_OUTOFMEMORY); + + return NOERROR; +} + +#ifdef OLD + VDATEPTROUT (phmfp, HICON); + VDATEPTRIN (szFile, char); + WCHAR szExe[MAX_STR]; + HICON hicon; + HDC hdc; + METAFILEPICT FAR* pmfp=NULL; + HRESULT hresult; + static int cxIcon = 0; + static int cyIcon = 0; + static int cxIconHiMetric = 0; + static int cyIconHiMetric = 0; + + *phmfp = NULL; + CLSID clsid; + if (clsidIn != CLSID_NULL) + { + clsid = clsidIn; + } + else + { + RetErr (GetClassFile (szFile, &clsid)); + } + ATOM aExe = wGetExeNameAtom (clsid); + if (0==GlobalGetAtomName (aExe, szExe, MAX_STR)) + { + Assert (0); + return ReportResult(0, E_UNEXPECTED, 0, 0); + } + hicon = ExtractIcon (hmodOLE2, szExe, 0/*first icon*/); + if (((HICON) 1)==hicon || NULL==hicon) + { + // ExtractIcon failed, so we can't support DVASPECT_ICON + return ResultFromScode (DV_E_DVASPECT); + } + *phmfp = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(METAFILEPICT)); + ErrZS (*phmfp, E_OUTOFMEMORY); + pmfp = (METAFILEPICT FAR*) GlobalLock (*phmfp); + ErrZS (pmfp, E_OUTOFMEMORY); + if (0==cxIcon) + { + // In units of pixels + Verify (cxIcon = GetSystemMetrics (SM_CXICON)); + Verify (cyIcon = GetSystemMetrics (SM_CYICON)); + // In units of .01 millimeter + cxIconHiMetric = (int)(long)wPixelsToHiMetric (cxIcon, giPpliX) ; + cyIconHiMetric = (int)(long)wPixelsToHiMetric (cyIcon, giPpliY) ; + } + pmfp->mm = MM_ANISOTROPIC; + pmfp->xExt = cxIconHiMetric; + pmfp->yExt = cyIconHiMetric; + hdc = CreateMetaFile (NULL); + SetWindowOrg (hdc, 0, 0); + SetWindowExt (hdc, cxIcon, cyIcon); + DrawIcon (hdc, 0, 0, hicon); + pmfp->hMF = CloseMetaFile (hdc); + ErrZ (pmfp->hMF); + Assert (wIsValidHandle (pmfp->hMF, NULL)); + GlobalUnlock (*phmfp); + Assert (wIsValidHandle (*phmfp, CF_METAFILEPICT)); + return NOERROR; + + errRtn: + if (pmfp) + GlobalUnlock (*phmfp); + if (*phmfp) + GlobalFree (*phmfp); + return hresult; +} +#endif + +#define DWTIMEOUT 1000L + +INTERNAL wTimedGetMessage + (LPMSG pmsg, + HWND hwnd, + WORD wFirst, + WORD wLast) +{ + DWORD dwStartTickCount = GetTickCount(); + while (!SSPeekMessage (pmsg, hwnd, wFirst, wLast, PM_REMOVE)) + { + if (GetTickCount() - dwStartTickCount > DWTIMEOUT) + { + if (!IsWindow (hwnd)) + return ResultFromScode (RPC_E_CONNECTION_LOST); + else + return ResultFromScode (RPC_E_SERVER_DIED); + } + } + return NOERROR; +} + + +INTERNAL wNormalize + (LPFORMATETC pformatetcIn, + LPFORMATETC pformatetcOut) +{ + if (pformatetcIn->cfFormat == 0 + && pformatetcIn->ptd == NULL // Is WildCard + && pformatetcIn->dwAspect == -1L + && pformatetcIn->lindex == -1L + && pformatetcIn->tymed == -1L) + { + pformatetcOut->cfFormat = CF_METAFILEPICT; + pformatetcOut->ptd = NULL; + pformatetcOut->dwAspect = DVASPECT_CONTENT; + pformatetcOut->lindex = DEF_LINDEX; + pformatetcOut->tymed = TYMED_MFPICT; + } + else + { + memcpy (pformatetcOut, pformatetcIn, sizeof(FORMATETC)); + } + return NOERROR; +} + + + +INTERNAL wVerifyFormatEtc + (LPFORMATETC pformatetc) +{ + intrDebugOut((DEB_ITRACE, + "wVerifyFormatEtc(pformatetc=%x)\n", + pformatetc)); + + VDATEPTRIN (pformatetc, FORMATETC); + if (!HasValidLINDEX(pformatetc)) + { + intrDebugOut((DEB_IERROR, "\t!HasValidLINDEX(pformatetc)\n")); + return(DV_E_LINDEX); + } + + if (0==(pformatetc->tymed & (TYMED_HGLOBAL | TYMED_MFPICT | TYMED_GDI))) + { + intrDebugOut((DEB_IERROR, + "\t0==(pformatetc->tymed & (TYMED_HGLOBAL | TYMED_MFPICT | TYMED_GDI))\n")); + return ResultFromScode (DV_E_TYMED); + } + if (0==(UtFormatToTymed (pformatetc->cfFormat) & pformatetc->tymed)) + { + intrDebugOut((DEB_IERROR, + "\t0==(UtFormatToTymed (pformatetc->cfFormat) & pformatetc->tymed)\n")); + return ResultFromScode (DV_E_TYMED); + } + if (0==(pformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON))) + { + intrDebugOut((DEB_IERROR, + "\t0==(pformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON))\n")); + + return ResultFromScode (DV_E_DVASPECT); + } + if (pformatetc->dwAspect & DVASPECT_ICON) + { + if (CF_METAFILEPICT != pformatetc->cfFormat) + { + intrDebugOut((DEB_IERROR, + "\tCF_METAFILEPICT != pformatetc->cfFormat\n")); + return ResultFromScode (DV_E_CLIPFORMAT); + } + + if (0==(pformatetc->tymed & TYMED_MFPICT)) + { + intrDebugOut((DEB_IERROR, + "\t0==(pformatetc->tymed & TYMED_MFPICT)\n")); + return ResultFromScode (DV_E_TYMED); + } + } + if (pformatetc->ptd) + { + if (IsBadReadPtr (pformatetc->ptd, sizeof (DWORD)) + || IsBadReadPtr (pformatetc->ptd, (size_t)pformatetc->ptd->tdSize)) + { + intrDebugOut((DEB_IERROR,"\tDV_E_DVTARGETDEVICE\n")); + + return ResultFromScode (DV_E_DVTARGETDEVICE); + } + } + return NOERROR; +} + + + +INTERNAL wClassesMatch + (REFCLSID clsidIn, + LPOLESTR szFile) +{ + CLSID clsid; + if (NOERROR==GetClassFile (szFile, &clsid)) + { + return clsid==clsidIn ? NOERROR : ResultFromScode (S_FALSE); + } + else + { + // If we can't determine the class of the file (because it's + // not a real file) then OK. Bug 3937. + return NOERROR; + } +} + + + +#ifdef KEVINRO_DUPLICATECODE + +This routine also appears in ole1.lib in the OLE232\OLE1 directory + +INTERNAL wWriteFmtUserType + (LPSTORAGE pstg, + REFCLSID clsid) +{ + HRESULT hresult = NOERROR; + LPOLESTR szProgID = NULL; + LPOLESTR szUserType = NULL; + + ErrRtnH (ProgIDFromCLSID (clsid, &szProgID)); + ErrRtnH (OleRegGetUserType (clsid, USERCLASSTYPE_FULL, &szUserType)); + ErrRtnH (WriteFmtUserTypeStg (pstg, RegisterClipboardFormat (szProgID), + szUserType)); + errRtn: + delete szProgID; + delete szUserType; + return hresult; +} +#endif + +#if DBG == 1 + +INTERNAL_(BOOL) wIsValidHandle + (HANDLE h, + CLIPFORMAT cf) // cf==NULL means normal memory +{ + LPVOID p; + if (CF_BITMAP == cf) + { + BITMAP bm; + return (0 != GetObject (h, sizeof(BITMAP), (LPVOID) &bm)); + } + if (CF_PALETTE == cf) + { + WORD w; + return (0 != GetObject (h, sizeof(w), (LPVOID) &w)); + } + if (!(p=GlobalLock(h))) + { + Puts ("Invalid handle"); + Puth (h); + Putn(); + return FALSE; + } + if (IsBadReadPtr (p, (WPARAM) min (UINT_MAX, GlobalSize(h)))) + { + GlobalUnlock (h); + return FALSE; + } + GlobalUnlock (h); + return TRUE; +} +INTERNAL_(BOOL) wIsValidAtom (ATOM a) +{ + WCHAR sz[MAX_STR]; + if (a==0) + return TRUE; + if (a < 0xC000) + return FALSE; + if (0==GlobalGetAtomName (a, sz, MAX_STR)) + return FALSE; + if ('\0'==sz[0]) + return FALSE; + return TRUE; +} + + +// A "gentle" assert used in reterr.h +// + + +INTERNAL_(void) wWarn + (LPSTR sz, + LPSTR szFile, + int iLine) +{ + intrDebugOut((DEB_WARN, + "Warning: %s:%u %s\n", + szFile,iLine,sz)); +} + +#endif // DBG + + diff --git a/private/ole32/com/remote/dde/client/dirs b/private/ole32/com/remote/dde/client/dirs new file mode 100644 index 000000000..94c45c76c --- /dev/null +++ b/private/ole32/com/remote/dde/client/dirs @@ -0,0 +1,37 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + Donna Liu (DonnaLi) 19-Dec-1993 + +!ENDIF + +# +# This is a list of all subdirectories that build required components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +DIRS= + +# +# This is a list of all subdirectories that build optional components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +OPTIONAL_DIRS= \ + + diff --git a/private/ole32/com/remote/dde/client/modallp.cxx b/private/ole32/com/remote/dde/client/modallp.cxx new file mode 100644 index 000000000..d6d79a806 --- /dev/null +++ b/private/ole32/com/remote/dde/client/modallp.cxx @@ -0,0 +1,201 @@ +/* + +copyright (c) 1992 Microsoft Corporation + +Module Name: + + modallp.cpp + +Abstract: + + This module contains the code to wait for reply on a remote call. + +Author: + Johann Posch (johannp) 01-March-1993 modified to use CoRunModalLoop + +*/ + +#include "ddeproxy.h" + + +#define DebWarn(x) +#define DebError(x) +#define DebAction(x) +#if DBG==1 +static unsigned iCounter=0; +#endif +// +// Called after posting a message (call) to a server +// +#pragma SEG(CDdeObject_WaitForReply) + + + +#ifdef _CHICAGO_ + //POSTPPC +INTERNAL_(BOOL) CDdeObject::CanMakeOutCall(LPDDE_CHANNEL pChannel) +{ + intrDebugOut((DEB_ITRACE,"::CanMakeOutCall (%x) returns %d \n",pChannel, + (pChannel->pCD && (pChannel->pCD->id != CALLDATAID_UNUSED)) ? FALSE : TRUE)); + return (pChannel->pCD && (pChannel->pCD->id != CALLDATAID_UNUSED)) ? FALSE : TRUE; +} +#endif + + +INTERNAL CDdeObject::WaitForReply + (LPDDE_CHANNEL pChannel, int iAwaitAck, BOOL fStdCloseDoc, BOOL fDetectTerminate) +{ +#ifdef _MAC +#else + CALLDATA CD; + IID iid = CLSID_NULL; + DDECALLDATA DdeCD; + MSG PrevMsg; + BOOL fPending; + HRESULT hres; + + + +#if DBG == 1 + unsigned iAutoCounter; + intrDebugOut((INTR_DDE, + "DdeObject::WaitForReply(%x) Call#(%x) awaiting %x\n", + this, + iAutoCounter=++iCounter, + iAwaitAck)); +#endif + + if (pChannel->pCD && (pChannel->pCD->id != CALLDATAID_UNUSED)) { + // this callinfo is in use + intrDebugOut((DEB_ERROR, + "DdeObject::WaitForReply(%x)ERROR: DDE: callinfo is used\n", this)); + return ResultFromScode (E_UNEXPECTED); + } + + + // Note: this is to detect a premature DDE_TERMINATE + // here we care about if we receive a WM_DDE_TERMINATE instead ACK + // the next call to WaitForReply will detect this state and return + // since the terminate was send prematurly (Excel is one of this sucker) + // + if ( fDetectTerminate ) { + Assert(m_wTerminate == Terminate_None); + // if this flag is on terminate should not execute the default code + // in the window procedure + m_wTerminate = Terminate_Detect; + } + + pChannel->iAwaitAck = iAwaitAck; + pChannel->dwStartTickCount = GetTickCount(); + + // start looking only for dde messages first + pChannel->msgFirst = WM_DDE_FIRST; + pChannel->msgLast = WM_DDE_LAST; + pChannel->msghwnd = pChannel->hwndCli; + PrevMsg.message = 0; + PrevMsg.time = 0; + + pChannel->fRejected = FALSE; + // see if there is a thread window for lrpc communication + // if so we have to dispatch this messages as well + fPending = FALSE; + + intrDebugOut((DEB_ITRACE, + "+++ Waiting for reply: server: %x, client %x Call#(%x) +++\n", + pChannel->hwndSvr, + pChannel->hwndCli, + iAutoCounter)); + + // prepare and enter the modal loop + DdeCD.hwndSvr = pChannel->hwndSvr; + DdeCD.hwndCli = pChannel->hwndCli; + DdeCD.wMsg = pChannel->wMsg; + DdeCD.wParam = (WPARAM) pChannel->hwndCli, + DdeCD.lParam = pChannel->lParam; + DdeCD.fInitialSend = TRUE; + + CD.id = CALLDATAID_UNUSED; + CD.lid = iid; + CD.TIDCallee = 0; + CD.pRpcMsg = (LPVOID) &DdeCD; + CD.CallCat = CALLCAT_SYNCHRONOUS; + CD.Event = 0; + + pChannel->pCD = &CD; + + // + // Setting this value tells DeleteChannel NOT to delete itself. + // If the value changes to Channel_DeleteNow while we are in + // the modal loop, this routine will delete the channel + // + pChannel->wChannelDeleted = Channel_InModalloop; + + // + // hres will be the return code from the message + // handlers, or from the channel itself. The return + // code comes from calls to SetCallState. Most of the + // time, it will be things like RPC_E_DDE_NACK. However, + // it may also return OUTOFMEMORY, or other ModalLoop + // problems. + // + + hres = pChannel->pCallCont->CallRunModalLoop(&CD); + + if (hres != NOERROR) + { + intrDebugOut((DEB_ITRACE, + "**************** CallRunModalLoop returns %x ***\n", + hres)); + } + + if (m_wTerminate == Terminate_Received) { + intrAssert(fDetectTerminate); + // + // There really wasn't an error, its just that the server decided + // to terminate. If we return an error here, the app may decide + // that things have gone awry. Excel, for example, will decide + // that the object could not be activated, even though it has + // already updated its cache information. + // + hres = NOERROR; + intrDebugOut((DEB_ITRACE, + "::WaitForReply setting hres=%x\n", + hres)); + intrDebugOut((DEB_ITRACE, + "::WaitForReply posting TERMINATE to self hwnd=%x\n", + DdeCD.hwndCli)); + // set state to normal and repost message + Verify (PostMessage (DdeCD.hwndCli, WM_DDE_TERMINATE, + (WPARAM)DdeCD.hwndSvr, (LPARAM)0)); + } + m_wTerminate = Terminate_None; + + // + // If the channel is to be deleted, then do it now. This flag would + // have been set in the DeleteChannel routine. + // + if (pChannel->wChannelDeleted == Channel_DeleteNow) + { + intrDebugOut((INTR_DDE, + "::WaitForReply(%x) Channel_DeleteNow pChannel(%x)\n", + pChannel)); + + pChannel->ReleaseReference(); + + // Excel will send TERMINATE before sending an ACK to StdCloseDoc + return ResultFromScode (fStdCloseDoc ? S_OK : RPC_E_DDE_POST); + } + pChannel->wChannelDeleted = 0; + + pChannel->iAwaitAck = 0; + pChannel->pCD = NULL; + + intrDebugOut((DEB_ITRACE, + "### Waiting for reply done: server: %x, client %x hres(%x)###\n", + pChannel->hwndSvr, + pChannel->hwndCli, + hres)); + + return hres; +#endif _MAC +} diff --git a/private/ole32/com/remote/dde/client/packmnkr.cxx b/private/ole32/com/remote/dde/client/packmnkr.cxx new file mode 100644 index 000000000..b4642bb8c --- /dev/null +++ b/private/ole32/com/remote/dde/client/packmnkr.cxx @@ -0,0 +1,273 @@ +/* + PackMnkr.cpp + PackageMoniker + + This module implements the CPackagerMoniker class and + CreatePackagerMoniker() + + Author: + Jason Fuller jasonful Nov-2-1992 + + Copyright (c) 1992 Microsoft Corporation +*/ + +#include <ole2int.h> +#include "packmnkr.h" +#include "..\server\ddedebug.h" +#include <ole1cls.h> + +ASSERTDATA + + +STDMETHODIMP CPackagerMoniker::QueryInterface + (REFIID riid, LPVOID * ppvObj) +{ + M_PROLOG(this); + VDATEIID (riid); + VDATEPTROUT (ppvObj, LPVOID); + + if ((riid == IID_IMoniker) || (riid == IID_IUnknown) || + (riid == IID_IPersistStream) || (riid == IID_IInternalMoniker)) + { + *ppvObj = this; + ++m_refs; + return NOERROR; + } + AssertSz (0, "Could not find interface\r\n"); + *ppvObj = NULL; + return ReportResult(0, E_NOINTERFACE, 0, 0); +} + + + +STDMETHODIMP_(ULONG) CPackagerMoniker::AddRef() +{ + M_PROLOG(this); + return ++m_refs; +} + + + +STDMETHODIMP_(ULONG) CPackagerMoniker::Release() +{ + M_PROLOG(this); + Assert (m_refs > 0); + if (0 == --m_refs) + { + m_pmk->Release(); + delete m_szFile; + delete this; + return 0; + } + return m_refs; +} + + + +STDMETHODIMP CPackagerMoniker::GetClassID (THIS_ LPCLSID lpClassID) +{ + M_PROLOG(this); + *lpClassID = CLSID_PackagerMoniker; + return NOERROR; +} + + + +STDMETHODIMP CPackagerMoniker::BindToObject (THIS_ LPBC pbc, LPMONIKER pmkToLeft, + REFIID riidResult, LPVOID * ppvResult) +{ + M_PROLOG(this); + WIN32_FIND_DATA fd; + HRESULT hr; + + // The following code ensures that the file exists before we try to bind it. + HANDLE hFind = FindFirstFile(m_szFile, &fd); + if (hFind != INVALID_HANDLE_VALUE) + { + hr = DdeBindToObject (m_szFile, CLSID_Package, m_fLink, riidResult, ppvResult); + FindClose(hFind); + } + else + hr = MK_E_CANTOPENFILE; + return hr; +} + +STDMETHODIMP CPackagerMoniker::IsRunning (THIS_ LPBC pbc, LPMONIKER pmkToLeft, + LPMONIKER pmkNewlyRunning) +{ + M_PROLOG(this); + VDATEIFACE (pbc); + + if (pmkToLeft) + VDATEIFACE (pmkToLeft); + if (pmkNewlyRunning) + VDATEIFACE (pmkNewlyRunning); + + // There is no way to tell if a packaged object is running + return ReportResult (0, S_FALSE, 0, 0); +} + + +STDAPI CreatePackagerMoniker(LPOLESTR szFile, LPMONIKER * ppmk, BOOL fLink ) +{ + return CPackagerMoniker::Create (szFile, ppmk, fLink); +} + +HRESULT CPackagerMoniker::Create(LPOLESTR szFile,LPMONIKER * ppmk, BOOL fLink ) +{ + HRESULT hresult; + VDATEPTROUT (ppmk, LPMONIKER); + *ppmk = NULL; + + CPackagerMoniker * pmkPack = new CPackagerMoniker; + if (NULL==pmkPack) + return ReportResult (0, E_OUTOFMEMORY, 0, 0); + ErrRtnH (CreateFileMoniker (szFile, &(pmkPack->m_pmk))); + + pmkPack->m_szFile = new WCHAR [lstrlenW(szFile)+1]; + lstrcpyW (pmkPack->m_szFile, szFile); + + pmkPack->m_fLink = fLink; + pmkPack->m_refs = 1; + + *ppmk = pmkPack; + return NOERROR; + +errRtn: + Assert (0); + delete pmkPack; + return hresult; +} + + + +///////////////////////////////////////////////////////////////////// +// The rest of these methods just delegate to m_pmk +// or return some error code. + + +STDMETHODIMP CPackagerMoniker::IsDirty (THIS) +{ + M_PROLOG(this); + return ReportResult(0, S_FALSE, 0, 0); + // monikers are immutable so they are either always dirty or never dirty. + // +} + +STDMETHODIMP CPackagerMoniker::Load (THIS_ LPSTREAM pStm) +{ + M_PROLOG(this); + return m_pmk->Load(pStm); +} + + +STDMETHODIMP CPackagerMoniker::Save (THIS_ LPSTREAM pStm, + BOOL fClearDirty) +{ + M_PROLOG(this); + return m_pmk->Save(pStm, fClearDirty); +} + + +STDMETHODIMP CPackagerMoniker::GetSizeMax (THIS_ ULARGE_INTEGER * pcbSize) +{ + M_PROLOG(this); + return m_pmk->GetSizeMax (pcbSize); +} + + // *** IMoniker methods *** +STDMETHODIMP CPackagerMoniker::BindToStorage (THIS_ LPBC pbc, LPMONIKER pmkToLeft, + REFIID riid, LPVOID * ppvObj) +{ + M_PROLOG(this); + *ppvObj = NULL; + return ReportResult(0, E_NOTIMPL, 0, 0); +} + +STDMETHODIMP CPackagerMoniker::Reduce (THIS_ LPBC pbc, DWORD dwReduceHowFar, LPMONIKER * + ppmkToLeft, LPMONIKER * ppmkReduced) +{ + M_PROLOG(this); + return m_pmk->Reduce (pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced); +} + +STDMETHODIMP CPackagerMoniker::ComposeWith (THIS_ LPMONIKER pmkRight, BOOL fOnlyIfNotGeneric, + LPMONIKER * ppmkComposite) +{ + M_PROLOG(this); + return m_pmk->ComposeWith (pmkRight, fOnlyIfNotGeneric, ppmkComposite); +} + +STDMETHODIMP CPackagerMoniker::Enum (THIS_ BOOL fForward, LPENUMMONIKER * ppenumMoniker) +{ + M_PROLOG(this); + return m_pmk->Enum (fForward, ppenumMoniker); +} + +STDMETHODIMP CPackagerMoniker::IsEqual (THIS_ LPMONIKER pmkOtherMoniker) +{ + M_PROLOG(this); + return m_pmk->IsEqual (pmkOtherMoniker); +} + +STDMETHODIMP CPackagerMoniker::Hash (THIS_ LPDWORD pdwHash) +{ + M_PROLOG(this); + return m_pmk->Hash (pdwHash); +} + +STDMETHODIMP CPackagerMoniker::GetTimeOfLastChange (THIS_ LPBC pbc, LPMONIKER pmkToLeft, + FILETIME * pfiletime) +{ + M_PROLOG(this); + return m_pmk->GetTimeOfLastChange (pbc, pmkToLeft, pfiletime); +} + +STDMETHODIMP CPackagerMoniker::Inverse (THIS_ LPMONIKER * ppmk) +{ + M_PROLOG(this); + return m_pmk->Inverse (ppmk); +} + +STDMETHODIMP CPackagerMoniker::CommonPrefixWith (LPMONIKER pmkOther, LPMONIKER * + ppmkPrefix) +{ + M_PROLOG(this); + return m_pmk->CommonPrefixWith (pmkOther, ppmkPrefix); +} + +STDMETHODIMP CPackagerMoniker::RelativePathTo (THIS_ LPMONIKER pmkOther, LPMONIKER * + ppmkRelPath) +{ + M_PROLOG(this); + return m_pmk->RelativePathTo (pmkOther, ppmkRelPath); +} + +STDMETHODIMP CPackagerMoniker::GetDisplayName (THIS_ LPBC pbc, LPMONIKER pmkToLeft, + LPOLESTR * lplpszDisplayName) +{ + M_PROLOG(this); + return m_pmk->GetDisplayName (pbc, pmkToLeft, lplpszDisplayName); +} + +STDMETHODIMP CPackagerMoniker::ParseDisplayName (THIS_ LPBC pbc, LPMONIKER pmkToLeft, + LPOLESTR lpszDisplayName, ULONG * pchEaten, + LPMONIKER * ppmkOut) +{ + M_PROLOG(this); + return m_pmk->ParseDisplayName (pbc, pmkToLeft, lpszDisplayName, pchEaten, + ppmkOut); +} + + +STDMETHODIMP CPackagerMoniker::IsSystemMoniker (THIS_ LPDWORD pdwMksys) +{ + M_PROLOG(this); + VDATEPTROUT (pdwMksys, DWORD); + + *pdwMksys = MKSYS_NONE; + return NOERROR; +} + + + diff --git a/private/ole32/com/remote/dde/client/packmnkr.h b/private/ole32/com/remote/dde/client/packmnkr.h new file mode 100644 index 000000000..bc312bfab --- /dev/null +++ b/private/ole32/com/remote/dde/client/packmnkr.h @@ -0,0 +1,63 @@ +/* + packmnkr.h +*/ + +class CPackagerMoniker : public IMoniker +{ + public: + // *** IUnknown methods *** + STDMETHOD(QueryInterface) ( REFIID riid, LPVOID * ppvObj) ; + STDMETHOD_(ULONG,AddRef) () ; + STDMETHOD_(ULONG,Release) () ; + + // *** IPersist methods *** + STDMETHOD(GetClassID) ( LPCLSID lpClassID) ; + + // *** IPersistStream methods *** + STDMETHOD(IsDirty) () ; + STDMETHOD(Load) ( LPSTREAM pStm) ; + STDMETHOD(Save) ( LPSTREAM pStm, + BOOL fClearDirty) ; + STDMETHOD(GetSizeMax) ( ULARGE_INTEGER * pcbSize) ; + + // *** IMoniker methods *** + STDMETHOD(BindToObject) ( LPBC pbc, LPMONIKER pmkToLeft, + REFIID riidResult, LPVOID * ppvResult) ; + STDMETHOD(BindToStorage) ( LPBC pbc, LPMONIKER pmkToLeft, + REFIID riid, LPVOID * ppvObj) ; + STDMETHOD(Reduce) ( LPBC pbc, DWORD dwReduceHowFar, LPMONIKER * + ppmkToLeft, LPMONIKER * ppmkReduced) ; + STDMETHOD(ComposeWith) ( LPMONIKER pmkRight, BOOL fOnlyIfNotGeneric, + LPMONIKER * ppmkComposite) ; + STDMETHOD(Enum) ( BOOL fForward, LPENUMMONIKER * ppenumMoniker) + ; + STDMETHOD(IsEqual) ( LPMONIKER pmkOtherMoniker) ; + STDMETHOD(Hash) ( LPDWORD pdwHash) ; + STDMETHOD(IsRunning) ( LPBC pbc, LPMONIKER pmkToLeft, LPMONIKER + pmkNewlyRunning) ; + STDMETHOD(GetTimeOfLastChange) ( LPBC pbc, LPMONIKER pmkToLeft, + FILETIME * pfiletime) ; + STDMETHOD(Inverse) ( LPMONIKER * ppmk) ; + STDMETHOD(CommonPrefixWith) ( LPMONIKER pmkOther, LPMONIKER * + ppmkPrefix) ; + STDMETHOD(RelativePathTo) ( LPMONIKER pmkOther, LPMONIKER * + ppmkRelPath) ; + STDMETHOD(GetDisplayName) ( LPBC pbc, LPMONIKER pmkToLeft, + LPOLESTR * lplpszDisplayName) ; + STDMETHOD(ParseDisplayName) ( LPBC pbc, LPMONIKER pmkToLeft, + LPOLESTR lpszDisplayName, ULONG * pchEaten, + LPMONIKER * ppmkOut) ; + STDMETHOD(IsSystemMoniker) ( LPDWORD pdwMksys) ; + + static HRESULT Create ( LPOLESTR szFile, LPMONIKER * ppmk, BOOL fLink) ; + + private: + + ULONG m_refs; + LPOLESTR m_szFile; + LPMONIKER m_pmk; + BOOL m_fLink; + + +}; + diff --git a/private/ole32/com/remote/dde/client/trgt_dev.h b/private/ole32/com/remote/dde/client/trgt_dev.h new file mode 100644 index 000000000..a2de2d4b3 --- /dev/null +++ b/private/ole32/com/remote/dde/client/trgt_dev.h @@ -0,0 +1,19 @@ +// trgt_dev.h + +// OLE 1.0 Target Device + +typedef struct _OLETARGETDEVICE +{ + USHORT otdDeviceNameOffset; + USHORT otdDriverNameOffset; + USHORT otdPortNameOffset; + USHORT otdExtDevmodeOffset; + USHORT otdExtDevmodeSize; + USHORT otdEnvironmentOffset; + USHORT otdEnvironmentSize; + BYTE otdData[1]; +} OLETARGETDEVICE; + +typedef OLETARGETDEVICE const FAR* LPCOLETARGETDEVICE; +typedef OLETARGETDEVICE FAR* LPOLETARGETDEVICE; + diff --git a/private/ole32/com/remote/dde/dirs b/private/ole32/com/remote/dde/dirs new file mode 100644 index 000000000..8d723ece9 --- /dev/null +++ b/private/ole32/com/remote/dde/dirs @@ -0,0 +1,36 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + Donna Liu (DonnaLi) 19-Dec-1993 + +!ENDIF + +# +# This is a list of all subdirectories that build required components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +DIRS= client server + +# +# This is a list of all subdirectories that build optional components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +OPTIONAL_DIRS= + diff --git a/private/ole32/com/remote/dde/server/daytona/makefile b/private/ole32/com/remote/dde/server/daytona/makefile new file mode 100644 index 000000000..1d3728d41 --- /dev/null +++ b/private/ole32/com/remote/dde/server/daytona/makefile @@ -0,0 +1,10 @@ +############################################################################ +# +# Copyright (C) 1992, Microsoft Corporation. +# +# All rights reserved. +# +############################################################################ + +!include $(NTMAKEENV)\makefile.def + diff --git a/private/ole32/com/remote/dde/server/daytona/sources b/private/ole32/com/remote/dde/server/daytona/sources new file mode 100644 index 000000000..f557ef159 --- /dev/null +++ b/private/ole32/com/remote/dde/server/daytona/sources @@ -0,0 +1,83 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + David Plummer (davepl) 19-Mar-94 + + Modifed by via awk to include global project include file + and to wrap precompiled header line within a conditional + that can be set in this include file. + + Donna Liu (DonnaLi) 19-Dec-1993 + +!ENDIF + +MAJORCOMP = cairole +MINORCOMP = com + +# +# This is the name of the target built from the source files specified +# below. The name should include neither the path nor the file extension. +# + +TARGETNAME= ddesvr + +# +# This specifies where the target is to be built. A private target of +# type LIBRARY or DYNLINK should go to obj, whereas a public target of +# type LIBRARY or DYNLINK should go to $(BASEDIR)\public\sdk\lib. +# + +TARGETPATH= obj + +# +# This specifies the type of the target, such as PROGRAM, DYNLINK, LIBRARY, +# etc. +# + +TARGETTYPE= LIBRARY + +INCLUDES = ..\.;..\..\client;..\..\..\..\..\common\daytona;..\..\..\..\..\ih;..\..\..;..\..\..\..\inc;..\..\..\..\idl\daytona;..\..\..\..\class;..\..\..\..\objact;..\..\..\..\..\ole232\inc + +!include ..\..\..\..\..\daytona.inc + +C_DEFINES= -DOLE_DDE_NO_GLOBAL_TRACKING=1\ + $(C_DEFINES) \ + + +SOURCES= \ + ..\ddeadv.cxx \ + ..\ddesink.cxx \ + ..\ddesite.cxx \ + ..\ddesrvr.cxx \ + ..\ddeutils.cxx \ + ..\doc.cxx \ + ..\item.cxx \ + ..\item2.cxx \ + ..\itemutil.cxx \ + ..\srvr.cxx \ + ..\srvrmain.cxx + + +UMTYPE= windows +UMAPPL= +UMTEST= +UMLIBS= + +# PRECOMPILED_INCLUDE= ..\headers.cxx + + diff --git a/private/ole32/com/remote/dde/server/ddeadv.cxx b/private/ole32/com/remote/dde/server/ddeadv.cxx new file mode 100644 index 000000000..0d03789ed --- /dev/null +++ b/private/ole32/com/remote/dde/server/ddeadv.cxx @@ -0,0 +1,132 @@ +// ddeadv.cpp +// +// Mapping from DDE advise to/from OLE 2.0 advises +// +// Author: +// Jason Fuller jasonful 8-16-92 +// +// Copyright (c) 1992 Microsoft Corporation + +#include "ole2int.h" +#include "srvr.h" +#include "ddedebug.h" +ASSERTDATA + + +INTERNAL CDefClient::DoOle20Advise + (OLE_NOTIFICATION options, + CLIPFORMAT cf) +{ + HRESULT hresult = NOERROR; + FORMATETC formatetc; + formatetc.cfFormat = cf; + formatetc.ptd = m_ptd; + formatetc.lindex = DEF_LINDEX; + formatetc.dwAspect = DVASPECT_CONTENT; + // only types 1.0 client wants + formatetc.tymed = TYMED_HGLOBAL | TYMED_MFPICT | TYMED_GDI; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::DoOle20Advise(options=%x,cf=%x)\n", + this, + options, + (ULONG)cf)); + ChkC(this); + switch (options) + { + case OLE_CHANGED: +#ifdef UPDATE + case OLE_SAVED: +#endif + if (0 == m_dwConnectionDataObj) + { + Assert (m_lpdataObj); + RetErr (m_lpdataObj->DAdvise (&formatetc,0/* ADVF_PRIMEFIRST*/, + &m_AdviseSink, + &m_dwConnectionDataObj)); + Assert (m_dwConnectionDataObj != 0); + } + // Fall through: + // Even for OLE_CHANGED do an Ole Advise so we get OnClose + // notifications for linked objects. + +#ifndef UPDATE + case OLE_SAVED: +#endif + case OLE_RENAMED: // Link case + case OLE_CLOSED: + Assert (m_lpoleObj); + // Only do one OleObject::Advise even if 1.0 client asks + // for two advises for two different formats and two events, + // i.e., native and metafile, save and close. + if (m_lpoleObj && 0==m_dwConnectionOleObj) + { + Puts ("Calling OleObject::Advise\r\n"); + Assert (m_dwConnectionOleObj == 0L); + hresult = m_lpoleObj->Advise (&m_AdviseSink, &m_dwConnectionOleObj); + if (hresult != NOERROR) + { + goto errRtn; + } + } + Assert (m_dwConnectionOleObj != 0); + break; + + default: + Assert(0); + break; + } + +errRtn: + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::DoOle20Advise hresult=%x\n", + this,hresult)); + + + return NOERROR; +} + + + + +INTERNAL CDefClient::DoOle20UnAdviseAll + (void) +{ + HRESULT hr; + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::DoOle20UnAdviseAll\n", + this)); + + ChkC(this); + if (m_dwConnectionOleObj != 0L) + { + if (m_lpoleObj) + { + intrDebugOut((DEB_ITRACE, + "%x ::DoOle20UnAdviseAll unadvise OLE obj\n", + this)); + Puts ("Unadvising ole obj\r\n"); + hr = m_lpoleObj->Unadvise (m_dwConnectionOleObj); + intrAssert(hr == NOERROR); + m_dwConnectionOleObj = 0L; + } + } + if (m_dwConnectionDataObj != 0L) + { + if (m_lpdataObj) + { + intrDebugOut((DEB_ITRACE, + "%x ::DoOle20UnAdviseAll unadvise DATA obj\n", + this)); + Puts ("Unadvising data obj\r\n"); + hr = m_lpdataObj->DUnadvise (m_dwConnectionDataObj); + intrAssert(hr == NOERROR); + m_dwConnectionDataObj = 0L; + } + } + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::DoOle20UnAdviseAll\n", + this)); + + return NOERROR; +} diff --git a/private/ole32/com/remote/dde/server/ddeatoms.h b/private/ole32/com/remote/dde/server/ddeatoms.h new file mode 100644 index 000000000..ba105ba17 --- /dev/null +++ b/private/ole32/com/remote/dde/server/ddeatoms.h @@ -0,0 +1,42 @@ +/* ddeatoms.h */ + +//This is here because the file is #included by both client and server files +#define fDdeCodeInOle2Dll 1 + +// These atoms are defined in srvrmain.cpp +extern ATOM aEditItems; +extern ATOM aFormats; +extern ATOM aOLE; +extern ATOM aProtocols; +extern ATOM aStatus; +extern ATOM aStdClose; +extern ATOM aStdCreate; +extern ATOM aStdCreateFromTemplate; +extern ATOM aStdEdit; +extern ATOM aStdExit; +extern ATOM aStdOpen; +extern ATOM aStdShowItem; +extern ATOM aSysTopic; +extern ATOM aTopics; + +// defined in ddewnd.cpp +extern ATOM aChange; +extern ATOM aClose; +extern ATOM aMSDraw; +extern ATOM aNullArg; +extern ATOM aOle; +extern ATOM aSave; +extern ATOM aStdColorScheme; +extern ATOM aStdDocDimensions; +extern ATOM aStdDocName; +extern ATOM aStdHostNames; +extern ATOM aStdTargetDevice ; +extern ATOM aSystem; + +// defined in ddewnd.cpp +extern CLIPFORMAT cfBinary; // "Binary format" +extern CLIPFORMAT cfNative; // "NativeFormat" + +// defined in srvrmain.cpp +extern CLIPFORMAT cfLink; // "ObjectLink" +extern CLIPFORMAT cfOwnerLink; // "Ownerlink" diff --git a/private/ole32/com/remote/dde/server/ddedebug.h b/private/ole32/com/remote/dde/server/ddedebug.h new file mode 100644 index 000000000..dfb7401e6 --- /dev/null +++ b/private/ole32/com/remote/dde/server/ddedebug.h @@ -0,0 +1,99 @@ +// ddeDebug.h +// +// Generic debug routines +// +// Author: +// Jason Fuller jasonful 8-16-92 +// + +#ifndef fDdedebug_h +#define fDdedebug_h + +#define INTR_DDE 0x00010000 +#define INTR_CHNL 0x00020000 +#define INTR_PARAM 0x00040000 + +//#define fDebugOutput +#define WIDECHECK(x) (x?x:L"<NULL>") +#define ANSICHECK(x) (x?x:"<NULL>") + +#if DBG == 1 +#define DEBUG_GUIDSTR(name,guid) WCHAR name [48]; StringFromGUID2( *guid , name , sizeof( name )); +#else +#define DEBUG_GUIDSTR(name,guid) +#endif +#ifdef _DEBUG + + // defined in clientddeworkr.cpp + BOOL wIsValidHandle (HANDLE, CLIPFORMAT); + BOOL wIsValidAtom (ATOM); + + #define DebugOnly(x) x + #define ChkC(p) Assert (p && p->m_chk==chkDefClient) + #define ChkS(p) Assert (p && p->m_chk==chkDdeSrvr) + #define ChkD(p) Assert ((p) && (p)->m_chk==chkDdeObj) + #define AssertIsDoc(p) Assert ((p) && (p)->m_pdoc==(p) && (p)->m_bContainer) + + #define ChkCR(p) RetZ (p && p->m_chk==chkDefClient) + #define ChkSR(p) RetZ (p && p->m_chk==chkDdeSrvr) + #define ChkDR(p) RetZ ((p) && (p)->m_chk==chkDdeObj) + #define AssertIsDocR(p) RetZ ((p) && (p)->m_pdoc==(p) && (p)->m_bContainer) + + #ifdef fDebugOutput + + #define Puti(i) do {char sz[50]; wsprintf(sz, " %lu ", (unsigned long) (i)); Puts(sz);} while(0) + #define Puth(i) do {char sz[50]; wsprintf(sz, " 0x%lx ", (unsigned long) (i)); Puts(sz);} while(0) + #define Puta(a) do {char sz[50]="NULL"; if (a) GlobalGetAtomName(a,sz,50); \ + Puth(a); Puts("\""); Puts(sz); Puts("\" "); } while(0) + #define Putsi(i) do { Puts(#i " = "); Puti(i); Puts("\n");} while (0) + #define Putn() Puts("\r\n") + + #else + + #undef Puts + #define Puts(i) ((void)0) + #define Puti(i) ((void)0) + #define Puth(i) ((void)0) + #define Puta(a) ((void)0) + #define Putsi(i) ((void)0) + #define Putn() ((void)0) + + #endif // fDebugOutput + #define DEBUG_OUT(a,b) OutputDebugStringA(a); +#else + #define DEBUG_OUT(a,b) + #define Puti(i) ((void)0) + #define Puth(i) ((void)0) + #define Puta(a) ((void)0) + #define Putsi(i) ((void)0) + #define Putn() ((void)0) + #define wIsValidHandle(h,cf) (TRUE) + #define wIsValidAtom(a) (TRUE) + #define DebugOnly(x) + #define ChkC(p) + #define ChkS(p) + #define ChkD(p) + #define AssertIsDoc(p) + #define ChkCR(p) + #define ChkSR(p) + #define ChkDR(p) + #define AssertIsDocR(p) + +#endif // _DEBUG + + +// Stuff common to both client and server directories + +#define POSITIVE_ACK (0x8000) +#define NEGATIVE_ACK (0x0000) + +#include <reterr.h> + +INTERNAL_(LPOLESTR) wAtomName (ATOM atom); +INTERNAL_(LPSTR) wAtomNameA (ATOM atom); +INTERNAL_(ATOM) wDupAtom (ATOM aSrc); + +INTERNAL wClassesMatch (REFCLSID clsid, LPOLESTR szFile); +INTERNAL wWriteFmtUserType (LPSTORAGE, REFCLSID); + +#endif // fDdedebug_h diff --git a/private/ole32/com/remote/dde/server/ddeerr.h b/private/ole32/com/remote/dde/server/ddeerr.h new file mode 100644 index 000000000..f35a88b63 --- /dev/null +++ b/private/ole32/com/remote/dde/server/ddeerr.h @@ -0,0 +1,78 @@ +//+--------------------------------------------------------------------------- +// +// Microsoft Windows +// Copyright (C) Microsoft Corporation, 1992 - 1993. +// +// File: ddeerr.h +// +// Contents: Error codes from the previous release +// +// Classes: +// +// Functions: +// +// History: 4-26-94 kevinro Commented/cleaned +// +// This is actually the contents from ole2anac.h, with some parts removed. +// Specifically, including ole2anac.h renamed DAdvise and friends, which +// is bad. +//---------------------------------------------------------------------------- +#if !defined( _OLE2ANAC_H_ ) +#define _OLE2ANAC_H_ + +typedef enum tagSTGSTATE +{ + STGSTATE_DOC = 1, + STGSTATE_CONVERT = 2, + STGSTATE_FILESTGSAME = 4 +} STGSTATE; + + +#define MK_E_EXCEEDED_DEADLINE MK_E_EXCEEDEDDEADLINE +#define MK_E_NEED_GENERIC MK_E_NEEDGENERIC +#define MK_E_INVALID_EXTENSION MK_E_INVALIDEXTENSION +#define MK_E_INTERMEDIATE_INTERFACE_NOT_SUPPORTED \ + MK_E_INTERMEDIATEINTERFACENONOT_SUPPORTED +#define MK_E_NOT_BINDABLE MK_E_NOTBINDABLE +#define S_TRUE S_OK + +#define E_BLANK OLE_E_BLANK +#define E_STATIC OLE_E_STATIC +#define E_NOTRUNNING OLE_E_NOTRUNNING +#define E_FORMAT DV_E_CLIPFORMAT +#define OLE_E_CLSID REGDB_E_CLASSNOTREG +#define OLE_E_NOTSUPPORTED E_NOTIMPL +#define OLE_E_REGDB_KEY REGDB_E_KEYMISSING +#define OLE_E_REGDB_FMT REGDB_E_INVALIDVALUE + + +#define OLEVERB_PRIMARY OLEIVERB_PRIMARY +#define OLEVERB_SHOW OLEIVERB_SHOW + +// these DDE error codes are not returned anymore; these definitions are +// here just to make existing code compile without changes. +#define RPC_E_FIRST MAKE_SCODE(SEVERITY_ERROR, FACILITY_RPC, 0x000) +#define RPC_E_DDE_FIRST MAKE_SCODE(SEVERITY_ERROR, FACILITY_RPC, 0x100) + +#define RPC_E_DDE_BUSY (RPC_E_DDE_FIRST + 0x0) +#define RPC_E_DDE_CANT_UPDATE (RPC_E_DDE_FIRST + 0x1) +#define RPC_E_DDE_INIT (RPC_E_DDE_FIRST + 0x2) +#define RPC_E_DDE_NACK E_FAIL +#define RPC_E_DDE_LAUNCH CO_E_APPNOTFOUND +#define RPC_E_DDE_POST RPC_E_SERVER_DIED +#define RPC_E_DDE_PROTOCOL (RPC_E_DDE_FIRST + 0x6) +#define RPC_E_DDE_REVOKE (RPC_E_DDE_FIRST + 0x7) +#define RPC_E_DDE_SYNTAX_EXECUTE RPC_E_INVALID_PARAMETER +#define RPC_E_DDE_SYNTAX_ITEM RPC_E_INVALID_PARAMETER +#define RPC_E_DDE_UNEXP_MSG (RPC_E_DDE_FIRST + 0xa) +#define RPC_E_DDE_DATA RPC_E_INVALID_PARAMETER + + +#define RPC_E_CONNECTION_LOST (RPC_E_FIRST + 0x6) +#define RPC_E_BUSY (RPC_E_FIRST + 0x0) +#define RPC_E_MSG_REJECTED (RPC_E_FIRST + 0x1) +#define RPC_E_CANCELLED (RPC_E_FIRST + 0x2) +#define RPC_E_DISPATCH_ASYNCCALL (RPC_E_FIRST + 0x4) + + +#endif // _OLE2ANAC_H_ diff --git a/private/ole32/com/remote/dde/server/ddeint.h b/private/ole32/com/remote/dde/server/ddeint.h new file mode 100644 index 000000000..d99fb29f3 --- /dev/null +++ b/private/ole32/com/remote/dde/server/ddeint.h @@ -0,0 +1,179 @@ +//+--------------------------------------------------------------------------- +// +// Microsoft Windows +// Copyright (C) Microsoft Corporation, 1992 - 1993. +// +// File: ddeint.h +// +// Contents: This file contains shared macros/state between the server +// and client directories +// Classes: +// +// Functions: +// +// History: 5-04-94 kevinro Commented/cleaned +// +//---------------------------------------------------------------------------- + +// +// BUGBUG: (KevinRo) The new definition of DVTARGETDEVICE uses an unsized array +// of bytes at the end. Therefore, the sizeof operator no longer works. So, I +// have calculated the size of the cbHeader by accounting for each member of +// the structure independently. I am not too proud of this at the moment, +// but need to move on. +// + +#define DEB_DDE_INIT (DEB_ITRACE|DEB_USER1) + +// names of the DDE window classes +#ifdef _CHICAGO_ +// Note: we have to create a unique string so that get +// register a unique class for each 16 bit app. +// The class space is global on chicago. +// +extern LPSTR szSYS_CLASSA; +extern LPSTR szCLIENT_CLASSA; +extern LPSTR szSRVR_CLASSA; +extern LPSTR szDOC_CLASSA; +extern LPSTR szITEM_CLASSA; +extern LPSTR szCOMMONCLASSA; + +#define DOC_CLASSA szDOC_CLASSA +#define SYS_CLASSA szSYS_CLASSA +#define CLIENT_CLASSA szCLIENT_CLASSA + +#define SYS_CLASS szSYS_CLASSA +#define CLIENT_CLASS szCLIENT_CLASSA +#define SRVR_CLASS szSRVR_CLASSA +#define SRVR_CLASS szSRVR_CLASSA +#define DOC_CLASS szDOC_CLASSA +#define ITEM_CLASS szITEM_CLASSA +#define COMMONCLASS szCOMMONCLASSA + + +#define DDEWNDCLASS WNDCLASSA +#define DdeRegisterClass RegisterClassA +#define DdeUnregisterClass UnregisterClassA +#define DdeCreateWindowEx SSCreateWindowExA + +#else + +#define SYS_CLASS L"Ole2SysWndClass" +#define SYS_CLASSA "Ole2SysWndClass" + +#define CLIENT_CLASS L"Ole2ClientWndClass" +#define CLIENT_CLASSA "Ole2ClientWndClass" + +#define SRVR_CLASS (OLESTR("SrvrWndClass")) +#define SRVR_CLASSA ("SrvrWndClass") + +#define DOC_CLASS (OLESTR("ViewObjWndClass")) +#define DOC_CLASSA ("ViewObjWndClass") + +#define ITEM_CLASS (OLESTR("ItemWndClass")) + +#define DDEWNDCLASS WNDCLASS +#define DdeRegisterClass RegisterClass +#define DdeUnregisterClass UnregisterClass +#define DdeCreateWindowEx CreateWindowEx + +#endif // !_CHICAGO_ + +STDAPI_(LRESULT) DocWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +STDAPI_(LRESULT) SrvrWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +STDAPI_(LRESULT) SysWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +STDAPI_(LRESULT) ClientDocWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +BOOL SendMsgToChildren (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + + +#define SIZEOF_DVTARGETDEVICE_HEADER (sizeof(DWORD) + (sizeof(WORD) * 4)) + +// forward declarations +class CDefClient; +typedef CDefClient FAR *LPCLIENT; + +class CDDEServer; +typedef CDDEServer FAR *LPSRVR; +typedef CDDEServer FAR *HDDE; // used by ClassFactory table + + +PCALLCONTROL GetDdeCallControlInterface(); +void ReleaseDdeCallControlInterface(); + +// +// The wire representation of STDDOCDIMENSIONS is a 16-bit +// format. This means instead of 4 longs, there are +// 4 shorts. This structure is used below to pick the data +// from the wire representation. Amazingly stupid, but +// backward compatible is the name of the game. +// +typedef struct tagRECT16 +{ + SHORT left; + SHORT top; + SHORT right; + SHORT bottom; + +} RECT16, *LPRECT16; + +//+--------------------------------------------------------------------------- +// +// Function: ConvertToFullHWND +// +// Synopsis: This function is used to convert a 16-bit HWND into a 32-bit +// hwnd +// +// Effects: When running in a VDM, depending on who dispatches the message +// we can end up with either a 16 or 32 bit window message. This +// routine is used to make sure we always deal with a 32bit +// HWND. Otherwise, some of our comparisions are incorrect. +// +// Arguments: [hwnd] -- HWND to convert. 16 or 32 bit is fine +// +// Returns: Always returns a 32 bit HWND +// +// History: 8-03-94 kevinro Created +// +// Notes: +// This routine calls a private function given to use by OLETHK32 +// +//---------------------------------------------------------------------------- +inline +HWND ConvertToFullHWND(HWND hwnd) +{ + if (IsWOWThreadCallable() && + ((((ULONG)hwnd & 0xFFFF0000) == 0) || + (((ULONG)hwnd & 0xFFFF0000) == 0xFFFF0000))) + { + return(g_pOleThunkWOW->ConvertHwndToFullHwnd(hwnd)); + } + return(hwnd); +} + +inline +void OleDdeDeleteMetaFile(HANDLE hmf) +{ + intrDebugOut((DEB_ITRACE, + "OleDdeDeleteMetaFile(%x)\n", + hmf)); + if (IsWOWThreadCallable()) + { + intrDebugOut((DEB_ITRACE, + "InWow: calling WOWFreeMetafile(%x)\n", + hmf)); + + if (!g_pOleThunkWOW->FreeMetaFile(hmf)) + { + return; + } + intrDebugOut((DEB_ITRACE, + "WOWFreeMetafile(%x) FAILED\n", + hmf)); + } + intrDebugOut((DEB_ITRACE, + "Calling DeleteMetaFile(%x)\n", + hmf)); + + DeleteMetaFile((HMETAFILE)hmf); +} diff --git a/private/ole32/com/remote/dde/server/ddepack.h b/private/ole32/com/remote/dde/server/ddepack.h new file mode 100644 index 000000000..ef250cafb --- /dev/null +++ b/private/ole32/com/remote/dde/server/ddepack.h @@ -0,0 +1,20 @@ + +#ifdef WIN32 +extern "C" +{ +#include <port1632.h> +} + +#define MAKE_DDE_LPARAM(msg,lo,hi) PackDDElParam(msg,(UINT)lo,(UINT)hi) + +#else + +#define GET_WM_DDE_EXECUTE_HDATA(wParam,lParam) ((HANDLE) HIWORD(lParam)) +#define GET_WM_DDE_DATA_HDATA(wParam,lParam) ((HANDLE) LOWORD(lParam)) +#define GET_WM_DDE_REQUEST_ITEM(wParam,lParam) ((ATOM) HIWORD(lParam)) +#define GET_WM_DDE_DATA_ITEM(wParam,lParam) ((ATOM) HIWORD(lParam)) +#define MAKE_DDE_LPARAM(msg,lo,hi) MAKELONG(lo,hi) +#define DDEFREE(msg,lParam) + +#endif + diff --git a/private/ole32/com/remote/dde/server/ddesink.cxx b/private/ole32/com/remote/dde/server/ddesink.cxx new file mode 100644 index 000000000..302db683e --- /dev/null +++ b/private/ole32/com/remote/dde/server/ddesink.cxx @@ -0,0 +1,251 @@ +// ddesink.cpp +// +// Methods for CDefClient::CAdviseSinkImpl +// +// Author: +// Jason Fuller jasonful 8-16-92 +// +// Copyright (c) 1990, 1991 Microsoft Corporation + + +#include <ole2int.h> +#include "srvr.h" +#include "ddedebug.h" + + +ASSERTDATA + +STDUNKIMPL_FORDERIVED (DefClient, AdviseSinkImpl) + + BOOL PeekOneMessage + (MSG FAR* pmsg, + HWND hwnd, + UINT message) +{ + // We have to verify pmsg->message because PeekMessage will return + // WM_QUIT even if you didn't ask for it. + + if (SSPeekMessage (pmsg, hwnd, message, message, PM_REMOVE)) + { + if (pmsg->message==message) + return TRUE; + else + { + AssertSz (pmsg->message == WM_QUIT, "Unexpected message"); + if (WM_QUIT==pmsg->message) + { + // Put message back + PostQuitMessage (pmsg->wParam); + } + return FALSE; + } + } + else + return FALSE; +} + + + + + + +STDMETHODIMP_(void) NC(CDefClient,CAdviseSinkImpl)::OnClose + (void) +{ + MSG msg; + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::OnClose\n", + this)); + + ChkC(m_pDefClient); + + m_pDefClient->m_fInOnClose = TRUE; + // AddRef/Release safety bracket. Do not remove. + m_pDefClient->m_pUnkOuter->AddRef(); + + #ifdef _DEBUG + if (m_pDefClient->m_bContainer) + { + if (NOERROR != m_pDefClient->NoItemConnections()) + Warn ("OnClose called on document before item"); + } + #endif + + if (m_pDefClient->m_ExecuteAck.f) + { + // in case the server closes in the middle of a DoVerb, send the ACK + // for the EXECUTE now to keep the messages in order. + m_pDefClient->SendExecuteAck (NOERROR); + } + + if (!m_pDefClient->m_fGotStdCloseDoc) + { + // if client sent us StdCloseDocument, then he certainly + // is not in a state to receive callbacks + m_pDefClient->ItemCallBack (OLE_CLOSED); + } + + // We have to check the message field because PeekMessage will return + // WM_QUIT even if you didn't ask for it. + if (PeekOneMessage (&msg, m_pDefClient->m_hwnd, WM_DDE_EXECUTE)) + { + LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,POSITIVE_ACK, + GET_WM_DDE_EXECUTE_HDATA(msg.wParam,msg.lParam)); + + intrDebugOut((DEB_ITRACE, + "%x ::OnClose found StdCloseDocument in queue\n", + this)); + + if(!PostMessageToClient ((HWND)msg.wParam, + WM_DDE_ACK, + (UINT) m_pDefClient->m_hwnd, + lp)) + { + DDEFREE(WM_DDE_ACK,lp); + } + + } + + + ChkC (m_pDefClient); + + if (m_pDefClient->m_bContainer) + { + // If the document (container) is closing, then we + // should send a TERMINATE to the client windows. + // We don't do this for items because a client window + // may still be connected to another item. + // Items within one document share one window. + + m_pDefClient->SendTerminateMsg (); + ChkC (m_pDefClient); + AssertIsDoc (m_pDefClient); + m_pDefClient->ReleaseAllItems(); + } + else + { + m_pDefClient->RemoveItemFromItemList (); + } + + // If item was deleted in client app, m_lpoleObj could be NULL + m_pDefClient->ReleaseObjPtrs (); + + // If "this" is an item, get the doc that contains this item + LPCLIENT pdoc = m_pDefClient->m_pdoc; + Assert (pdoc); + + Assert (pdoc->m_chk==chkDefClient); + if (pdoc->m_chk==chkDefClient && pdoc->m_fRunningInSDI) + if (pdoc->m_fRunningInSDI) + { + Puts ("Running in SDI\r\n"); + // The server app never registered a class factory, so no + // RevokeClassFactory will trigger the destruction of the + // CDdeServer, so we do it here if there are no other clients + // connected to that CDdeServer + if (pdoc->m_psrvrParent->QueryRevokeClassFactory()) + { + // Assert (No sibling documents) + Verify (NOERROR==pdoc->m_psrvrParent->Revoke()); + pdoc->m_psrvrParent = NULL; + } + } + m_pDefClient->m_fInOnClose = FALSE; + + // AddRef/Release safety bracket. Do not remove. + // Do not use m_pDefClient after this Release. + m_pDefClient->m_pUnkOuter->Release(); + + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::OnClose\n", + this)); +} + + + + +STDMETHODIMP_(void) NC(CDefClient,CAdviseSinkImpl)::OnSave + (THIS) +{ + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::OnSave\n", + this)); + + ChkC(m_pDefClient); + if (!m_pDefClient->m_fInOleSave) + { + // If we called OleSave to get the native data, then of course + // we will get an OnSave notification. + m_pDefClient->ItemCallBack (OLE_SAVED); + } + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::OnSave\n", + this)); +} + + + +STDMETHODIMP_(void) NC(CDefClient,CAdviseSinkImpl)::OnDataChange + (THIS_ FORMATETC FAR* pFormatetc, + STGMEDIUM FAR* pStgmed) +{ + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::OnDataChange pFormatetc=%x\n", + this, + pFormatetc)); + // note we are ignoring both the pformatetc and the pStgMed. + // ItemCallBack will ask (using GetData) for the data the client wants. + // We are treating a call to this function as a simple Ping. + + ChkC(m_pDefClient); + m_pDefClient->ItemCallBack (OLE_CHANGED); + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::OnDataChange\n", + this)); +} + + + +STDMETHODIMP_(void) NC(CDefClient,CAdviseSinkImpl)::OnRename + (THIS_ LPMONIKER pmk) +{ + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::OnRename pmk=%x\n", + this,pmk)); + + LPOLESTR szFile=NULL; + + ChkC(m_pDefClient); + if (Ole10_ParseMoniker (pmk, &szFile, NULL) != NOERROR) + { + // Wrong type of moniker + intrDebugOut((DEB_IERROR, + "%x ::OnRename pmk=%x wrong moniker\n", + this,pmk)); + } + else + { + intrDebugOut((DEB_ITRACE, + "%x ::OnRename pmk=%x pmk.Name=(%ws)\n", + this, + pmk, + WIDECHECK(szFile))); + // Notify client + m_pDefClient->ItemCallBack (OLE_RENAMED, szFile); + CoTaskMemFree(szFile); + } + + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::OnRename\n", + this)); +} + + + +STDMETHODIMP_(void) NC(CDefClient,CAdviseSinkImpl)::OnViewChange + (THIS_ DWORD aspects, LONG lindex) +{ + // Response to IViewObjectAdvise::Advise, which we do not do +} + + diff --git a/private/ole32/com/remote/dde/server/ddesite.cxx b/private/ole32/com/remote/dde/server/ddesite.cxx new file mode 100644 index 000000000..6f1a4e503 --- /dev/null +++ b/private/ole32/com/remote/dde/server/ddesite.cxx @@ -0,0 +1,89 @@ +// ddesite.cpp +// +// Methods for CDefClient::COleClientSiteImpl +// +// Author: +// Jason Fuller jasonful 8-16-92 +// +// Copyright (c) 1990, 1991 Microsoft Corporation + + +#include <ole2int.h> +#include "srvr.h" +#include "ddedebug.h" + +ASSERTDATA + +STDUNKIMPL_FORDERIVED (DefClient, OleClientSiteImpl) + + +STDMETHODIMP NC(CDefClient,COleClientSiteImpl)::SaveObject + (void) +{ + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::SaveObject\n", + this)); + + ChkC(m_pDefClient); + + if (!m_pDefClient->m_fGotStdCloseDoc) + m_pDefClient->ItemCallBack (OLE_SAVED); + + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::SaveObject\n", + this)); + return NOERROR; +} + + + +STDMETHODIMP NC(CDefClient,COleClientSiteImpl)::GetContainer + (LPOLECONTAINER FAR * lplpContainer) +{ + VDATEPTROUT( lplpContainer, LPOLECONTAINER); + *lplpContainer = NULL; + + ChkC(m_pDefClient); + return ResultFromScode (E_NOTIMPL); +} + + + +STDMETHODIMP NC(CDefClient,COleClientSiteImpl)::GetMoniker + (DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk) +{ + VDATEPTROUT( ppmk, LPMONIKER); + *ppmk = NULL; + + ChkC(m_pDefClient); + // OLE 1.0 does not support linking to embeddings + return ReportResult(0, E_NOTIMPL, 0, 0); +} + +STDMETHODIMP NC(CDefClient,COleClientSiteImpl)::ShowObject + (void) +{ + ChkC(m_pDefClient); + Puts ("OleClientSite::ShowObject\r\n"); + // REVIEW: what are we supposed do? + return ResultFromScode (E_NOTIMPL); +} + +STDMETHODIMP NC(CDefClient,COleClientSiteImpl)::OnShowWindow + (BOOL fShow) +{ + ChkC(m_pDefClient); + Puts ("OleClientSite::OnShowWindow\r\n"); + // REVIEW: what are we supposed do? + return NOERROR; +} + +STDMETHODIMP NC(CDefClient,COleClientSiteImpl)::RequestNewObjectLayout(void) +{ + ChkC(m_pDefClient); + Puts ("OleClientSite::RequestNewObjectLayout\r\n"); + return ReportResult(0, S_FALSE, 0, 0); +} + + + diff --git a/private/ole32/com/remote/dde/server/ddesrvr.cxx b/private/ole32/com/remote/dde/server/ddesrvr.cxx new file mode 100644 index 000000000..aa9c4f2fd --- /dev/null +++ b/private/ole32/com/remote/dde/server/ddesrvr.cxx @@ -0,0 +1,839 @@ +/* + ddesrvr.cpp + + Author: + Jason Fuller jasonful 8-11-92 +*/ + +#include <ole2int.h> +#include <dde.h> +#include <olerem.h> +#include "srvr.h" +#include "ddeatoms.h" +#include "ddesrvr.h" +#include "ddedebug.h" +#include "map_up.h" + +#include "map_dwp.h" + +ASSERTDATA + +// Dde Common Window stuff + +UINT cCommonWindows = 0; + +#ifdef _CHICAGO_ +// Note: we have to create a unique string so that get +// register a unique class for each 16 bit app. +// The class space is global on chicago. +// +LPSTR szSYS_CLASSA = "Ole2SysWndClass 0x######## "; +LPSTR szCLIENT_CLASSA = "Ole2ClientWndClass 0x######## "; +LPSTR szSRVR_CLASSA = "SrvrWndClass 0x######## "; +LPSTR szDOC_CLASSA = "ViewObjWndClass 0x######## "; +LPSTR szITEM_CLASSA = "ItemWndClass 0x######## "; +LPSTR szCOMMONCLASSA = "DdeCommonWindowClass 0x######## "; + +LPSTR szDdeServerWindow = "DDE Server Window"; +#define szDdeCommonWindowClass szCOMMONCLASSA +#else +const LPOLESTR szDdeServerWindow = OLESTR("DDE Server Window"); +const LPOLESTR szDdeCommonWindowClass = OLESTR("DdeCommonWindowClass"); +#endif + +//+--------------------------------------------------------------------------- +// +// Function: CreateDdeSrvrWindow +// +// Synopsis: When CoRegisterClassObject is called, this function +// is called to create a DDE window to listen for DDE messages +// from a 1.0 client. +// +// Effects: +// +// Arguments: [clsid] -- +// [aClass] -- +// [phwnd] -- +// [fIsRunning] -- +// [aOriginalClass] -- +// [cnvtyp] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-27-94 kevinro Commented/cleaned +// 13-Jul-94 BruceMa Make register/unregister dde window class +// thread safe +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL CreateDdeSrvrWindow + (REFCLSID clsid, + ATOM aClass, + HWND FAR* phwnd, // optional out parm: created window + BOOL fIsRunning, // Is the item atom a file in the ROT? + ATOM aOriginalClass, // for TreatAs/ConvertTo case + CNVTYP cnvtyp) +{ + intrDebugOut((DEB_DDE_INIT,"0 _IN CreateDdeSrvrWindow\n")); + + VDATEHEAP(); + HWND hwnd = NULL; + + HRESULT hresult = NOERROR; + + DdeClassInfo ddeClassInfo; + + ddeClassInfo.dwContextMask = CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER; + ddeClassInfo.fClaimFactory = FALSE; + + // Null out parameter in case of error + if (phwnd) + { + *phwnd = NULL; + } + + intrAssert (wIsValidAtom (aClass)); + + // + // See if this process is registered as a class server for + // the requested class. If it isn't, then check for a running + // object. + // + if (GetClassInformationForDde(clsid,&ddeClassInfo) == FALSE) + { + intrDebugOut((DEB_DDE_INIT, + "CreateDdeSrvrWindow No class information available\n")); + + // + // The ClassObject was not found in the table. + // + + if (fIsRunning) + { + // Link case. + // An SDI app was launched by the user (without "-Embedding"). + // It did not register its class factory. (It never does.) + // Meanwhile, a DDE_INIT with a filename as an item atom was + // broadcasted. + // We are in the task of the SDI app that loaded that filename, + // so this function was called. + // So we need to create the window even though no class factory + // was registered. + // Call CDDEServer::Create with a lot of NULLs. + // Once the DDE_INIT is passed along to the server window, it + // should immediately cause a doc window to be created. + // Must be SDI or we wouldn't have this problem. + // + // This works because we are going to attempt to 'bind' to the + // object which is the subject of the link. If the link object + // was registered as running, we will find it. Otherwise, the + // attempt to create via the class factory will fail, since the + // class factory doesn't exist. + // + + intrDebugOut((DEB_DDE_INIT, + "::CreateDdeServerWindow fIsRunning - override dwFlags\n")); + + // + // NULL out the entire structure, then set only the flags + // + memset(&ddeClassInfo,0,sizeof(ddeClassInfo)); + ddeClassInfo.dwFlags = REGCLS_SINGLEUSE; + + + } + else + { + intrDebugOut((DEB_DDE_INIT, + "CreateDdeServerWindow Returning FALSE\n")); + + hresult = S_FALSE; + goto errRtn; + } + } + intrDebugOut((DEB_DDE_INIT, + "::CreateDdeServerWindow found class\n")); + // Create() does the real work: creates a CDDEServer and the window. + WCHAR szClass[MAX_STR]; + lstrcpyW (szClass, wAtomName (aClass)); + Assert (szClass[0]); + + hresult = CDDEServer::Create(szClass, + clsid, + &ddeClassInfo, + &hwnd, + aOriginalClass, + cnvtyp); + if (hresult != NOERROR) + { + intrDebugOut((DEB_IERROR, + "CreateDdeServerWindow CDDEServer::Create returns %x\n", + hresult)); + goto errRtn; + } + + Assert (IsWindowValid(hwnd)); + + // Fill in out parameter + if (phwnd) + { + *phwnd = hwnd; + } + + +errRtn: + VDATEHEAP(); + intrDebugOut((DEB_DDE_INIT, + "0 _OUT CreateDdeSrvrWindow %x\n", + hresult)); + return hresult; + +} + + + +//+--------------------------------------------------------------------------- +// +// Function: DestroyDdeSrvrWindow +// +// Synopsis: Destroy a DDE server window +// +// Effects: +// +// Arguments: [hwnd] -- Window to destroy +// [aClass] -- Class for server +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 6-24-94 kevinro Created +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL DestroyDdeSrvrWindow + (HWND hwnd, + ATOM aClass) +{ + intrDebugOut((DEB_ITRACE, + "0 _IN DestroyDdeSrvrWindow\n")); + VDATEHEAP(); + Assert (IsAtom (aClass)); + + // Make sure it is a server window + RetZ (IsWindowValid (hwnd)); + RetZ (GetWindowWord (hwnd, WW_LE) == WC_LE); + + + // Get the Common window for this task. + + HWND hwndCommonServer = (HWND)TLSGetDdeServer(); + + if (hwndCommonServer == NULL) + { + intrDebugOut((DEB_IERROR,"hwndCommonServer != NULL\n")); + return(E_UNEXPECTED); + } + if (!IsWindow(hwndCommonServer)) + { + intrAssert(IsWindow(hwndCommonServer)); + return(E_UNEXPECTED); + } + + // Get the map from the common window + CMapUintPtr FAR *pmapClassToHwnd; + Assert (sizeof (CMapUintPtr FAR *)==sizeof(LONG)); + pmapClassToHwnd = (CMapUintPtr FAR *) GetWindowLong (hwndCommonServer, 0); + Assert (pmapClassToHwnd); + + // Make sure the window we're deleting is the server window for this class + void *hwndSrvr; + RetZ (pmapClassToHwnd->Lookup (aClass,hwndSrvr) && hwndSrvr == hwnd); + + RetZ (SSDestroyWindow (hwnd)); + + // Remove this window from the map + pmapClassToHwnd->RemoveKey (aClass); + + VDATEHEAP(); + intrDebugOut((DEB_ITRACE, + "0 _OUT DestroyDdeSrvrWindow\n")); + + return NOERROR; +} + +//+--------------------------------------------------------------------------- +// +// Function: DdeCommonWndProc +// +// Synopsis: Window proc for the common dde server window that +// listens for all WM_DDE_INITIATEs +// +// Effects: When a DDE_INITIATE comes in, this routine will determine +// the class of the object being requested. If the class is +// served by this thread, then it will create a window to +// converse with the server. +// +// Arguments: [hWnd] -- hWnd of Common DDE +// [wMsg] -- msg +// [wParam] -- Return Window to converse with +// [lParam] -- HIWORD(aItem) LOWORD(aClass) +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-27-94 kevinro Commented/cleaned +// +// Notes: +// +// When running in a VDM, it is possible that this window was dispatched +// without having a full window handle. This happens when the getmessage +// was dispatched from 16-bit. Therefore, we need to convert the hwnd to +// a full hwnd before doing any comparision functions. +// +//---------------------------------------------------------------------------- +STDAPI_(LRESULT) +DdeCommonWndProc(HWND hwndIn, UINT wMsg, WPARAM wParam, LPARAM lParam) +{ + + switch (wMsg) + { + case WM_DDE_INITIATE: + { + VDATEHEAP(); + ATOM aClass = LOWORD(lParam); + ATOM aItem = HIWORD(lParam); + HWND hwnd; + + CNVTYP cnvtyp = cnvtypNone; + + BOOL fIsFile= FALSE; // Must initialize + BOOL fIsRunning= FALSE; // Must initialize + BOOL fUnsavedDoc = FALSE; // Is the "file" really an unsaved doc + HWND hwndServer; + HRESULT hresult; + + + // + // From this point forward, we need to insure we are using a + // FULL hwnd. + // + hwnd = ConvertToFullHWND(hwndIn); + + // + // The following should already be initialized + // + intrAssert (aOLE != NULL); + intrAssert (aSysTopic != NULL); + + if (aItem==aOLE || aItem==aSysTopic + || (fIsFile=IsFile (aItem, &fUnsavedDoc))) + { + + + intrDebugOut((DEB_DDE_INIT, + "DdeCommonWndProc:hWnd(%x) DDE_INITIATE cls(%ws)\n", + hwnd, + wAtomName(aClass))); + + // + // Get the ClassToHwnd map for this thread + // + CMapUintPtr FAR *pmapClassToHwnd; + Assert (sizeof (CMapUintPtr FAR *)==sizeof(LONG)); + pmapClassToHwnd = (CMapUintPtr FAR *) GetWindowLong (hwnd, 0); + Assert (pmapClassToHwnd); + + + // Convert atom to CLSID, taking into account + // TreatAs and AutoConvert. + CLSID clsid; + ATOM aOriginalClass = aClass; + + if (CLSIDFromAtomWithTreatAs (&aClass, &clsid, &cnvtyp) != NOERROR) + { + intrDebugOut((DEB_IERROR,"Could not get clsid for this class\n")); + return 0L; + } + + void *pServerTmp; + if (TRUE == pmapClassToHwnd->Lookup (aClass, pServerTmp)) + { + // + // Since a server window for this class already exists, but is a child window + // of ours, we will send it this message directly. + // + + intrDebugOut((DEB_DDE_INIT, + "DdeCommonWndProc Server cls exists. Forwarding to %x\n", + pServerTmp)); + + return SSSendMessage ((HWND)pServerTmp, WM_DDE_INITIATE, wParam,lParam); + + } + + if (CoIsOle1Class (clsid)) + { + // We have no business intercepting Initiates sent + // to 1.0 servers + intrDebugOut((DEB_DDE_INIT, + "DdeCommonWndProc: Its a OLE 1.0 class\n")); + return 0L; + } + + if (fIsFile) + { + // Link case + WCHAR szFile[MAX_STR]; + + WORD cb=GlobalGetAtomName (aItem, szFile, MAX_STR); + Assert (cb>0 && cb < MAX_STR-1); + intrDebugOut((DEB_DDE_INIT, + "Looking for file %ws\n",szFile)); + + IsRunningInThisTask (szFile, &fIsRunning); + } + + // If it's not a file, it can't be running, obviously. + intrAssert (fIsFile || !fIsRunning); + + if (NOERROR == (hresult=(CreateDdeSrvrWindow (clsid, + aClass, + &hwndServer, + fIsRunning, + aOriginalClass, + cnvtyp)))) + { + + // Indicate that we have created a server window + // for this class. We could have used any value in + // place of hwndServer_. It's just a flag. + // REVIEW jasonful: how to handle OOM? + + pmapClassToHwnd->SetAt (wDupAtom(aClass), hwndServer); + +#if DBG == 1 + // Verify the SetAt we just did. + void FAR* pv; + Verify (pmapClassToHwnd->Lookup(aClass, pv)); + Assert (pv == hwndServer); +#endif + // Pass the INITIATE along to the real, + // newly-created server window and forge + // the sender's hwnd to be whoever called + // the common server window. + // SendMessage should return 1L is doc is running, + // indicating an ACK was sent. + Assert (IsWindowValid (hwndServer)); + SSSendMessage (hwndServer, WM_DDE_INITIATE, wParam,lParam); + intrDebugOut((DEB_DDE_INIT, + "DdeCommonWndProc:hWnd(%x) DDE_INITIATE complete(%ws)\n", + hwnd, + wAtomName(aClass))); + VDATEHEAP(); + } + else + { + if (S_FALSE!=GetScode(hresult)) + { + intrDebugOut((DEB_IERROR, + "DCWP: CreateDdeSrvrWindow failed %x\n", + hresult)); + } + } + } + else + { + // + // We have a DDE_INITIATE message that needs to be forwarded to our + // child window. + // + return SendMsgToChildren(hwnd,wMsg,wParam,lParam); + } + return 0L; + } + break; + + case WM_DESTROY: + { + // + // When this window is destroyed, we cleanup the + // windows attached data. + // + + CMapUintPtr FAR *pmapClassToHwnd; + pmapClassToHwnd = (CMapUintPtr FAR *) GetWindowLong (hwndIn, 0); + + // + // Make sure there are no server windows + // created by this common window still extant. If there are, print out + // a message on a debug build. Otherwise, there really isn't much we + // can do about it. We are already closing down. The DDE emulation layer + // will send appropriate terminate messages. + // + + #if DBG == 1 + if (pmapClassToHwnd && !pmapClassToHwnd->IsEmpty()) + { + intrDebugOut((DEB_ERROR, + "DCDW Leaking active OLE 1.0 clients\n")); + intrDebugOut((DEB_ERROR, + "There were active OLE 1.0 connections at shutdown\n")); + } + #endif + delete pmapClassToHwnd; + return(0); + } + + + + default: + return SSDefWindowProc (hwndIn, wMsg, wParam, lParam); + } +} + + + + + COleStaticMutexSem commonDdeMutex; + + + +//+--------------------------------------------------------------------------- +// +// Function: CreateCommonDdeWindow +// +// Synopsis: Creates a DDE window for initiating conversations with this +// threads objects. +// +// Effects: Creates a window that responds to DDE_INITIATE messages, and +// determines if it needs to respond to the INITIATE. This +// routine is called by OleInitializeEx() +// +// The handle to the created window is placed in the TLS +// structure. +// +// Arguments: [void] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-27-94 kevinro Converted to OLE32 +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL CreateCommonDdeWindow + (void) +{ + intrDebugOut((DEB_ITRACE,"%p _IN CreateCommonDdeWindow\n",0)); + + HRESULT hr = NOERROR; + HWND hwndDdeServer; + // + // If a DdeServer window already exists, then return NOERROR. + // If Com has been initialized but Ole has not, then we dont + // create a window, we just return NOERROR. This way, COM-only + // servers dont start serving OLE1 clients. + // + + COleTls tls; + hwndDdeServer = tls->hwndDdeServer; + if ( hwndDdeServer != NULL || tls->cOleInits == 0) + { + intrDebugOut((DEB_ITRACE, + "CreateCommonDocWindow: HWND(%x) cOleInits(%x)\n", + hwndDdeServer, + tls->cOleInits)); + goto exitRtn; + } + + // + // Only need to register the window class once per + // process so we protect it via a critical section + // + { + COleStaticLock lck(commonDdeMutex); + + if (0 == cCommonWindows) + { + // Register "DDE Common window" class + // + DDEWNDCLASS wc; + wc.style = 0; + wc.lpfnWndProc = DdeCommonWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof (CMapUintPtr FAR*); + Assert (g_hmodOLE2); + wc.hInstance = g_hmodOLE2; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = szDdeCommonWindowClass; + + if (!DdeRegisterClass(&wc) ) + { + // + // It is possible that the register has failed because + // the class was previously registered, but failed to + // unregister. We are ignoring it, because if the + // class really couldn't register, then the CreateWindow + // will fail, which is what we really care about anyway. + // + intrDebugOut((DEB_IERROR, + "RegisterClass() %s has failed %x\n", szDdeCommonWindowClass, + GetLastError())); + intrAssert(!"CreateCommonDdeWindow register failed."); + + } + } + + cCommonWindows++; + } + + if (!(hwndDdeServer = DdeCreateWindowEx(0, szDdeCommonWindowClass, + szDdeServerWindow, + WS_POPUP,0,0,0,0, + NULL,NULL, + g_hmodOLE2, NULL))) + { + intrDebugOut((DEB_IERROR, + "CreateCommonDocWindow() has failed %x\n", + GetLastError())); + + hr = E_OUTOFMEMORY; + goto exitRtn; + } + + intrDebugOut((DEB_ITRACE, + "CreateCommonDocWindow() hwndDdeServer=%x\n", + hwndDdeServer)); + + // Give the common window a map from classes to server windows + + CMapUintPtr FAR *pmapClassToHwnd; + + Assert (sizeof(LONG)==sizeof (CMapUintPtr FAR*)); + + if ((pmapClassToHwnd = new CMapUintPtr) == NULL) + { + intrDebugOut((DEB_ERROR,"pmapClassToHwnd != NULL\n")); + hr = E_OUTOFMEMORY; + goto errRtn; + } + + SetWindowLong (hwndDdeServer, 0, (LONG)pmapClassToHwnd); + // + // Set the pointer to the server in the TLS data + // + tls->hwndDdeServer = hwndDdeServer; + + hr = NOERROR; + +exitRtn: + + intrDebugOut((DEB_ITRACE,"%p _OUT CreateCommonDocWindow (%x)\n",0,hr)); + + return(hr); + + // + // In the error case, if the hwnDdeServer != NULL, then destroy it + // +errRtn: + if (hwndDdeServer != NULL) + { + SSDestroyWindow(hwndDdeServer); + } + + goto exitRtn; +} + + + + + +//+--------------------------------------------------------------------------- +// +// Function: DestroyCommonDdeWindow +// +// Synopsis: Destroys the common DDE Server window +// +// Effects: +// +// Arguments: [void] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-27-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL DestroyCommonDdeWindow + (void) +{ + intrDebugOut((DEB_ITRACE,"%p _IN DestroyCommonDdeWindow\n",0)); + + HRESULT hr = NOERROR; + HWND hwndDdeServer = (HWND)TLSGetDdeServer(); + + if (hwndDdeServer == NULL) + { + hr = E_UNEXPECTED; + goto errRtn; + } +#if 0 + // We do not need to validate this window since we created it! + if (!IsWindowValid(hwndDdeServer)) + { + intrAssert(!"IsWindowValid"); + hr = E_UNEXPECTED; + goto errRtn; + } +#endif + // + // Get the map from the common window + // + + + // + // If destroying this window fails, there isn't much we can + // do about it. + // + if(!SSDestroyWindow (hwndDdeServer)) + { + intrAssert(!"DestroyWindow"); + hr = E_UNEXPECTED; + } + else + { + intrDebugOut((DEB_ITRACE, + "DestroyCommonDocWindow() hwndDdeServer=%x\n", + hwndDdeServer)); + + // Must take a mutex around unregistering the class because another + // thread may be trying to register the window class at the same time + COleStaticLock lck(commonDdeMutex); + + cCommonWindows--; + + if (cCommonWindows == 0) + { + if(!DdeUnregisterClass (szDdeCommonWindowClass, g_hmodOLE2)) + { + intrDebugOut((DEB_ERROR, + "DestroyCommonDocWindow(): UnregisterClass has failed error:>%x<\n", + GetLastError())); + intrAssert(!"DestroyCommonDdeWindow unregister failed."); + // + // If unregistering the class fails, there isn't a + // whole lot we can do about it. Its possible that + // there were still active client windows. + // + hr = E_UNEXPECTED; + } + } + } + + if(!TLSSetDdeServer(NULL)) + { + intrAssert(!"TLSSetDdeServer failed\n"); + hr = E_UNEXPECTED; + } +errRtn: + intrDebugOut((DEB_ITRACE,"%p _OUT DestroyCommonDdeWindow %x\n",0,hr)); + return hr; +} + +//+--------------------------------------------------------------------------- +// +// Function: IsRunningInThisTask +// +// Synopsis: Determine if the given file is running in the current task +// +// Effects: Calls a special function in the ROT to determine if the +// file szFile is loaded as a moniker in the current task +// +// Arguments: [szFile] -- Filename +// [pf] -- Points to a BOOL. Returned TRUE if running +// +// History: 6-29-94 kevinro Created +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL IsRunningInThisTask(LPOLESTR szFileIn,BOOL FAR* pf) // out parm +{ + HRESULT hresult; + + intrDebugOut((DEB_DDE_INIT, + "IsRunninginThisTask szFileIn=%ws\n", + WIDECHECK(szFileIn))); + + // + // The RunningObjectTable always stores LONG filenames, therefore we + // need to convert this name to the long name for the lookup. + // + + WCHAR szFile[MAX_PATH]; + if ((lstrlenW(szFileIn) == 0) || (GetLongPathNameW(szFileIn,szFile,MAX_PATH) == 0)) + { + // + // Unable to determine a long path for this object. Use whatever we were + // handed. + // + intrDebugOut((DEB_DDE_INIT,"No conversion to long path. Copy szFileIn\n")); + lstrcpyW(szFile,szFileIn); + } + + intrDebugOut((DEB_DDE_INIT,"Long file szFile(%ws)\n",szFile)); + + hresult = GetLocalRunningObjectForDde(szFile,NULL); + + *pf = (hresult == S_OK); + + intrDebugOut((DEB_DDE_INIT, + "IsRunninginThisTask szFile=%ws returns %s\n", + WIDECHECK(szFile), + *pf?"TRUE":"FALSE")); + return NOERROR; +} diff --git a/private/ole32/com/remote/dde/server/ddesrvr.h b/private/ole32/com/remote/dde/server/ddesrvr.h new file mode 100644 index 000000000..291b2c389 --- /dev/null +++ b/private/ole32/com/remote/dde/server/ddesrvr.h @@ -0,0 +1,26 @@ +/* + ddesrvr.h + Header file for ddesrvr.cpp + + Author: + Jason Fuller jasonful 8-11-92 +*/ + +#ifndef fDdesrvr_h +#define fDdesrvr_h + +// Defined in cftable.cpp +STDAPI RemGetInfoForCid + (REFCLSID clsid, + LPDWORD pgrf, + LPCLASSFACTORY FAR* ppCF, + LPHANDLE FAR* pphwndDde, + BOOL FAR* FAR* ppfAvail, + BOOL fEvenIfHidden=FALSE); + +INTERNAL DestroyDdeSrvrWindow (HWND hwnd, ATOM aClass); +INTERNAL CreateCommonDdeWindow (void); +INTERNAL DestroyCommonDdeWindow (void); + +INTERNAL IsRunningInThisTask (LPOLESTR szFile, BOOL FAR* pf); +#endif diff --git a/private/ole32/com/remote/dde/server/ddeutils.cxx b/private/ole32/com/remote/dde/server/ddeutils.cxx new file mode 100644 index 000000000..272a6a2f1 --- /dev/null +++ b/private/ole32/com/remote/dde/server/ddeutils.cxx @@ -0,0 +1,1015 @@ +/****************************** Module Header ******************************\ +* Module Name: ddeutils.c +* +* Purpose: Conatains all the utility routines +* +* Created: 1990 +* +* Copyright (c) 1990, 1991 Microsoft Corporation +* +* History: +* Raor, Srinik (../../1990) Designed and coded +* +\***************************************************************************/ +#include <windows.h> +#include "ole2int.h" +//#include "cmacs.h" +#include <dde.h> +#include "srvr.h" +#include "ddesrvr.h" +#include "ddedebug.h" +ASSERTDATA + + +#define WM_NCMOUSEFIRST WM_NCMOUSEMOVE +#define WM_NCMOUSELAST WM_NCMBUTTONDBLCLK + + + +#define KB_64 65536 + +extern ATOM aTrue; +extern ATOM aFalse; + +extern ATOM aStdCreateFromTemplate; +extern ATOM aStdCreate; +extern ATOM aStdOpen; +extern ATOM aStdEdit; +extern ATOM aStdShowItem; +extern ATOM aStdClose; +extern ATOM aStdExit; +extern ATOM aStdDoVerbItem; + + +//ScanBoolArg: scans the argument which is not included in +//the quotes. These args could be only TRUE or FALSE for +//the time being. !!!The scanning routines should be +//merged and it should be generalized. + +INTERNAL_(LPSTR) ScanBoolArg +( +LPSTR lpstr, +BOOL FAR *lpflag +) +{ + + + LPSTR lpbool; + ATOM aShow; + char ch; + + lpbool = lpstr; + + // !!! These routines does not take care of quoted quotes. + + while((ch = *lpstr) && (!(ch == ')' || ch == ','))) + lpstr++; + + if(ch == NULL) + return NULL; + + *lpstr++ = NULL; // terminate the arg by null + + // if terminated by paren, then check for end of command + // syntax. + + // Check for the end of the command string. + if (ch == ')') { + if (*lpstr++ != ']') + return NULL; + + if(*lpstr != NULL) + return NULL; //finally should be terminated by null. + + } + + aShow = GlobalFindAtomA (lpbool); + if (aShow == aTrue) + *lpflag = TRUE; + + else { + if (aShow ==aFalse) + *lpflag = FALSE; + else + return NULL;; + } + return lpstr; +} + + +//+--------------------------------------------------------------------------- +// +// Function: CreateUnicodeFromAnsi +// +// Synopsis: Creates a UNICODE string from an ANSI string +// +// Effects: Makes a new UNICODE string from the given ANSI string. +// The new UNICODE string is returned. Memory is allocated +// using PrivMemAlloc +// +// Arguments: [lpAnsi] -- Ansi version of string +// +// Requires: +// +// Returns: NULL if cannot create new string. +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 6-07-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +LPOLESTR CreateUnicodeFromAnsi( LPCSTR lpAnsi) +{ + WCHAR buf[MAX_PATH]; + ULONG ccbuf; + LPOLESTR lpWideStr; + + if ((ccbuf=MultiByteToWideChar(CP_ACP,0,lpAnsi,-1,buf,MAX_PATH)) + == FALSE) + { + intrAssert(!"Unable to convert characters"); + return NULL; + } + + lpWideStr = (LPOLESTR) PrivMemAlloc(ccbuf * sizeof(WCHAR)); + + if (lpWideStr != NULL) + { + memcpy(lpWideStr,buf,ccbuf*sizeof(WCHAR)); + } + return(lpWideStr); +} +//+--------------------------------------------------------------------------- +// +// Function: CreateAnsiFromUnicode +// +// Synopsis: Creates an Ansi string from a UNICODE string +// +// Effects: Makes a new ANSI string from the given UNICODE string. +// The new string is returned. Memory is allocated +// using PrivMemAlloc +// +// Arguments: [lpUnicode] -- Unicode version of string +// +// Requires: +// +// Returns: NULL if cannot create new string. +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 6-07-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +LPSTR CreateAnsiFromUnicode( LPCOLESTR lpUnicode) +{ + char buf[MAX_PATH]; + ULONG ccbuf; + LPSTR lpAnsiStr; + + ccbuf = WideCharToMultiByte(CP_ACP, + 0, + lpUnicode, + -1, + buf, + MAX_PATH, + NULL, + NULL); + + + if (ccbuf == FALSE) + { + intrAssert(!"Unable to convert characters"); + return NULL; + } + + lpAnsiStr = (LPSTR) PrivMemAlloc(ccbuf * sizeof(char)); + + if (lpAnsiStr != NULL) + { + memcpy(lpAnsiStr,buf,ccbuf); + } + return(lpAnsiStr); +} + +//ScannumArg: Checks for the syntax of num arg in Execute and if +//the arg is syntactically correct, returns the ptr to the +//beginning of the next arg and also, returns the number +//Does not take care of the last num arg in the list. + +INTERNAL_(LPSTR) ScanNumArg +( +LPSTR lpstr, +LPINT lpnum +) +{ + + WORD val = 0; + char ch; + + while((ch = *lpstr++) && (ch != ',')) { + if (ch < '0' || ch >'9') + return NULL; + val += val * 10 + (ch - '0'); + + } + + if(!ch) + return NULL; + + *lpnum = val; + return lpstr; +} + + + + +//ScanArg: Checks for the syntax of arg in Execute and if +//the arg is syntactically correct, returns the ptr to the +//beginning of the next arg or to the end of the excute string. + +INTERNAL_(LPSTR) ScanArg +( +LPSTR lpstr +) +{ + + + // !!! These routines does not take care of quoted quotes. + + // first char should be quote. + + if (*(lpstr-1) != '\"') + return NULL; + + while(*lpstr && *lpstr != '\"') + lpstr++; + + if(*lpstr == NULL) + return NULL; + + *lpstr++ = NULL; // terminate the arg by null + + if(!(*lpstr == ',' || *lpstr == ')')) + return NULL; + + + if(*lpstr++ == ','){ + + if(*lpstr == '\"') + return ++lpstr; + // If it is not quote, leave the ptr on the first char + return lpstr; + } + + // terminated by paren + // already skiped right paren + + // Check for the end of the command string. + if (*lpstr++ != ']') + return NULL; + + if(*lpstr != NULL) + return NULL; //finally should be terminated by null. + + return lpstr; +} + +// ScanCommand: scanns the command string for the syntax +// correctness. If syntactically correct, returns the ptr +// to the first arg or to the end of the string. + +INTERNAL_(WORD) ScanCommand +( +LPSTR lpstr, +WORD wType, +LPSTR FAR * lplpnextcmd, +ATOM FAR * lpAtom +) +{ + // !!! These routines does not take care of quoted quotes. + // and not taking care of blanks arround the operators + + // !!! We are not allowing blanks after operators. + // Should be allright! since this is arestricted syntax. + + char ch; + LPSTR lptemp = lpstr; + + + while(*lpstr && (!(*lpstr == '(' || *lpstr == ']'))) + lpstr++; + + if(*lpstr == NULL) + return NULL; + + ch = *lpstr; + *lpstr++ = NULL; // set the end of command + + *lpAtom = GlobalFindAtomA (lptemp); + + if (!IsOleCommand (*lpAtom, wType)) + return NON_OLE_COMMAND; + + if (ch == '(') { + ch = *lpstr++; + + if (ch == ')') { + if (*lpstr++ != ']') + return NULL; + } + else { + if (ch != '\"') + return NULL; + } + + *lplpnextcmd = lpstr; + return OLE_COMMAND; + } + + // terminated by ']' + + if (*(*lplpnextcmd = lpstr)) // if no nul termination, then it is error. + return NULL; + + return OLE_COMMAND; +} + + +//MakeDataAtom: Creates a data atom from the item string +//and the item data otions. + +INTERNAL_(ATOM) MakeDataAtom +( +ATOM aItem, +int options +) +{ + WCHAR buf[MAX_STR]; + + if (options == OLE_CHANGED) + return DuplicateAtom (aItem); + + if (!aItem) + buf[0] = NULL; + else + GlobalGetAtomName (aItem, buf, MAX_STR); + + if (options == OLE_CLOSED) + lstrcatW (buf, OLESTR("/Close")); + else { + if (options == OLE_SAVED) + lstrcatW (buf, OLESTR("/Save")); + else + AssertSz (0, "Bad option\n"); + } + + Puts ("MakeDataAtom "); Puts(buf); Putn(); + if (buf[0]) + return wGlobalAddAtom (buf); + else + return NULL; +} + +//DuplicateAtom: Duplicates an atom +INTERNAL_(ATOM) DuplicateAtom +( +ATOM atom +) +{ + WCHAR buf[MAX_STR]; + + if (!atom) + return NULL; + + GlobalGetAtomName (atom, buf, MAX_STR); + return wGlobalAddAtom (buf); +} + +// MakeGlobal: makes global out of strings. +// works only for << 64k + +INTERNAL_(HANDLE) MakeGlobal +( +LPSTR lpstr +) +{ + + int len = 0; + HANDLE hdata = NULL; + LPSTR lpdata = NULL; + + len = strlen (lpstr) + 1; + + hdata = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, len); + + if (hdata == NULL || (lpdata = (LPSTR) GlobalLock (hdata)) == NULL) + goto errRtn; + + + memcpy(lpdata, lpstr, (DWORD)len); + GlobalUnlock (hdata); + return hdata; + +errRtn: + Assert (0); + if (lpdata) + GlobalUnlock (hdata); + + + if (hdata) + GlobalFree (hdata); + + return NULL; + +} + + +INTERNAL_(BOOL) CLSIDFromAtom(ATOM aClass, LPCLSID lpclsid) +{ + WCHAR szProgID[MAX_STR]; + if (!ISATOM (aClass)) + return FALSE; + WORD cb=GlobalGetAtomName (aClass, szProgID, MAX_STR); + Assert (cb>0 && cb < (MAX_STR - 1)); + + return CLSIDFromProgID(szProgID, lpclsid) == S_OK; +} + +// CLSIDFromAtomWithTreatAs +// +// Input: *paClass +// Output: *pclsid == corresponding CLSID, taking into account TreatAs and +// AutoConvert +// *paClass == atom correpsonding to *pclsid +// +#pragma SEG(CLSIDFromAtomWithTreatAs) +INTERNAL CLSIDFromAtomWithTreatAs + (ATOM FAR* paClass, + LPCLSID pclsid, + CNVTYP FAR* pcnvtyp) +{ + HRESULT hr; + + + intrDebugOut((DEB_ITRACE, + "%p _IN CLSIDFromAtomWithTreatAs(paClass=%x," + "pclsid=%x,pcnvtyp=%x)\n",0, + paClass,pclsid,pcnvtyp)); + + LPOLESTR szProgID = NULL; + CLSID clsidNew; + + if (!CLSIDFromAtom (*paClass, pclsid)) + { + hr = S_FALSE; + goto exitRtn; + } + + DEBUG_GUIDSTR(clsidStr,pclsid); + + intrDebugOut((DEB_ITRACE,"Guid %ws",clsidStr)); + if (CoGetTreatAsClass (*pclsid, &clsidNew) == NOERROR) + { + DEBUG_GUIDSTR(newStr,pclsid); + + intrDebugOut((DEB_ITRACE," cnvtypTreatAs %ws\n",newStr)); + if (pcnvtyp) + *pcnvtyp = cnvtypTreatAs; + } + else if (OleGetAutoConvert (*pclsid, &clsidNew) == NOERROR) + { + DEBUG_GUIDSTR(newStr,pclsid); + intrDebugOut((DEB_ITRACE," cnvtypConvertTo %ws\n",newStr)); + if (pcnvtyp) + *pcnvtyp = cnvtypConvertTo; + } + else + { + intrDebugOut((DEB_ITRACE," no conversion\n")); + if (pcnvtyp) + *pcnvtyp = cnvtypNone; + clsidNew = *pclsid; // no translation + } + + hr = ProgIDFromCLSID(clsidNew, &szProgID); + if (FAILED(hr)) + { + intrDebugOut((DEB_ITRACE," ProgIDFromCLSID failed\n")); + goto exitRtn; + } + + intrDebugOut((DEB_ITRACE,"ProgIDFromCLSID returns %ws\n",szProgID)); + *paClass = GlobalAddAtom (szProgID); + *pclsid = clsidNew; + CoTaskMemFree(szProgID); + +exitRtn: + intrDebugOut((DEB_ITRACE, + "%p OUT CLSIDFromAtomWithTreatAs returns %x\n", + 0,hr)); + + return hr; +} + + +INTERNAL_(BOOL) PostMessageToClientWithReply +( +HWND hWnd, +UINT wMsg, +WPARAM wParam, // posting window +LPARAM lParam, +UINT wReplyMsg +) +{ + MSG msg; + + if (!IsWindowValid (hWnd)) + { + AssertSz(FALSE, "Client's window is missing"); + return FALSE; + } + + if (!IsWindowValid ((HWND)wParam)) + { + AssertSz (0, "Posting window is invalid"); + return FALSE; + } + + // Post message to client failed. Treat it as if we got the reply. + if (!PostMessageToClient (hWnd, wMsg, wParam, lParam)) + return FALSE; + + return NOERROR == wTimedGetMessage (&msg, (HWND)wParam, WM_DDE_TERMINATE, + WM_DDE_TERMINATE); +} + + + +INTERNAL_(BOOL) PostMessageToClient +( + HWND hWnd, + UINT wMsg, + WPARAM wParam, + LPARAM lParam +) +{ + UINT c=0; + + while (c < 10) + { + if (!IsWindowValid (hWnd)) { + Warn ("Client's window is missing"); + return FALSE; + } + Puts ("Posting"); Puth(wMsg); Puts("to"); Puth(hWnd); Putn(); + if (PostMessage (hWnd, wMsg, wParam, lParam)) + return TRUE; // success + else + { + Yield(); + c++; // try again + } + } + return FALSE; +} + + +INTERNAL_(BOOL) IsWindowValid + (HWND hwnd) +{ + HTASK htask; + + if (!IsWindow (hwnd)) + return FALSE; + + htask = GetWindowThreadProcessId(hwnd, NULL); + +#ifndef WIN32 + if (IsTask(htask)) +#endif + return TRUE; + + return FALSE; +} + + + +INTERNAL_(BOOL) UtilQueryProtocol +( +ATOM aClass, +LPOLESTR lpprotocol +) +{ + HKEY hKey; + WCHAR key[MAX_STR]; + WCHAR cclass[MAX_STR]; + + if (!aClass) + return FALSE; + + if (!GlobalGetAtomName (aClass, cclass, MAX_STR)) + return FALSE; + + lstrcpyW (key, cclass); + lstrcatW (key, OLESTR("\\protocol\\")); + lstrcatW (key, lpprotocol); + lstrcatW (key, OLESTR("\\server")); + if (RegOpenKey (HKEY_CLASSES_ROOT, key, &hKey) != ERROR_SUCCESS) + return FALSE; + RegCloseKey (hKey); + return TRUE; +} + + + +INTERNAL_(BOOL) IsOleCommand +( +ATOM aCmd, +WORD wType +) +{ + if (wType == WT_SRVR) { + if ((aCmd == aStdCreateFromTemplate) + || (aCmd == aStdCreate) + || (aCmd == aStdOpen) + || (aCmd == aStdEdit) + || (aCmd == aStdShowItem) + || (aCmd == aStdClose) + || (aCmd == aStdExit)) + return TRUE; + } + else { + if ((aCmd == aStdClose) + || (aCmd == aStdDoVerbItem) + || (aCmd == aStdShowItem)) + return TRUE; + } + + return FALSE; +} +INTERNAL wFileBind + (LPOLESTR szFile, + LPUNKNOWN FAR* ppUnk) +{ + HRESULT hresult = NOERROR; + LPBC pbc = NULL; + LPMONIKER pmk = NULL; + *ppUnk = NULL; + ErrRtnH (CreateBindCtx (0, &pbc)); + ErrRtnH (CreateFileMoniker (szFile, &pmk)); + ErrRtnH (pmk->BindToObject (pbc, NULL, IID_IUnknown, (LPLPVOID) ppUnk)); + errRtn: +// AssertOutPtrIface(hresult, *ppUnk); + if (pbc) + pbc->Release(); + if (pmk) + pmk->Release(); + return hresult; +} + +// SynchronousPostMessage +// +// Post a message and wait for the ack. +// (jasonful) +// +INTERNAL SynchronousPostMessage + (HWND hWndTo, // also who you expect the reply from + UINT wMsg, + WPARAM wParam, + LPARAM lParam) +{ +#ifdef _MAC +#else + + HRESULT hresult = NOERROR; + + static unsigned iCounter; + + + HWND hWndFrom = (HWND) wParam; + + + + RetZ (IsWindowValid(hWndFrom)); + RetZ (IsWindowValid(hWndTo)); + + Assert (wMsg != WM_DDE_INITIATE); // can't check for positive ack. + + RetZS (PostMessage (hWndTo, wMsg, wParam, lParam), RPC_E_SERVER_DIED); + + MSG msg; + RetErr (wTimedGetMessage (&msg, hWndFrom, WM_DDE_ACK, WM_DDE_ACK)); + Assert (msg.message == WM_DDE_ACK); + if (!( GET_WM_DDE_ACK_STATUS(msg.wParam,msg.lParam) & POSITIVE_ACK)) + hresult = ResultFromScode (RPC_E_DDE_NACK); + if (msg.hwnd != hWndFrom) + hresult = ResultFromScode (RPC_E_DDE_UNEXP_MSG); + + + + return hresult; +#endif _MAC +} + + +INTERNAL wFileIsRunning + (LPOLESTR szFile) +{ + LPMONIKER pmk = NULL; + LPBINDCTX pbc=NULL; + HRESULT hresult; + + RetErr (CreateBindCtx (0, &pbc)); + ErrRtnH (CreateFileMoniker (szFile, &pmk)); + hresult = pmk->IsRunning (pbc, NULL, NULL); + errRtn: + if (pbc) + pbc->Release(); + if (pmk) + pmk->Release(); + return hresult; +} + + + + +//+--------------------------------------------------------------------------- +// +// Function: IsFile +// +// Synopsis: Given a handle to an atom, determine if it is a file +// +// Effects: Attempts to get the files attributes. If there are no +// attributes, then the file doesn't exist. +// +// Arguments: [a] -- Atom for filename +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 5-03-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL_ (BOOL) IsFile + (ATOM a, BOOL FAR* pfUnsavedDoc) +{ + LPMONIKER pmk = NULL; + LPBC pbc = NULL; + LPRUNNINGOBJECTTABLE pROT=NULL; + + WCHAR szFile [MAX_STR]; + if (0==GlobalGetAtomName (a, szFile, MAX_STR)) + return FALSE; + + DWORD dwAttribs = GetFileAttributes(szFile); + + /* flags prevent sharing violation*/ + if (dwAttribs != 0xFFFFFFFF) + { + if (pfUnsavedDoc) + *pfUnsavedDoc = FALSE; + return TRUE; + } + // This will deal with unsaved documents in the ROT. + // We do NOT want to call pmk->IsRunning because if a 2.0 client called + // DdeIsRunning, we do not want call it here, because then we get stuck + // in an infinite loop. We only care about true 2.0 running objects. + + + // + // BUGBUG: KevinRo There is a function (GetPathFromRot) that could replace + // the following code sequence. + // + + BOOL f= NOERROR==CreateBindCtx (0, &pbc) && + NOERROR==CreateFileMoniker (szFile, &pmk) && + NOERROR==pbc->GetRunningObjectTable (&pROT) && + NOERROR==pROT->IsRunning (pmk) ; + if (pROT) + pROT->Release(); + if (pmk) + pmk->Release(); + if (pbc) + pbc->Release(); + if (pfUnsavedDoc) + *pfUnsavedDoc = TRUE; + return f; + + +} + +// wCompatibleClasses +// +// Determine if class "aClient" is Auto-Converted to class "aSrvr" or +// Treated-As class "aSrvr". +// (Does not check if aClient==aSrvr) +// +#pragma SEG(wCompatibleClasses) +INTERNAL wCompatibleClasses + (ATOM aClient, + ATOM aSrvr) +{ + CLSID clsidClient, clsidSrvr, clsidTo; + HRESULT hresult; + RetZS (CLSIDFromAtom (aClient, &clsidClient), S_FALSE); + RetZS (CLSIDFromAtom (aSrvr, &clsidSrvr ), S_FALSE); + if (NOERROR==OleGetAutoConvert (clsidClient, &clsidTo) + && clsidTo == clsidSrvr) + { + // aClient is Auto-Converted to aSrvr + return NOERROR; + } + hresult = CoGetTreatAsClass(clsidClient, &clsidTo); + if (hresult != NOERROR) + { + intrDebugOut((DEB_IERROR, + "wCompatibleClasses CoGetTreatAs returns %x\n", + hresult)); + return(hresult); + } + + if (clsidTo == clsidSrvr) + { + // aClient is Treated-As aSrvr + return NOERROR; + } + return ResultFromScode (S_FALSE); // not compatible +} + + + +// wCreateStgAroundNative +// +// Build an OLE2 storage around 1.0 native data by putting it in +// stream "\1Ole10Native" and creating valid CompObj and OLE streams. +// Return the IStorage and the ILockBytes it is built on. +// +INTERNAL wCreateStgAroundNative + (HANDLE hNative, + ATOM aClassOld, + ATOM aClassNew, + CNVTYP cnvtyp, + ATOM aItem, + LPSTORAGE FAR* ppstg, + LPLOCKBYTES FAR* pplkbyt) +{ + HRESULT hresult; + LPSTORAGE pstg = NULL; + LPLOCKBYTES plkbyt = NULL; + LPOLESTR szUserType = NULL; + WCHAR szClassOld [256]; + CLSID clsid; + ATOM aClass; + *ppstg = NULL; + + intrDebugOut((DEB_ITRACE, + "%p wCreateStgAroundNative(hNative=%x,aClassOld=%x" + ",aClassNew=%x cnvtyp=%x,aItem=%x)\n", + 0,hNative,aClassOld,aClassNew,cnvtyp,aItem)); + + // Create temporary docfile on our ILockBytes + ErrRtnH (CreateILockBytesOnHGlobal (NULL,/*fDeleteOnRelease*/TRUE,&plkbyt)); + + Assert (plkbyt); + + ErrRtnH (StgCreateDocfileOnILockBytes (plkbyt, grfCreateStg, 0, &pstg)); + + RetZ (pstg); + Assert (NOERROR==StgIsStorageILockBytes(plkbyt)); + + aClass = (cnvtyp == cnvtypConvertTo)?aClassNew:aClassOld; + + if (CLSIDFromAtom (aClass,(LPCLSID)&clsid) == FALSE) + { + hresult = REGDB_E_CLASSNOTREG; + goto errRtn; + } + + ErrRtnH (WriteClassStg (pstg, clsid)); + + // The UserType always corresponds to the clsid. + ErrRtnH (OleRegGetUserType (clsid, USERCLASSTYPE_FULL, &szUserType)); + + // The format is always the 1.0 format (classname/progid) + ErrZS (GlobalGetAtomName (aClassOld, szClassOld, 256), E_UNEXPECTED); + + ErrRtnH (WriteFmtUserTypeStg (pstg, RegisterClipboardFormat(szClassOld), + szUserType)); + + + if (cnvtyp == cnvtypConvertTo) + { + // SetConvertStg also writes a complete default Ole Stream + ErrRtnH (SetConvertStg (pstg, TRUE)); + } + else + { + ErrRtnH (WriteOleStg (pstg, NULL, (CLIPFORMAT)0, NULL)); + } + ErrRtnH (StSave10NativeData (pstg, hNative, FALSE)); + if (aItem) + { + ErrRtnH (StSave10ItemName (pstg, wAtomNameA (aItem))); + } + *ppstg = pstg; + *pplkbyt = plkbyt; + return NOERROR; + + errRtn: + if (pstg) + pstg->Release(); + if (plkbyt) + plkbyt->Release(); + CoTaskMemFree(szUserType); + return hresult; +} + + +#ifdef _DEBUG + + +INTERNAL_ (BOOL) IsAtom (ATOM a) +{ + WCHAR sz[256]= {0}; + if (a < 0xc000) + return FALSE; + WORD cb=GlobalGetAtomName (a, sz, 256); + Assert (lstrlenW(sz) == (int) cb); + return cb>0 && cb < MAX_STR; +} + + +#include <limits.h> +#undef GlobalFree + + + + +INTERNAL_(HANDLE) wGlobalFree (HANDLE h) +{ + LPVOID p; + Assert ((GlobalFlags(h) & GMEM_LOCKCOUNT)==0); + if (!(p=GlobalLock(h))) + { + Puts ("Cannot free handle"); + Puth (h); + Putn(); + AssertSz(0, "Invalid Handle\r\n"); + } + Assert (!IsBadReadPtr (p, (UINT) min (UINT_MAX, GlobalSize(h)))); + Assert (GlobalUnlock(h)==0); + Verify (!GlobalFree (h)); + Puts ("FREEING "); + Puth (h); + Putn (); + return NULL; // success +} + + + +#undef GlobalDeleteAtom + +INTERNAL_(ATOM) wGlobalDeleteAtom (ATOM a) +{ + WCHAR sz[256]; + Assert (0 != GlobalGetAtomName (a, sz, 256)); + Assert (0==GlobalDeleteAtom (a)); + return (ATOM)0; +} + +INTERNAL_(int) wCountChildren + (HWND h) +{ + int c = 0; + HWND hwndChild = GetWindow (h, GW_CHILD); + while (hwndChild) + { + c++; + hwndChild = GetWindow (hwndChild, GW_HWNDNEXT); + } + return c; +} + + +#endif // _DEBUG diff --git a/private/ole32/com/remote/dde/server/dirs b/private/ole32/com/remote/dde/server/dirs new file mode 100644 index 000000000..94c45c76c --- /dev/null +++ b/private/ole32/com/remote/dde/server/dirs @@ -0,0 +1,37 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + Donna Liu (DonnaLi) 19-Dec-1993 + +!ENDIF + +# +# This is a list of all subdirectories that build required components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +DIRS= + +# +# This is a list of all subdirectories that build optional components. +# Each subdirectory name should appear on a line by itself. The build +# follows the order in which the subdirectories are specified. +# + +OPTIONAL_DIRS= \ + + diff --git a/private/ole32/com/remote/dde/server/doc.cxx b/private/ole32/com/remote/dde/server/doc.cxx new file mode 100644 index 000000000..3975d4d3e --- /dev/null +++ b/private/ole32/com/remote/dde/server/doc.cxx @@ -0,0 +1,1680 @@ +/***************************************************************************\ +* Module Name: Doc.c Document Main module +* +* Purpose: Includes All the document level object communication related. +* +* Created: Oct 1990. +* +* Copyright (c) 1990, 1991 Microsoft Corporation +* +* History: +* Raor (../10/1990) Designed, coded (modified for 2.0) +* +\***************************************************************************/ + +#include "ole2int.h" +//#include "cmacs.h" +#include <dde.h> + +#include "srvr.h" +#include "ddedebug.h" +#include "valid.h" +ASSERTDATA + +extern ATOM aStdClose; +extern ATOM aStdShowItem; +extern ATOM aStdDoVerbItem; +extern ATOM aStdDocName; +extern ATOM aTrue; +extern ATOM aFalse; + +extern HINSTANCE hdllInst; +extern HANDLE hddeRename; +extern HWND hwndRename; + + +// HRESULT DdeHandleIncomingCall(HWND hwndCli, WORD wCallType); + +// +// Call CoHandleIncomingCall which will call the message filter +// Note: only call this functions with: +// - CALLTYPE_TOPLEVEL ... for synchranous calls +// - CALLTYPE_ASYNC ... for async calls +// +HRESULT DdeHandleIncomingCall(HWND hwndCli, WORD wCallType) +{ + + Assert(!"DdeHandleIncomingCall not implemented"); + + return(RPC_E_CALL_REJECTED); + + // Review: bug: get the correcr hwnd + switch ( /* CoHandleIncomingCall(hwndCli, wCallType, NULL) */ wCallType) { + default: + case SERVERCALL_ISHANDLED: // call can be proccesed + return NOERROR; + + case SERVERCALL_REJECTED: // call rejected + return ResultFromScode(RPC_E_CALL_REJECTED); + + case SERVERCALL_RETRYLATER: // call should be retried later + return ResultFromScode(RPC_E_DDE_BUSY); + } +} + + +INTERNAL CDefClient::Create +( + LPSRVR lhOLESERVER, + LPUNKNOWN lpunkObj, + LPOLESTR lpdocName, + const BOOL fSetClientSite, + const BOOL fDoAdvise, + const BOOL fRunningInSDI, // optional + HWND FAR* phwnd // optional +) +{ + LPSRVR lpsrvr = NULL; + LPCLIENT lpclient = NULL; + HANDLE hclient = NULL; + HRESULT hresult = NOERROR; + + intrDebugOut((DEB_ITRACE, + "0 _IN CDefClient::Create(lpsrvr=%x,lpdocName=%ws)\n", + lhOLESERVER,WIDECHECK(lpdocName))); + + // REVIEW: server's termination has already started. Are + // we going to see this condition in the synchronous mode. + lpsrvr = (LPSRVR)lhOLESERVER; + if (lpsrvr && lpsrvr->m_bTerminate) + { + Assert(0); + return ReportResult(0, RPC_E_DDE_REVOKE, 0, 0); + } + +#ifdef FIREWALLS + PROBE_READ(lpunkObj); + PROBE_READ(lpmkObj); + PROBE_WRITE(lplhobj); +#endif + + lpclient = new CDefClient (/*pUnkOuter==*/NULL);; + + lpclient->m_pCallControl = GetDdeCallControlInterface(); + + intrAssert(lpclient->m_pCallControl != NULL); + + if (lpclient->m_pCallControl == NULL) + { + intrDebugOut((DEB_IWARN, + "CDefClient::Create(%ws) CallControlGet failed\n", + WIDECHECK(lpdocName))); + + goto errRtn; + } + + + Assert(lpclient->m_pUnkOuter); + + lpclient->m_aItem = wGlobalAddAtom (/*lpszObjName*/lpdocName); + lpclient->m_fRunningInSDI = fRunningInSDI; + lpclient->m_psrvrParent = lpsrvr; + // A doc has itself as its containing document + lpclient->m_pdoc = lpclient; + + ErrRtnH (lpunkObj->QueryInterface (IID_IOleObject, + (LPLPVOID) &lpclient->m_lpoleObj)); + + ErrRtnH (lpunkObj->QueryInterface (IID_IDataObject, + (LPLPVOID) &lpclient->m_lpdataObj)); + + // Lock object; do after the QI so that ReleaseObjPtrs will unlock correctly + lpclient->m_fLocked = + (NOERROR==CoLockObjectExternal (lpunkObj, TRUE, /*dont care*/ FALSE)); + + if (!(lpclient->m_hwnd = SSCreateWindowExA(0, DOC_CLASSA,"DDE ViewObj", + WS_CHILD,0,0,0,0,lpsrvr->m_hwnd,NULL, hdllInst, NULL))) + { + intrDebugOut((DEB_ITRACE,"CDefClient::Create() couldn't create window\n")); + goto errRtn; + } + + + if (fDoAdvise) + { + // This is for Packager, in particular, and manual links. + // If client does not advise on any data, we still need + // to do an OLE advise so we can get OnClose notifications. + ErrRtnH (lpclient->DoOle20Advise (OLE_CLOSED, (CLIPFORMAT)0)); + } + + intrDebugOut((DEB_ITRACE," Doc window %x created\n",lpclient->m_hwnd)); + + // Set out parm (window) + if (phwnd != NULL) + { + *phwnd = lpclient->m_hwnd; + } + + if (fSetClientSite) + { + // Should not set the client site if the object has not been + // initialized yet, by BindMoniker (i.e. PersistFile::Load) + // or PersistStorage::Load + if (lpclient->SetClientSite() != NOERROR) + { + goto errRtn; + } + } + + Putsi(lpclient->m_cRef); + + SetWindowLong (lpclient->m_hwnd, 0, (LONG)lpclient); + SetWindowWord (lpclient->m_hwnd, WW_LE, WC_LE); + SetWindowLong (lpclient->m_hwnd,WW_HANDLE, + (GetWindowLong (lpsrvr->m_hwnd, WW_HANDLE))); + + hresult = NOERROR; + +exitRtn: + + intrDebugOut((DEB_ITRACE, + "0 _OUT CDefClient::Create(lpsrvr=%x,lpdocName=%ws) hr=%x\n", + lhOLESERVER, + WIDECHECK(lpdocName), + hresult)); + + + return(hresult); +errRtn: + intrDebugOut((DEB_ITRACE,"CDefClient::Create() in error handling routine\n")); + if (lpclient) + { + if (lpclient->m_pCallControl) + ReleaseDdeCallControlInterface(); + + if (lpclient->m_hwnd) + SSDestroyWindow (lpclient->m_hwnd); + + if (lpclient->m_aItem) + GlobalDeleteAtom (lpclient->m_aItem); + delete lpclient; + } + hresult = E_OUTOFMEMORY; + goto exitRtn; +} + + + +INTERNAL CDefClient::Revoke (BOOL fRelease) +{ + Puts ("DefClient::Revoke "); Puth(this); Puta(m_aItem); Putn(); + + ChkC(this); + + + ReleaseObjPtrs(); + + // We are done with this CDefClient but someone may still have a reference + // to an instance of one of our nested classes. In particular, an advise + // holder may be holding on to our sink, or an item may have a pointer + // to us if we are its parent document. So we cannot actually do a + // "delete this". + // The corresponding AddRef is in CDefClient::Create + // or CDefClient::RegisterItem + + m_pUnkOuter->Release(); + + Puts ("DefClient::Revoke done\r\n"); + return NOERROR; +} + + + +INTERNAL CDefClient::ReleaseObjPtrs + (void) +{ + intrDebugOut((DEB_ITRACE, + "%p _IN CDefClient::ReleaseObjPtrs\n", + this)); + + ULONG ulResult; + + if (m_lpoleObj && m_fLocked) + { + // Unlock object. Set m_fLocked to FALSE first to prevent reentrant + // problems (unlock causes close which causes this routine to be called) + + m_fLocked = FALSE; + CoLockObjectExternal(m_lpoleObj, FALSE, TRUE); + } + if (m_lpoleObj) + { + if (m_fDidSetClientSite) + m_lpoleObj->SetClientSite(NULL); + DoOle20UnAdviseAll(); + Assert (m_lpoleObj); + if (m_lpoleObj) + { + ulResult = m_lpoleObj->Release(); + m_lpoleObj = NULL; + } + intrDebugOut((DEB_ITRACE, + "%p _OUT ::ReleaseObjPtrs lpoleObj ulResult=%x\n", + this,ulResult)); + } + if (m_lpdataObj) + { + // Must do it this way because the Release can cause recursion + LPDATAOBJECT pdata = m_lpdataObj; + m_lpdataObj = NULL; + ulResult = pdata->Release(); + intrDebugOut((DEB_ITRACE, + "%p _OUT ::ReleaseObjPtrs pdata ulResult=%x\n", + this,ulResult)); + } + + intrDebugOut((DEB_ITRACE, + "%p _OUT CDefClient::ReleaseObjPtrs\n", + this)); + return NOERROR; +} +#if 000 +//RevokeAllDocs : revokes all the doc objects attached to a given +//server. + +INTERNAL_(HRESULT) CDDEServer::RevokeAllDocObjs () +{ + + HWND hwnd; + HWND hwndnext; + LPCLIENT lpclient; + Puts ("RevokeAllDocObjs\r\n"); + ChkS(this); + + hwnd = GetWindow (m_hwnd, GW_CHILD); + + // Go thru each of the child windows and revoke the corresponding + // document. Doc windows are child windows for the server window. + + while (hwnd){ + // sequence is important + hwndnext = GetWindow (hwnd, GW_HWNDNEXT); + lpclient = ((LPCLIENT)GetWindowLong (hwnd, 0)); + lpclient->Revoke(); + hwnd = hwndnext; + } + return NOERROR; +} +#endif + +// FindDoc: Given a doc obj, searches for the doc obj +// in the given class factory tree. returns true if the +// doc obj is available. + + +INTERNAL_(LPCLIENT) CDDEServer::FindDocObj +( +LPSTR lpdocname +) +{ + ATOM aItem; + HWND hwnd; + LPCLIENT lpclient; + + ChkS(this); + aItem = (ATOM)GlobalFindAtomA (lpdocname); + Assert (IsWindowValid (m_hwnd)); + hwnd = GetWindow (m_hwnd, GW_CHILD); + Assert (NULL==hwnd || IsWindowValid (hwnd)); + + while (hwnd) + { + lpclient = (LPCLIENT)GetWindowLong (hwnd, 0); + if (lpclient->m_aItem == aItem) + { + intrDebugOut((DEB_ITRACE, + "FindDocObj found %s lpclient=%x\n", + lpdocname, + lpclient)); + return lpclient; + } + hwnd = GetWindow (hwnd, GW_HWNDNEXT); + } + return NULL; +} + +BOOL PostAckToClient(HWND hwndClient,HWND hwndServer,ATOM aItem,DWORD retval) +{ + HRESULT hr = TRUE; + intrDebugOut((DEB_ITRACE, + "0 _IN PostAckToClient(hwndClient=%x,hwndServer=%x,aItem=%x(%ws)\n", + hwndClient, + hwndServer, + aItem, + wAtomName(aItem))); + + DWORD status = 0; + SET_MSG_STATUS (retval, status); + + LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem); + + if (!PostMessageToClient (hwndClient, + WM_DDE_ACK, + (UINT)hwndServer, + lp)) + { + DDEFREE(WM_DDE_ACK,lp); + hr = FALSE; + } + intrDebugOut((DEB_ITRACE, + "0 _OUT PostAckToClient returns %x\n", + hr)); + + return hr; +} + +//+--------------------------------------------------------------------------- +// +// Function: DocHandleIncomingCall +// +// Synopsis: Setup and call the CallControl to dispatch a call to the doc +// +// Effects: A call has been made from the client that requires us to call +// into our server. This must be routed through the call control. +// This routine sets up the appropriate data structures, and +// calls into the CallControl. The CallControl will in turn +// call DocDispatchIncomingCall to actually process the call. +// +// This routine should only be called by the DocWndProc +// +// +// Arguments: [pDocData] -- Points to DOCDISPATCHDATA for this call +// This contains all required information for +// handling the message. +// +// Requires: +// +// Returns: If an error is returned, it is assumed that the Dispatch +// routine was not reached. DocDispatchIncomingCall() should +// not be returning an error. +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 6-05-94 kevinro Commented/cleaned +// +// Notes: +// +// This is a co-routine with DocDispatchIncomingCall. See that routine +// for more details +// +//---------------------------------------------------------------------------- +INTERNAL DocHandleIncomingCall(PDOCDISPATCHDATA pDocData) +{ + HRESULT hresult = NOERROR; + DISPATCHDATA dispatchdata; + INTERFACEINFO32 ifInfo; + + IID iid; // Currently, we have a random iid, based on whatever is on + // the stack. These calls do not nest, so this isn't supposed + // to matter. + + + intrAssert(pDocData != NULL); + + ICallControl *lpCallCont = pDocData->lpclient->m_pCallControl; + + intrDebugOut((DEB_ITRACE, + "0 _IN DocHandleIncomingCall lpclient=%x pDocData=%x\n", + pDocData->lpclient, + pDocData)); + + // + // It would be very bad if this didn't exist. + // + intrAssert(lpCallCont); + + // + // There is no information to provide here + // By setting pUnk to NULL, the CallControl will pass the + // message filter a NULL ifInfo. + // + + ifInfo.pUnk = NULL; + ifInfo.wMethod=0; + + // + // TERMINATE messages must always be handled ASYNC, and cannot + // be rejected. + // + if (pDocData->msg == WM_DDE_TERMINATE) + { + ifInfo.callcat = CALLCAT_ASYNC; + } + else + { + ifInfo.callcat = CALLCAT_SYNCHRONOUS; + } + + dispatchdata.pData = (LPVOID) pDocData; + pDocData->wDispFunc = DDE_DISP_DOCWNDPROC; + + hresult = lpCallCont->HandleDispatchCall((DWORD)GetWindowTask(pDocData->hwnd), + iid, + &ifInfo, + &dispatchdata); + + intrDebugOut((DEB_ITRACE, + "0 _OUT DocHandleIncomingCall hresult=%x\n", + hresult)); + + return(hresult); +} + +//+--------------------------------------------------------------------------- +// +// Function: DocDispatchIncomingCall +// +// Synopsis: Dispatch a call into the client. +// +// Effects: This is a co-routine to DocHandleIncomingCall. This routine +// is called to implement functions that call into the CDefClient +// object. It is dispatched by the call control stuff, and helps +// to insure the server is ready to accept these calls. +// +// This routine is coded as a continuation of the DocWndProc. +// There is a switch on the message. Each message does slightly +// different things. The code to handle each message was snatched +// from the original DocWndProc, before it was converted to the +// new call control mechanism. +// +// +// Arguments: [pDocData] -- Points to Doc Dispatch Data, which are the +// parameters to DocWndProc which need processing +// +// Requires: +// pDocData cannot be NULL +// +// Returns: +// This routine will always return NOERROR. There are no useful +// error returns to be made from here. If you decide to return +// an error, check the DocHandleIncomingCall and DocWndProc to be +// sure the error paths are correctly handled. Some of the +// cases do additional error processing in the DocWndProc on +// error. +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 6-05-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL DocDispatchIncomingCall(PDOCDISPATCHDATA pDocData) +{ + LPCLIENT lpclient = pDocData->lpclient; + BOOL fack; + HANDLE hdata = pDocData->hdata; + ATOM aItem = pDocData->aItem; + WPARAM wParam = pDocData->wParam; + HWND hwnd = pDocData->hwnd; + HRESULT retval; + + + + intrDebugOut((DEB_ITRACE, + "0 _IN DocDispatchIncomingCall pDocData(%x)\n", + pDocData)); + + intrAssert(pDocData); + + // + // This switch statement is intended to continue the functionality found + // in the DocWndProc. These routines are directly interrelated to the + // same cases in DocWndProc, and need special care before changing. + // + switch (pDocData->msg) + { + case WM_DDE_TERMINATE: + { + intrDebugOut((DEB_ITRACE, + "DDIC: WM_DDE_TERMINATE hwnd=%x \n", + pDocData->hwnd)); + + // + // Here is a fine hack for you. 32-bit applications appear to shut + // down slightly differently than 16-bit applications. There is a + // problem with Lotus Notes interacting with 32-bit OFFICE apps. + // When notes has done an OleCreateFromFile, it starts the + // 32-bit hidden, and does a normal DDE conversation. However, + // on termination, the 32-bit Doc Window was going away during + // this routine. Since the world is now multi-tasking, Lotus + // Notes was seeing its server window die because we get + // pre-empted during DeleteItemsFromList giving the 16-bit app a + // chance to run. Since Lotus is in the + // standard OleQueryReleaseStatus() loop, it will detect that the + // server has shutdown BEFORE it gets the terminate message. + // Go figure. So, insure that we post the reply DDE_TERMINATE + // before destroying our window, or the 16-bit applications + // won't like us. + // + PostMessageToClient ((HWND)wParam, WM_DDE_TERMINATE, + (UINT) hwnd, NULL); + + // Client initiated the termination. So, we should remove + // his window from any of our doc or items' lists. + lpclient->DeleteFromItemsList ((HWND)wParam + /*, lpclient->m_fEmbed*/); + + ChkC (lpclient); + + + // REVIEW: If the termination is sent from the client side, + // lpoleObj will not be NULL. + if (lpclient->m_cClients == 0 && lpclient->m_fEmbed) + { + Assert (lpclient->m_chk==chkDefClient); + lpclient->ReleaseAllItems (); + Assert (lpclient->m_chk==chkDefClient); + Assert (NULL==lpclient->m_lpoleObj && + NULL==lpclient->m_lpdataObj) ; + + } + break; + } + + case WM_DDE_EXECUTE: + { + + intrDebugOut((DEB_ITRACE, + "DDIC: WM_DDE_EXECUTE hwnd=%x hdata=%x\n", + pDocData->hwnd, + pDocData->hdata)); + + // + // The following state variables appear to be used by + // the execute code. + // + lpclient->m_ExecuteAck.f = TRUE; // assume we will need to + lpclient->m_ExecuteAck.hdata = hdata; + lpclient->m_ExecuteAck.hwndFrom = (HWND)wParam; + lpclient->m_ExecuteAck.hwndTo = hwnd; + + // + // In the event that the command is a StdClose, we need + // to force the client to stay around for the duration of + // the call. + // + lpclient->m_pUnkOuter->AddRef(); + + retval = lpclient->DocExecute (hdata); + + if (lpclient->m_ExecuteAck.f) + { + lpclient->SendExecuteAck (retval); + } + + lpclient->m_pUnkOuter->Release(); + break; + + } + case WM_DDE_POKE: + { + int iStdItem; + intrDebugOut((DEB_ITRACE, + "DDIC: WM_DDE_POKE hwnd=%x aItem=%x(%ws) hdata=%x\n", + hwnd, + aItem, + wAtomName(aItem), + hdata)); + + if (iStdItem = GetStdItemIndex (aItem)) + { + retval = lpclient->PokeStdItems ((HWND)wParam, + aItem, + hdata, + iStdItem); + } + else + { + retval = lpclient->PokeData ((HWND)wParam, + aItem, + hdata); + // This is allowed to fail. PowerPoint tries to poke + // data with cfFormat=="StdSave" and "StdFont" + } + + if (!PostAckToClient((HWND)wParam,hwnd,aItem,retval)) + { + goto errRtn; + } + break; + } + case WM_DDE_ADVISE: + { + intrDebugOut((DEB_ITRACE, + "DDIC: WM_DDE_ADVISE hwnd=%x aItem=%x(%ws) hdata=%x\n", + hwnd, + aItem, + wAtomName(aItem), + hdata)); + + if (IsAdviseStdItems (aItem)) + { + retval = lpclient->AdviseStdItems ((HWND)wParam, + aItem, + hdata, + (BOOL FAR *)&fack); + } + else + { + retval = lpclient->AdviseData ((HWND)wParam, + aItem, + hdata, + (BOOL FAR *)&fack); + } + + if (fack) + { + if (!PostAckToClient((HWND)wParam,hwnd,aItem,retval)) + { + GlobalFree(hdata); + } + } + else if (aItem != NULL) + { + GlobalDeleteAtom (aItem); + } + break; + } + case WM_DDE_UNADVISE: + { + intrDebugOut((DEB_ITRACE, + "DDIC: WM_DDE_UNADVISE hwnd=%x aItem=%x(%ws)\n", + hwnd, + aItem, + wAtomName(aItem))); + + retval = lpclient->UnAdviseData ((HWND)wParam, aItem); + + if (!PostAckToClient((HWND)wParam,hwnd,aItem,retval)) + { + goto errRtn; + } + break; + } + case WM_DDE_REQUEST: + { + intrDebugOut((DEB_ITRACE, + "DDIC: WM_DDE_REQUEST hwnd=%x aItem=%x(%ws) cfFormat=%x\n", + hwnd, + aItem, + wAtomName(aItem), + (USHORT)LOWORD(pDocData->lParam))); + + retval = lpclient->RequestData ((HWND)wParam, + aItem, + LOWORD(pDocData->lParam), + (HANDLE FAR *)&hdata); + + if (retval == NOERROR) + { + // post the data message and we are not asking for any + // acknowledge. + + intrDebugOut((DEB_ITRACE, + "DDIC: posting WM_DDE_DATA\n")); + + LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_DATA,hdata,aItem); + if (!PostMessageToClient ((HWND)wParam, WM_DDE_DATA, (UINT) hwnd,lp)) + { + // hdata will be freed by the client because fRelease + // was set to true by MakeDdeData (called by RequestData) + + DDEFREE(WM_DDE_DATA,lp); + goto errRtn; + } + } + else + { + if (!PostAckToClient((HWND)wParam,hwnd,aItem,retval)) + { + goto errRtn; + } + } + break; + } + default: + // + // Whoops, this is very bad. We should never get here. + // + intrAssert(!"Unknown MSG in DocWndProc: Very Bad indeed"); + + + } + +exitRtn: + intrDebugOut((DEB_ITRACE, + "0 _OUT DocDispatchIncomingCall pDocData(%x) hr = 0\n", + pDocData)); + + return(NOERROR); +errRtn: + intrDebugOut((DEB_IERROR, + "***** ERROR DDIC pDocData(%x) Post ACK failed. \n", + pDocData)); + + if (aItem != NULL) + { + GlobalDeleteAtom (aItem); + } + goto exitRtn; +} + + +//+--------------------------------------------------------------------------- +// +// Function: DocWndProc +// +// Synopsis: Document Window Procedure +// +// Effects: Processes DDE messages for a document window. +// +// Arguments: [hwnd] -- +// [msg] -- +// [wParam] -- +// [lParam] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 6-05-94 kevinro Commented/cleaned +// +// Notes: +// +// When running in a VDM, it is possible that this window was dispatched +// without having a full window handle. This happens when the getmessage +// was dispatched from 16-bit. Therefore, we need to convert the hwnd to +// a full hwnd before doing any comparision functions. +// +//---------------------------------------------------------------------------- +STDAPI_(LRESULT) DocWndProc ( +HWND hwndIn, +UINT msg, +WPARAM wParam, +LPARAM lParam +) +{ + + // + // Since this is the DocWndProc, we aren't going to initialize + // any of the local variables. This function is called as a WNDPROC, + // which is pretty often. + // + + DOCDISPATCHDATA docData; + LPCLIENT lpclient; + WORD status=0; + HANDLE hdata; + ATOM aItem; + HRESULT retval; + LPOLEOBJECT lpoleObj; + HWND hwnd; + DebugOnly (HWND hwndClient;) + + // REVIEW: We need to take care of the bug, related to + // Excel. Excel does the sys level connection and sends + // terminates immediately before making the connection + // to the doc level. If we send release to classfactory + // app may revoke the classfactory. + + + // REVIEW: It may not be necessary to do the blocking. + // ReVIEW: For fixing the ref count right way for + // CreateInstance Vs. WM_DDE_INIT + +#ifdef LATER + if (AddMessage (hwnd, msg, wParam, lParam, WT_DOC)) + return 0L; +#endif + + switch (msg){ + + case WM_CREATE: + intrDebugOut((DEB_ITRACE, + "DocWndProc: CreateWindow hwndIn=%x\n", + hwndIn)); + break; + + + case WM_DDE_INITIATE: + hwnd = ConvertToFullHWND(hwndIn); + intrAssert(IsWindowValid(hwnd)); + lpclient = (LPCLIENT)GetWindowLong (hwnd, 0); + + intrDebugOut((DEB_ITRACE, + "DocWndProc: WM_DDE_INITIATE hwnd=%x\n", + hwnd)); + + ChkC(lpclient); + + + // REVIEW: We may not allow initiates to get thru + // while we are waiting for terminates. So, this case + // may not arise + + // Need to verify that m_pCI is not NULL during incoming + // calls from the client. + // + if (lpclient->m_pCallData) + { + intrDebugOut((DEB_ITRACE, + "DocWndProc: No initiates while waiting on terminate\n")); + + break; + } + // if we are the document then respond. + + if (! (lpclient->m_aItem == (ATOM)(HIWORD(lParam)))) + { + break; + } + + // We can enterain this client. Put this window in the client list + // and acknowledge the initiate. + + if (!AddClient ((LPHANDLE)&lpclient->m_hcli, (HWND)wParam, (HWND)wParam)) + { + break; + } + + + // post the acknowledge + DuplicateAtom (LOWORD(lParam)); + DuplicateAtom (HIWORD(lParam)); + SSSendMessage ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, lParam); + + lpclient->m_cClients++; + lpclient->m_fCreatedNotConnected = FALSE; + lpoleObj = lpclient->m_lpoleObj; + + // we have added an addref because of createinstance. + + if (lpclient->m_bCreateInst) + { + lpclient->m_bCreateInst = FALSE; + } + + return 1L; // fAckSent + break; + + + case WM_DDE_EXECUTE: + { + hwnd = ConvertToFullHWND(hwndIn); + intrAssert(IsWindowValid(hwnd)); + lpclient = (LPCLIENT)GetWindowLong (hwnd, 0); + + hdata = GET_WM_DDE_EXECUTE_HDATA(wParam,lParam); + intrDebugOut((DEB_ITRACE, + "DocWndProc: WM_DDE_EXECUTE hwnd=%x hdata=%x\n", + hwnd, + hdata)); + + ChkC(lpclient); + +#ifdef FIREWALLS + // find the client in the client list. + hwndClient = FindClient (lpclient->m_hcli, (HWND)wParam, FALSE); + AssertSz (hwndClient, "Client is missing from the server"); +#endif + if (!IsWindowValid ((HWND)wParam) || lpclient->m_pCallData) + { + if (lpclient->m_pCallData) + { + // This means the terminate has already been sent + // to this window (from AdviseSink::OnClose) so + // we can ignore the StdCloseDocument. + } + else + { + intrAssert(!"Execute received from dead sending window"); + } + // Since we are not sending an ACK, the sender will not + // have the chance to free the hCommands handle. + DDEFREE(WM_DDE_ACK,lParam); + // GlobalFree (hdata); + break; + } + + // + // Fill in the used items in DocData + // + docData.hwnd = hwnd; + docData.msg = msg; + docData.wParam = wParam; + docData.hdata = hdata; + docData.lpclient = lpclient; + + retval = DocHandleIncomingCall(&docData); + + // + // If error return, then we didn't call DocDispatchIncomingCall + // and therefore need to send a NACK + // + if (retval != NOERROR) + { + lpclient->SendExecuteAck (retval); + } + break; + } + case WM_DDE_TERMINATE: + hwnd = ConvertToFullHWND(hwndIn); + intrAssert(IsWindowValid(hwnd)); + lpclient = (LPCLIENT)GetWindowLong (hwnd, 0); + + intrDebugOut((DEB_ITRACE, + "DocWndProc: WM_DDE_TERMINATE hwnd=%x\n", + hwnd)); + + ChkC(lpclient); + + // + // If m_pCallData, then we are are waiting for a terminate, which + // means we generated the original terminate message. If + // this is so, then we are waiting for a reply to the + // terminate. Set the AckState and break; + // + if (lpclient->m_pCallData) + { + intrAssert(lpclient->m_pCallControl != NULL); + if (lpclient->m_pCallControl != NULL) + { + lpclient->m_pCallControl->SetCallState(lpclient->m_pCallData, + SERVERCALLEX_ISHANDLED, + NOERROR); + } + break; + } + + +#ifdef _DEBUG + // find the client in the client list. + hwndClient = (HWND)FindClient (lpclient->m_hcli,(HWND)wParam, FALSE); + AssertSz(hwndClient, "Client is missing from the server"); +#endif + AssertIsDoc (lpclient); + Assert (lpclient->m_cClients > 0); + lpclient->m_cClients--; + + // Necessary safety bracket + lpclient->m_pUnkOuter->AddRef(); + + // terminate has to be handled always + // The DocHandleIncomingCall() routine will set the + // calltype to be CALLTYPE_ASYNC + // async calls are never rejected + + docData.hwnd = hwnd; + docData.msg = msg; + docData.wParam = wParam; + docData.lpclient = lpclient; + + retval = DocHandleIncomingCall(&docData); + + intrAssert(retval == NOERROR); + + // Necessary safety bracket + lpclient->m_pUnkOuter->Release(); + break; + + case WM_DESTROY: + + intrDebugOut((DEB_ITRACE, + "DocWndProc: WM_DESTROY\n")); + break; + + case WM_DDE_POKE: + { + hwnd = ConvertToFullHWND(hwndIn); + intrAssert(IsWindowValid(hwnd)); + lpclient = (LPCLIENT)GetWindowLong (hwnd, 0); + hdata = GET_WM_DDE_POKE_HDATA(wParam,lParam); + aItem = GET_WM_DDE_POKE_ITEM(wParam,lParam); + ChkC(lpclient); + + if (!IsWindowValid ((HWND) wParam) || lpclient->m_pCallData) + { + // The sending window is invalid or we have already sent a + // TERMINATE to it (as indicated by m_pCI != NULL). + // We cannot ACK the message, so we must free any + // handles or atoms. + Warn ("Ignoring message"); + + FreePokeData (hdata); +LDeleteAtom: + + if (aItem != NULL) + { + GlobalDeleteAtom (aItem); + } + break; + } + + docData.hwnd = hwnd; + docData.msg = msg; + docData.wParam = wParam; + docData.hdata = hdata; + docData.aItem = aItem; + docData.lpclient = lpclient; + + retval = DocHandleIncomingCall(&docData); + if (retval != NOERROR) + { + SET_MSG_STATUS (retval, status); + + // !!! If the fRelease is false and the post fails + // then we are not freeing the hdata. Are we supposed to + + // REVIEW: The assumption is + LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem); + if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (UINT) hwnd,lp)) + { + DDEFREE(WM_DDE_ACK,lp); + goto LDeleteAtom; + } + } + // johannp: set the busy bit here in the status word + break; + } + + + case WM_DDE_ADVISE: + { + hwnd = ConvertToFullHWND(hwndIn); + intrAssert(IsWindowValid(hwnd)); + lpclient = (LPCLIENT)GetWindowLong (hwnd, 0); + HANDLE hOptions = GET_WM_DDE_ADVISE_HOPTIONS(wParam,lParam); + aItem = GET_WM_DDE_ADVISE_ITEM(wParam,lParam); + + ChkC(lpclient); + if (!IsWindowValid ((HWND)wParam) || lpclient->m_pCallData) + { +AdviseErr: + Warn ("Ignoring advise message"); + // + // GlobalFree wants a handle, we are giving it a DWORD. + // + GlobalFree (hOptions); + break; + } + docData.hwnd = hwnd; + docData.msg = msg; + docData.wParam = wParam; + docData.hdata = hOptions; + docData.aItem = aItem; + docData.lpclient = lpclient; + + retval = DocHandleIncomingCall(&docData); + + if (retval != NOERROR) + { + SET_MSG_STATUS (retval, status); + + LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem); + + if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (UINT) hwnd,lp)) + { + DDEFREE(WM_DDE_ACK,lp); + goto AdviseErr; + } + } + break; + } + case WM_DDE_UNADVISE: + { + hwnd = ConvertToFullHWND(hwndIn); + intrAssert(IsWindowValid(hwnd)); + lpclient = (LPCLIENT)GetWindowLong (hwnd, 0); + + aItem = HIWORD(lParam); + ChkC(lpclient); + if (!IsWindowValid ((HWND)wParam) || lpclient->m_pCallData) + { + goto LDeleteAtom; + } + docData.hwnd = hwnd; + docData.msg = msg; + docData.wParam = wParam; + docData.aItem = aItem; + docData.lpclient = lpclient; + + retval = DocHandleIncomingCall(&docData); + + if (retval != NOERROR) + { + SET_MSG_STATUS (retval, status); + LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem); + + if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (UINT) hwnd,lp)) + { + DDEFREE(WM_DDE_ACK,lp); + goto LDeleteAtom; + } + } + + break; + } + case WM_DDE_REQUEST: + { + hwnd = ConvertToFullHWND(hwndIn); + intrAssert(IsWindowValid(hwnd)); + lpclient = (LPCLIENT)GetWindowLong (hwnd, 0); + + aItem = HIWORD(lParam); + + ChkC(lpclient); + if (!IsWindowValid ((HWND) wParam) || lpclient->m_pCallData) + { + goto LDeleteAtom; + } + docData.hwnd = hwnd; + docData.msg = msg; + docData.wParam = wParam; + docData.lParam = lParam; + docData.aItem = aItem; + docData.lpclient = lpclient; + + retval = DocHandleIncomingCall(&docData); + if (retval != NOERROR) + { + if (retval == RPC_E_DDE_BUSY) + { + status = 0x4000; + } + else + { + status = 0; // negative acknowledge + } + + LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_ACK,status,aItem); + // if request failed, then acknowledge with error. + if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (UINT) hwnd,lp)) + { + DDEFREE(WM_DDE_ACK,lp); + goto LDeleteAtom; + } + } + break; + } + default: + return SSDefWindowProc (hwndIn, msg, wParam, lParam); + + } + + return 0L; + +} + + + + +INTERNAL_(void) CDefClient::SendExecuteAck + (HRESULT hresult) +{ + AssertIsDoc (this); + WORD status = NULL; + SET_MSG_STATUS (hresult, status); + + m_ExecuteAck.f = FALSE; + + LPARAM lParam = MAKE_DDE_LPARAM (WM_DDE_ACK,status, + (UINT) m_ExecuteAck.hdata); + // Post the acknowledge to the client + if (!PostMessageToClient (m_ExecuteAck.hwndFrom, WM_DDE_ACK, + (UINT) m_ExecuteAck.hwndTo, lParam)) + { + Assert (0); + // the window either died or post failed, delete the data + DDEFREE (WM_DDE_ACK,lParam); + GlobalFree (m_ExecuteAck.hdata); + } +} + + + +//DocExecute: Interprets the execute command for the +//document conversation. + + +INTERNAL CDefClient::DocExecute + (HANDLE hdata) +{ + + ATOM acmd; + BOOL fShow; + BOOL fActivate; + + HANDLE hdup = NULL; + HRESULT retval = ReportResult(0, S_OOM, 0, 0); + + LPSTR lpitemname; + LPSTR lpopt; + LPSTR lpnextarg; + LPSTR lpdata = NULL; + LPSTR lpverb = NULL; + INT verb; + WORD wCmdType; + + ChkC(this); + + intrDebugOut((DEB_ITRACE, + "%p _IN CDefClient::DocExecute(hdata=%x)\n", + this, + hdata)); + + // !!!Can we modify the string which has been passed to us + // rather than duplicating the data. This will get some speed + // and save some space. + + if(!(hdup = UtDupGlobal(hdata,GMEM_MOVEABLE))) + goto errRtn; + + if (!(lpdata = (LPSTR)GlobalLock (hdup))) + goto errRtn; + + retval = ReportResult(0, RPC_E_DDE_SYNTAX_EXECUTE, 0, 0); + + intrDebugOut((DEB_ITRACE, + "%p _IN CDefClient::DocExecute command=(%s)\n", + this, + lpdata)); + + if(*lpdata++ != '[') // commands start with the left sqaure bracket + goto errRtn; + + // scan the command and scan upto the first arg. + if (!(wCmdType = ScanCommand(lpdata, WT_DOC, &lpnextarg, &acmd))) + goto errRtn; + + if (wCmdType == NON_OLE_COMMAND) { + +#ifdef LATER + if (lpsrvr = (LPSRVR) GetWindowLong (GetParent (hwnd), 0)) { + if (!UtilQueryProtocol (lpsrvr->aClass, PROTOCOL_EXECUTE)) + retval = OLE_ERROR_PROTOCOL; + else { +#ifdef FIREWALLS + if (!CheckPointer (lpoledoc, WRITE_ACCESS)) + AssertSz (0, "Invalid LPOLESERVERDOC"); + else if (!CheckPointer (lpoledoc->lpvtbl, WRITE_ACCESS)) + AssertSz (0, "Invalid LPOLESERVERDOCVTBL"); + else + AssertSz (lpoledoc->lpvtbl->Execute, + "Invalid pointer to Execute method"); +#endif + + retval = (*lpoledoc->lpvtbl->Execute) (lpoledoc, hdata); + } + + } +#endif + AssertSz(0, "Doc level execute is being called"); + + goto errRtn; + } + + + ////////////////////////////////////////////////////////////////////////// + // + // [StdCloseDocument] + // + ////////////////////////////////////////////////////////////////////////// + if (acmd == aStdClose){ + + LPCLIENT lpclient=NULL; + // if not terminated by NULL error + if (*lpnextarg) + goto errRtn; + + if ((retval = FindItem (NULL, (LPCLIENT FAR *)&lpclient)) != NOERROR) + return retval; + + + lpclient->m_fGotStdCloseDoc = TRUE; + retval = lpclient->m_lpoleObj->Close (OLECLOSE_SAVEIFDIRTY); + goto end; + } + + ////////////////////////////////////////////////////////////////////////// + // + // [StdDoVerbItem("itemname", verb, BOOL, BOOL] + // + ////////////////////////////////////////////////////////////////////////// + if (acmd == aStdDoVerbItem){ + lpitemname = lpnextarg; + + if(!(lpverb = ScanArg(lpnextarg))) + goto errRtn; + + + if(!(lpnextarg = ScanNumArg(lpverb, &verb))) + goto errRtn; + +#ifdef FIREWALLS + AssertSz (verb < 9 , "Unexpected verb number"); +#endif + + // now scan the show BOOL + + if (!(lpnextarg = ScanBoolArg (lpnextarg, (BOOL FAR *)&fShow))) + goto errRtn; + + fActivate = FALSE; + + // if activate BOOL is present, scan it. + + if (*lpnextarg) { + if (!(lpnextarg = ScanBoolArg (lpnextarg, (BOOL FAR *)&fActivate))) + goto errRtn; + } + + if (*lpnextarg) + goto errRtn; + + if (m_fEmbed) + { + // This is a totally bogus call to SetHostNames whose only + // purpose is to notify the server that this is an embedded + // (not linked) object. + if (!m_fDidRealSetHostNames) + { + Puts ("Bogus call to SetHostNames before DoVerb\r\n"); + m_lpoleObj->SetHostNames (OLESTR("Container"), OLESTR("Object")); + } + } + // REVIEW: We are assuming that calling the Docdoverb method + // will not post any more DDE messahes. + + retval = DocDoVerbItem (lpitemname, verb, fShow, !fActivate); + goto end; + } + + + + + + ////////////////////////////////////////////////////////////////////////// + // + // [StdShowItem("itemname"[, "true"])] + // + ////////////////////////////////////////////////////////////////////////// + if (acmd != aStdShowItem) + goto errRtn; + + lpitemname = lpnextarg; + + if(!(lpopt = ScanArg(lpitemname))) + goto errRtn; + + // Now scan for optional parameter. + + fActivate = FALSE; + + if (*lpopt) { + + if(!(lpnextarg = ScanBoolArg (lpopt, (BOOL FAR *)&fActivate))) + goto errRtn; + + if (*lpnextarg) + goto errRtn; + + + } + + if (m_fEmbed) + { + // This is a totally bogus call to SetHostNames whose only + // purpose is to notify the server that this is an embedded + // (not linked) object. + // REVIEW LINK + if (!m_fDidRealSetHostNames) + { + Puts ("Bogus call to SetHostNames before ShowItem\r\n"); + m_lpoleObj->SetHostNames (OLESTR("Container"), OLESTR("Object")); + } + } + + retval = DocShowItem (lpitemname, !fActivate); + +end: +errRtn: + if (lpdata) + GlobalUnlock (hdup); + + if (hdup) + GlobalFree (hdup); + + intrDebugOut((DEB_ITRACE, + "%p _OUT CDefClient::DocExecute(hdata=%x) hresult=%x\n", + this, + hdata, + retval)); + + return (HRESULT)retval; +} + + + +INTERNAL_(HRESULT) CDefClient::DocShowItem +( +LPSTR lpAnsiitemname, +BOOL fAct +) +{ + LPCLIENT lpclient; + HRESULT retval; + LPOLEOBJECT lpoleObj; + + ChkC(this); + WCHAR lpitemname[MAX_STR]; + + if (MultiByteToWideChar(CP_ACP,0,lpAnsiitemname,-1,lpitemname,MAX_STR) == FALSE) + { + Assert(!"Unable to convert characters"); + return(E_UNEXPECTED); + } + + if ((retval = FindItem (lpitemname, (LPCLIENT FAR *)&lpclient)) + != NOERROR) + return retval; + + ChkC(lpclient); + + lpoleObj = lpclient->m_lpoleObj; + + +#ifdef FIREWALLS1 + if (!CheckPointer (lpoleObj->lpvtbl, WRITE_ACCESS)) + AssertSz (0, "Invalid LPOLEOBJECTVTBL"); + else + AssertSz (lpoleObj->lpvtbl->DoVerb, + "Invalid pointer to DoVerb method"); +#endif + + // protocol sends false for activating and TRUE for not activating. + // for api send TRUE for avtivating and FALSE for not activating. + return lpclient->m_lpoleObj->DoVerb(OLEVERB_SHOW, NULL, NULL, NULL, NULL, NULL); +} + + + +INTERNAL_(HRESULT) CDefClient::DocDoVerbItem +( +LPSTR lpAnsiitemname, +WORD verb, +BOOL fShow, +BOOL fAct +) +{ + LPCLIENT lpclient; + HRESULT retval; + + WCHAR lpitemname[MAX_STR]; + + if (MultiByteToWideChar(CP_ACP,0,lpAnsiitemname,-1,lpitemname,MAX_STR) == FALSE) + { + Assert(!"Unable to convert characters"); + return(E_UNEXPECTED); + } + + ChkC(this); + Puts ("DefClient::DocDoVerbItem\r\n"); + if ((retval = FindItem (lpitemname, (LPCLIENT FAR *)&lpclient)) + != NOERROR) + return retval; + ChkC(lpclient); + +#ifdef FIREWALLS1 + if (!CheckPointer (lpclient->lpoleObj->lpvtbl, WRITE_ACCESS)) + AssertSz (0, "Invalid LPOLEOBJECTVTBL"); + else + AssertSz (lpclient->lpoleObj->lpvtbl->DoVerb, + "Invalid pointer to DoVerb method"); +#endif + + // pass TRUE to activate and False not to activate. Differnt from + // protocol. + + retval = lpclient->m_lpoleObj->DoVerb(verb, NULL, &m_OleClientSite, NULL, NULL, NULL); + // Apparently an obsolete version of Lotus Notes is the only + // container (other than Cltest) that sets fShow=FALSE + if (!fShow && lpclient->m_lpoleObj && lpclient->m_fEmbed) + lpclient->m_lpoleObj->DoVerb(OLEIVERB_HIDE, NULL, &m_OleClientSite, NULL, NULL, NULL); + return retval; +} + +INTERNAL CDefClient::DoInitNew() +{ + HRESULT hresult; + ATOM aClass; + LPPERSISTSTORAGE pPersistStg=NULL; + + hresult = m_lpoleObj->QueryInterface(IID_IPersistStorage, + (LPLPVOID)&pPersistStg); + if (hresult == NOERROR) + { + CLSID clsid; + RetZ (pPersistStg); + ErrRtnH (CreateILockBytesOnHGlobal ((HGLOBAL)NULL, + /*fDeleteOnRelease*/ TRUE, + &m_plkbytNative)); + ErrZS (m_plkbytNative, E_OUTOFMEMORY); + + ErrRtnH (StgCreateDocfileOnILockBytes + (m_plkbytNative, + grfCreateStg, 0, + &m_pstgNative)); + + ErrZS (m_pstgNative, E_OUTOFMEMORY); + + aClass = m_psrvrParent->m_cnvtyp == cnvtypTreatAs ? m_psrvrParent->m_aOriginalClass + : m_psrvrParent->m_aClass; + // Write appropriate class tag + ErrZS (CLSIDFromAtom (aClass,(LPCLSID)&clsid), + REGDB_E_CLASSNOTREG); + ErrRtnH (WriteClassStg (m_pstgNative, clsid)); + + // Provide server with a storage to use for its persistent + // storage, i.e., native data. We remember this IStorage and the + // ILockBytes it is built on. + ErrRtnH (pPersistStg->InitNew(m_pstgNative)); + m_fGotEditNoPokeNativeYet = FALSE; + + // Now that we have initialized the object, we are allowed to + // set the client site, and advise. + ErrRtnH (SetClientSite()); + + // This is for Packager, in particular. If client does not advise + // on any data, we still need to do an OLE advise so we can get + // OnClose notifications. + DoOle20Advise (OLE_CLOSED, (CLIPFORMAT)0); + } + else + { + AssertSz (0, "Can't get IPersistStorage from OleObj\r\n"); + } + + m_fEmbed = TRUE; + +errRtn: + if (pPersistStg) + pPersistStg->Release(); + return hresult; +} + + +// FreePokeData: Frees the poked dats. +INTERNAL_(void) FreePokeData +( +HANDLE hdde +) +{ + DDEPOKE FAR * lpdde; + Puts ("FreePokeData\r\n"); + + if (hdde) { + if (lpdde = (DDEPOKE FAR *) GlobalLock (hdde)) { + GlobalUnlock (hdde); + FreeGDIdata (*(LPHANDLE)lpdde->Value, lpdde->cfFormat); + } + + GlobalFree (hdde); + } +} + + + +// Returns TRUE if GDI format else returns FALSE + +INTERNAL_(BOOL) FreeGDIdata +( +HANDLE hData, +CLIPFORMAT cfFormat +) +{ + Puts ("FreeGDIData\r\n"); + if (cfFormat == CF_METAFILEPICT) { + LPMETAFILEPICT lpMfp; + + if (lpMfp = (LPMETAFILEPICT) GlobalLock (hData)) { + GlobalUnlock (hData); + DeleteMetaFile (lpMfp->hMF); + } + + GlobalFree (hData); + } + else if (cfFormat == CF_BITMAP) + DeleteObject (hData); + else if (cfFormat == CF_DIB) + GlobalFree (hData); + else + return FALSE; + + return TRUE; +} diff --git a/private/ole32/com/remote/dde/server/item.cxx b/private/ole32/com/remote/dde/server/item.cxx new file mode 100644 index 000000000..f268cdbcc --- /dev/null +++ b/private/ole32/com/remote/dde/server/item.cxx @@ -0,0 +1,1210 @@ +/****************************** Module Header ******************************\ +* Module Name: Item.c Object(item) main module +* +* Purpose: Includes All the object releated routiens. +* +* Created: Oct 1990. +* +* Copyright (c) 1990, 1991 Microsoft Corporation +* +* History: +* Raor (../10/1990) Designed, coded +* +* +\***************************************************************************/ + + +#include "ole2int.h" +//#include "cmacs.h" +#include <dde.h> +#include "ddeatoms.h" +#include "ddedebug.h" +#include "srvr.h" +#include "itemutil.h" + +ASSERTDATA + + +// !!!change child enumeration. +// !!!No consistency in errors (Sometimes Bools and sometimes HRESULT). + + +//SearchItem: Searches for a given item in a document tree. +//If found, returns the corresponding client ptr. + +INTERNAL_(LPCLIENT) CDefClient::SearchItem +( +LPOLESTR lpitemname +) + +{ + ATOM aItem; + LPCLIENT lpclient; + + ChkC(this); + Assert (m_pdoc==this); + Assert (m_bContainer); + + Puts ("DefClient::SearchItem\r\n"); + // If the item passed is an atom, get its name. + if (!HIWORD(lpitemname)) + aItem = (ATOM) (LOWORD((DWORD)lpitemname)); + else if (!lpitemname[0]) + aItem = NULL; + else + aItem = GlobalFindAtom (lpitemname); + + // walk thru the items list and mtach for the itemname. + lpclient = this; + + while (lpclient) { + ChkC(lpclient); + if (lpclient->m_aItem == aItem) + return lpclient; + // The NULL item is the client that is a container (the whole doc). + // REVIEW: jasonful + if (lpclient->m_bContainer && aItem==NULL) + return lpclient; + lpclient = lpclient->m_lpNextItem; + } + + Puts ("SearchItem failed\r\n"); + return NULL; + +} + + + +// FindItem: Given the itemname and the doc obj ptr, +// searches for the the item (object) in the document tree. +// Items are lonked to the doc obj. + +INTERNAL_(HRESULT) CDefClient::FindItem +( +LPOLESTR lpitemname, +LPCLIENT FAR * lplpclient +) +{ + LPCLIENT lpclient; + WCHAR buf[MAX_STR]; + + Puts ("DefClient::FindItem "); Puts (lpitemname); Putn(); + ChkC(this); + + if (lpclient = SearchItem (lpitemname)) { + // we found the item window + + ChkC(lpclient); + *lplpclient = lpclient; + return NOERROR; + + } + + if (!HIWORD(lpitemname)){ + if (LOWORD(lpitemname)) + GlobalGetAtomName ((ATOM)LOWORD((DWORD)lpitemname), + buf, MAX_STR); + else + buf[0] = NULL; + + lpitemname = buf; + } + + // Item (object)window is not created yet. Let us create one. + return RegisterItem (lpitemname, lplpclient, TRUE); +} + + + +//RegisterItem: Given the document handle and the item string +//creates item with the given name in the doc obj list.. + +INTERNAL CDefClient::RegisterItem + (LPOLESTR lpitemname, + LPCLIENT FAR * lplpclient, + BOOL bSrvr) +{ + LPCLIENT pitemNew = NULL; + HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0); + LPOLEOBJECT lpoleObj = NULL; + LPOLEITEMCONTAINER lpcontainer; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::RegisterItem(%ws)\n", + this,WIDECHECK(lpitemname))); + ChkC(this); + AssertIsDoc(this); + *lplpclient = NULL; + + ErrZS (pitemNew = new CDefClient(NULL), E_OUTOFMEMORY); + + pitemNew->m_bTerminate = FALSE; + pitemNew->m_bContainer = FALSE; // not a container, i.e.,document + + + // Set containing document + pitemNew->m_pdoc = this; + m_pUnkOuter->AddRef(); // item keeps its document alive + // Corresponding Release is in CDefClient::~CDefClient + + if (!HIWORD(lpitemname)) { + AssertSz (!bSrvr, "invalid lpitemname in RegisterItem\r\n"); + pitemNew->m_aItem = LOWORD((DWORD)lpitemname); + } + else if (!lpitemname[0]) + pitemNew->m_aItem = NULL; + else + pitemNew->m_aItem = wGlobalAddAtom (lpitemname); + + lpoleObj = m_lpoleObj; + + // Call the server if the item is not one of the standard items. + if (bSrvr) { + + // Call the server app for container interface + hresult = lpoleObj->QueryInterface (IID_IOleItemContainer, (LPVOID FAR *)&lpcontainer); + + if (hresult != NOERROR) + { + intrDebugOut((DEB_IERROR, + "%x ::RegisterItem(%ws) No IOleContainer intr\n", + this,WIDECHECK(lpitemname))); + goto errRtn; + } + + hresult = lpcontainer->GetObject(lpitemname, BINDSPEED_INDEFINITE, 0, + IID_IOleObject, (LPLPVOID)&pitemNew->m_lpoleObj); + + if (hresult != NOERROR) + { + intrDebugOut((DEB_ERROR, + "IOleItemContainer::GetObject(%ws,...) failed (hr=%x)\n", + lpitemname, + hresult)); + } + + lpcontainer->Release (); + if (hresult != NOERROR) + goto errRtn; + + hresult = pitemNew->m_lpoleObj->QueryInterface (IID_IDataObject, (LPLPVOID) + &pitemNew->m_lpdataObj); + + if (hresult != NOERROR) + { + intrDebugOut((DEB_ERROR, + "::QueryInterface(IID_IDataObject) failed (hr=%x)\n", + hresult)); + pitemNew->m_lpoleObj->Release(); + goto errRtn; + } + + + // This is for Packager, in particular. If client does not advise + // on any data, we still need to do an OLE advise so we can get + // OnClose notifications. + pitemNew->DoOle20Advise (OLE_CLOSED, (CLIPFORMAT)0); + } + + + + // This keeps the CDefClient alive until _we_ are done with it + // The corresponding Release is in CDefClient::Revoke + pitemNew->m_pUnkOuter->AddRef(); + + pitemNew->m_lpNextItem = m_lpNextItem; + pitemNew->m_hwnd = m_hwnd; // set the window handle to + // same as the doc level window + + m_lpNextItem = pitemNew; + *lplpclient = pitemNew; + + hresult = NOERROR; + goto exitRtn; + +errRtn: + if (pitemNew) { + delete pitemNew; + } + +exitRtn: + intrDebugOut((DEB_ITRACE, + "%x CDefClient::RegisterItem(%ws) hresult=%x\n", + this,WIDECHECK(lpitemname),hresult)); + + + return(hresult); +} + + + +// Return NOERROR if "this" document has no items which have connections +// (client windows). +// +INTERNAL CDefClient::NoItemConnections (void) +{ + PCLINFO pclinfo = NULL; + HANDLE hcliPrev = NULL; + HANDLE hcli; + PCLILIST pcli; + HANDLE *phandle; + + ChkCR (this); + AssertIsDoc (this); + LPCLIENT pitem; + for (pitem = m_lpNextItem; + pitem; + pitem = pitem->m_lpNextItem) + { + ChkCR (pitem); + if (pitem->m_aItem == aStdDocName) + continue; + hcli = pitem->m_hcliInfo; + while (hcli) + { + if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL) + return ResultFromScode (S_FALSE); + + phandle = (HANDLE *) (pcli->info); + while (phandle < (HANDLE *)(pcli + 1)) + { + if (*phandle) + { + LocalUnlock (hcli); + return ResultFromScode (S_FALSE); + } + else + { + phandle++; + phandle++; + } + } + + hcliPrev = hcli; + hcli = pcli->hcliNext; + LocalUnlock (hcliPrev); + } + } + return NOERROR; +} + + + +INTERNAL_(void) CDefClient::DeleteAdviseInfo (void) +{ + + + PCLINFO pclinfo = NULL; + HANDLE hcliPrev = NULL; + PCLILIST pcli; + HANDLE *phandle; + HANDLE hcli; + HANDLE hcliInfo; + + Puts ("DefClient::DeleteAdviseInfo\r\n"); + ChkC(this); + hcli = m_hcliInfo; + while (hcli) { + if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL) + return; + + phandle = (HANDLE *) (pcli->info); + while (phandle < (HANDLE *)(pcli + 1)) { + if (*phandle) { + *phandle++ = 0; + + // delete the printer dev info block + if(pclinfo = (PCLINFO)LocalLock ((hcliInfo = *phandle++))){ + if(pclinfo->hdevInfo) + GlobalFree (pclinfo->hdevInfo); + + LocalUnlock (hcliInfo); + // no free if lock failed + LocalFree (hcliInfo); + } + } else { + phandle++; + phandle++; + + } + } + + hcliPrev = hcli; + hcli = pcli->hcliNext; + LocalUnlock (hcliPrev); + LocalFree (hcliPrev); // free the block; + } + m_hcliInfo = NULL; +} + + + +//DeleteFromItemsList: Deletes a client from the object lists of +//all the objects of a given document. Thie client possibly +//is terminating the conversation with our doc window. +// +INTERNAL_(void) CDefClient::DeleteFromItemsList + (HWND hwndClient) +{ + HANDLE hclinfo; + PCLINFO pclinfo; + LPCLIENT lpclient; + LPCLIENT FAR* ppitemLast = NULL; + BOOL fRevokedDoc = FALSE; + static int staticcounter; + int counter = ++staticcounter; + + Puts ("DefClient::DeleteFromItemsList "); Puti(counter); Putn(); + AssertIsDoc(this); + lpclient = this; + ppitemLast = &m_lpNextItem; + while (lpclient) + { + ChkC(lpclient); + BOOL fDoc = (lpclient==this); + if (fDoc) + { + AssertIsDoc (lpclient); + // Remove window from doc's master list + HWND hwnd = (HWND) FindClient (lpclient->m_hcli, hwndClient, /*fDelete*/TRUE); + Assert (hwnd==hwndClient); + } + + hclinfo = FindClient (lpclient->m_hcliInfo, hwndClient, /*fDelete*/TRUE); + LPCLIENT pitemNext = lpclient->m_lpNextItem; + + // We must make sure no other client is connected (linked) + // to this item before deleting. + if (!fDoc && AreNoClients (lpclient->m_hcliInfo)) + { + Assert (ppitemLast); + if (ppitemLast && !fDoc) + { + // Remove from linked list + *ppitemLast = lpclient->m_lpNextItem; + } + fRevokedDoc |= fDoc; + lpclient->Revoke (); + } + else + { + ppitemLast = &(lpclient->m_lpNextItem); + } + if (hclinfo) + { + if(pclinfo = (PCLINFO)LocalLock (hclinfo)) + { + if(pclinfo->hdevInfo) + GlobalFree (pclinfo->hdevInfo); + LocalUnlock (hclinfo); + } + LocalFree (hclinfo); + } + lpclient = pitemNext; + } + + // Handle invisible update + if (!fRevokedDoc && !m_fEmbed //&& !m_fGotDdeAdvise + && NOERROR ==NoItemConnections() + && AreNoClients (m_hcliInfo) + && AreNoClients (m_hcli) ) + { + ChkC (this); + Assert (m_lpoleObj); + Assert (m_lpdataObj); + ReleaseObjPtrs(); + } + + Puts ("DefClient::DeleteFromItemsList Done "); Puti(counter); Putn(); +} + + +INTERNAL_(void) CDefClient::RemoveItemFromItemList + (void) +{ + // Make sure it's an item + Assert (m_pdoc != this && !m_bContainer); + + LPCLIENT lpclient = m_pdoc; + ChkC (lpclient); + LPCLIENT FAR* ppitemLast = &(m_pdoc->m_lpNextItem); + + while (lpclient) + { + ChkC(lpclient); + if (lpclient==this) + { + // Remove from linked list + *ppitemLast = lpclient->m_lpNextItem; + break; + } + ppitemLast = &(lpclient->m_lpNextItem); + lpclient = lpclient->m_lpNextItem; + } + Revoke(); +} + + + + +INTERNAL_(void) CDefClient::ReleaseAllItems () +{ + LPCLIENT lpclient; + + Puts ("DefClient::ReleaseAllItems\r\n"); + AssertIsDoc(this); + + // leave the doc level object. + lpclient = m_lpNextItem; + + while (lpclient) + { + ChkC(this); + LPCLIENT pitemNext = lpclient->m_lpNextItem; + lpclient->Revoke(); + lpclient = pitemNext; + } + // After revoking all the items, we can't keep any refernces to them. + m_lpNextItem = NULL; +} + + + +INTERNAL_(void) CDefClient::DeleteAllItems () +{ + LPCLIENT lpclient; + + Puts ("DefClient::DeleteAllItems\r\n"); + AssertIsDoc(this); + + // leave the doc level object. + lpclient = m_lpNextItem; + + while (lpclient) + { + ChkC(lpclient); + if (ISATOM(lpclient->m_aItem)) + GlobalDeleteAtom (lpclient->m_aItem); + // Delete client advise info + lpclient->DeleteAdviseInfo (); + + lpclient = lpclient->m_lpNextItem; + } +} + + + + +// PokeData: Prepares and gives the data to the server app thru +// the SetData object method. + +INTERNAL CDefClient::PokeData(HWND hwndClient,ATOM aItem,HANDLE hPoke) +{ + HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0); + DDEPOKE FAR * lpPoke = NULL; + int format; + BOOL fRelease = FALSE; + LPPERSISTSTORAGE pPersistStg=NULL; + FORMATETC formatetc; + STGMEDIUM medium; + + // Due to a C7 bug, do not use a structure initialization for STGMEDIUM + medium.tymed = TYMED_HGLOBAL; + medium.hGlobal = NULL; // invalid + medium.pUnkForRelease= NULL; + + intrDebugOut((DEB_ITRACE, + "%p CDefClient::PokeData(hwndClient=%x,aItem=%x,hPoke=%x)\n", + this,hwndClient,aItem,hPoke)); + + ChkC(this); + AssertIsDoc (this); + + + // Until now, m_aItem had been the client-generated (ugly) document name. + // Now it becomes the actual item name, which will almost always be NULL. + // Only in the TreatAs/ConvertTo case will it be non-NULL. + m_aItem = aItem; + + formatetc.cfFormat = 0; /* invalid */ + formatetc.ptd = m_ptd; + formatetc.lindex = DEF_LINDEX; + formatetc.dwAspect = DVASPECT_CONTENT; + formatetc.tymed = TYMED_HGLOBAL; + + ErrZS (hPoke && (lpPoke = (DDEPOKE FAR *) GlobalLock (hPoke)), + E_OUTOFMEMORY); + + format = formatetc.cfFormat = (UINT)(unsigned short)lpPoke->cfFormat; + Assert (format); + fRelease = lpPoke->fRelease; + + // We found the item. Now prepare the data to be given to the object + // MakeItemData returns a newly allocated handle. + if (!(medium.hGlobal = MakeItemData (lpPoke, hPoke, format))) + goto errRtn; + + // Change type acording to format (not that default has been set above) + if (format == CF_METAFILEPICT) + formatetc.tymed = medium.tymed = TYMED_MFPICT; + else + if (format == CF_BITMAP) + formatetc.tymed = medium.tymed = TYMED_GDI; + + // Now send the data to the object + + + if (formatetc.cfFormat==g_cfNative) + { + m_fGotEditNoPokeNativeYet = FALSE; + + // Cannot do SetData. Must do PersisStg::Load on an IStorage + // made from the native data, i.e., medium.hGlobal. + + Assert (m_plkbytNative==NULL); + ErrRtnH (CreateILockBytesOnHGlobal (medium.hGlobal, + /*fDeleteOnRelease*/TRUE, + &m_plkbytNative)); + + Assert (m_pstgNative==NULL); + + if (NOERROR==StgIsStorageILockBytes(m_plkbytNative)) + { + // This is a flattened 2.0 storage + ErrRtnH (StgOpenStorageOnILockBytes (m_plkbytNative, + (LPSTORAGE)NULL, + STGM_READWRITE| STGM_SHARE_EXCLUSIVE| STGM_DIRECT, + (SNB)NULL, + 0, + &m_pstgNative)); + } + else + { + // It is a raw 1.0 Native handle. + // This is the TreatAs/ ConvertTo case. + LPLOCKBYTES plkbyt = NULL; + Assert (m_psrvrParent->m_aOriginalClass); + + ErrRtnH (wCreateStgAroundNative (medium.hGlobal, + m_psrvrParent->m_aOriginalClass, + m_psrvrParent->m_aClass, + m_psrvrParent->m_cnvtyp, + m_aItem, + &m_pstgNative, + &plkbyt)); + + + Assert (m_plkbytNative); + if (m_plkbytNative) + { + // This should free the original native hGlobal also. + m_plkbytNative->Release(); + medium.hGlobal = NULL; + } + m_plkbytNative = plkbyt; + + } + + RetZ (m_pstgNative); + Assert (m_lpoleObj); + ErrRtnH (m_lpoleObj->QueryInterface (IID_IPersistStorage, + (LPLPVOID) &pPersistStg)); + hresult = pPersistStg->Load (m_pstgNative); + pPersistStg->Release(); + pPersistStg=NULL; + ErrRtnH (hresult); + + // Now that we have initialized the object, we can call SetClientSite + ErrRtnH (SetClientSite() ); + + // This is for Packager, in particular. If client does not advise + // on any data, we still need to do an OLE advise so we can get + // OnClose notifications. + ErrRtnH (DoOle20Advise (OLE_CLOSED, (CLIPFORMAT)0)); + } + else + { + if (m_fGotEditNoPokeNativeYet) + { + // We got StdEdit, but instead of getting Poke for native data, + // we got poke for someother format. So we want to generate + // InitNew() call for the object. + + ErrRtnH (DoInitNew()); // the function clears the flag + } + + // Not native format, do SetData + // Callee frees medium, i.e., the hglobal returned by MakeItemData + Assert (m_lpdataObj); + hresult = m_lpdataObj->SetData (&formatetc, &medium, TRUE); +#ifdef _DEBUG + if (hresult != NOERROR) + { + Puts ("****WARNING: SetData failed. cfFormat=="); + WCHAR sz[100]; + GetClipboardFormatName (formatetc.cfFormat, sz, 100); + Puts (sz); + Putn(); + } +#endif + // We free the data if server deos not return NOERROR. + // Otherwise server must've deleted it. + if (hresult == NOERROR) + medium.hGlobal = NULL; + } + + +errRtn: + GlobalUnlock (hPoke); + + if (fRelease && hPoke) + GlobalFree (hPoke); + +// Do NOT free medium.hGlobal, because it becomes the hGlobal on which +// m_plkbytNative (and therefore m_pstgNative) is based. +// It will be freed when m_plkbytNative is Release(). +// if (medium.hGlobal) +// ReleaseStgMedium(&medium); + + if (pPersistStg) + pPersistStg->Release(); + + return hresult; +} + + + +INTERNAL_(HRESULT) CDefClient::UnAdviseData + (HWND hwndClient, + ATOM aItem) +{ + WCHAR buf[MAX_STR]; + int options; + LPCLIENT lpclient; + HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0); + HANDLE hclinfo = NULL; + PCLINFO pclinfo = NULL; + + Puts ("DefClient::UnadviseData\r\n"); + ChkC(this); + + if (aItem == NULL) + { + buf[0] = NULL; + } + else + { + GlobalGetAtomName (aItem, buf, MAX_STR); + } + + // Scan for the advise options like "Close", "Save" etc + // at the end of the item. + + ErrRtnH (ScanItemOptions (buf, (int far *)&options)); + + // Now get the corresponding object. + ErrRtnH (FindItem (buf, (LPCLIENT FAR *)&lpclient)); + + // Find the client structure to be attached to the object. + if ((hclinfo = FindClient (lpclient->m_hcliInfo, hwndClient, FALSE)) == NULL || + (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL ) + { + hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0); + goto errRtn; + } + + pclinfo->options &= (~(0x0001 << options)); + +errRtn: + if (pclinfo) + LocalUnlock (hclinfo); + return hresult; + +} + + + +// AdviseStdItems: This routine takes care of the DDEADVISE for a +//particular object in given document. Creates a client strutcure +//and attaches to the property list of the object window. + +INTERNAL_(HRESULT) CDefClient::AdviseStdItems +( + +HWND hwndClient, +ATOM aItem, +HANDLE hopt, +BOOL FAR * lpfack +) +{ + + DDEADVISE FAR *lpopt; + HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0); + + + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::AdviseStdItems(hwndClient=%x,aItem=%x(%ws),hopt=%x)\n", + this, + hwndClient, + aItem, + wAtomName(aItem), + hopt)); + + ChkC(this); + ErrZS (lpopt = (DDEADVISE FAR *) GlobalLock (hopt), E_OUTOFMEMORY); + + AssertSz (aItem == aStdDocName, "AdviseStdItem is not Documentname"); + + *lpfack = lpopt->fAckReq; + hresult = (HRESULT)SetStdInfo (hwndClient, OLESTR("StdDocumentName"), NULL); + + + if (lpopt) + GlobalUnlock (hopt); + +errRtn: + + if (hresult == NOERROR) + { + // Rules say to free handle if ACK will be positive + GlobalFree (hopt); + } + Assert (hresult==NOERROR); + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::AdviseStdItems hresult=%x\n", + this, + hresult)); + + return hresult; +} + + + +//AdviseData: This routine takes care of the DDE_ADVISE for a +//particular object in given document. Creates a client strutcure +//and attaches to the property list of the object window. + +INTERNAL CDefClient::AdviseData +( +HWND hwndClient, +ATOM aItem, +HANDLE hopt, +BOOL FAR * lpfack +) +{ + DDEADVISE FAR *lpopt = NULL; + int format = NULL; + WCHAR buf[MAX_STR]; + OLE_NOTIFICATION options; + LPCLIENT lpclient; + HRESULT hresult = ReportResult(0, E_UNEXPECTED, 0, 0); + HANDLE hclinfo = NULL; + PCLINFO pclinfo = NULL; + BOOL fAllocatedClInfo = FALSE; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::AdviseData(hwndClient=%x,aItem=%x(%ws),hopt=%x)\n", + this, + hwndClient, + aItem, + wAtomName(aItem), + hopt)); + ChkC(this); + if (m_fGotEditNoPokeNativeYet) { + // We got StdEdit, but instead of getting Poke for native data, + // we got advise. So we want to generate InitNew() call for + // the object. + + DoInitNew(); // the function clears the flag + } + + m_fGotDdeAdvise = TRUE; + + ErrZS (lpopt = (DDEADVISE FAR *) GlobalLock (hopt), E_OUTOFMEMORY); + + if (!aItem) + buf[0] = NULL; + else + GlobalGetAtomName (aItem, buf, MAX_STR); + + // Scan for the advise options like "Close", "Save" etc + // at the end of the item. + + // ack flag should be set before the error return. Otherwise the + // the atom is getting deleted. + + *lpfack = lpopt->fAckReq; + ErrRtnH (ScanItemOptions (buf, (int far *)&options)); + + // Now get the corresponding item. + ErrRtnH (FindItem (buf, (LPCLIENT FAR *)&lpclient)); + + if (!IsFormatAvailable ((CLIPFORMAT)(unsigned short)lpopt->cfFormat)){ + hresult = ReportResult(0, DV_E_CLIPFORMAT, 0, 0); // this format is not supported; + goto errRtn; + } + + lpclient->DoOle20Advise (options, (CLIPFORMAT)(unsigned short)lpopt->cfFormat); + + + // Create the client structure to be attcahed to the object. + if (!(hclinfo = FindClient (lpclient->m_hcliInfo, hwndClient, FALSE))) + { + hclinfo = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (CLINFO)); + fAllocatedClInfo = TRUE; + } + + + if (hclinfo == NULL || (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL){ + hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0); + goto errRtn; + } + + // Remember the client window (Needed for sending DATA later on + // when the data change message comes from the server) + + pclinfo->hwnd = hwndClient; + if ((CLIPFORMAT)(unsigned short)lpopt->cfFormat == g_cfNative) + pclinfo->bnative = TRUE; + else + pclinfo->format = (CLIPFORMAT)(unsigned short)lpopt->cfFormat; + + // Remeber the data transfer options + pclinfo->options |= (1 << options) ; + + pclinfo->bdata = !lpopt->fDeferUpd; + LocalUnlock (hclinfo); + pclinfo = NULL; + + // if the entry exists already, delete it. + FindClient (lpclient->m_hcliInfo, hwndClient, /*fDelete*/TRUE); + + // Now add this client to item client list + // !!! This error recovery is not correct. + if(!AddClient ((LPHANDLE)&lpclient->m_hcliInfo, hwndClient, hclinfo)) + goto errRtn; + + +errRtn: + if (lpopt) + GlobalUnlock (hopt); + + if (pclinfo) + LocalUnlock (hclinfo); + + if (hresult==NOERROR) + { + // hresult==NOERROR iff we will send a postive ACK, so we must + // free the hOptions handle. + GlobalFree (hopt); + } + else + { + intrDebugOut((DEB_IERROR, + "%x ::AdviseData() failing.\n",this)); + // We free hclinfo because it was not stored in the item's + // client list via the AddClient just before the errRtn label. + if (hclinfo && fAllocatedClInfo) + LocalFree (hclinfo); + + } + + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::AdviseData() returns hresult = %x\n", + this, hresult)); + + return hresult; + +} + + + + + +INTERNAL_(BOOL) CDefClient::IsFormatAvailable + (CLIPFORMAT cfFormat) +{ + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::IsFormatAvailable(cfFormat=%x)\n", + this, cfFormat)); + + ChkC(this); + + BOOL f = ((cfFormat==g_cfNative) || UtIsFormatSupported (m_lpdataObj, DATADIR_GET, cfFormat)); + + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::IsFormatAvailable(cfFormat=%x) returning %x\n", + this, cfFormat,f)); + + return f; +} + + +//RequestData: Sends data in response to a DDE Request message. +// for agiven doc and an object. + +INTERNAL_(HRESULT) CDefClient::RequestData +( +HWND hwndClient, +ATOM aItem, +USHORT cfFormat, +LPHANDLE lphdde +) +{ + + HRESULT hresult = NOERROR; + LPCLIENT lpclient; + FORMATETC formatetc; + STGMEDIUM medium; + // Due to a C7 bug, do not use a structure initialization for STGMEDIUM + medium.tymed = TYMED_NULL; + medium.hGlobal = 0; + medium.pUnkForRelease= NULL; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::RequestData(hwndClient=%x,aItem=%x(%ws),cfFormat=%x,lphdde=%x)\n", + this, + hwndClient, + aItem, + wAtomName(aItem), + cfFormat, + lphdde)); + ChkC(this); + + // If edit environment Send data if we can + if (aItem == aEditItems) + { + hresult = RequestDataStd (aItem, lphdde); + goto exitRtn; + } + + hresult = FindItem ((LPOLESTR) MAKEINTATOM(aItem),(LPCLIENT FAR *)&lpclient); + if (hresult != NOERROR) + { + goto errRtn; + } + + ChkC (lpclient); + + formatetc.cfFormat = cfFormat; + formatetc.ptd = lpclient->m_ptd; + formatetc.lindex = DEF_LINDEX; + formatetc.dwAspect = DVASPECT_CONTENT; + formatetc.tymed = TYMED_HGLOBAL; + + + hresult = ReportResult(0, DV_E_FORMATETC, 0, 0); + if (!lpclient->IsFormatAvailable (formatetc.cfFormat)) + { + goto errRtn; + } + + + // Now ask the item for the given format data + + SendDevInfo (hwndClient); + + wSetTymed (&formatetc); + hresult = lpclient->GetData (&formatetc, &medium); + if (hresult != NOERROR) + { + intrDebugOut((DEB_IERROR, + "GetData returns hresult=%x\n", + hresult)); + goto errRtn; + } + if (medium.tymed & ~(TYMED_HGLOBAL | TYMED_MFPICT | TYMED_GDI)) + { + AssertSz (0, "Got a storage medium of type other than hGlobal"); + goto errRtn; + } + if (cfFormat == CF_METAFILEPICT) + { + ChangeOwner (medium.hGlobal); + } + + + // Duplicate the DDE data + // medium.hGlobal is freed by MakeDdeData or by the client once the + // DDE_DATA is posted with *lphdde. + if (MakeDDEData (medium.hGlobal, cfFormat, lphdde, TRUE)){ + // !!! Why do we have to duplicate the atom + DuplicateAtom (aItem); + hresult = NOERROR; + } + else + hresult = E_OUTOFMEMORY; + +errRtn: +exitRtn: + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::RequestData() returning %x\n", + this, hresult)); + + return hresult; +} + + + +// REVIEW: needs review. Item callvback has to be split + +// ItemCallback: Calback routine for the server to inform the +// data changes. When the change message is received, DDE data +// message is sent to each of the clients depending on the +// options. + +INTERNAL_(HRESULT) CDefClient::ItemCallBack +( + int msg, // notification message + LPOLESTR szNewName // for OLE_RENAMED notification +) +{ + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::ItemCallBack(msg=%x,szNewName=%x)\n", + this, + szNewName)); + + HRESULT hresult = NOERROR; + BOOL bSaved; + LPCLIENT lpclientRename; + LPCLIENT lpclient; + + ChkC(this); + + if (msg == OLE_RENAMED) { + + Assert (szNewName); + intrDebugOut((DEB_ITRACE, + "%x ::ItemCallBack(szNewName=(%ws))\n", + WIDECHECK(szNewName))); + + + if (!m_bContainer) + { + lpclient = (LPCLIENT)GetWindowLong (m_hwnd, 0); + Assert (lpclient==m_pdoc); + } + else + lpclient = this; + + Assert (lpclient->m_chk==chkDefClient); + + // Replace the internally-stored name + if (lpclient->m_aItem) + { + GlobalDeleteAtom (lpclient->m_aItem); + lpclient->m_aItem = wGlobalAddAtom (szNewName); + } + + + // find if any StdDocName item is present at all + if (lpclientRename = + lpclient->SearchItem ((LPOLESTR) MAKEINTATOM(aStdDocName))) + { + HANDLE hDdeData=NULL; + + // + // We have a new name in UNICODE. Need to create a new + // name in ANSI. + // + LPSTR lpName = CreateAnsiFromUnicode(szNewName); + + HANDLE hNewName = wNewHandle (lpName, strlen(lpName) + 1); + + PrivMemFree(lpName); + + // hNewName is freed by MakeDDEData + + if (!MakeDDEData (hNewName, (int)g_cfBinary, &hDdeData, FALSE)) + { + hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0); + goto errrtn; + } + + Assert (hDdeData); + lpclientRename->SendRenameMsgs (hDdeData); + GlobalFree (hDdeData); + + // Post termination for each of the doc clients that did not + // advise on rename + lpclient->TerminateNonRenameClients (lpclientRename); + } + + + Assert (FALSE == lpclient->m_fEmbed); + + // REVIEW: what is this? + //lpclient->m_fEmbed = FALSE; + + hresult = NOERROR; + + errrtn: + Assert (hresult == NOERROR); + goto exitRtn; + + } else { + + // Enumerate all the clients and send DDE_DATA if necessary. + bSaved = SendDataMsg (msg); + + // REVIEW: Hack from 1.0 for old pre-OLE-library apps + if ((msg == OLE_SAVED) && m_fEmbed && !bSaved) + return ReportResult(0, RPC_E_DDE_CANT_UPDATE, 0, 0); + + hresult = NOERROR; + } + +exitRtn: + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::ItemCallBack() returning hresult=%x\n", + this,hresult)); + + return(hresult); +} + + +// This func should definitely be replaced by use of MFC map. (IsEmpty) +INTERNAL_(BOOL) AreNoClients (HANDLE hcli) +{ + HANDLE hcliPrev = NULL; + PCLILIST pcli; + HANDLE *phandle; + + while (hcli) { + if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL) + { + Puth (hcli); + Putn(); + Assert(0); + return TRUE; + } + + phandle = (HANDLE *) pcli->info; + while (phandle < (HANDLE *)(pcli + 1)) + { + if (*phandle) + { + LocalUnlock (hcli); + return FALSE; + } + phandle++; + phandle++; + } + hcliPrev = hcli; + hcli = pcli->hcliNext; + LocalUnlock (hcliPrev); + } + return TRUE; +} + + +#ifdef _DEBUG +// For use in CodeView +// NOTE: Returns a static string +INTERNAL_(LPOLESTR) a2s (ATOM a) +{ + static WCHAR sz[256]; + GlobalGetAtomName (a, sz, 256); + return sz; +} +#endif diff --git a/private/ole32/com/remote/dde/server/item2.cxx b/private/ole32/com/remote/dde/server/item2.cxx new file mode 100644 index 000000000..20def4815 --- /dev/null +++ b/private/ole32/com/remote/dde/server/item2.cxx @@ -0,0 +1,1400 @@ +//+--------------------------------------------------------------------------- +// +// Microsoft Windows +// Copyright (C) Microsoft Corporation, 1992 - 1993. +// +// File: item2.cxx +// +// Contents: +// +// Classes: +// +// Functions: +// +// History: 6-07-94 kevinro Converted to NT and commented +// +//---------------------------------------------------------------------------- + +#include "ole2int.h" +#include <dde.h> +#include "ddeatoms.h" +#include "ddedebug.h" +#include "srvr.h" +#include "itemutil.h" +#include "trgt_dev.h" +#include <stddef.h> +#ifndef WIN32 +// #include <print.h> +#endif + +ASSERTDATA + + +INTERNAL_(void) CDefClient::TerminateNonRenameClients +( +LPCLIENT lprenameClient +) +{ + + HANDLE hcliPrev = NULL; + PCLILIST pcli; + HANDLE *phandle; + HANDLE hcli; + HWND hwndClient; + LPCLIENT lpdocClient; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::TerminateNonRenameClients(lprenClient=%x)\n", + this, + lprenameClient)); + + // items also keep the parents window handle. + hwndClient = m_hwnd; + lpdocClient = (LPCLIENT)GetWindowLong (m_hwnd, 0); + + + hcli = m_hcliInfo; + while (hcli) + { + if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL) + { + break; + } + + phandle = (HANDLE *) (pcli->info); + while (phandle < (HANDLE *)(pcli + 1)) + { + if (*phandle) + { + // This client is in the rename list. So, no termination + if(!FindClient (lprenameClient->m_hcliInfo, *phandle, FALSE)) + { + +#ifdef KEVINRO_I_CHANGED_THIS +// +// BUGBUG: (KevinRo) I don't understand why this didn't just call Terminate() instead. +// There may be the potential for problems on this PostMessageToClient, since it doesn't +// do the ModalLoop stuff. It is going to busy wait by doing Peeks +// +// I have changed this to call Terminate +// + PostMessageToClientWithReply ((HWND)*phandle, + WM_DDE_TERMINATE, + (UINT) hwndClient, NULL, + WM_DDE_TERMINATE); +#endif + // + // Terminate will send a WM_DDE_TERMINATE at the client + // + Terminate((HWND)*phandle,hwndClient); + + // delete this client from all the items lists. + lpdocClient->DeleteFromItemsList ((HWND)*phandle); + } + } + phandle++; + phandle++; + } + + hcliPrev = hcli; + hcli = pcli->hcliNext; + LocalUnlock (hcliPrev); + } + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::TerminateNonRenameClients\n", + this)); + +} + + + +INTERNAL CDefClient::Terminate + (HWND hwndTo, + HWND hwndFrom) +{ + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::Terminate hwndTo=%x hwndFrom=%x\n", + this, + hwndTo, + hwndFrom)); + + CALLDATA CD; + IID iid = CLSID_NULL; + DDECALLDATA DdeCD; + HRESULT hresult; + + DdeCD.hwndSvr = hwndTo; + DdeCD.hwndCli = hwndFrom; + DdeCD.wMsg = WM_DDE_TERMINATE; + DdeCD.wParam = (WPARAM)hwndFrom, + DdeCD.lParam = 0; + DdeCD.fInitialSend = FALSE; + + CD.id = CALLDATAID_UNUSED; + CD.lid = iid; + CD.TIDCallee = 0; + CD.pRpcMsg = (LPVOID) &DdeCD; + CD.CallCat = CALLCAT_SYNCHRONOUS; + CD.Event = 0; + + // + // Setting the pCallData variable effects the way that the + // DocWndProc handles WM_DDE_TERMINATE. If it is set, then this + // object initiated the terminate, and will not reply to the + // TERMINATE. It will allow us to leave the CallRunModalLoop + // + m_pCallData = &CD; + + hresult = m_pCallControl->CallRunModalLoop(&CD); + + m_pCallData = NULL; + + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::Terminate hresult = %x\n", + this,hresult)); + + return(hresult); +} + + +INTERNAL_(void) CDefClient::SendTerminateMsg () +{ + + HANDLE hcliPrev = NULL; + PCLILIST pcli; + HANDLE *phandle; + HANDLE hcli; + HWND hwnd; + LPCLIENT lpdocClient; + static int staticcounter; + int counter = ++staticcounter; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::SendTerminateMsg\n", + this)); + + // items also keep the document's window handle + + Assert (IsWindow (m_hwnd)); + + if (!IsWindow (m_hwnd)) + { + goto exitRtn; + } + + hwnd = m_hwnd; + + lpdocClient = (LPCLIENT)GetWindowLong (m_hwnd, 0); + + Assert (lpdocClient); + + if (NULL==lpdocClient) + { + goto exitRtn; + } + + Assert (lpdocClient==m_pdoc); + AssertIsDoc (lpdocClient); + // If "this" is a document (container) then iterate through + // and terminate all its client windows. If "this" is an item + // just terminate that item's client windows. + hcli = m_bContainer ? lpdocClient->m_hcli : m_hcliInfo; + while (hcli) + { + if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL) + { + goto exitRtn; + } + phandle = (HANDLE *) (pcli->info); + while (phandle < (HANDLE *)(pcli + 1)) + { + if ((HWND)*phandle) + { + intrDebugOut((DEB_ITRACE, + "%x ::SendTerminateMsg on hwnd=%x\n", + this, + (HWND)*phandle)); + + Terminate ((HWND)*phandle, hwnd); + + Assert (lpdocClient->m_cClients > 0); + + lpdocClient->m_cClients--; + + HWND hwndClient = *(HWND *)phandle; + // This window is no longer a client. + + // Remove window from document's master list + // and its item's list. + lpdocClient->DeleteFromItemsList (hwndClient); + } + // + // (KevinRo): Don't understand why the phandle is + // incremented twice. This is the same as the original + // code. Leaving it for now, since I don't have enough + // information. + // + phandle++; + phandle++; + } + + hcliPrev = hcli; + hcli = pcli->hcliNext; + LocalUnlock (hcliPrev); + } + +exitRtn: + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::SendTerminateMsg\n", + this)); + +} + + + +// SendRenameMsg: enumerates the clients for the rename item +// and sends rename message for all the clients. + +INTERNAL_(void) CDefClient::SendRenameMsgs +( +HANDLE hddeRename +) +{ + ATOM aData = NULL; + HANDLE hdde = NULL; + PCLINFO pclinfo = NULL; + HWND hwndClient; + + HANDLE hcliPrev = NULL; + PCLILIST pcli; + HANDLE *phandle; + HANDLE hcli; + HANDLE hcliInfo; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::SendRenameMsgs(hddeRename=%x)\n", + this, + hddeRename)); + + hcli = m_hcliInfo; + LPARAM lp; + while (hcli) + { + if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL) + { + goto exitRtn; + } + + + phandle = (HANDLE *) (pcli->info); + while (phandle < (HANDLE *)(pcli + 1)) + { + if (*phandle++) + { + hdde = NULL; + aData = NULL; + + if (!(pclinfo = (PCLINFO) LocalLock (hcliInfo = *phandle++))) + { + goto exitRtn; + } + + + // Make the item atom with the options. + aData = DuplicateAtom (aStdDocName); + hdde = UtDupGlobal (hddeRename,GMEM_MOVEABLE); + + hwndClient = pclinfo->hwnd; + LocalUnlock (hcliInfo); + + // Post the message + + lp = MAKE_DDE_LPARAM(WM_DDE_DATA,hdde,aData); + + if (!PostMessageToClient (hwndClient, + WM_DDE_DATA, + (UINT) m_hwnd, + lp)) + { + DDEFREE(WM_DDE_DATA,lp); + if (hdde) + GlobalFree (hdde); + if (aData) + GlobalDeleteAtom (aData); + } + } + else + { + phandle++; + } + + } + + hcliPrev = hcli; + hcli = pcli->hcliNext; + LocalUnlock (hcliPrev); + } + +exitRtn: + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::SendRenameMsgs void return\n", + this)); + +} + + + +INTERNAL_(BOOL) CDefClient::SendDataMsg +( +WORD msg // notification message +) +{ + + HANDLE hcliPrev = NULL; + PCLILIST pcli; + HANDLE *phandle; + HANDLE hcli; + BOOL bSaved = FALSE; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::SendDataMsg(msg=%x)\n", + this, + msg)); + + hcli = m_hcliInfo; + while (hcli) + { + if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL) + { + break; + } + phandle = (HANDLE *) (pcli->info); + while (phandle < (HANDLE *)(pcli + 1)) { + if (*phandle++) + bSaved = SendDataMsg1 (*phandle++, msg); + else + phandle++; + } + + hcliPrev = hcli; + hcli = pcli->hcliNext; + LocalUnlock (hcliPrev); + } + + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::SendDataMsg() returns %x)\n", + this,bSaved)); + + return bSaved; +} + + + +//SendDataMsg: Send data to the clients, if the data change options +//match the data advise options. + +INTERNAL_(BOOL) CDefClient::SendDataMsg1 +( +HANDLE hclinfo, // handle of the client info +WORD msg // notification message +) +{ + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::SendDataMsg1(hclinfo=%x,msg=%x)\n", + this, + hclinfo, + msg)); + + PCLINFO pclinfo = NULL; + HANDLE hdde = NULL; + ATOM aData = NULL; + HRESULT retval; + BOOL bSaved = FALSE; + + + ChkC (this); + if (m_lpdataObj == NULL) goto errRtn; + + // LATER: Allow server to give us other tymed's beside HGLOBAL and do + // the conversion ourselves, e.g., IStorageToHGlobal() + + FORMATETC formatetc;// = {0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; + STGMEDIUM medium;// = {TYMED_NULL, NULL, NULL}; + formatetc.ptd = m_ptd; + formatetc.dwAspect = DVASPECT_CONTENT; + formatetc.lindex = DEF_LINDEX; + formatetc.tymed = TYMED_HGLOBAL; + medium.tymed = TYMED_NULL; + medium.hGlobal=0; // not really necessary + medium.pUnkForRelease = NULL; + + if (!(pclinfo = (PCLINFO) LocalLock (hclinfo))) + { + goto errRtn; + } + + // if the client dead, then no message + if (!IsWindowValid(pclinfo->hwnd)) + { + goto errRtn; + } + + + // + // (KevinRo) UPDATE was not defined in the OLE 2.01 code base + // +#ifdef UPDATE + // OLE_SAVED is what 1.0 clients expect to get for embedded objects. + if (msg==OLE_CHANGED && m_fEmbed) + msg=OLE_SAVED; +#endif + + if (pclinfo->options & (0x0001 << msg)) + { + bSaved = TRUE; + SendDevInfo (pclinfo->hwnd); + + // send message if the client needs data for every change or + // only for the selective ones he wants. + + // now look for the data option. + if (pclinfo->bnative){ + // prepare native data + if (pclinfo->bdata){ + + // Wants the data with DDE_DATA message + // Get native data from the server. + + // GetData + formatetc.cfFormat = g_cfNative; + wSetTymed (&formatetc); + retval = GetData (&formatetc, &medium); + + if (retval != NOERROR) + { + Assert(0); + goto errRtn; + } + Assert (medium.tymed==TYMED_HGLOBAL); + Assert (medium.hGlobal); + + // Prepare the DDE data block. + // REVIEW: MakeDDEData frees medium.hGlobal manually, but should + // really call ReleaseStgMedium. + if(!MakeDDEData (medium.hGlobal, (int)g_cfNative, (LPHANDLE)&hdde, FALSE)) + { + goto errRtn; + } + } + + + // Make the item atom with the options. + aData = MakeDataAtom (m_aItem, msg); + + intrDebugOut((DEB_ITRACE, + "%x ::SendDataMsg1 send NativeData to hwnd=%x" + "format %x\n", + this, + pclinfo->hwnd, + pclinfo->format)); + + LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_DATA,hdde,aData); + if (!PostMessageToClient(pclinfo->hwnd, + WM_DDE_DATA, + (UINT) m_hwnd, + lp)) + + + { + DDEFREE(WM_DDE_DATA,lp); + // + // The two data items will be free'd on exit + // + goto errRtn; + } + hdde = NULL; + aData = NULL; + } + + + // Now post the data for the display format + + if (pclinfo->format) + { + if (pclinfo->bdata) + { + intrDebugOut((DEB_ITRACE, + "%x ::SendDataMsg1 GetData on cf = %x\n", + pclinfo->format)); + // Must reset because previous call to GetData set it. + medium.tymed = TYMED_NULL; + + // GetData + formatetc.cfFormat = pclinfo->format; + wSetTymed (&formatetc); + Assert (IsValidInterface (m_lpdataObj)); + retval = m_lpdataObj->GetData (&formatetc, &medium); + + if (retval != NOERROR) + { + intrDebugOut((DEB_IERROR, + "m_lpdataObj->GetData returns %x\n", + retval)); + goto errRtn; + } + + + if (pclinfo->format == CF_METAFILEPICT) + ChangeOwner (medium.hGlobal); + + if(!MakeDDEData (medium.hGlobal, pclinfo->format, (LPHANDLE)&hdde, FALSE)) + goto errRtn; + + } + + // atom is deleted. So, we need to duplicate for every post + aData = MakeDataAtom (m_aItem, msg); + // now post the message to the client; + intrDebugOut((DEB_ITRACE, + "%x ::SendDataMsg1 send PresentationData to hwnd=%x" + " cf=%x\n", + this, + pclinfo->hwnd, + pclinfo->format)); + + LPARAM lp = MAKE_DDE_LPARAM(WM_DDE_DATA,hdde,aData); + + if (!PostMessageToClient(pclinfo->hwnd, + WM_DDE_DATA, + (UINT) m_hwnd, + lp)) + { + DDEFREE(WM_DDE_DATA,lp); + goto errRtn; + } + + hdde = NULL; + aData = NULL; + } + + } + + +errRtn: + if (pclinfo) + LocalUnlock (hclinfo); + + if (hdde) + GlobalFree (hdde); + + if (aData) + GlobalDeleteAtom (aData); + + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::SendDataMsg1() returns %x\n", + this,bSaved)); + + + return bSaved; + +} + + + +// FixWriteBug +// +// `Write' gives a target device that is missing a NULL between +// the device name and the driver name. This function creates +// a fixed 1.0 target device. +// +// REVIEW: There is another Write bug we should work around. +// Write does not send the "extra bytes" that are supposed to follow +// the DEVMODE. It puts the Environment immediately after the DEVMODE. +// So the driver will read the Environment thinking it is the extra bytes. +// To fix this, FixWriteBug() should zero out the Environment bytes; the +// 2.0 target device does not use them anyway. +// + INTERNAL FixWriteBug + (HANDLE hTD, + LPHANDLE ph) +{ + HRESULT hresult; + LPBYTE pChunk2; + LPBYTE pNewChunk2; + const LPCOLETARGETDEVICE ptd1 = (LPCOLETARGETDEVICE) GlobalLock (hTD); + RetZS (ptd1, E_OUTOFMEMORY); + + HANDLE hNew = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, + GlobalSize (hTD) + 1); + RetZS (hNew, E_OUTOFMEMORY); + const LPBYTE pNew = (LPBYTE) GlobalLock (hNew); + RetZS (pNew, E_OUTOFMEMORY); + ULONG cbChunk1 = 7 * sizeof(UINT) + ptd1->otdDriverNameOffset; + ULONG cbChunk2 = GlobalSize (hTD) - cbChunk1; + ErrZS (!IsBadWritePtr (pNew, (UINT)cbChunk1), E_OUTOFMEMORY); + memcpy (pNew, ptd1, cbChunk1); + pNew[cbChunk1] = '\0'; // insert the missing NULL + + pNewChunk2 = pNew + cbChunk1 + 1; + pChunk2 = (LPBYTE)ptd1 + cbChunk1; + ErrZS (!IsBadWritePtr (pNewChunk2, (UINT)cbChunk2), E_OUTOFMEMORY); + Assert (!IsBadReadPtr (pChunk2, (UINT)cbChunk2)); + memcpy (pNewChunk2, pChunk2, cbChunk2); + + // Fix up the offsets to accomodate the added NULL + #define macro(x) if (ptd1->otd##x##Offset > ptd1->otdDeviceNameOffset)\ + ((LPOLETARGETDEVICE)pNew)->otd##x##Offset++; + macro (DriverName) + macro (PortName) + macro (ExtDevmode) + macro (Environment) + #undef macro + + GlobalUnlock (hNew); + GlobalUnlock (hTD); + *ph = hNew; + return NOERROR; + + errRtn: + if (pNew) + GlobalUnlock (hNew); + if (ptd1) + GlobalUnlock (hTD); + return hresult; +} + + + + + + +// Convert10TargetDevice +// +INTERNAL Convert10TargetDevice + (HANDLE hTD, // 1.0 Target Device + DVTARGETDEVICE FAR* FAR* pptd2) // Out parm, corresponding 2.0 TD +{ + intrDebugOut((DEB_ITRACE, + "0 _IN Convert10TargetDevice hTD=%x\n",hTD)); + + ULONG cbData1, cbData2; + + if (NULL==hTD) + { + Assert(0); + return ReportResult(0, E_INVALIDARG, 0, 0); + } + + if (*pptd2) + { + // delete old target device + PrivMemFree(*pptd2); + *pptd2 = NULL; + } + + LPOLETARGETDEVICE ptd1 = (LPOLETARGETDEVICE) GlobalLock (hTD); + + RetZS (ptd1, E_OUTOFMEMORY); + + if ((ptd1->otdDeviceNameOffset < ptd1->otdDriverNameOffset) + && (ptd1->otdDeviceNameOffset + + strlen (LPSTR(((BYTE *)ptd1->otdData) + + ptd1->otdDeviceNameOffset)) + 1 > ptd1->otdDriverNameOffset)) + { + // No NULL between device and driver name + HANDLE hNew; + GlobalUnlock (hTD); + RetErr (FixWriteBug (hTD, &hNew)); + HRESULT hresult = Convert10TargetDevice (hNew, pptd2); + Verify (0==GlobalFree (hNew)); + return hresult; + } + // Word Bug + DEVMODEA UNALIGNED *pdevmode = (DEVMODEA UNALIGNED *) + (((BYTE *)ptd1->otdData)+ ptd1->otdExtDevmodeOffset); + + if ( HIBYTE(pdevmode->dmSpecVersion) < 3 + || HIBYTE(pdevmode->dmSpecVersion) > 6 + || pdevmode->dmDriverExtra > 0x1000) + { + if (0==ptd1->otdEnvironmentSize) + { + // Sometimes Word does not give an environment. + ptd1->otdExtDevmodeOffset = 0; + ptd1->otdExtDevmodeSize = 0; + } + else + { + // DevMode is garbage, use environment instead. + ptd1->otdExtDevmodeOffset = ptd1->otdEnvironmentOffset; + ptd1->otdExtDevmodeSize = ptd1->otdEnvironmentSize; + } + } + + // These next assert does not HAVE to be true, + // but it's a sanity check. + Assert (ptd1->otdDeviceNameOffset + + strlen (LPSTR(((BYTE *)ptd1->otdData) + + ptd1->otdDeviceNameOffset)) + 1 + == ptd1->otdDriverNameOffset); + + + // Excel has zeroes for DevMode and Environment offsets and sizes + + // Calculate size of Data block. Many 1.0 clients don't make their + // target device data block big enough for the DEVMODE.dmDriverExtra + // bytes (and they don't copy those bytes either). We can't reconstruct + // the bytes out of thin air, but we can at least make sure there's not + // a GP fault when the printer driver tries to access those bytes in + // a call to CreateDC. Any extra bytes are zeroed. + cbData2 = ptd1->otdExtDevmodeOffset + ptd1->otdExtDevmodeSize; + + if (ptd1->otdExtDevmodeOffset != 0) + { + cbData2 += ((DEVMODEA UNALIGNED *)((LPBYTE)ptd1->otdData + + ptd1->otdExtDevmodeOffset))->dmDriverExtra; + } + + cbData2 = max (cbData2, + ptd1->otdPortNameOffset + strlen (LPCSTR( + ((BYTE *)ptd1->otdData) + ptd1->otdPortNameOffset)) + 1); + + // Calculate size of OLE2 Target Device + // + // Its the size of the DVTARGETDEVICE header, plus the cbData2 + // The definition of DVTARGETDEVICE currently uses an unsized array + // of bytes at the end, therefore we can not just do a sizeof(). + // + + ULONG cbTD2 = SIZEOF_DVTARGETDEVICE_HEADER + cbData2; + + // Allocate OLE2 Target Device + *pptd2 = (DVTARGETDEVICE FAR*) PrivMemAlloc(cbTD2); + if (IsBadWritePtr (*pptd2, cbTD2) + || IsBadWritePtr ((*pptd2)->tdData, cbData2)) + { + AssertSz (0, "out of memory"); + GlobalUnlock (hTD); + return ResultFromScode (E_OUTOFMEMORY); + } + _fmemset (*pptd2, '\0', cbTD2); + + // OLE2 offsets are from the beginning of the DVTARGETDEVICE + const ULONG cbOffset = offsetof (DVTARGETDEVICE, tdData); + + // Fill in new Target Device + + (*pptd2)->tdSize = cbTD2; + + #define Convert(a) \ + ((*pptd2)->td##a##Offset = (USHORT)(ptd1->otd##a##Offset + cbOffset)) + + Convert (DeviceName); + Convert (DriverName); + Convert (PortName); + if (ptd1->otdExtDevmodeOffset != 0) + Convert (ExtDevmode); + else // Excel uses 0 + (*pptd2)->tdExtDevmodeOffset = 0; + + // Calculate size of 1.0 data block in case the 1.0 target + // device is incorrectly not big enough. + cbData1 = (size_t) GlobalSize(hTD) - offsetof (OLETARGETDEVICE, otdData); + + #undef Convert + _fmemcpy ((*pptd2)->tdData, ptd1->otdData, min(cbData1, cbData2)); + + GlobalUnlock (hTD); + + // + // At this point, pptd2 holds an ANSI version of a DVTARGET device + // + // Now, we need to convert it to a UNICODE version. There are routines + // for doing this in the UTILS.H file. + // + + DVTDINFO dvtdInfo; + DVTARGETDEVICE * pdvtd32 = NULL; + HRESULT hr; + + hr = UtGetDvtd16Info(*pptd2, &dvtdInfo); + if (hr != NOERROR) + { + goto errRtn; + } + + pdvtd32 = (DVTARGETDEVICE *) PrivMemAlloc(dvtdInfo.cbConvertSize); + + if (pdvtd32 == NULL) + { + goto errRtn; + } + + hr = UtConvertDvtd16toDvtd32(*pptd2, &dvtdInfo, pdvtd32); + + if (hr != NOERROR) + { + PrivMemFree(pdvtd32); + pdvtd32=NULL; + } + +errRtn: + + PrivMemFree(*pptd2); + *pptd2 = pdvtd32; + + return hr; +} +//+--------------------------------------------------------------------------- +// +// Method: CDefClient::PokeStdItems +// +// Synopsis: Pokes the data for the standard items. +// +// Effects: +// +// For StdHostnames, StdDocDimensions and SetColorScheme the data is +// sent immediately and for the the StdTargetDeviceinfo the +// data is set in each client block and the data is sent just +// before the GetData call for rendering the right data. +// +// Arguments: [hwndClient] -- +// [aItem] -- +// [hdata] -- +// [index] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 6-07-94 kevinro Commented +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL CDefClient::PokeStdItems(HWND hwndClient, + ATOM aItem, + HANDLE hdata, + int index) +{ + DDEDATA FAR * lpdata = NULL; + HANDLE hnew = NULL; + LPHOSTNAMES lphostnames; + HRESULT retval = E_OUTOFMEMORY; + WORD format; + BOOL fRelease; + + intrDebugOut((DEB_ITRACE, + "%p _IN CDefClient::PokeStdItems(hwndClient=%x,aItem=%x(%ws)hdata=%x,index=%x)\n", + this, + hwndClient, + aItem, + wAtomName(aItem), + hdata, + index)); + + if (m_fGotEditNoPokeNativeYet) + { + // We got StdEdit, but instead of getting Poke for native data, + // we got poke for some std items. So we want to generate InitNew() + // call for the object. + + DoInitNew(); // the function clears the flag + } + + if(!(hdata && (lpdata = (DDEDATA FAR *)GlobalLock (hdata)))) + { + goto errRtn; + } + + format = lpdata->cfFormat; + fRelease = lpdata->fRelease; + + AssertSz (format == (int)g_cfBinary, "Format is not binary"); + + // we have extracted the data successfully. + m_lpoleObj = m_lpoleObj; + + if (index == STDHOSTNAMES) + { + lphostnames = (LPHOSTNAMES)lpdata->Value; + // + // The client should have sent the HOSTNAMES in ANSI. This + // means we need to convert them to UNICODE before we can + // use them. + // + LPOLESTR lpstrClient = CreateUnicodeFromAnsi((LPSTR)(lphostnames->data) + lphostnames->clientNameOffset); + LPOLESTR lpstrDoc = CreateUnicodeFromAnsi((LPSTR)(lphostnames->data) + lphostnames->documentNameOffset); + + intrDebugOut((DEB_ITRACE, + "%p ::PokeStdItems setting hostnames Client(%ws) Doc(%ws) \n", + this, + lpstrClient, + lpstrDoc)); + + retval = (HRESULT)m_lpoleObj->SetHostNames(lpstrClient,lpstrDoc); + + if (retval==NOERROR) + { + m_fDidRealSetHostNames = TRUE; + } + + PrivMemFree(lpstrClient); + PrivMemFree(lpstrDoc); + + goto end; + } + + + if (index == STDDOCDIMENSIONS) + { + + SIZEL size; + size.cy = ((LPRECT16)(lpdata->Value))->top; + size.cx = ((LPRECT16)(lpdata->Value))->left; + intrDebugOut((DEB_ITRACE, + "%p ::PokeStdItems STDDOCDIMENSIONS cy=%x cx=%x\n", + this, + size.cy, + size.cx)); + retval = m_lpoleObj->SetExtent (DVASPECT_CONTENT, &size); + + goto end; + + } + + + if (index == STDCOLORSCHEME) { + intrDebugOut((DEB_ITRACE, + "%p ::PokeStdItems setting STDCOLORSCHEME\n",this)); + + retval = m_lpoleObj->SetColorScheme((LPLOGPALETTE)(lpdata->Value)); + + goto end; + } + + // Target Device + if (index == STDTARGETDEVICE) + { + intrDebugOut((DEB_ITRACE, + "%p ::PokeStdItems setting STDTARGETDEVICE\n",this)); + + if (!(hnew = MakeItemData ((DDEPOKE FAR *)lpdata, hdata, format))) + goto errRtn; + + retval = Convert10TargetDevice (hnew, &m_ptd); + goto end; + + } + retval = E_UNEXPECTED; + + intrAssert(!"::PokeStdItems - Unknown index\n"); + + // + // (KevinRo) Found the following line already commented out. + // + //(HRESULT)SetStdInfo (hwndClient, (LPOLESTR) (MAKELONG(STDTARGETDEVICE,0)),hnew); + +end: +errRtn: + if (hnew) + // can only be global memory block + GlobalFree (hnew); + + if (lpdata) { + GlobalUnlock (hdata); + if (retval == NOERROR && fRelease) + GlobalFree (hdata); + } + + intrDebugOut((DEB_ITRACE, + "%p _OUT CDefClient::PokeStdItems() hresult = %x\n", + this, + retval)); + + return retval; +} + + + + + + +// SetStdInfo: Sets the targetdevice info. Creates a client +// for "StdTargetDevice". This item is created only within the +// lib and it is never visible in server app. When the change +// message comes from the server app, before we ask for +// the data, we send the targetdevice info if there is +// info for the client whom we are trying to send the data +// on advise. + + +INTERNAL_(HRESULT) CDefClient::SetStdInfo +( +HWND hwndClient, +LPOLESTR lpitemname, +HANDLE hdata +) +{ + HANDLE hclinfo = NULL; + PCLINFO pclinfo = NULL; + LPCLIENT lpclient; + HRESULT retval = NOERROR; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::SetStdInfo(hwndClient=%x,ItemName=(%ws),hdata=%x)\n", + this, + hwndClient, + lpitemname, + hdata)); + // + // first create/find the StdTargetDeviceItem. + // + + if ((lpclient = SearchItem (lpitemname)) == NULL) + { + retval = (HRESULT)RegisterItem (lpitemname,(LPCLIENT FAR *)&lpclient, FALSE); + if (retval != NOERROR) + { + goto errRtn; + } + } + + if(hclinfo = FindClient (lpclient->m_hcliInfo, hwndClient, FALSE)) + { + if (pclinfo = (PCLINFO) LocalLock (hclinfo)) + { + if (pclinfo->hdevInfo) + GlobalFree (pclinfo->hdevInfo); + pclinfo->bnewDevInfo = TRUE; + if (hdata) + pclinfo->hdevInfo = UtDupGlobal (hdata,GMEM_MOVEABLE); + else + pclinfo->hdevInfo = NULL; + pclinfo->hwnd = hwndClient; + LocalUnlock (hclinfo); + + // We do not have to reset the client because we did not + // change the handle it self. + } + } + else + { + // Create the client structure to be attcahed to the object. + hclinfo = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (CLINFO)); + if (hclinfo == NULL || (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL) + goto errRtn; + + pclinfo->bnewDevInfo = TRUE; + if (hdata) + pclinfo->hdevInfo = UtDupGlobal (hdata,GMEM_MOVEABLE); + else + pclinfo->hdevInfo = NULL; + + pclinfo->hwnd = hwndClient; + LocalUnlock (hclinfo); + + + // Now add this client to item client list + // !!! This error recovery is not correct. + if (!AddClient ((LPHANDLE)&lpclient->m_hcliInfo, hwndClient, hclinfo)) + goto errRtn; + } + +exitRtn: + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::SetStdInfo() hresult=%x\n", + this,retval)); + + return retval; +errRtn: + Assert(0); + if (pclinfo) + LocalUnlock (hclinfo); + + if (hclinfo) + LocalFree (hclinfo); + + retval = E_OUTOFMEMORY; + goto exitRtn; +} + + +// SendDevInfo: Sends targetdevice info to the the object. +// Caches the last targetdevice info sent to the object. +// If the targetdevice block is same as the one in the +// cache, then no targetdevice info is sent. +// (!!! There might be some problem here getting back +// the same global handle). + +INTERNAL_(void) CDefClient::SendDevInfo +( +HWND hWndCli +) +{ + + HANDLE hclinfo = NULL; + PCLINFO pclinfo = NULL; + HANDLE hdata; + LPCLIENT lpdocClient; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::SendDevInfo(hwndCli=%x)\n", + this, + hWndCli)); +#if 0 + if (!m_bContainer) + lpdocClient = (LPCLIENT)GetWindowLong (m_hwnd, 0); + else + lpdocClient = this; +#endif + + // find if any StdTargetDeviceInfo item is present at all + AssertIsDoc(m_pdoc); + lpdocClient = m_pdoc->SearchItem ((LPOLESTR) (MAKELONG(STDTARGETDEVICE, 0))); + if (lpdocClient == NULL) + { + goto exitRtn; + } + + hclinfo = FindClient (lpdocClient->m_hcliInfo, hWndCli, FALSE); + + // This client has not set any target device info. no need to send + // any stdtargetdevice info + if (hclinfo != NULL) { + if (!(pclinfo = (PCLINFO)LocalLock (hclinfo))) + goto end; + + // if we cached it, do not send it again. + if ((!pclinfo->bnewDevInfo) && pclinfo->hdevInfo == m_hdevInfo) + goto end; + + pclinfo->bnewDevInfo = FALSE; + if(!(hdata = UtDupGlobal (pclinfo->hdevInfo,GMEM_MOVEABLE))) + goto end; + } else { + + // already screen + if (!m_hdevInfo) + goto end; + + //for screen send NULL. + hdata = NULL; + } + + + + if (pclinfo) + { + m_hdevInfo = pclinfo->hdevInfo; + } + else + { + m_hdevInfo = NULL; + } + + + + // !!! error case who frees the data?' + +end: + if (pclinfo) + LocalUnlock (hclinfo); + +exitRtn: + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::SendDevInfo(hwndCli=%x)\n", + this, + hWndCli)); + return; +} + + + + +// Constructor +CDefClient::CDefClient (LPUNKNOWN pUnkOuter): m_Unknown (this), + m_OleClientSite (this), + m_AdviseSink (this) +{ + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::CDefClient(pUnkOuter=%x)\n", + this, + pUnkOuter)); + + m_pUnkOuter = pUnkOuter ? pUnkOuter : &m_Unknown; + m_bContainer = TRUE; + m_lpoleObj = NULL; + m_lpdataObj = NULL; + m_bCreateInst = FALSE; + m_bTerminate = FALSE; + m_termNo = 0; + m_hcli = NULL; + m_lpNextItem = NULL; + m_cRef = 0; + m_hwnd = (HWND)0; + m_hdevInfo = NULL; + m_hcliInfo = NULL; + m_fDidRealSetHostNames= FALSE; + m_fDidSetClientSite = FALSE; + m_fGotDdeAdvise = FALSE; + m_fCreatedNotConnected = FALSE; + m_fInOnClose = FALSE; + m_fInOleSave = FALSE; + m_dwConnectionOleObj = 0L; + m_dwConnectionDataObj = 0L; + m_fGotStdCloseDoc = FALSE; + m_fEmbed = FALSE; + m_cClients = 0; + m_plkbytNative = NULL; + m_pstgNative = NULL; + m_fRunningInSDI = FALSE; + m_psrvrParent = NULL; + m_ptd = NULL; + m_pdoc = NULL; + m_chk = chkDefClient; + m_ExecuteAck.f = FALSE; + m_fGotEditNoPokeNativeYet = FALSE; + m_fLocked = FALSE; + m_pCallData = NULL; + m_pCallControl = NULL; + // CDefClient::Create does all the real work. + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::CDefClient(pUnkOuter=%x)\n", + this, + pUnkOuter)); + +} + + +CDefClient::~CDefClient (void) +{ + // This should be more object-oriented. + // But right now, this BOOL tells us what kind of obj + // (doc or item) "this" is + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::~CDefClient\n", + this)); + + Puts ("~CDefClient "); Puta(m_aItem); Putn(); + BOOL fDoc = (m_pdoc==this); + + Assert (m_chk==chkDefClient); + + ReleaseObjPtrs (); + + if (m_pdoc && !fDoc) + { + Assert (m_pdoc->m_chk==chkDefClient); + m_pdoc->m_pUnkOuter->Release(); + } + if (fDoc) + { + // delete all the items(objects) for this doc + DeleteAllItems (); + if (m_fRunningInSDI && m_psrvrParent + && m_psrvrParent->QueryRevokeClassFactory()) + { + m_psrvrParent->Revoke(); + } + + } + + if (ISATOM(m_aItem)) + GlobalDeleteAtom (m_aItem); + if (m_plkbytNative) + { + m_plkbytNative->Release(); + Assert (m_pstgNative); + // They always go together + } + if (m_pstgNative) + m_pstgNative->Release(); + if (m_ptd) + PrivMemFree(m_ptd); + + // Delete client advise info + DeleteAdviseInfo (); + if (fDoc && IsWindow(m_hwnd)) + { + SSDestroyWindow (m_hwnd); + } + if (m_pCallControl) + { + ReleaseDdeCallControlInterface(); + } + intrDebugOut((DEB_ITRACE, + "%x _OUT CDefClient::~CDefClient\n", + this)); + +} + + +// +// Unknown Implementation +// + +STDMETHODIMP NC(CDefClient,CUnknownImpl)::QueryInterface + (REFIID iid, + LPVOID FAR* ppv) +{ + intrDebugOut((DEB_ITRACE,"%p CDefClient::QueryInterface()\n",this)); + + if (iid == IID_IUnknown) + { + *ppv = (LPVOID) &m_pDefClient->m_Unknown; + AddRef(); + return NOERROR; + } + else if (iid==IID_IAdviseSink) + *ppv = (LPVOID) &m_pDefClient->m_AdviseSink; + else if (iid==IID_IOleClientSite) + *ppv = (LPVOID) &m_pDefClient->m_OleClientSite; + else + { + *ppv = NULL; + return ReportResult(0, E_NOINTERFACE, 0, 0); + } + m_pDefClient->m_pUnkOuter->AddRef(); + + return NOERROR; +} + + +STDMETHODIMP_(ULONG) NC(CDefClient,CUnknownImpl)::AddRef() +{ + intrDebugOut((DEB_ITRACE, + "%p CDefClient::AddRef() returns %x\n", + this, + m_pDefClient->m_cRef+1)); + + return ++m_pDefClient->m_cRef; +} + + +STDMETHODIMP_(ULONG) NC(CDefClient,CUnknownImpl)::Release() +{ + AssertSz (m_pDefClient->m_cRef, "Release is being called on ref count of zero"); + if (--m_pDefClient->m_cRef == 0) + { + delete m_pDefClient; + intrDebugOut((DEB_ITRACE, + "%p CDefClient::Release() returns 0\n", + this)); + return 0; + } + intrDebugOut((DEB_ITRACE, + "%p CDefClient::Release() returns %x\n", + this, + m_pDefClient->m_cRef)); + + return m_pDefClient->m_cRef; +} diff --git a/private/ole32/com/remote/dde/server/itemutil.cxx b/private/ole32/com/remote/dde/server/itemutil.cxx new file mode 100644 index 000000000..c0ba1b0f0 --- /dev/null +++ b/private/ole32/com/remote/dde/server/itemutil.cxx @@ -0,0 +1,516 @@ +// itemutil.h// +// routines used by item.cpp +// They used to be in item.cpp but it got too big. + + +#include "ole2int.h" +#include "srvr.h" +#include "itemutil.h" +#include "ddedebug.h" + +ASSERTDATA + + +//ScanItemOptions: Scan for the item options like Close/Save etc. + +INTERNAL_(HRESULT) ScanItemOptions +( +LPOLESTR lpbuf, +int far *lpoptions +) +{ + + ATOM aModifier; + + *lpoptions = OLE_CHANGED; + while ( *lpbuf && *lpbuf != '/') lpbuf++; + + // no modifier same as /change + + if (*lpbuf == NULL) + return NOERROR; + + *lpbuf++ = NULL; // seperate out the item string + // We are using this in the caller. + + if (!(aModifier = GlobalFindAtom (lpbuf))) + return ReportResult(0, RPC_E_DDE_SYNTAX_ITEM, 0, 0); + + if (aModifier == aChange) + return NOERROR; + + // Is it a save? + if (aModifier == aSave){ + *lpoptions = OLE_SAVED; + return NOERROR; + } + // Is it a Close? + if (aModifier == aClose){ + *lpoptions = OLE_CLOSED; + return NOERROR; + } + + // unknow modifier + return ReportResult(0, RPC_E_DDE_SYNTAX_ITEM, 0, 0); + +} + + + + +//MakeDDEData: Create a Global DDE data handle from the server +// app data handle. + +INTERNAL_(BOOL) MakeDDEData +( +HANDLE hdata, +int format, +LPHANDLE lph, +BOOL fResponse +) +{ + DWORD size; + HANDLE hdde = NULL; + DDEDATA FAR *lpdata= NULL; + BOOL bnative; + LPSTR lpdst; + LPSTR lpsrc; + + Puts ("MakeDDEData\r\n"); + + if (!hdata) { + *lph = NULL; + return TRUE; + } + + + if (bnative = !(format == CF_METAFILEPICT + || format == CF_DIB + || format == CF_BITMAP)) + { + // g_cfNative, CF_TEXT, g_cfBinary + size = GlobalSize (hdata) + sizeof (DDEDATA); + } + else + size = sizeof (LONG) + sizeof (DDEDATA); + + + hdde = (HANDLE) GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, size); + if (hdde == NULL || (lpdata = (DDEDATA FAR *) GlobalLock (hdde)) == NULL) + goto errRtn; + + // set the data otions. Ask the client to delete + // it always. + + lpdata->fAckReq = FALSE; + lpdata->fRelease = TRUE; // release the data + lpdata->cfFormat = format; + lpdata->fResponse = fResponse; + + if (!bnative) + // If not native, stick in the handle what the server gave us. + *(LPHANDLE)lpdata->Value = hdata; + + else { + // copy the native data junk here. + lpdst = (LPSTR)lpdata->Value; + if(!(lpsrc = (LPSTR)GlobalLock (hdata))) + goto errRtn; + + size -= sizeof (DDEDATA); + memcpy (lpdst, lpsrc, size); + GlobalUnlock (hdata); + GlobalFree (hdata); + + } + + GlobalUnlock (hdde); + *lph = hdde; + return TRUE; + +errRtn: + if (lpdata) + GlobalUnlock (hdde); + + if (hdde) + GlobalFree (hdde); + + if (bnative) + GlobalFree (hdata); + + return FALSE; +} + + + +// IsAdviseStdItems: returns true if the item is one of the standard items +// StdDocName; +INTERNAL_(BOOL) IsAdviseStdItems ( +ATOM aItem +) +{ + + if ( aItem == aStdDocName) + return TRUE; + else + return FALSE; +} + + + +// GetStdItemIndex: returns index to Stditems in the "stdStrTable" if the item +// is one of the standard items StdHostNames, StdTargetDevice, +// StdDocDimensions, StdColorScheme +WCHAR * stdStrTable[STDHOSTNAMES+1] = {NULL, + OLESTR("StdTargetDevice"), + OLESTR("StdDocDimensions"), + OLESTR("StdColorScheme"), + OLESTR("StdHostNames")}; + +INTERNAL_(int) GetStdItemIndex ( +ATOM aItem +) +{ + + WCHAR str[MAX_STR]; + + if (!aItem) + return NULL; + + if (!GlobalGetAtomName (aItem, str, MAX_STR)) + return NULL; + + if (!lstrcmpiW (str, stdStrTable[STDTARGETDEVICE])) + return STDTARGETDEVICE; + else if (!lstrcmpiW (str, stdStrTable[STDHOSTNAMES])) + return STDHOSTNAMES; + else if (!lstrcmpiW (str, stdStrTable[STDDOCDIMENSIONS])) + return STDDOCDIMENSIONS; + else if (!lstrcmpiW (str, stdStrTable[STDCOLORSCHEME])) + return STDCOLORSCHEME; + + return NULL; +} + + + + +void ChangeOwner + (HANDLE hmfp) +{ + +#ifndef WIN32 + LPMETAFILEPICT lpmfp; + if (lpmfp = (LPMETAFILEPICT) GlobalLock (hmfp)) + { + SetMetaFileBitsBetter (lpmfp->hMF); + GlobalUnlock (hmfp); + } +#endif +} + + +INTERNAL_(HANDLE) MakeItemData +( +DDEPOKE FAR * lpPoke, +HANDLE hPoke, +CLIPFORMAT cfFormat +) +{ + HANDLE hnew; + LPBYTE lpnew; + DWORD dwSize; + + Puts ("MakeItemData\r\n"); + + if (cfFormat == CF_METAFILEPICT) + return DuplicateMetaFile (*(LPHANDLE)lpPoke->Value); + + if (cfFormat == CF_BITMAP) + return (HANDLE)DuplicateBitmap (*(HBITMAP *)lpPoke->Value); + + if (cfFormat == CF_DIB) + return UtDupGlobal (*(LPHANDLE)lpPoke->Value,GMEM_MOVEABLE); + + // Now we are dealing with normal case + if (!(dwSize = GlobalSize (hPoke))) + return NULL; + + dwSize -= sizeof (DDEPOKE) - sizeof(BYTE); + + // Use GMEM_ZEROINIT so there is no garbage after the data in field Value. + // This may be important when making an IStorage from native data, + // but I'm not sure. + // Note that the Value field itself could have garbage + // at the end if the hData of the DDE_POKE message is bigger than + // necessary, i.e., + // GlobalSize(hData) > sizeof(DDEPOKE) - sizeof(Value) + realsize(Value) + + // A DocFile is of size 512n + DebugOnly ( + if (cfFormat==g_cfNative && dwSize%512 != 0) + { + Putsi(dwSize); + Puts ("DDE_POKE.Value not of size 512n\r\n"); + } + ) + + if (hnew = GlobalAlloc (GMEM_MOVEABLE|GMEM_ZEROINIT, dwSize)) { + if (lpnew = (LPBYTE) GlobalLock (hnew)) { + memcpy (lpnew, lpPoke->Value, dwSize); + GlobalUnlock (hnew); + } + else { + GlobalFree (hnew); + hnew = NULL; + } + } + + return hnew; +} + + + +INTERNAL_(HANDLE) DuplicateMetaFile +( +HANDLE hSrcData +) +{ + LPMETAFILEPICT lpSrcMfp; + LPMETAFILEPICT lpDstMfp = NULL; + HANDLE hMF = NULL; + HANDLE hDstMfp = NULL; + + Puts ("DuplicateMetaFile\r\n"); + + if (!(lpSrcMfp = (LPMETAFILEPICT) GlobalLock(hSrcData))) + return NULL; + + GlobalUnlock (hSrcData); + + if (!(hMF = CopyMetaFile (lpSrcMfp->hMF, NULL))) + return NULL; + + if (!(hDstMfp = GlobalAlloc (GMEM_MOVEABLE, sizeof(METAFILEPICT)))) + goto errMfp; + + if (!(lpDstMfp = (LPMETAFILEPICT) GlobalLock (hDstMfp))) + goto errMfp; + + GlobalUnlock (hDstMfp); + + *lpDstMfp = *lpSrcMfp; + lpDstMfp->hMF = (HMETAFILE)hMF; + return hDstMfp; +errMfp: + // + // The following Metafile was created in this + // process. Therefore, the delete shouldn't need to + // call the DDE functions for deleting the DDE pair + // + if (hMF) + DeleteMetaFile ((HMETAFILE)hMF); + + if (hDstMfp) + GlobalFree (hDstMfp); + + return NULL; +} + + + +INTERNAL_(HBITMAP) DuplicateBitmap +( +HBITMAP hold +) +{ + HBITMAP hnew; + HANDLE hMem; + LPBYTE lpMem; + LONG retVal = TRUE; + DWORD dwSize; + BITMAP bm; + + // !!! another way to duplicate the bitmap + + Puts ("DuplicateBitmap\r\n"); + + GetObject (hold, sizeof(BITMAP), (LPSTR) &bm); + dwSize = ((DWORD) bm.bmHeight) * ((DWORD) bm.bmWidthBytes) * + ((DWORD) bm.bmPlanes) * ((DWORD) bm.bmBitsPixel); + + if (!(hMem = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, dwSize))) + return NULL; + + if (!(lpMem = (LPBYTE) GlobalLock (hMem))){ + GlobalFree (hMem); + return NULL; + } + + GetBitmapBits (hold, dwSize, lpMem); + if (hnew = CreateBitmap (bm.bmWidth, bm.bmHeight, + bm.bmPlanes, bm.bmBitsPixel, NULL)) + retVal = SetBitmapBits (hnew, dwSize, lpMem); + + GlobalUnlock (hMem); + GlobalFree (hMem); + + if (hnew && (!retVal)) { + DeleteObject (hnew); + hnew = NULL; + } + + return hnew; +} + + + + +// CDefClient::GetData +// +// Perform a normal GetData on m_lpdataObj, but if g_cfNative is requested, +// do an OleSave onto our IStorage implemented +// on top of an ILockBytes, then convert the ILockBytes to an hGlobal. +// This flattened IStorage will be used as the native data. +// +INTERNAL CDefClient::GetData + (LPFORMATETC pformatetc, + LPSTGMEDIUM pmedium) +{ + LPPERSISTSTORAGE pPersistStg=NULL; + HANDLE hNative =NULL; + HANDLE hNativeDup =NULL; + HRESULT hresult =NOERROR; + BOOL fFreeHNative = FALSE; + CLSID clsid; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDefClient::GetData(%x,%x)\n", + this, + pformatetc, + pmedium)); + + intrDebugOut((DEB_ITRACE, + " ::GetData format=%x\n", + pformatetc->cfFormat)); + + if (pformatetc->cfFormat==g_cfNative) + { + ErrRtnH (m_lpdataObj->QueryInterface (IID_IPersistStorage, + (LPLPVOID) &pPersistStg)); + ErrZ (pPersistStg); + if (NULL==m_pstgNative) + { + // Embed from file case + Assert (NULL==m_plkbytNative); + ErrRtnH (CreateILockBytesOnHGlobal (NULL, + /*fDeleteOnRelease*/TRUE, + &m_plkbytNative)); + + Assert (m_plkbytNative); + + ErrRtnH (StgCreateDocfileOnILockBytes (m_plkbytNative, + grfCreateStg, 0, &m_pstgNative)); + + ErrZ (m_pstgNative); + Assert (NOERROR==StgIsStorageILockBytes(m_plkbytNative)); + + m_fInOleSave = TRUE; + hresult = OleSave (pPersistStg, m_pstgNative, FALSE); + pPersistStg->SaveCompleted(NULL); + m_fInOleSave = FALSE; + ErrRtnH (hresult); + } + else + { + // Get the native data by calling OleSave + m_fInOleSave = TRUE; + hresult = OleSave (pPersistStg, m_pstgNative, TRUE); + pPersistStg->SaveCompleted(NULL); + m_fInOleSave = FALSE; + ErrRtnH (hresult); + } + ErrRtnH (ReadClassStg (m_pstgNative, &clsid)); + if (CoIsOle1Class (clsid)) + { + // TreatAs case: + // Get Native data from "\1Ole10Native" stream + fFreeHNative = TRUE; + ErrRtnH (StRead10NativeData (m_pstgNative, &hNative)); + } + else + { + + Assert (NOERROR==StgIsStorageILockBytes (m_plkbytNative)); + + ErrRtnH (GetHGlobalFromILockBytes (m_plkbytNative, &hNative)); + } + + ErrZ (wIsValidHandle (hNative, g_cfNative)); + + // Must duplicate because we let the client free the handle, + // so it can't be the one our ILockBytes depends on. + hNativeDup = UtDupGlobal (hNative, GMEM_DDESHARE | GMEM_MOVEABLE); + ErrZ (wIsValidHandle (hNativeDup, g_cfNative)); + + if (GlobalSize(hNativeDup) % 512 != 0) + { + Puts ("WARNING:\r\n\t"); + Putsi (GlobalSize(hNativeDup)); + } + + pmedium->tymed = TYMED_HGLOBAL; + pmedium->hGlobal = hNativeDup; + pmedium->pUnkForRelease = NULL; + + pPersistStg->Release(); + hresult = NOERROR; + goto exitRtn; + } + else + { + // Anything but native + hresult = m_lpdataObj->GetData (pformatetc, pmedium); +// AssertOutStgmedium(hresult, pmedium); + goto exitRtn; + } + + +errRtn: + if (hNative && fFreeHNative) + GlobalFree (hNative); + if (pPersistStg) + pPersistStg->Release(); + + pmedium->tymed = TYMED_NULL; + pmedium->pUnkForRelease = NULL; + +exitRtn: + intrDebugOut((DEB_ITRACE, + "%x OUT CDefClient::GetData() return %x\n", + this, + hresult)); + return hresult; +} + + +// Set pformatetc->tymed based on pformatetc->cfFormat +// +INTERNAL wSetTymed + (LPFORMATETC pformatetc) +{ + if (pformatetc->cfFormat == CF_METAFILEPICT) + { + pformatetc->tymed = TYMED_MFPICT; + } + else if (pformatetc->cfFormat == CF_PALETTE || + pformatetc->cfFormat == CF_BITMAP) + { + pformatetc->tymed = TYMED_GDI; + } + else + { + pformatetc->tymed = TYMED_HGLOBAL; + } + return NOERROR; +} diff --git a/private/ole32/com/remote/dde/server/itemutil.h b/private/ole32/com/remote/dde/server/itemutil.h new file mode 100644 index 000000000..e9af61df2 --- /dev/null +++ b/private/ole32/com/remote/dde/server/itemutil.h @@ -0,0 +1,14 @@ +// itemutil.h +// +// Corresponds to itemutil.cpp + +void ChangeOwner (HANDLE hmfp); +INTERNAL ScanItemOptions (LPSTR lpbuf, int far *lpoptions); +INTERNAL_(BOOL) MakeDDEData (HANDLE hdata, int format, LPHANDLE lph, BOOL fResponse); +INTERNAL_(BOOL) IsAdviseStdItems (ATOM aItem); +INTERNAL_(int) GetStdItemIndex (ATOM aItem); +void ChangeOwner (HANDLE hmfp); +INTERNAL_(HANDLE) MakeItemData (DDEPOKE FAR *lpPoke, HANDLE hPoke, CLIPFORMAT cfFormat); +INTERNAL_(HANDLE) DuplicateMetaFile (HANDLE hSrcData); +INTERNAL_(HBITMAP) DuplicateBitmap (HBITMAP hold); +INTERNAL wSetTymed (LPFORMATETC pformatetc); diff --git a/private/ole32/com/remote/dde/server/srvr.cxx b/private/ole32/com/remote/dde/server/srvr.cxx new file mode 100644 index 000000000..7027bf8df --- /dev/null +++ b/private/ole32/com/remote/dde/server/srvr.cxx @@ -0,0 +1,2369 @@ + +/****************************** Module Header ******************************\ +* Module Name: Srvr.c Server Main module +* +* Purpose: Includes All the server communication related routines. +* +* Created: Oct 1990. +* +* Copyright (c) 1985, 1986, 1987, 1988, 1989 Microsoft Corporation +* +* History: +* Raor: Wrote the original version. +* +* +\***************************************************************************/ + +#include "ole2int.h" +//#include <shellapi.h> +// #include "cmacs.h" +#include <dde.h> + +// for RemDdeRevokeClassFactory and HDDESRVR +#include <olerem.h> + +#include "srvr.h" +#include "ddedebug.h" +#include "ddesrvr.h" +ASSERTDATA + +extern HINSTANCE hdllInst; + +#define WM_DONOTDESTROY WM_USER+1 + +#ifdef FIREWALLS +BOOL bShowed = FALSE; +void ShowVersion (void); +#endif + +#ifdef _CHICAGO_ +#define DdeCHAR CHAR +#define Ddelstrcmp lstrcmpA +#define DdeGetClassName GetClassNameA +#define szCDDEServer "CDDEServer" +#else +#define DdeCHAR WCHAR +#define Ddelstrcmp lstrcmpW +#define DdeGetClassName GetClassName +#define szCDDEServer OLESTR("CDDEServer") +#endif + +//+--------------------------------------------------------------------------- +// +// Method: CDDEServer::Create +// +// Synopsis: Create a server window to service a particular class +// +// Effects: Using lpclass, and the information in lpDdeInfo, create +// a server window that is ready to respond to initiate +// messages from this class. +// +// Arguments: [lpclass] -- Class name +// [rclsid] -- Class ID +// [lpDdeInfo] -- Class Object information +// [phwnd] -- Out pointer for new window +// [aOriginalClass] -- For TreatAs/Convert to case +// [cnvtyp] -- Conversion type +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 5-28-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL CDDEServer::Create + (LPOLESTR lpclass, + REFCLSID rclsid, + LPDDECLASSINFO lpDdeInfo, + HWND FAR * phwnd, + ATOM aOriginalClass, + CNVTYP cnvtyp) +{ + // REVIEW what happens if we have two MDI servers register the + // same class factory?. + + LPSRVR lpDDEsrvr = NULL; + ATOM aExe = NULL; + + intrDebugOut((DEB_DDE_INIT, + "0 _IN CDDEServer::Create(lpclass=%ws)\n", + lpclass)); + + // add the app atom to global list + if (!ValidateSrvrClass (lpclass, &aExe)) + { + intrDebugOut((DEB_IWARN, + "CDDEServer::Create(%ws) Invalid Class\n", + lpclass)); + + return OLE_E_CLSID; + } + + lpDDEsrvr = new CDDEServer; + RetZS (lpDDEsrvr, E_OUTOFMEMORY); + + + lpDDEsrvr->m_pCallControl = GetDdeCallControlInterface(); + + intrAssert(lpDDEsrvr->m_pCallControl != NULL); + + if (lpDDEsrvr->m_pCallControl == NULL) + { + intrDebugOut((DEB_IWARN, + "CDDEServer::Create(%ws) CallControlGet failed\n", + lpclass)); + + goto errReturn; + } + + // set the signature handle and the app atom. + lpDDEsrvr->m_chk = chkDdeSrvr; + lpDDEsrvr->m_aClass = wGlobalAddAtom (lpclass); + lpDDEsrvr->m_clsid = rclsid; // Class ID (already TreatAs'd) + lpDDEsrvr->m_aOriginalClass = wDupAtom (aOriginalClass); + lpDDEsrvr->m_pClassFactory = NULL; + lpDDEsrvr->m_dwClassFactoryKey = lpDdeInfo->dwRegistrationKey; + lpDDEsrvr->m_aExe = aExe; + lpDDEsrvr->m_cnvtyp = cnvtyp; + lpDDEsrvr->m_fcfFlags = lpDdeInfo->dwFlags; + + lpDDEsrvr->m_bTerminate = FALSE; // Set if we are terminating. + lpDDEsrvr->m_hcli = NULL; // handle to the first block of clients list + lpDDEsrvr->m_termNo = 0; // termination count + lpDDEsrvr->m_cSrvrClients= 0; // no of clients; + lpDDEsrvr->m_fDoNotDestroyWindow= 0; + + + + + +#ifdef FIREWALLS + AssertSz(lpDdeInfo.dwFlags <= REGCLS_MULTI_SEPARATE, "invalid server options"); +#endif + + // Create the server window and do not show it. + // + // We are explicitly calling CreateWindowA here. + // The DDE tracking layer will attempt to convert hCommands to UNICODE + // if the two windows in the conversation are both UNICODE. + // This window is created as a child of the common server window for this + // thread. When this thread dies, the common server window is destroyed if + // it exists, which will cause all of the child windows to be destroyed also. + // + // + if (!(lpDDEsrvr->m_hwnd = DdeCreateWindowEx (0, SRVR_CLASS, + szCDDEServer, + WS_OVERLAPPED | WS_CHILD, + 0,0,0,0, + (HWND)TLSGetDdeServer(), + NULL, + hdllInst, NULL))) + { + goto errReturn; + + } + + // + // The following will inform the class object in the class registration table + // that this window should be notified when the class object is revoked. This + // enables the window to shutdown properly. + // + // If there isn't a class factory, which happens for single instance servers + // which were launched with a filename, then m_dwClassFactory will be 0, + // in which case we don't make the set call. + // + if(lpDDEsrvr->m_dwClassFactoryKey != 0) + { + if(!SetDdeServerWindow(lpDDEsrvr->m_dwClassFactoryKey,lpDDEsrvr->m_hwnd)) + { + intrDebugOut((DEB_IERROR, + "0 CDDEServer::Create unable to SetDdeServerWindow\n")); + goto errReturn; + } + } + + intrDebugOut((DEB_DDE_INIT, + "DDE Server window for %ws created in task %x\n", + lpclass,GetCurrentThreadId())); + + // save the ptr to the server struct in the window. + SetWindowLong (lpDDEsrvr->m_hwnd, 0, (LONG)lpDDEsrvr); + + // Set the signature. + SetWindowWord (lpDDEsrvr->m_hwnd, WW_LE, WC_LE); + + *phwnd = lpDDEsrvr->m_hwnd; + + + intrDebugOut((DEB_DDE_INIT, + "0 _OUT CDDEServer::Create returns %x\n", + NOERROR)); + return NOERROR; + +errReturn: + AssertSz (0, "CDDEServer::Create errReturn"); + if (lpDDEsrvr) + { + if (lpDDEsrvr->m_pCallControl) + ReleaseDdeCallControlInterface(); + + if (lpDDEsrvr->m_hwnd) + SSDestroyWindow (lpDDEsrvr->m_hwnd); + + if (lpDDEsrvr->m_aClass) + GlobalDeleteAtom (lpDDEsrvr->m_aClass); + + if (lpDDEsrvr->m_aExe) + GlobalDeleteAtom (lpDDEsrvr->m_aExe); + delete lpDDEsrvr; + } + + intrDebugOut((DEB_IERROR, + "0 _OUT CDDEServer::Create returns %x\n", + E_OUTOFMEMORY)); + + return E_OUTOFMEMORY; +} + + + +// ValidateSrvrClass checks whether the given server class is valid by +// looking in the registration database. + +INTERNAL_(BOOL) ValidateSrvrClass ( +LPOLESTR lpclass, +ATOM FAR * lpAtom +) +{ + WCHAR buf[MAX_STR]; + LONG cb = MAX_STR; + WCHAR key[MAX_STR]; + LPOLESTR lptmp; + LPOLESTR lpbuf; + WCHAR ch; + CLSID clsid; + + if (CLSIDFromProgID (lpclass, &clsid) != NOERROR) + { + // ProgId is not correctly registered in reg db + return FALSE; + } + + lstrcpyW (key, lpclass); + lstrcatW (key, OLESTR("\\protocol\\StdFileEditing\\server")); + + if (RegQueryValue (HKEY_CLASSES_ROOT, key, buf, &cb)) + return TRUE; + + if (!buf[0]) + { + AssertSz (0, "ValidateSrvrClass failed."); + return FALSE; + } + + // Get exe name without path and then get an atom for that + lptmp = lpbuf = buf; + while (ch = *lptmp) + { + lptmp++; + if (ch == '\\' || ch == ':') + lpbuf = lptmp; + } + *lpAtom = wGlobalAddAtom (lpbuf); + + return TRUE; +} + + + +INTERNAL RemDdeRevokeClassFactory + (LPSRVR lpsrvr) +{ + HRESULT hr; + intrDebugOut((DEB_ITRACE, + "0 _IN RemDdeRevokeClassFactory(%x)\n", + lpsrvr)); + + ChkS(lpsrvr); + hr = lpsrvr->Revoke(); + intrDebugOut((DEB_ITRACE, + "0 OUT RemDdeRevokeClassFactory(%x) %x\n", + lpsrvr,hr)); + return(hr); +} + + + +INTERNAL CDDEServer::Revoke () +{ + intrDebugOut((DEB_ITRACE, + "%x _IN CDDEServer::Revoke() m_cSrvrClients=%x\n", + this, + m_cSrvrClients)); + HRESULT hr; + + ChkS(this); + + // + // Can't revoke if there are still clients. QueryRevokeCLassFactory + // determines if there are still clients attached. + // + if (!QueryRevokeClassFactory ()) + { + intrDebugOut((DEB_IERROR, + "QueryRevokeClassFactory failed!")); + hr = RPC_E_DDE_REVOKE; + goto exitRtn; + } + + if (m_cSrvrClients) + { + m_bTerminate = TRUE; + // if there are any clients connected to this classfactory, + // send terminates. + SendServerTerminateMsg (); + m_bTerminate = FALSE; + } + + hr = FreeSrvrMem (); + +exitRtn: + intrDebugOut((DEB_ITRACE, + "%x OUT CDDEServer::Revoke(%x) hr = %x\n", + this, hr)); + return hr; +} + +INTERNAL_(void) CDDEServer::SendServerTerminateMsg () +{ + + HANDLE hcliPrev = NULL; + PCLILIST pcli; + HANDLE *phandle; + HANDLE hcli; + + intrDebugOut((DEB_ITRACE, + "%x _IN CDDEServer::SendServerTerminateMsg\n", + this)); + + hcli = m_hcli; + while (hcli) { + if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL) + { + Assert(0); + goto exitRtn; + } + + phandle = (HANDLE *) (pcli->info); + while (phandle < (HANDLE *)(pcli + 1)) { + if (*phandle) + { + PostMessageToClientWithReply ((HWND)(*phandle), WM_DDE_TERMINATE, + (WPARAM) m_hwnd, NULL, WM_DDE_TERMINATE); + Assert (m_cSrvrClients); + m_cSrvrClients--; + } + phandle++; + phandle++; + } + + hcliPrev = hcli; + hcli = pcli->hcliNext; + LocalUnlock (hcliPrev); + } + +exitRtn: + intrDebugOut((DEB_ITRACE, + "%x OUT CDDEServer::SendServerTerminateMsg\n", + this)); + +} + +//+--------------------------------------------------------------------------- +// +// Method: CDDEServer::FreeSrvrMem +// +// Synopsis: Free's up a CDDEServer. +// +// Effects: +// +// Arguments: [void] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 6-26-94 kevinro Commented +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL CDDEServer::FreeSrvrMem + (void) +{ + HRESULT hr; + // REVIEW: Not clear how this works in the synchronous mode + // Release for class factory is called only when everything is + // cleaned and srvr app can post WM_QUIT at this stage + + intrDebugOut((DEB_ITRACE, + "%x _IN CDDEServer::FreeSrvrMem\n", + this)); + + PCLILIST pcliPrev; + HANDLE hcli, hcliPrev; + + if (m_bTerminate) + { + AssertSz (0, "terminate flag is not FALSE"); + } + + + if (m_aExe) + { + GlobalDeleteAtom (m_aExe); + } + + + // We deliberately do not call this->Lock (FALSE) + // If the server has revoked his class object without + // waiting for his Lock count to go to zero, then + // presumably he doesn't need us to unlock him. In fact, + // doing such an unlock might confuse a server who then + // tries to call CoRevokeClassObject recursively. + if (m_pClassFactory) + { + m_pClassFactory->Release(); + m_pClassFactory = NULL; + } + + hcli = m_hcli; + while (hcli) + { + hcliPrev = hcli; + if (pcliPrev = (PCLILIST) LocalLock (hcliPrev)) + { + hcli = pcliPrev->hcliNext; + } + else + { + AssertSz (0, "Corrupt internal data structure or out-of-memory"); + hcli = NULL; + } + Verify (0==LocalUnlock (hcliPrev)); + Verify (NULL==LocalFree (hcliPrev)); + } + + hr = DestroyDdeSrvrWindow(m_hwnd,m_aClass); + if (hr != NOERROR) + { + // + // Well now, if DestroyWindow fails, there isn't a whole heck of + // alot we can do about it. It could mean that the window was + // destroyed previously, or the parent window was destroyed during + // thread shutdown. We should still continue to cleanup + // + intrDebugOut((DEB_IERROR, + "%x CDDEServer::FreeSrvrMem DestroyDdeSrvrWindow failed %x\n", + this, + hr)); + } + + if (m_aClass) + { + GlobalDeleteAtom (m_aClass); + } + + if (m_pCallControl) + { + ReleaseDdeCallControlInterface(); + } + + delete this; + + intrDebugOut((DEB_ITRACE, + "%x _OUT CDDEServer::FreeSrvrMem\n", + this)); + return NOERROR; +} + +//+--------------------------------------------------------------------------- +// +// Function: SrvrHandleIncomingCall +// +// Synopsis: Setup and call the CallControl to dispatch a call to the server +// +// Effects: A call has been made from the client that requires us to call +// into our server. This must be routed through the call control. +// This routine sets up the appropriate data structures, and +// calls into the CallControl. The CallControl will in turn +// call SrvrDispatchIncomingCall to actuall process the call. +// +// This routine should only be called by the SrvrWndProc +// +// +// Arguments: [lpsrvr] -- Points to the server +// [hwnd] -- hwnd of server +// [hdata] -- Handle to data +// [wParam] -- hwnd of client +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 6-05-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL SrvrHandleIncomingCall(LPSRVR lpsrvr, + HWND hwnd, + HANDLE hdata, + HWND wParam) +{ + VDATEHEAP(); + HRESULT hresult = NOERROR; + IID iid; + SRVRDISPATCHDATA srvrdispdata; + DISPATCHDATA dispatchdata; + INTERFACEINFO32 ifInfo; + ICallControl *lpCallCont = lpsrvr->m_pCallControl; + + intrDebugOut((DEB_ITRACE, + "0 _IN SrvrHandleIncomingCall lpsrvr=%x hwnd=%x hdata=%x wParam=%x\n", + lpsrvr, + hwnd, + hdata, + wParam)); + + // + // It would be very bad if this didn't exist. + // + intrAssert(lpCallCont); + + // + // There is no information to provide here + // By setting pUnk to NULL, the CallControl will pass the + // message filter a NULL ifInfo. + // + + ifInfo.pUnk = NULL; + ifInfo.wMethod=0; + ifInfo.callcat = CALLCAT_SYNCHRONOUS; + + dispatchdata.pData = (LPVOID) &srvrdispdata; + + srvrdispdata.wDispFunc = DDE_DISP_SRVRWNDPROC; + srvrdispdata.hwnd = hwnd; + srvrdispdata.hData = hdata; + srvrdispdata.wParam = wParam; + srvrdispdata.lpsrvr = lpsrvr; + + hresult = lpCallCont->HandleDispatchCall((DWORD)GetWindowTask(hwnd), + iid, + &ifInfo, + &dispatchdata); + + intrDebugOut((DEB_ITRACE, + "0 _OUT SrvrHandleIncomingCall hresult=%x\n", + hresult)); + + return(hresult); +} + +//+--------------------------------------------------------------------------- +// +// Function: SrvrDispatchIncomingCall +// +// Synopsis: Dispatch a call into the server. +// +// Effects: At the moment, the only incoming call that requires handling +// by the server window is Execute. This routine dispatchs to it, +// and returns. +// +// Arguments: [psdd] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 6-05-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL SrvrDispatchIncomingCall(PSRVRDISPATCHDATA psdd) +{ + VDATEHEAP(); + HRESULT hr; + intrDebugOut((DEB_ITRACE, + "0 _IN SrvrDispatchIncomingCall psdd(%x)\n",psdd)); + + hr = psdd->lpsrvr->SrvrExecute (psdd->hwnd, + psdd->hData, + (HWND)(psdd->wParam)); + + intrDebugOut((DEB_ITRACE, + "0 _OUT SrvrDispatchIncomingCall psdd(%x) hr =%x\n", + psdd, + hr)); + + return(hr); +} + + +// REVIEW: Revoking Class Factory will not be successful if +// any clients are either connected to the classfactory +// or to the object instances. + + + +//+--------------------------------------------------------------------------- +// +// Function: SrvrWndProc +// +// Synopsis: This is the server window procedure. +// +// Effects: +// +// Arguments: [hwndIn] -- Window handle (may not be full. See note) +// [msg] -- +// [wParam] -- +// [lParam] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 8-03-94 kevinro Created +// +// Notes: +// +// When running in a VDM, it is possible that this window was dispatched +// without having a full window handle. This happens when the getmessage +// was dispatched from 16-bit. Therefore, we need to convert the hwnd to +// a full hwnd before doing any comparision functions. +// +//---------------------------------------------------------------------------- +STDAPI_(LRESULT) SrvrWndProc ( +HWND hwndIn, +UINT msg, +WPARAM wParam, +LPARAM lParam +) +{ + BOOL fRevoke=FALSE; + LPSRVR lpsrvr; + WORD status = NULL; + HANDLE hdata; + ATOM aItem; + HRESULT retval; + + // + // The following hwnd variable is used to determine the full HWND, in the + // event we were dispatched in a 16 bit process. + // + HWND hwnd; + +#ifdef FIREWALLS + HWND hwndClient; +#endif + + + switch (msg){ + + case WM_DDE_INITIATE: + VDATEHEAP(); +#ifdef FIREWALLS + AssertSz (lpsrvr, "No server window handle in server window"); +#endif + hwnd = ConvertToFullHWND(hwndIn); + + lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0); + if (lpsrvr->m_bTerminate){ + // we are terminating, no more connections + break; + } + + // class is not matching, so it is not definitely for us. + // for apps sending the EXE for initiate, do not allow if the app + // is mutiple instance (Bug fix for winworks). + + if (!(lpsrvr->m_aClass == (ATOM)(LOWORD(lParam)) || + (NOERROR==wCompatibleClasses (LOWORD(lParam), lpsrvr->m_aClass)) || + (lpsrvr->m_aExe == (ATOM)(LOWORD(lParam)) && IsSingleServerInstance() ))) + { + break; + } + + intrDebugOut((DEB_DDE_INIT,"::SrvrWndProc INITIATE\n")); + + + if (!lpsrvr->HandleInitMsg (lParam)) + { + if (!(aSysTopic == (ATOM)(HIWORD(lParam)))) + { + // + // If this isn't a sys topic, then it must be a request for + // a specific document. Send a message to the + // children windows, asking for the document. If one of them + // may send an ACK to the client. + // + + // if the server window is not the right window for + // DDE conversation, then try with the doc windows. + BOOL fAckSent = SendInitMsgToChildren (hwnd, msg, wParam, lParam); + +#ifdef KEVINRO_OLDCODE + The following code was removed, because I don't belive it is required + any longer. I am not 100% sure yet, so I have left it in. If you find it, + you can probably remove it. + It appears to be trying to claim the SINGLE_USE class factory from the class + factory table. It does this when a child document window sends an ACK to the + client, claiming to support the document being asked for. It really doesn't + make too much sense here, since a single use server would have already removed + its class factory if there was an open document. + + Anyway, the 16-bit version had a direct hack into the class factory table. We + don't have that anymore, so this code wouldn't work anyway. + + if (lpsrvr->m_fcfFlags==REGCLS_SINGLEUSE) + { + if (lpsrvr->m_pfAvail) + { + // Hide the entry in the class factory table so that no 2.0 + // client can connect to the same server. + Assert (!IsBadWritePtr (lpsrvr->m_pfAvail, sizeof(BOOL))); + *(lpsrvr->m_pfAvail) = FALSE; + } + } +#endif // KEVINRO_OLDCODE + intrDebugOut((DEB_DDE_INIT,"SrvrWndProc Child Init\n")); + return fAckSent; + } + break; + } + + // We can enterain this client. Put him in our client list + // and acknowledge the initiate. + + if (!AddClient ((LPHANDLE)&lpsrvr->m_hcli, (HWND)wParam,(HWND)/*fLocked*/FALSE)) + { + break; + } + + // + // Now its time to grab up the class factory from the class + // factory table. When this window was created, the class factory + // was available. However, it is possible that it has already + // been claimed by someone else. So, we try grabbing it (which + // normally should succeed). If it fails, then delete the client + // and don't acknowledge. + // + + if (lpsrvr->m_pClassFactory == NULL) + { + DdeClassInfo ddeInfo; + ddeInfo.dwContextMask = CLSCTX_LOCAL_SERVER | + CLSCTX_INPROC_SERVER; + intrDebugOut((DEB_DDE_INIT,"SrvrWndProc getting class factory\n")); + // + // The following asks for control of the class + // factory in the case of a single use class + // + ddeInfo.fClaimFactory = TRUE; + ddeInfo.dwRegistrationKey = lpsrvr->m_dwClassFactoryKey; + + if (GetClassInformationFromKey(&ddeInfo) == FALSE) + { + intrDebugOut((DEB_IERROR,"SrvrWndProc failed to get class factory\n")); + // + // Whoops, we were not able to grab the class factory + // Cleanup and hop out + if (!FindClient ((LPHANDLE)lpsrvr->m_hcli,(HWND)wParam, TRUE)) + { + intrAssert(!"FindClient failed\n"); + } + return(0); + } + lpsrvr->m_pClassFactory = (IClassFactory *)ddeInfo.punk; + lpsrvr->m_fcfFlags = ddeInfo.dwFlags; + } + + intrAssert(lpsrvr->m_pClassFactory != NULL); + + lpsrvr->m_cSrvrClients++; + + lpsrvr->Lock (TRUE, (HWND)wParam); + + // Post acknowledge + DuplicateAtom (LOWORD(lParam)); + DuplicateAtom (HIWORD(lParam)); + SSSendMessage ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, lParam); + + + return 1L; // fAckSent==TRUE + VDATEHEAP(); + break; + + + case WM_DDE_EXECUTE: + VDATEHEAP(); + hwnd = ConvertToFullHWND(hwndIn); + + lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0); + + hdata = GET_WM_DDE_EXECUTE_HDATA(wParam,lParam); + +#ifdef FIREWALLS + AssertSz (lpsrvr, "No server handle in server window"); +#endif + + intrDebugOut((DEB_ITRACE,"SrvrWndProc WM_DDE_EXECUTE\n")); + +#ifdef FIREWALLS + // find the client in the client list. + hwndClient = FindClient (lpsrvr->m_hcli, (HWND)wParam, FALSE); + AssertSz (hwndClient, "Client is missing from the server") +#endif + // Are we terminating + if (lpsrvr->m_bTerminate) { + intrDebugOut((DEB_ITRACE, + "SrvrWndProc WM_DDE_EXECUTE ignored for TERMINATE\n")); + // !!! are we supposed to free the data + GlobalFree (hdata); + break; + } + + retval = SrvrHandleIncomingCall(lpsrvr,hwnd,hdata,(HWND)wParam); + + if (NOERROR!=retval) + { + intrDebugOut((DEB_IERROR, + "SrvrWndProc SrvrHandleIncomingCall fail %x\n", + retval)); + } + SET_MSG_STATUS (retval, status) + + if (!lpsrvr->m_bTerminate) + { + // REVIEW: We are making an assumption that, we will not be posting + // any DDE messages because of calling the SrvrExecute. + // If we post any messages, before we post the acknowledge + // we will be in trouble. + + lParam = MAKE_DDE_LPARAM(WM_DDE_ACK,status,(UINT) hdata); + + intrDebugOut((DEB_ITRACE, + "SrvrWndProc WM_DDE_EXECUTE sending %x for ack\n",status)); + + // Post the acknowledge to the client + if (!PostMessageToClient ((HWND) wParam, + WM_DDE_ACK, (UINT) hwnd, lParam)) { + // if the window died or post failed, delete the atom. + GlobalFree (hdata); + DDEFREE(WM_DDE_ACK,lParam); + } + } + VDATEHEAP(); + break; + + + + case WM_DDE_TERMINATE: + intrDebugOut((DEB_ITRACE, + "SrvrWndProc WM_DDE_TERMINATE\n")); + + hwnd = ConvertToFullHWND(hwndIn); + + lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0); + +#ifdef FIREWALLS + // find the client in the client list. + hwndClient = FindClient (lpsrvr->m_hcli, (HWND)wParam, FALSE); + AssertSz (hwndClient, "Client is missing from the server") +#endif + Putsi (lpsrvr->m_bTerminate); + if (lpsrvr->m_bTerminate) + { + AssertSz (0, "Unexpected code path"); + } + else + { + // If client initiated the terminate. post matching terminate + PostMessageToClient ((HWND)wParam, + WM_DDE_TERMINATE, + (UINT) hwnd, + NULL); + --lpsrvr->m_cSrvrClients; + if (0==lpsrvr->m_cSrvrClients + && lpsrvr->QueryRevokeClassFactory()) + { +#ifdef KEVINRO_OLD_CODE + if (lpsrvr->m_phwndDde) + { + // Remove from class factory table + *(lpsrvr->m_phwndDde) = (HWND)0; + } +#endif // KEVINRO_OLD_CODE + fRevoke = TRUE; + } + + lpsrvr->Lock (FALSE, (HWND)wParam); // Unlock server + FindClient (lpsrvr->m_hcli, (HWND)wParam, /*fDelete*/TRUE); + + if (fRevoke) + { + lpsrvr->Revoke(); + } + } + break; + + + case WM_DDE_REQUEST: + aItem = GET_WM_DDE_REQUEST_ITEM(wParam,lParam); + + hwnd = ConvertToFullHWND(hwndIn); + + lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0); + + intrDebugOut((DEB_ITRACE, + "SrvrWndProc WM_DDE_REQUEST(aItem=%x)\n",aItem)); + + if (lpsrvr->m_bTerminate || !IsWindowValid ((HWND) wParam)) + { + goto RequestErr; + } + + if(RequestDataStd (aItem, (HANDLE FAR *)&hdata) != NOERROR) + { + + lParam = MAKE_DDE_LPARAM(WM_DDE_ACK,0x8000,aItem); + + // if request failed, then acknowledge with error. + if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, + (UINT) hwnd, lParam)) + { + DDEFREE(WM_DDE_ACK,lParam); +RequestErr: + if (aItem) + { + GlobalDeleteAtom (aItem); + } + + } + } + else + { + lParam = MAKE_DDE_LPARAM(WM_DDE_REQUEST, + (UINT) hdata,(UINT) aItem); + + // post the data message and we are not asking for any + // acknowledge. + + if (!PostMessageToClient ((HWND)wParam, WM_DDE_DATA, + (UINT) hwnd, lParam)) + { + GlobalFree (hdata); + DDEFREE(WM_DDE_REQUEST,lParam); + goto RequestErr; + } + } + break; + + case WM_DONOTDESTROY: + intrDebugOut((DEB_ITRACE, + "SrvrWndProc WM_DONOTDESTROY %x\n", + wParam)); + + // + // This message is only sent by 32-bit code that has been + // given our full handle + // + + lpsrvr = (LPSRVR)GetWindowLong (hwndIn, 0); + + // + // The WM_DONOTDESTROY message tells the server how to + // handle the following WM_USER message. If wParam is set, + // then the m_fDoNotDestroyWindow flag will be set, which + // keeps us from destroying the server window. If cleared, + // it will enable the destruction. This message is sent + // from the MaybeCreateDocWindow routine + // + + lpsrvr->m_fDoNotDestroyWindow = wParam; + return 0; + break; + + case WM_USER: + intrDebugOut((DEB_ITRACE, + "SrvrWndProc WM_USER\n")); + // + // This message is only sent by 32-bit code that has been + // given our full handle + // + + lpsrvr = (LPSRVR)GetWindowLong (hwndIn, 0); + + // cftable.cpp sends a WM_USER message to destory the DDE + // server window when a 2.0 client has connected to a + // SDI 2.0 server (and no 1.0 client should be allowed to also + // connect. + // cftable.cpp cannot call RemDdeRevokeClassFactory directly + // becuase they may be in different processes. + // + // The m_fDoNotDestroyWindow flag is used by + // MaybeCreateDocWindow in the case that the server is a + // single use server, and revokes its class factory when + // an object is created. MaybeCreateDocWindow will set this + // flag, telling us to ignore the message. + // + // returning 0 means we did destroy, 1 means we did not. + + if (!lpsrvr->m_fDoNotDestroyWindow) + { + RemDdeRevokeClassFactory(lpsrvr); + return(0); + } + return 1; + break; + + default: + return SSDefWindowProc (hwndIn, msg, wParam, lParam); + } + + return 0L; +} + +//+--------------------------------------------------------------------------- +// +// Method: CDDEServer::HandleInitMsg +// +// Synopsis: Determine if we are going to handle the INITIATE message. +// +// Effects: +// +// Arguments: [lParam] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 5-28-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL_(BOOL) CDDEServer::HandleInitMsg(LPARAM lParam) +{ + + // If it is not system or Ole, this is not the server. + if (!((aSysTopic == (ATOM)(HIWORD(lParam))) || (aOLE == (ATOM)(HIWORD(lParam))))) + { + return FALSE; + } + Assert (m_fcfFlags<=REGCLS_MULTI_SEPARATE); + + // single instance MDI accept + if (m_fcfFlags != REGCLS_SINGLEUSE) + { + return TRUE; + } + + // this server is multiple instance. So, check for any clients or docs. + if (!GetWindow (m_hwnd, GW_CHILD) && 0==m_cSrvrClients) + return TRUE; + + return FALSE; +} + + + +// AddClient: Adds a client entry to the list. +// Each client entry is a pair of handles; key handle +// and data handle. Ecah list entry contains space for +// MAX_LIST of pairs of handles. + +INTERNAL_(BOOL) AddClient +( +LPHANDLE lphead, // ptr to loc which contains the head handle +HANDLE hkey, // key +HANDLE hdata // hdata +) +{ + + HANDLE hcli = NULL; + HANDLE hcliPrev = NULL; + PCLILIST pcli; + HANDLE *phandle; + + + hcli = *lphead; + + // if the entry is already present, return error. + if (hcli && FindClient (hcli, hkey, FALSE)) + return FALSE; + + while (hcli) { + if (hcliPrev) + LocalUnlock (hcliPrev); + + if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL) + return FALSE; + + phandle = (HANDLE *) pcli->info; + while (phandle < (HANDLE *)(pcli + 1)) { + if (*phandle == NULL) { + *phandle++ = hkey; + *phandle++ = hdata; + LocalUnlock (hcli); + return TRUE; + } + phandle++; + phandle++; + } + hcliPrev = hcli; + hcli = pcli->hcliNext; + lphead = (LPHANDLE)&pcli->hcliNext; + } + + // not in the list. + hcli = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (CLILIST)); + if (hcli == NULL) + goto errRtn; + + if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL) + goto errRtn; + + // set the link to this handle in the previous entry + *lphead = hcli; + if (hcliPrev) + LocalUnlock (hcliPrev); + + phandle = (HANDLE *) pcli->info; + *phandle++ = hkey; + *phandle++ = hdata; + LocalUnlock (hcli); + return TRUE; + +errRtn: + + if (hcliPrev) + LocalUnlock (hcliPrev); + + if (hcli) + LocalFree (hcli); + + return FALSE; + +} + + +// FindClient: finds a client and deletes the client if necessary. +INTERNAL_(HANDLE) FindClient +( +HANDLE hcli, +HANDLE hkey, +BOOL bDelete +) +{ + HANDLE hcliPrev = NULL; + PCLILIST pcli; + HANDLE *phandle; + HANDLE hdata; + + while (hcli) { + if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL) + return FALSE; + + phandle = (HANDLE *) pcli->info; + while (phandle < (HANDLE *)(pcli + 1)) { + if (*phandle == hkey) { + if (bDelete) + *phandle = NULL; + + hdata = *++phandle; + LocalUnlock (hcli); + return hdata; + } + phandle++; + phandle++; + } + hcliPrev = hcli; + hcli = pcli->hcliNext; + LocalUnlock (hcliPrev); + + } + return NULL; +} + + +//+--------------------------------------------------------------------------- +// +// Method: CDDEServer::SrvrExecute +// +// Synopsis: takes care of the WM_DDE_EXECUTE for the server. +// +// Effects: Parses the EXECUTE string, and determines what it should be +// done. +// +// Arguments: [hwnd] -- Server window +// [hdata] -- Handle to EXECUTE string +// [hwndClient] -- Client window +// +// Requires: +// hdata is an ANSI string. It was passed to us by a DDE client. +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 6-05-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL CDDEServer::SrvrExecute +( +HWND hwnd, +HANDLE hdata, +HWND hwndClient +) +{ + intrDebugOut((DEB_ITRACE, + "%x _IN CDDESrvr::SrvrExecute(hwnd=%x,hdata=%x,hwndClient=%x)\n", + this, + hwnd, + hdata, + hwndClient)); + + ATOM aCmd; + BOOL fActivate; + + LPSTR lpdata = NULL; + HANDLE hdup = NULL; + HRESULT hresult = E_UNEXPECTED; + + LPSTR lpdocname; + LPSTR lptemplate; + LPCLIENT lpdocClient = NULL; + LPSTR lpnextarg; + LPSTR lpclassname; + LPSTR lpitemname; + LPSTR lpopt; + CLSID clsid; + WORD wCmdType; + BOOL bCreateInst = FALSE; + LPUNKNOWN pUnk = NULL; + + LPPERSISTSTORAGE pPersistStg=NULL; + + // REVIEW: if any methods called on the objects genarate DDE messages + // before we return from Execute, we will be in trouble. + + + // REVIEW: this code can be lot simplified if we do the argument scanning + // seperately and return the ptrs to the args. Rewrite later on. + + ErrZS (hdup = UtDupGlobal (hdata,GMEM_MOVEABLE), E_OUTOFMEMORY); + + ErrZS (lpdata = (LPSTR)GlobalLock (hdup), E_OUTOFMEMORY); + + intrDebugOut((DEB_ITRACE, + "CDDESrvr::SrvrExecute(lpdata = %s)\n",lpdata)); + + if (*lpdata++ != '[') // commands start with the left sqaure bracket + { + hresult = ResultFromScode (RPC_E_DDE_SYNTAX_EXECUTE); + goto errRtn; + } + + hresult = ReportResult(0, RPC_E_DDE_SYNTAX_EXECUTE, 0, 0); + // scan upto the first arg + if (!(wCmdType = ScanCommand (lpdata, WT_SRVR, &lpdocname, &aCmd))) + goto errRtn; + + if (wCmdType == NON_OLE_COMMAND) + { + if (!UtilQueryProtocol (m_aClass, PROTOCOL_EXECUTE)) + hresult = ReportResult(0, RPC_E_DDE_PROTOCOL, 0, 0); + else { + // REVIEW: StdExecute has to be mapped on to the StdCommandProtocol + // What command do we map on to? + + AssertSz (0, "StdExecute is being called for server"); + } + + goto errRtn1; + } + + if (aCmd == aStdExit) + { + if (*lpdocname) + goto errRtn1; + + hresult = NOERROR; + // REVIEW: Do we have to initiate any terminations from the + // the servr side? Check how this works with excel. + goto end2; + } + + // scan the next argument. + if (!(lpnextarg = ScanArg(lpdocname))) + goto errRtn; + + ////////////////////////////////////////////////////////////////////////// + // + // [StdShowItem("docname", "itemname"[, "true"])] + // + ////////////////////////////////////////////////////////////////////////// + + if (aCmd == aStdShowItem) { + + // first find the documnet. If the doc does not exist, then + // blow it off. + + if (!(lpdocClient = FindDocObj (lpdocname))) + goto errRtn1; + + lpitemname = lpnextarg; + + if( !(lpopt = ScanArg(lpitemname))) + goto errRtn1; + + // scan for the optional parameter + // Optional can be only TRUE or FALSE. + + fActivate = FALSE; + if (*lpopt) { + + if( !(lpnextarg = ScanBoolArg (lpopt, (BOOL FAR *)&fActivate))) + goto errRtn1; + + if (*lpnextarg) + goto errRtn1; + + } + + + // scan it. But, igonre the arg. + hresult = lpdocClient->DocShowItem (lpitemname, !fActivate); + goto end2; + + + + } + + ////////////////////////////////////////////////////////////////////////// + // + // [StdCloseDocument ("docname")] + // + ////////////////////////////////////////////////////////////////////////// + + if (aCmd == aStdClose) { + if (!(lpdocClient = FindDocObj (lpdocname))) + goto errRtn1; + + if (*lpnextarg) + goto errRtn1; + + // REVIEW: Do we have to do anything for shutting down the + // the app? Is the client going to initiate the terminate?. + // if we need to initiate the terminates, make sure we post + // the ACK first. + + lpdocClient->Revoke(); + goto end2; + } + + + if (aCmd == aStdOpen) + { + // find if any doc level object is already registerd. + // if the object is registerd, then no need to call srvr app. + if (FindDocObj (lpdocname)) + { + // A client has already opened the document or user opened the + // doc. We should do an addref to the docobj + +#ifdef TRY + if (m_cSrvrClients == 0) + // Why are we doing this? + hresult = lpdocClient->m_lpoleObj->AddRef(); + else +#endif + hresult = NOERROR; + goto end1; + } + } + + if (aCmd == aStdCreate || aCmd == aStdCreateFromTemplate) { + lpclassname = lpdocname; + lpdocname = lpnextarg; + if( !(lpnextarg = ScanArg(lpdocname))) + goto errRtn1; + + } + + // check whether we can create/open more than one doc. + + if ((m_fcfFlags == REGCLS_SINGLEUSE) && + GetWindow (m_hwnd, GW_CHILD)) + goto errRtn; + + + ErrZ (CLSIDFromAtom(m_aClass, &clsid)); + + + // + // Generate a wide version of the name + // + + WCHAR awcWideDocName[MAX_STR]; + + if (MultiByteToWideChar(CP_ACP,0,lpdocname,-1,awcWideDocName,MAX_STR) == FALSE) + { + Assert(!"Unable to convert characters"); + hresult = E_UNEXPECTED; + goto errRtn; + } + + ////////////////////////////////////////////////////////////////////////// + // + // [StdOpenDocument ("docname")] + // + ////////////////////////////////////////////////////////////////////////// + + // Document does not exist. + if (aCmd == aStdOpen) + { + ErrRtnH (wClassesMatch (clsid, awcWideDocName)); + ErrRtnH (wFileBind (awcWideDocName, &pUnk)); + } + + + ErrRtnH (CreateInstance (clsid, awcWideDocName, lpdocname, pUnk, &lpdocClient, hwndClient)); + bCreateInst = TRUE; + + if (aCmd == aStdOpen) + { + // Temporary flag to indicate someone will INITIATE on this doc. + // The flag is reset after the INITITATE. + // This is Yet-Another-Excel-Hack. See ::QueryRevokeClassFactory + lpdocClient->m_fCreatedNotConnected = TRUE; + } + else + { + lpdocClient->m_fEmbed = TRUE; + } + + ////////////////////////////////////////////////////////////////////////// + // + // [StdNewDocument ("classname", "docname")] + // + ////////////////////////////////////////////////////////////////////////// + + if (aCmd == aStdCreate) + { + hresult = lpdocClient->DoInitNew(); + lpdocClient->m_fCreatedNotConnected = TRUE; + goto end; + } + + + ////////////////////////////////////////////////////////////////////////// + // + // [StdNewFormTemplate ("classname", "docname". "templatename)] + // + ////////////////////////////////////////////////////////////////////////// + if (aCmd == aStdCreateFromTemplate) + { + ErrRtnH (lpdocClient->DoInitNew()); + lpdocClient->m_fCreatedNotConnected = TRUE; + IPersistFile FAR * lpPF; + lptemplate = lpnextarg; + + if(!(lpnextarg = ScanArg(lpnextarg))) + { + goto errRtn; + } + + + hresult = lpdocClient->m_lpoleObj->QueryInterface(IID_IPersistFile,(LPLPVOID)&lpPF); + if (hresult == NOERROR) + { + WCHAR awcWideTemplate[MAX_STR]; + + if (MultiByteToWideChar(CP_ACP,0,lpdocname,-1,awcWideTemplate,MAX_STR) != FALSE) + { + hresult = lpPF->Load(awcWideTemplate, 0); + } + else + { + Assert(!"Unable to convert characters"); + lpPF->Release(); + hresult = E_UNEXPECTED; + goto end; + } + + lpPF->Release(); + lpdocClient->m_fEmbed = TRUE; + } + else + { + goto end; + } + } + ////////////////////////////////////////////////////////////////////////// + // + // [StdEditDocument ("docname")] + // + ////////////////////////////////////////////////////////////////////////// + // REVIEW: Do we have to call InitNew for editing an embedded object + + if (aCmd == aStdEdit) + { + lpdocClient->m_fEmbed = TRUE; + lpdocClient->m_fGotEditNoPokeNativeYet = TRUE; + lpdocClient->m_fCreatedNotConnected = TRUE; + goto end; + } + + intrDebugOut((DEB_IERROR, + "%x CDDESrvr::SrvrExecute Unknown command\n", + this)); + +end: + + if (hresult != NOERROR) + goto errRtn; +end1: + // make sure that the srg string is indeed terminated by + // NULL. + if (*lpnextarg) + { + hresult = RPC_E_DDE_SYNTAX_EXECUTE; + } +errRtn: + + if ( hresult != NOERROR) + { + if (bCreateInst && lpdocClient) + { + lpdocClient->DestroyInstance (); + lpdocClient = NULL; //DestroyInstance invalidates the pointer + } + } + +end2: +errRtn1: + + if (lpdata) + GlobalUnlock (hdup); + + if (hdup) + GlobalFree (hdup); + if (pUnk) + pUnk->Release(); + + if (pPersistStg) + pPersistStg->Release(); + + Assert (GetScode(hresult) != E_UNEXPECTED); + + intrDebugOut((DEB_ITRACE, + "%x _OUT CDDESrvr::SrvrExecute hresult=%x\n", + this, + hresult)); + + return hresult; +} + + + + +// Maybe CreateDocWindow +// +// Return NOERROR only if a doc window was created and it sent an ACK. +// + + +//+--------------------------------------------------------------------------- +// +// Function: MaybeCreateDocWindow +// +// Synopsis: Determine if a DocWindow should be created +// +// Effects: Given a class, and a filename atom, determine if this thread +// should be the server for this request. +// +// Arguments: [aClass] -- Class of object (PROGID) +// [aFile] -- Filename (ATOM) +// [hwndDdeServer] -- HWND of CDDEServer +// [hwndSender] -- HWND of new requesting client +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 6-29-94 kevinro Created +// +// Notes: +// +//---------------------------------------------------------------------------- + INTERNAL MaybeCreateDocWindow + (ATOM aClass, + ATOM aFile, + HWND hwndDdeServer, + HWND hwndSender) +{ + CLSID clsid = CLSID_NULL; + LPUNKNOWN pUnk = NULL; + HWND hwndClient = NULL; + ULONG fAckSent = FALSE; + LPSRVR pDdeSrvr = NULL; + WCHAR szFile [MAX_STR]; + BOOL fTrue = TRUE; + BOOL fRunningInSDI = FALSE; + HRESULT hresult = NOERROR; + IClassFactory *pcf = NULL; + IPersistFile *ppf = NULL; + DdeClassInfo ddeClassInfo; + + intrDebugOut((DEB_DDE_INIT, + "MaybeCreateDocWindow(aClass=%x(%ws),aFile=%x," + "hwndDdeServer=%x,hwndSender=%x\n", + aClass,wAtomName(aClass),aFile,hwndDdeServer,hwndSender)); + + // + // If the window isn't valid, it would be very bad. + // + if (!IsWindowValid(hwndDdeServer)) + { + intrDebugOut((DEB_DDE_INIT, + "MaybeCreateDocWindow: hwndDdeServer is invalid\n")); + hresult = E_UNEXPECTED; + goto exitRtn; + } + + // + // We need the filename, which is passed in an Atom + // + Assert (IsFile (aFile)); + if (GlobalGetAtomName(aFile,szFile,MAX_STR) == 0) + { + // + // The filename was not valid + // + hresult = S_FALSE; + intrDebugOut((DEB_IERROR, + "MaybeCreateDocWindow Invalid file atom\n")); + goto exitRtn; + } + + intrDebugOut((DEB_DDE_INIT, + "MaybeCreateDocWindow File=(%ws)\n", + WIDECHECK(szFile))); + + // + // Get the class of the object. The class was passed as an atom + // in the INITIATE message. + // + if (CLSIDFromAtomWithTreatAs (&aClass, &clsid, NULL)) + { + intrDebugOut((DEB_IERROR, + "MaybeCreateDocWindow CLSIDFromAtom failed\n")); + + hresult = S_FALSE; + goto exitRtn; + } + + if (CoIsOle1Class(clsid)) + { + // we shouldn't even be looking at this INIT message + hresult = S_FALSE; + intrDebugOut((DEB_DDE_INIT, + "MaybeCreateDocWindow Its an OLE 1.0 class\n")); + goto exitRtn; + } + + // + // First of three cases is to see if the object is running in our + // local apartment. If it is, then this is the object we need to create + // a DDEServer for. + // + // Otherwise, We are going to try and load this file. + // Therefore, we need the class factory from the CFT. + // + // GetClassInformationForDde won't find a match if the class factory was + // single use, and is now hidden or invalid. + // + // If there was no class information available, then we are going to + // check to see if the object is in the local ROT. If it is in the + // local ROT, then we will use it, since it is registered and + // available for use by others + // + + ddeClassInfo.dwContextMask = CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER; + ddeClassInfo.fClaimFactory = TRUE; + + if ( GetLocalRunningObjectForDde(szFile, &pUnk) == NOERROR) + { + intrDebugOut((DEB_DDE_INIT, + "Found %ws in ROT\n",WIDECHECK(szFile))); + // + // Elsewhere in the code, we need to know if this is an SDI server. + // The old code determined this by detecting that there is a running + // object, and there was no class factory registered. + // This is sick, and obscene. Compatibilities says we need to get the + // class info anyway. However, we don't want to claim it. + // + + ddeClassInfo.fClaimFactory = FALSE; + fRunningInSDI = !GetClassInformationForDde(clsid,&ddeClassInfo); + } + else if (!GetClassInformationForDde(clsid,&ddeClassInfo)) + { + intrDebugOut((DEB_IERROR, + "No class registered for %ws\n",WIDECHECK(szFile))); + + hresult = S_FALSE; + goto exitRtn; + } + else + { + // + // Otherwise, we are registered as the server for this class. This + // means we can create this object. + // + // A 1.0 client will have launched the server with a command line + // like server.exe -Embedding filename The server ignored the filename + // so now we must make it load the file by binding the moniker. + // + // KevinRo: The old code did a bind moniker here, on the filename, + // which went through the ROT, didn't find the object, so went for + // a server. This isn't terribly safe, since we could end up binding + // out of process when we really didn't mean to. So, I have made this + // routine just use the ClassFactory we retrieve from the + // local class factory table. + // + + intrDebugOut((DEB_DDE_INIT, + "Found classinfo: Loading %ws\n",WIDECHECK(szFile))); + + + // + // Need to insure that the server doesn't go away on us. The following + // tells the server not to destroy itself. + // + SSSendMessage(hwndDdeServer,WM_DONOTDESTROY,TRUE,0); + + intrAssert(ddeClassInfo.punk != NULL); + pcf = (IClassFactory *) ddeClassInfo.punk; + + hresult = pcf->CreateInstance(NULL,IID_IUnknown,(void **)&pUnk); + + if (hresult != NOERROR) + { + intrDebugOut((DEB_IERROR, + "MaybeCreateDocWindow CreateInstancefailed File=(%ws)\n", + WIDECHECK(szFile))); + goto sndMsg; + } + + // + // Get the IPersistFile interface, and ask the object to load + // itself. + // + hresult = pUnk->QueryInterface(IID_IPersistFile,(void **)&ppf); + if (hresult != NOERROR) + { + intrDebugOut((DEB_IERROR, + "MaybeCreateDocWindow QI IPF failed File=(%ws)\n", + WIDECHECK(szFile))); + goto sndMsg; + } + // + // Attempt to load the object. The flags STGM_READWRITE are the + // same default values used by a standard bind context. + // + hresult = ppf->Load(szFile,STGM_READWRITE); + if (hresult != NOERROR) + { + intrDebugOut((DEB_IERROR, + "MaybeCreateDocWindow ppf->Load(%ws) failed %x\n", + WIDECHECK(szFile), + hresult)); + goto sndMsg; + } +sndMsg: + SSSendMessage(hwndDdeServer,WM_DONOTDESTROY,FALSE,0); + if (hresult != NOERROR) + { + goto exitRtn; + + } + intrDebugOut((DEB_DDE_INIT, + "Loading %ws complete\n",WIDECHECK(szFile))); + + } + + + intrAssert(IsWindowValid(hwndDdeServer)); + intrAssert (pUnk); + + pDdeSrvr = (LPSRVR) GetWindowLong (hwndDdeServer, 0); + if (pDdeSrvr == NULL) + { + intrAssert(pDdeSrvr != NULL); + hresult = E_UNEXPECTED; + goto exitRtn; + } + + // This actually creates the doc window as a child of the server window + // Do not set the client site becuase this is a link. + hresult = CDefClient::Create (pDdeSrvr, + pUnk, + szFile, + /*fSetClientSite*/FALSE, + /*fDoAdvise*/TRUE, + fRunningInSDI, + &hwndClient); + + if (hresult != NOERROR) + { + intrDebugOut((DEB_IERROR, + "MaybeCreateDocWindow CDefClient::Create failed %x\n", + hresult)); + goto exitRtn; + } + + Assert (IsWindowValid (hwndClient)); + + // + // Pass along the original DDE_INIT to the newly created window. + // That window should respond by sending an ACK to the 1.0 client. + // + fAckSent = SSSendMessage (hwndClient, + WM_DDE_INITIATE, + (UINT) hwndSender, + MAKELONG(aClass, aFile)); + if (!fAckSent) + { + intrDebugOut((DEB_IERROR, + "MaybeCreateDocWindow !fAckSent\n")); + hresult = CO_E_APPDIDNTREG; + } + +exitRtn: + + if (ppf) + { + ppf->Release(); + } + if (pUnk) + { + pUnk->Release(); + } + if (pcf) + { + pcf->Release(); + } + + intrDebugOut((DEB_DDE_INIT, + "MaybeCreateDocWindow returns %x\n", + hresult)); + return hresult; +} + + +//+--------------------------------------------------------------------------- +// +// Function: SendMsgToChildren +// +// Synopsis: This routine sends the msg to all child windows. +// +// Arguments: [hwnd] -- Hwnd of parent window +// [msg] -- Message and parameters to send +// [wParam] -- +// [lParam] -- +// +// Notes: This routine will stop on the first non-zero return code. +// +//---------------------------------------------------------------------------- +BOOL SendMsgToChildren (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + intrDebugOut((DEB_ITRACE, + "0 _IN SendMsgToChildren(hwnd=%x,msg=%x,wParam=%x,lParam=%x)\n", + hwnd,msg,wParam,lParam)); + + BOOL fAckSent = FALSE; + + hwnd = GetWindow(hwnd, GW_CHILD); + + // + // This routine is to be called only from one place, which is + // in the handling of WM_DDE_INITIATE. Because of that, we will terminate + // the loop on the first non-zero return code. + // + Assert (msg == WM_DDE_INITIATE); + + while (hwnd) + { + intrDebugOut((DEB_ITRACE," SendMsgToChildren send to hwnd=%x\n",hwnd)); + + if (fAckSent = (1L==SSSendMessage (hwnd, msg, wParam, lParam))) + { + break; + } + + hwnd = GetWindow (hwnd, GW_HWNDNEXT); + } + + intrDebugOut((DEB_ITRACE,"0 OUT SendMsgToChildren returns %x\n",fAckSent)); + return(fAckSent); +} + + +//+--------------------------------------------------------------------------- +// +// Function: SendInitMsgToChildren +// +// Synopsis: Sends an init message to all child windows of the hwnd +// +// Effects: This routine will send an init message to all children +// of the given window. It is assuming that the lParam is +// the atom that contains the topic (ie filename) of the +// object being looked for. +// +// Arguments: [hwnd] -- hwnd of server window +// [msg] -- MSG to send +// [wParam] -- hwnd of client window +// [lParam] -- HIWORD(lParam) is atom of filename +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Algorithm: +// +// History: 6-28-94 kevinro Commented +// +// Notes: +// +//---------------------------------------------------------------------------- +BOOL SendInitMsgToChildren (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + intrDebugOut((DEB_DDE_INIT, + "0 _IN SendInitMsgToChildren(hwnd=%x,msg=%x,wParam=%x,lParam=%x)\n", + hwnd,msg,wParam,lParam)); + + BOOL fAckSent = FALSE; + + fAckSent = SendMsgToChildren(hwnd,msg,wParam,lParam); + + // + // If no windows acknowledged, then we might need to create a doc window + // + if (!fAckSent) + { + ATOM aTopic = HIWORD(lParam); + Assert (IsAtom(aTopic)); + + // if someone's trying to initiate on a filename, i.e., for a link + // then create the doc window on demand because 2.0 servers do not + // register doc windows. They don't even accept "-Embedding filename" + // on the command line + if (aTopic != aOLE && aTopic != aSysTopic && IsFile (aTopic)) + { + intrDebugOut((DEB_DDE_INIT," Initiate for link %ws\n",wAtomName(aTopic))); + HRESULT hresult = MaybeCreateDocWindow (LOWORD(lParam), aTopic, + hwnd, (HWND)wParam); + + fAckSent = (NOERROR==hresult); + } + } + intrDebugOut((DEB_DDE_INIT, + "0 _OUT SendInitMsgToChildren fAckSent=%x\n",fAckSent)); + return fAckSent; +} + + + +INTERNAL_(HRESULT) RequestDataStd +( +ATOM aItem, +LPHANDLE lphdde +) +{ + + + HANDLE hnew = NULL; + + if (!aItem) + goto errRtn; + + if (aItem == aEditItems){ + hnew = MakeGlobal ("StdHostNames\tStdDocDimensions\tStdTargetDevice"); + goto PostData; + + } + + if (aItem == aProtocols) { + hnew = MakeGlobal ("Embedding\tStdFileEditing"); + goto PostData; + } + + if (aItem == aTopics) { + hnew = MakeGlobal ("Doc"); + goto PostData; + } + + if (aItem == aFormats) { + hnew = MakeGlobal ("Picture\tBitmap"); + goto PostData; + } + + if (aItem == aStatus) { + hnew = MakeGlobal ("Ready"); + goto PostData; + } + + // format we do not understand. + goto errRtn; + +PostData: + + // Duplicate the DDE data + if (MakeDDEData (hnew, CF_TEXT, lphdde, TRUE)){ + // !!! why are we duplicating the atom. + DuplicateAtom (aItem); + return NOERROR; + } +errRtn: + return ReportResult(0, S_FALSE, 0, 0); +} + + +//IsSingleServerInstance: returns true if the app is single server app else +//false. + +INTERNAL_(BOOL) IsSingleServerInstance () +{ + HWND hwnd; + WORD cnt = 0; + HTASK hTask; + DdeCHAR buf[MAX_STR]; + + hwnd = GetWindow (GetDesktopWindow(), GW_CHILD); + hTask = GetCurrentThreadId(); + + while (hwnd) { + if (hTask == ((HTASK) GetWindowThreadProcessId (hwnd,NULL))) { + DdeGetClassName (hwnd, buf, MAX_STR); + if (Ddelstrcmp (buf, SRVR_CLASS) == 0) + cnt++; + } + hwnd = GetWindow (hwnd, GW_HWNDNEXT); + } +#ifdef FIREWALLS + AssertSz (cnt > 0, "srvr window instance count is zero"); +#endif + if (cnt == 1) + return TRUE; + else + return FALSE; + +} + + +// QueryRevokeClassFactory: returns FALSE if there are clients +// connected tothis class factory; +INTERNAL_(BOOL) CDDEServer::QueryRevokeClassFactory () +{ + + HWND hwnd; + LPCLIENT lpclient; + + Assert (IsWindow (m_hwnd)); + hwnd = GetWindow (m_hwnd, GW_CHILD); + while (hwnd) + { + Assert (IsWindow (hwnd)); + lpclient = (LPCLIENT)GetWindowLong (hwnd, 0); + if (lpclient->m_cClients != 0 || lpclient->m_fCreatedNotConnected) + return FALSE; + hwnd = GetWindow (hwnd, GW_HWNDNEXT); + } + return TRUE; +} + + + +//+--------------------------------------------------------------------------- +// +// Method: CDDEServer::CreateInstance +// +// Synopsis: Create an instance of a document +// +// Effects: +// +// Arguments: [lpclassName] -- +// [lpWidedocName] -- +// [lpdocName] -- +// [pUnk] -- +// [lplpdocClient] -- +// [hwndClient] -- +// +// Requires: +// +// Returns: +// +// Signals: +// +// Modifies: +// +// Derivation: +// +// Algorithm: +// +// History: 5-30-94 kevinro Commented/cleaned +// +// Notes: +// +//---------------------------------------------------------------------------- +INTERNAL CDDEServer::CreateInstance +( +REFCLSID lpclassName, +LPOLESTR lpWidedocName, +LPSTR lpdocName, +LPUNKNOWN pUnk, +LPCLIENT FAR* lplpdocClient, +HWND hwndClient) +{ + intrDebugOut((DEB_ITRACE, + "%p _IN CDDEServer::CreateInstance(lpWidedocName=%ws,hwndClient=%x)\n", + this, + WIDECHECK(lpWidedocName), + hwndClient)); + + + LPUNKNOWN pUnk2=NULL; + LPOLEOBJECT lpoleObj= NULL; // unknown object + HRESULT hresult; + + ChkS(this); + + if (NULL==pUnk) + { + Assert (m_pClassFactory); + hresult = m_pClassFactory->CreateInstance (NULL, IID_IUnknown, (LPLPVOID)&pUnk2); + + if (hresult != NOERROR) + { + return hresult; + } + + // Now that we have *used* the DDE server window, we can unlock + // the server. + // The OLE1 OleLockServer API opens a dummy DDE system channel + // and just leaves it open until OleunlockServer is called. + // Since we have now used this channel, we know it was not created + // for the purpose of locking the server. + this->Lock (FALSE, hwndClient); + + // if it is an SDI app, we must revoke the ClassFactory after using it + // it is only good for "one-shot" createinstance call. + if (m_fcfFlags == REGCLS_SINGLEUSE) + { + m_pClassFactory->Release(); // done with the ClassFactory + Puts ("NULLing m_pCF\r\n"); + m_pClassFactory = NULL; + } + } + else + { + pUnk2 = pUnk; + pUnk->AddRef(); + } + + hresult = CDefClient::Create ((LPSRVR)this, + pUnk2, + lpWidedocName, + /*fSetClientSite*/FALSE, + /*fDoAdvise*/pUnk!=NULL); + + intrAssert (pUnk2 != NULL); + if (pUnk2 != NULL) + { + pUnk2->Release(); + } + + pUnk2 = NULL; + + // REVIEW: error recovery + if (!(*lplpdocClient = FindDocObj (lpdocName))) + { + intrAssert(!"Document created but not found"); + } + else + { + // set the server instance flag so that WM_DDE_INITIATE will not icrement + // the ref count. (EXCEL BUG) + (*lplpdocClient)->m_bCreateInst = TRUE; + } + intrDebugOut((DEB_ITRACE, + "%p _OUT CDDEServer::CreateInstance hresult=%x\n", + this,hresult)); + return hresult; +} + + +INTERNAL_(void) CDDEServer::Lock + (BOOL fLock, // lock or unlock? + HWND hwndClient) // on behalf of which window? +{ + intrDebugOut((DEB_ITRACE, + "%p _IN CDDEServer::Lock(fLock=%x,hwndCient=%x)\n", + this, + fLock, + hwndClient)); + + VDATEHEAP(); + BOOL fIsLocked = (BOOL) FindClient (m_hcli, hwndClient, /*fDelete*/FALSE); + + if (fLock && !fIsLocked) + { + if (m_pClassFactory) + { + intrDebugOut((DEB_ITRACE, + "%p ::Locking %x\n", + this, + m_pClassFactory)); + + m_pClassFactory->LockServer (TRUE); + // Only way to change the data associated with a client window + // is to delete it and re-add it with the new data. + FindClient (m_hcli, hwndClient, /*fDelete*/ TRUE); + AddClient (&m_hcli, hwndClient, (HANDLE) TRUE); // mark as locked + } + } + else if (!fLock && fIsLocked) + { + if (m_pClassFactory) + { + intrDebugOut((DEB_ITRACE, + "%p ::UnLocking %x\n", + this, + m_pClassFactory)); + m_pClassFactory->LockServer (FALSE); + FindClient (m_hcli, hwndClient, /*fDelete*/ TRUE); + AddClient (&m_hcli, hwndClient, (HANDLE) FALSE); //mark as unlocked + } + } + VDATEHEAP(); + intrDebugOut((DEB_ITRACE, + "%p _OUT CDDEServer::Lock(fLock=%x,hwndCient=%x)\n", + this, + fLock, + hwndClient)); +} + + + + + +INTERNAL CDefClient::DestroyInstance + (void) +{ + Puts ("DestroyInstance\r\n"); + // We just created the instance. we ran into error. + // just call Release. + m_pUnkOuter->AddRef(); + ReleaseObjPtrs(); + Verify (0==m_pUnkOuter->Release()); + // "this" should be deleted now + return NOERROR; +} + + + +INTERNAL CDefClient::SetClientSite + (void) +{ + HRESULT hresult = m_lpoleObj->SetClientSite (&m_OleClientSite); + if (hresult==NOERROR) + { + m_fDidSetClientSite = TRUE; + } + else + { + Warn ("SetClientSite failed"); + } + return hresult; +} + + + diff --git a/private/ole32/com/remote/dde/server/srvr.h b/private/ole32/com/remote/dde/server/srvr.h new file mode 100644 index 000000000..e599fb019 --- /dev/null +++ b/private/ole32/com/remote/dde/server/srvr.h @@ -0,0 +1,522 @@ +/****************************** Module Header ******************************\ +* Module Name: srvr.h +* +* PURPOSE: Private definitions file for server code +* +* Created: 1990 +* +* Copyright (c) 1990, 1991 Microsoft Corporation +* +* History: +* Raor (../../90,91) Original +* +\***************************************************************************/ +// +// One of the oleint.h routines redefines GlobalAlloc and friends +// to perform some memory tracking functions. +// +// This doesn't work in these files, since the tracking functions +// add tail checking, and size to the data structures. GlobalSize +// is a common function to use to determine how much data to +// serialize, plus it turns out that the other side of a DDE +// connection will often be the caller to free the memory. +// +// Therefore, OLE_DDE_NO_GLOBAL_TRACKING is used to disable this in the +// global header file ih\memapi.hxx. Check to insure this +// flag is set on the compile line +// +#if !defined(OLE_DDE_NO_GLOBAL_TRACKING) +error OLE_DDE_OLE_DDE_NO_GLOBAL_TRACKING must be defined to build this directory +#endif + +#include <dde.h> +#include <ddeerr.h> +#include "ddeatoms.h" +#include "ddepack.h" +#include <callcont.hxx> +#include <ddeint.h> +#include <ddechc.hxx> +#include <longname.h> + +//#define UPDATE +/* + if UPDATE is defined it means: + If a 1.0 client advises on save, also do a data advise. + This way the client will always + have an up-to-date picture (and native data) with respect to a + 2.0 server, like 2.0 clients do. + If a 1.0 client is prepared to accept data at save time + it should be able to handle data on each change: it is exactly + as if the user chose File.Update after each change. + In fact the item atom is appended with /Save, (see SendDataMsg1) + which is sort of a lie, but is what a 1.0 client expects for an + embedded object. + This is a UI issue. +*/ + +#define DEFSTD_ITEM_INDEX 0 +#define STDTARGETDEVICE 1 +#define STDDOCDIMENSIONS 2 +#define STDCOLORSCHEME 3 +#define STDHOSTNAMES 4 + + +#define PROTOCOL_EDIT (OLESTR("StdFileEditing")) +#define PROTOCOL_EXECUTE (OLESTR("StdExecute")) + +#define ISATOM(a) ((a >= 0xC000) && (a <= 0xFFFF)) + +// same limit as in OLE 1.0 +#define MAX_STR 124 + +#define WW_LPTR 0 // ptr tosrvr/doc/item +#define WW_HANDLE 4 // instance handle +#define WW_LE 8 // signature + + +#define WC_LE 0x4c45 // LE chars + + +// Signatures for validity checking +typedef enum +{ + chkDdeSrvr = 0x1234, + chkDefClient = 0x5678 +} CHK; + + +const DWORD grfCreateStg = STGM_READWRITE | STGM_SHARE_EXCLUSIVE + | STGM_DIRECT | STGM_CREATE ; + + +// If we running under WLO, the HIGHWORD of version number will be >= 0x0A00 +#define VER_WLO 0x0A00 + +extern "C" WORD CheckPointer (LPVOID, int); + +#define READ_ACCESS 0 +#define WRITE_ACCESS 1 + +#define PROBE_READ(lp){\ + if (!CheckPointer(lp, READ_ACCESS))\ + return ReportResult(0, E_INVALIDARG, 0, 0); \ +} + +#define PROBE_WRITE(lp){\ + if (!CheckPointer(lp, WRITE_ACCESS))\ + return ReportResult(0, E_INVALIDARG, 0, 0); \ +} + +#define OLE_COMMAND 1 +#define NON_OLE_COMMAND 2 + + +#define WT_SRVR 0 // server window +#define WT_DOC 1 // document window + +#define PROBE_BLOCK(lpsrvr) { \ + if (lpsrvr->bBlock) \ + return ReportResult(0, S_SERVER_BLOCKED, 0, 0); \ +} + + +#define SET_MSG_STATUS(retval, status) { \ + if (!FAILED (GetScode (retval))) \ + status |= 0x8000; \ + if (GetScode(retval) == RPC_E_SERVERCALL_RETRYLATER)\ + status |= 0x4000; \ +} + + +/* Codes for CallBack events */ +typedef enum { + OLE_CHANGED, /* 0 */ + OLE_SAVED, /* 1 */ + OLE_CLOSED, /* 2 */ + OLE_RENAMED, /* 3 */ +} OLE_NOTIFICATION; + +typedef enum { cnvtypNone, cnvtypConvertTo, cnvtypTreatAs } CNVTYP; + +typedef struct _QUE : public CPrivAlloc { // nodes in Block/Unblock queue + HWND hwnd; //*** + UINT msg; // window + WPARAM wParam; // procedure parameters + LPARAM lParam; //*** + HANDLE hqNext; // handle to next node +} QUE; + +typedef QUE NEAR * PQUE; +typedef QUE FAR * LPQUE; + +// structure for maintaining the client info. +#define LIST_SIZE 10 +typedef struct _CLILIST : public CPrivAlloc { + HANDLE hcliNext; + HANDLE info[LIST_SIZE * 2]; +}CLILIST; + +typedef CLILIST FAR *LPCLILIST; +typedef CLILIST *PCLILIST; + + +class FAR CDDEServer +{ + public: + static HRESULT Create (LPOLESTR lpclass, + REFCLSID rclsid, + LPDDECLASSINFO lpDdeInfo, + HWND FAR * phwnd, + ATOM aOriginalClass, + CNVTYP cnvtyp); + + INTERNAL_(BOOL) HandleInitMsg (LPARAM); + INTERNAL SrvrExecute (HWND, HANDLE, HWND); + INTERNAL Revoke (void); + INTERNAL_(BOOL) QueryRevokeClassFactory (void); + INTERNAL_(LPCLIENT) FindDocObj (LPSTR lpDoc); + INTERNAL_(void) Lock (BOOL fLock, HWND hwndClient); + + + CLSID m_clsid; // Class ID + DWORD m_dwClassFactoryKey; // Class factory reg key + LPCLASSFACTORY m_pClassFactory; // class factory + ICallControl * m_pCallControl; // Call control interface + BOOL m_bTerminate; // Set if we are terminating. + HWND m_hwnd; // corresponding window + HANDLE m_hcli; // handle to the first block of clients list + int m_termNo; // termination count + int m_cSrvrClients; // no of clients; + DWORD m_fcfFlags; // Class factory instance usage flags + CNVTYP m_cnvtyp; + CHK m_chk; + + ATOM m_aClass; // class atom + ATOM m_aOriginalClass; // for TreatAs/ConvertTo case + ATOM m_aExe; + + BOOL m_fDoNotDestroyWindow; // When set, server wnd ingores WM_USER + + private: + INTERNAL_(void) SendServerTerminateMsg (void); + INTERNAL RevokeAllDocObjs (void); + INTERNAL FreeSrvrMem (void); + INTERNAL CreateInstance (REFCLSID clsid, LPOLESTR lpWidedocName, LPSTR lpdocName, + LPUNKNOWN pUnk, LPCLIENT FAR* lplpdocClient, + HWND hwndClient); + + +}; + + + + +BOOL SendInitMsgToChildren (HWND, UINT msg, WPARAM wParam, LPARAM lParam); + +INTERNAL RequestDataStd (ATOM, HANDLE FAR *); +INTERNAL_(BOOL) ValidateSrvrClass (LPOLESTR, ATOM FAR *); +INTERNAL_(ATOM) GetExeAtom (LPOLESTR); +INTERNAL_(BOOL) AddClient (LPHANDLE, HANDLE, HANDLE); +INTERNAL_(HANDLE) FindClient (HANDLE hCli, HANDLE hkey, BOOL fDelete); + +INTERNAL_(BOOL) IsSingleServerInstance (void); + +INTERNAL_(void) UtilMemCpy (LPSTR, LPSTR, DWORD); +INTERNAL_(HANDLE) DuplicateData (HANDLE); +INTERNAL_(LPSTR) ScanBoolArg (LPSTR, BOOL FAR *); +INTERNAL_(LPSTR) ScanNumArg (LPSTR, LPINT); +INTERNAL_(LPSTR) ScanArg(LPSTR); +INTERNAL_(ATOM) MakeDataAtom (ATOM, int); +INTERNAL_(ATOM) DuplicateAtom (ATOM); +INTERNAL_(BOOL) CLSIDFromAtom(ATOM aClass, LPCLSID lpclsid); +INTERNAL CLSIDFromAtomWithTreatAs (ATOM FAR* paClass, LPCLSID lpclsid, + CNVTYP FAR* pcnvtyp); +INTERNAL wFileIsRunning (LPOLESTR szFile); +INTERNAL wFileBind (LPOLESTR szFile, LPUNKNOWN FAR* ppUnk); +INTERNAL wCreateStgAroundNative (HANDLE hNative, + ATOM aClassOld, + ATOM aClassNew, + CNVTYP cnvtyp, + ATOM aItem, + LPSTORAGE FAR* ppstg, + LPLOCKBYTES FAR* pplkbyt); +INTERNAL wCompatibleClasses (ATOM aClient, ATOM aSrvr); + + + + +typedef struct FARSTRUCT : public CPrivAlloc { + BOOL f; // do we need to send an ack? + // If this is FALSE, other fields don't matter + HGLOBAL hdata; + HWND hwndFrom; // who sent the execute? + HWND hwndTo; +} EXECUTEACK; + + +// client struct definitions. + + + +class FAR CDefClient : public CPrivAlloc +{ + public: + static INTERNAL Create + (LPSRVR pDdeSrvr, + LPUNKNOWN lpunkObj, + LPOLESTR lpdocName, + const BOOL fSetClientSite, + const BOOL fDoAdvise, + const BOOL fRunningInSDI = FALSE, + HWND FAR* phwnd = NULL); + + INTERNAL DocExecute (HANDLE); + INTERNAL DocDoVerbItem (LPSTR, WORD, BOOL, BOOL); + INTERNAL DocShowItem (LPSTR, BOOL); + INTERNAL DestroyInstance (); + INTERNAL_(void) DeleteFromItemsList (HWND h); + INTERNAL_(void) RemoveItemFromItemList (void); + INTERNAL_(void) ReleasePseudoItems (void); + INTERNAL_(void) ReleaseAllItems (); + INTERNAL PokeStdItems (HWND, ATOM, HANDLE,int); + INTERNAL PokeData (HWND, ATOM, HANDLE); + INTERNAL AdviseData (HWND, ATOM, HANDLE, BOOL FAR *); + INTERNAL AdviseStdItems (HWND, ATOM, HANDLE, BOOL FAR *); + INTERNAL UnAdviseData (HWND, ATOM); + INTERNAL RequestData (HWND, ATOM, USHORT, HANDLE FAR *); + INTERNAL Revoke (BOOL fRelease=TRUE); + INTERNAL ReleaseObjPtrs (void); + INTERNAL_(void) DeleteAdviseInfo (); + INTERNAL DoOle20Advise (OLE_NOTIFICATION, CLIPFORMAT); + INTERNAL DoOle20UnAdviseAll (void); + INTERNAL SetClientSite (void); + INTERNAL NoItemConnections (void); + INTERNAL_(void) SendExecuteAck (HRESULT hresult); + INTERNAL DoInitNew(void); + INTERNAL Terminate(HWND, HWND); + + CHK m_chk; // signature + ICallControl * m_pCallControl; // Call control for this doc + IUnknown FAR* m_pUnkOuter; + LPOLEOBJECT m_lpoleObj; // corresponding oleobj + LPDATAOBJECT m_lpdataObj; // corresponding dataobj + BOOL m_bCreateInst; // instance is just created. + BOOL m_bTerminate; // REVIEW: The next two fields may not be necessary. + int m_termNo; + ATOM m_aItem; // item atom or index for some std items + HANDLE m_hcli; // handle to the first block of clients list (Document only) + CDefClient FAR *m_lpNextItem; // ptr to the next item. + BOOL m_bContainer; // Is document? + BOOL m_cRef; + HWND m_hwnd; // doc window (only needed in document) + HANDLE m_hdevInfo; // latest printer dev info sent + HANDLE m_hcliInfo; // advise info for each of the clients + BOOL m_fDidRealSetHostNames; + BOOL m_fDidSetClientSite; + BOOL m_fGotDdeAdvise; + BOOL m_fCreatedNotConnected; + BOOL m_fInOnClose; + BOOL m_fInOleSave; + EXECUTEACK m_ExecuteAck; + DWORD m_dwConnectionOleObj; + DWORD m_dwConnectionDataObj; + LPLOCKBYTES m_plkbytNative; // These two fields always refer to + LPSTORAGE m_pstgNative; // to the same bits: + // The server's persistent storage is + // used as its native data. + BOOL m_fRunningInSDI;// Link case: file was already open in + // an SDI app which does not register a + // class factory. + LPSRVR m_psrvrParent; // (Document only) + DVTARGETDEVICE FAR* m_ptd; + BOOL m_fGotStdCloseDoc; + BOOL m_fGotEditNoPokeNativeYet; + BOOL m_fLocked; // locked by CoLockObjectExternal ? + + // If not zero, then we are waiting for a matching TERMINATE + + CALLDATA * m_pCallData; + + + + + + // REVIEW: These fields might be necssary for doc (old) level object + BOOL m_fEmbed; // embedded object (Document only) + int m_cClients; // (Document only) + LPCLIENT m_pdoc; // containing document (for items) or self (for docs) + + +implementations: + + STDUNKDECL (CDefClient,DefClient); + + /*** IOleClientSite ***/ + implement COleClientSiteImpl : IOleClientSite + { + public: + // Constructor + COleClientSiteImpl (CDefClient FAR* pDefClient) + { m_pDefClient = pDefClient; + } + STDMETHOD(QueryInterface) (REFIID, LPVOID FAR *); + STDMETHOD_(ULONG,AddRef) (void); + STDMETHOD_(ULONG,Release) (void); + + /*** IOleClientSite methods ***/ + STDMETHOD(SaveObject) (THIS); + STDMETHOD(GetMoniker) (THIS_ DWORD dwAssign, DWORD dwWhichMoniker, + LPMONIKER FAR* ppmk); + STDMETHOD(GetContainer) (THIS_ LPOLECONTAINER FAR* ppContainer); + STDMETHOD(ShowObject) (THIS); + STDMETHOD(OnShowWindow) (THIS_ BOOL fShow); + STDMETHOD(RequestNewObjectLayout) (THIS); + + private: + CDefClient FAR* m_pDefClient; + }; + + DECLARE_NC (CDefClient, COleClientSiteImpl) + COleClientSiteImpl m_OleClientSite; + + + + /*** IAdviseSink ***/ + implement CAdviseSinkImpl : IAdviseSink + { + public: + // Constructor + CAdviseSinkImpl (CDefClient FAR* pDefClient) + { m_pDefClient = pDefClient; + } + + STDMETHOD(QueryInterface) (REFIID, LPVOID FAR *); + STDMETHOD_(ULONG,AddRef) (void); + STDMETHOD_(ULONG,Release) (void); + + /**** IAdviseSink methods ****/ + STDMETHOD_(void,OnDataChange)(THIS_ FORMATETC FAR* pFormatetc, + STGMEDIUM FAR* pStgmed) ; + STDMETHOD_(void,OnViewChange)(THIS_ DWORD aspects, LONG lindex) ; + STDMETHOD_(void,OnExtentChange)(DWORD dwAspect, LPSIZEL lpsizel) {} + STDMETHOD_(void,OnRename)(THIS_ LPMONIKER pmk) ; + STDMETHOD_(void,OnSave)(THIS) ; + STDMETHOD_(void,OnClose)(THIS) ; + + private: + CDefClient FAR* m_pDefClient; + }; + + DECLARE_NC (CDefClient, CAdviseSinkImpl) + CAdviseSinkImpl m_AdviseSink; + +ctor_dtor: + CDefClient (LPUNKNOWN pUnkOuter); + ~CDefClient (void); + +private: + INTERNAL ItemCallBack (int msg, LPOLESTR szNewName = NULL); + INTERNAL_(void) SendTerminateMsg (); + INTERNAL_(BOOL) SendDataMsg1 (HANDLE, WORD); + INTERNAL_(BOOL) SendDataMsg (WORD); + INTERNAL_(void) TerminateNonRenameClients (LPCLIENT); + INTERNAL_(void) SendRenameMsgs (HANDLE); + INTERNAL RegisterItem (LPOLESTR, LPCLIENT FAR *, BOOL); + INTERNAL FindItem (LPOLESTR, LPCLIENT FAR *); + INTERNAL_(LPCLIENT) SearchItem (LPOLESTR); + INTERNAL_(void) DeleteAllItems (); + INTERNAL SetStdInfo (HWND, LPOLESTR, HANDLE); + INTERNAL_(void) SendDevInfo (HWND); + INTERNAL_(BOOL) IsFormatAvailable (CLIPFORMAT); + INTERNAL GetData (LPFORMATETC, LPSTGMEDIUM); +}; + + + + +typedef struct _CLINFO : public CPrivAlloc { /*clInfo*/ // client transaction info + HWND hwnd; // client window handle + BOOL bnative; // doe sthis client require native + int format; // dusplay format + int options; // transaction advise time otipns + BOOL bdata; // need wdat with advise? + HANDLE hdevInfo; // device info handle + BOOL bnewDevInfo; // new device info +} CLINFO; + +typedef CLINFO *PCLINFO; + + + +INTERNAL_(BOOL) MakeDDEData (HANDLE, int, LPHANDLE, BOOL); +INTERNAL_(HANDLE) MakeGlobal (LPSTR); +INTERNAL ScanItemOptions (LPOLESTR, int far *); +INTERNAL_(int) GetStdItemIndex (ATOM); +INTERNAL_(BOOL) IsAdviseStdItems (ATOM); +INTERNAL_(HANDLE) MakeItemData (DDEPOKE FAR *, HANDLE, CLIPFORMAT); +INTERNAL_(BOOL) AddMessage (HWND, unsigned, WORD, LONG, int); + + + +#define ITEM_FIND 1 // find the item +#define ITEM_DELETECLIENT 2 // delete the client from item clients +#define ITEM_DELETE 3 // delete th item window itself +#define ITEM_SAVED 4 // item saved + +// host names data structcure +typedef struct _HOSTNAMES : public CPrivAlloc { + WORD clientNameOffset; + WORD documentNameOffset; + BYTE data[1]; +} HOSTNAMES; + +typedef HOSTNAMES FAR * LPHOSTNAMES; + + +// routines in UTILS.C +LPOLESTR CreateUnicodeFromAnsi( LPCSTR lpAnsi); +LPSTR CreateAnsiFromUnicode( LPCOLESTR lpAnsi); +INTERNAL_(HANDLE) DuplicateData (HANDLE); +INTERNAL_(LPSTR) ScanLastBoolArg (LPSTR); +INTERNAL_(LPSTR) ScanArg(LPSTR); +INTERNAL_(WORD) ScanCommand(LPSTR, WORD, LPSTR FAR *, ATOM FAR *); +INTERNAL_(ATOM) MakeDataAtom (ATOM, int); +INTERNAL_(ATOM) DuplicateAtom (ATOM); +INTERNAL_(WORD) StrToInt (LPOLESTR); +INTERNAL_(BOOL) PostMessageToClientWithReply (HWND, UINT, WPARAM, LPARAM, UINT); +INTERNAL_(BOOL) PostMessageToClient (HWND, UINT, WPARAM, LPARAM); +INTERNAL_(BOOL) IsWindowValid (HWND); +INTERNAL_(BOOL) IsOleCommand (ATOM, WORD); +INTERNAL_(BOOL) UtilQueryProtocol (ATOM, LPOLESTR); +INTERNAL SynchronousPostMessage (HWND, UINT, WPARAM, LPARAM); +INTERNAL_(BOOL) IsAtom (ATOM); +INTERNAL_(BOOL) IsFile (ATOM a, BOOL FAR* pfUnsavedDoc = NULL); + + +// routines for queueing messages and posting them +INTERNAL_(BOOL) UnblockPostMsgs(HWND, BOOL); +INTERNAL_(BOOL) BlockPostMsg (HWND, WORD, WORD, LONG); +INTERNAL_(BOOL) IsBlockQueueEmpty (HWND); + +// routine in GIVE2GDI.ASM +extern "C" HANDLE FAR PASCAL GiveToGDI (HANDLE); + + +// routine in item.c +INTERNAL_(HBITMAP) DuplicateBitmap (HBITMAP); +INTERNAL_(HANDLE) DuplicateMetaFile (HANDLE); +INTERNAL_(BOOL) AreNoClients (HANDLE hcli); +#ifdef _DEBUG +INTERNAL_(LPOLESTR) a2s (ATOM); +#endif + +// routines in doc.c +INTERNAL_(void) FreePokeData (HANDLE); +INTERNAL_(BOOL) FreeGDIdata (HANDLE, CLIPFORMAT); +INTERNAL DdeHandleIncomingCall(HWND hwndCli, WORD wCallType); + + +// in ddeworkr.cpp +INTERNAL_(HANDLE) wNewHandle (LPSTR lpstr, DWORD cb); +INTERNAL wTimedGetMessage (LPMSG pmsg, HWND hwnd, WORD wFirst, WORD wLast); +INTERNAL_(ATOM) wGlobalAddAtom (LPCOLESTR sz); diff --git a/private/ole32/com/remote/dde/server/srvrmain.cxx b/private/ole32/com/remote/dde/server/srvrmain.cxx new file mode 100644 index 000000000..546cb34c0 --- /dev/null +++ b/private/ole32/com/remote/dde/server/srvrmain.cxx @@ -0,0 +1,388 @@ +/****************************** Module Header ******************************\ +* Module Name: Srvrmain.c Server Main module +* +* Purpose: Includes server intialization and termination code. +* +* Created: Oct 1990. +* +* Copyright (c) 1990, 1991 Microsoft Corporation +* +* History: +* Raor (../10/1990) Designed, coded +* Raor (03/../1992) Modified for OLE 2.0 +* +\***************************************************************************/ + +#include "ole2int.h" +#include <dde.h> +// #include "cmacs.h" +#include "srvr.h" +#include "ddeatoms.h" +#include "ddedebug.h" +ASSERTDATA + +ATOM aStdExit = NULL; // "StdExit" +ATOM aStdCreate = NULL; // "StdNewDicument" +ATOM aStdOpen = NULL; // "StdOpenDocument" +ATOM aStdEdit = NULL; // "StdOpenDocument" +ATOM aStdCreateFromTemplate = NULL; // "StdNewFromTemplate" +ATOM aStdClose = NULL; // "StdCloseDocument" +ATOM aStdShowItem = NULL; // "StdShowItem" +ATOM aStdDoVerbItem = NULL; // "StddoVerbItem" +ATOM aSysTopic = NULL; // "System" +ATOM aOLE = NULL; // "OLE" +ATOM aProtocols = NULL; // "Protocols" +ATOM aTopics = NULL; // "Topics" +ATOM aFormats = NULL; // "Formats" +ATOM aStatus = NULL; // "Status" +ATOM aEditItems = NULL; // "Edit items +ATOM aTrue = NULL; // "True" +ATOM aFalse = NULL; // "False" + + +ATOM aStdHostNames; +ATOM aStdTargetDevice ; +ATOM aStdDocDimensions; +ATOM aStdColorScheme; +ATOM aChange; +ATOM aSave; +ATOM aClose; +ATOM aStdDocName; +ATOM aMSDraw; + + +HINSTANCE hdllInst = NULL; + +UINT cOleInitializeCalled = 0; + +INTERNAL_(BOOL) DDELibMain ( + HANDLE hInst, + WORD wDataSeg, + WORD cbHeapSize, + LPOLESTR lpszCmdLine +) +{ + DDEWNDCLASS wc; + + intrDebugOut((DEB_ITRACE, + "%p _IN DDELibMain hInst=%x\n", + 0, + hInst)); + + InterlockedIncrement((LONG *)&cOleInitializeCalled); + + if (cOleInitializeCalled > 1) + { + intrDebugOut((DEB_ITRACE, + "%p OUT DDELibMain cOleIinitalizedCalled > 1\n",0)); + + + // we already did the "once-per-machine" initialization + return TRUE; + } + + hdllInst = (HINSTANCE)hInst; + +#ifdef _NT1X_ + if( !aStdExit ) + { + + // On NT3.51, user preregisters all of these formats for us, + // thus giving us a big speed improvement during startup (because + // these atoms never change). + // Chicago and Cairo do not yet have this functionality. + + aStdExit = GlobalFindAtom(OLESTR("StdExit")); + + aStdCreate = aStdExit + 1; + Assert(aStdCreate == GlobalFindAtom (OLESTR("StdNewDocument"))); + + aStdOpen = aStdExit + 2; + Assert(aStdOpen == GlobalFindAtom (OLESTR("StdOpenDocument"))); + + aStdEdit = aStdExit + 3; + Assert(aStdEdit == GlobalFindAtom (OLESTR("StdEditDocument"))); + + aStdCreateFromTemplate = aStdExit + 4; + Assert(aStdCreateFromTemplate == + GlobalFindAtom(OLESTR("StdNewfromTemplate"))); + + aStdClose = aStdExit + 5; + Assert(aStdClose == GlobalFindAtom (OLESTR("StdCloseDocument"))); + + aStdShowItem = aStdExit + 6; + Assert(aStdShowItem == GlobalFindAtom (OLESTR("StdShowItem"))); + + aStdDoVerbItem = aStdExit + 7; + Assert(aStdDoVerbItem == GlobalFindAtom (OLESTR("StdDoVerbItem"))); + + aSysTopic = aStdExit + 8; + Assert(aSysTopic == GlobalFindAtom (OLESTR("System"))); + + aOLE = aStdExit + 9; + Assert(aOLE == GlobalFindAtom (OLESTR("OLEsystem"))); + + aStdDocName = aStdExit + 10; + Assert(aStdDocName == GlobalFindAtom (OLESTR("StdDocumentName"))); + + aProtocols = aStdExit + 11; + Assert(aProtocols == GlobalFindAtom (OLESTR("Protocols"))); + + aTopics = aStdExit + 12; + Assert(aTopics == GlobalFindAtom (OLESTR("Topics"))); + + aFormats = aStdExit + 13; + Assert(aFormats == GlobalFindAtom (OLESTR("Formats"))); + + aStatus = aStdExit + 14; + Assert(aStatus == GlobalFindAtom (OLESTR("Status"))); + + aEditItems = aStdExit + 15; + Assert(aEditItems == GlobalFindAtom (OLESTR("EditEnvItems"))); + + aTrue = aStdExit + 16; + Assert(aTrue == GlobalFindAtom (OLESTR("True"))); + + aFalse = aStdExit + 17; + Assert(aFalse == GlobalFindAtom (OLESTR("False"))); + + aChange = aStdExit + 18; + Assert(aChange == GlobalFindAtom (OLESTR("Change"))); + + aSave = aStdExit + 19; + Assert(aSave == GlobalFindAtom (OLESTR("Save"))); + + aClose = aStdExit + 20; + Assert(aClose == GlobalFindAtom (OLESTR("Close"))); + + aMSDraw = aStdExit + 21; + Assert(aMSDraw == GlobalFindAtom (OLESTR("MSDraw"))); + + } + +#else // !_NT1X_ + + aStdExit = GlobalAddAtomA("StdExit"); + + aStdCreate = GlobalAddAtomA("StdNewDocument"); + aStdOpen = GlobalAddAtomA("StdOpenDocument"); + aStdEdit = GlobalAddAtomA("StdEditDocument"); + aStdCreateFromTemplate = GlobalAddAtomA("StdNewfromTemplate"); + + aStdClose = GlobalAddAtomA("StdCloseDocument"); + aStdShowItem = GlobalAddAtomA("StdShowItem"); + aStdDoVerbItem = GlobalAddAtomA("StdDoVerbItem"); + aSysTopic = GlobalAddAtomA("System"); + aOLE = GlobalAddAtomA("OLEsystem"); + aStdDocName = GlobalAddAtomA("StdDocumentName"); + + aProtocols = GlobalAddAtomA("Protocols"); + aTopics = GlobalAddAtomA("Topics"); + aFormats = GlobalAddAtomA("Formats"); + aStatus = GlobalAddAtomA("Status"); + aEditItems = GlobalAddAtomA("EditEnvItems"); + + aTrue = GlobalAddAtomA("True"); + aFalse = GlobalAddAtomA("False"); + + aChange = GlobalAddAtomA("Change"); + aSave = GlobalAddAtomA("Save"); + aClose = GlobalAddAtomA("Close"); + aMSDraw = GlobalAddAtomA("MSDraw"); + +#endif // !_NT1X_ + + + wc.style = NULL; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(LPVOID) + //Ask for extra space for storing the + //ptr to srvr/doc/iteminfo. + sizeof (ULONG) + // for LE chars + sizeof (HANDLE); // for keeping the hDLLInst. + + wc.hInstance = hdllInst; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + + +#ifdef _CHICAGO_ + if (IsWOWThread()) + { + DWORD dwThreadId= GetCurrentThreadId(); + wsprintfA(szSYS_CLASSA ,"Ole2SysWndClass %08X", + CoGetCurrentProcess()); + wsprintfA(szCLIENT_CLASSA,"Ole2ClientWndClass %08X", + CoGetCurrentProcess()); + wsprintfA(szSRVR_CLASSA ,"SrvrWndClass %08X", + CoGetCurrentProcess()); + wsprintfA(szDOC_CLASSA ,"ViewObjWndClass %08X", + CoGetCurrentProcess()); + wsprintfA(szITEM_CLASSA ,"ItemWndClass %08X", + CoGetCurrentProcess()); + wsprintfA(szCOMMONCLASSA ,"DdeCommonWindowClass %08X", + CoGetCurrentProcess()); + } +#endif // _CHICAGO_ + + // + // Here we are going to register our Window classes. Because it is + // possible that a previous application failed to unregister these + // classes, we are going to ignore registration errors. If we get + // to the point where we are really going to create a window, and the + // window isn't registered, the CreateWindow call will fail. + // + + // Srvr window class + wc.lpfnWndProc = (WNDPROC)SrvrWndProc; + wc.lpszClassName= SRVR_CLASS; + + if (!DdeRegisterClass(&wc)) + { + intrDebugOut((DEB_IERROR, + "RegisterClass SrvrWndProc failed %x\n", + GetLastError())); + intrAssert(!"RegisterClass SrvrWndProc failed %x\n"); + } + + + + // document window class + wc.lpfnWndProc = (WNDPROC)DocWndProc; + wc.lpszClassName = DOC_CLASS; + + if (!DdeRegisterClass(&wc)) + { + intrDebugOut((DEB_IERROR, + "RegisterClass SrvrWndProc failed %x\n", + GetLastError())); + intrAssert(!"RegisterClass SrvrWndProc failed %x\n"); + } + + // + // The following supports code in the client directory. + // + wc.lpfnWndProc = (WNDPROC) ClientDocWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(LONG); //we are storing longs + wc.lpszClassName= CLIENT_CLASS; + + if (!DdeRegisterClass(&wc)) + { + intrDebugOut((DEB_IERROR, + "RegisterClass ClientDocWndProc failed %x\n", + GetLastError())); + } + wc.lpfnWndProc = (WNDPROC) SysWndProc; + wc.lpszClassName = SYS_CLASS; + + if (!DdeRegisterClass(&wc)) + { + intrDebugOut((DEB_IERROR, + "RegisterClass ClientDocWndProc failed %x\n", + GetLastError())); + intrAssert(!"RegisterClass SrvrWndProc failed %x\n"); + } + + + return TRUE; +} + + +INTERNAL_(void) DDEWEP ( + BOOL fSystemExit +) +{ + + Puts("DdeWep\r\n"); + + //* protect against bogous calls to + + if (0==cOleInitializeCalled) return; + + if (--cOleInitializeCalled > 0) + { + // not done yet + return; + } + + if (fSystemExit != WEP_FREE_DLL) + { + AssertSz (0, "Bad parm to Wep"); + return; + } + + // free the global atoms. + + // on NT3.51, these atoms were pre-allocated for us by user, we do + // not need to free them. +#ifndef _NT1X_ + + if (aStdExit) + GlobalDeleteAtom (aStdExit); + if (aStdCreate) + GlobalDeleteAtom (aStdCreate); + if (aStdOpen) + GlobalDeleteAtom (aStdOpen); + if (aStdEdit) + GlobalDeleteAtom (aStdEdit); + if (aStdCreateFromTemplate) + GlobalDeleteAtom (aStdCreateFromTemplate); + if (aStdClose) + GlobalDeleteAtom (aStdClose); + if (aStdShowItem) + GlobalDeleteAtom (aStdShowItem); + if (aStdDoVerbItem) + GlobalDeleteAtom (aStdDoVerbItem); + if (aSysTopic) + GlobalDeleteAtom (aSysTopic); + if (aOLE) + GlobalDeleteAtom (aOLE); + if (aStdDocName) + GlobalDeleteAtom (aStdDocName); + + if (aProtocols) + GlobalDeleteAtom (aProtocols); + if (aTopics) + GlobalDeleteAtom (aTopics); + if (aFormats) + GlobalDeleteAtom (aFormats); + if (aStatus) + GlobalDeleteAtom (aStatus); + if (aEditItems) + GlobalDeleteAtom (aEditItems); + + if (aTrue) + GlobalDeleteAtom (aTrue); + if (aFalse) + GlobalDeleteAtom (aFalse); + + if (aChange) + GlobalDeleteAtom (aChange); + if (aSave) + GlobalDeleteAtom (aSave); + if (aClose) + GlobalDeleteAtom (aClose); + + if (aMSDraw) + GlobalDeleteAtom (aMSDraw); + +#endif // !_NT1X_ + + // + // We aren't checking error codes here. Because the server application + // can shut down on a whim, its possible that we had outstanding windows + // At this point, there isn't a thing we can do about it. + // + + // + // No reason to add a bunch of new code to only Unregister + // the class at the right moment when Chicago will clean up + // for us. + // + DdeUnregisterClass (SRVR_CLASS, hdllInst); + DdeUnregisterClass (DOC_CLASS, hdllInst); + DdeUnregisterClass (SYS_CLASS, hdllInst); + DdeUnregisterClass (CLIENT_CLASS, hdllInst); +} |