summaryrefslogtreecommitdiffstats
path: root/private/ole32/com/dde/server/srvr.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'private/ole32/com/dde/server/srvr.cxx')
-rw-r--r--private/ole32/com/dde/server/srvr.cxx2497
1 files changed, 2497 insertions, 0 deletions
diff --git a/private/ole32/com/dde/server/srvr.cxx b/private/ole32/com/dde/server/srvr.cxx
new file mode 100644
index 000000000..2f2d8eb40
--- /dev/null
+++ b/private/ole32/com/dde/server/srvr.cxx
@@ -0,0 +1,2497 @@
+
+/****************************** Module Header ******************************\
+* Module Name: Srvr.c Server Main module
+*
+* Purpose: Includes All the server communication related routines.
+*
+* Created: Oct 1990.
+*
+* Copyright (c) 1985, 1986, 1987, 1988, 1989 Microsoft Corporation
+*
+* History:
+* Raor: Wrote the original version.
+*
+*
+\***************************************************************************/
+
+#include "ole2int.h"
+//#include <shellapi.h>
+// #include "cmacs.h"
+#include <dde.h>
+
+// for RemDdeRevokeClassFactory and HDDESRVR
+#include <olerem.h>
+
+#include "srvr.h"
+#include "ddedebug.h"
+#include "ddesrvr.h"
+ASSERTDATA
+
+#define WM_DONOTDESTROY WM_USER+1
+
+#ifdef FIREWALLS
+BOOL bShowed = FALSE;
+void ShowVersion (void);
+#endif
+
+#ifdef _CHICAGO_
+#define DdeCHAR CHAR
+#define Ddelstrcmp lstrcmpA
+#define DdeGetClassName GetClassNameA
+#define szCDDEServer "CDDEServer"
+#else
+#define DdeCHAR WCHAR
+#define Ddelstrcmp lstrcmpW
+#define DdeGetClassName GetClassName
+#define szCDDEServer OLESTR("CDDEServer")
+#endif
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDDEServer::Create
+//
+// Synopsis: Create a server window to service a particular class
+//
+// Effects: Using lpclass, and the information in lpDdeInfo, create
+// a server window that is ready to respond to initiate
+// messages from this class.
+//
+// Arguments: [lpclass] -- Class name
+// [rclsid] -- Class ID
+// [lpDdeInfo] -- Class Object information
+// [phwnd] -- Out pointer for new window
+// [aOriginalClass] -- For TreatAs/Convert to case
+// [cnvtyp] -- Conversion type
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-28-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL CDDEServer::Create
+ (LPOLESTR lpclass,
+ REFCLSID rclsid,
+ LPDDECLASSINFO lpDdeInfo,
+ HWND FAR * phwnd,
+ ATOM aOriginalClass,
+ CNVTYP cnvtyp)
+{
+ // REVIEW what happens if we have two MDI servers register the
+ // same class factory?.
+
+ LPSRVR lpDDEsrvr = NULL;
+ ATOM aExe = NULL;
+
+ intrDebugOut((DEB_DDE_INIT,
+ "0 _IN CDDEServer::Create(lpclass=%ws)\n",
+ lpclass));
+
+ // add the app atom to global list
+ if (!ValidateSrvrClass (lpclass, &aExe))
+ {
+ intrDebugOut((DEB_IWARN,
+ "CDDEServer::Create(%ws) Invalid Class\n",
+ lpclass));
+
+ return OLE_E_CLSID;
+ }
+
+ lpDDEsrvr = new CDDEServer;
+ RetZS (lpDDEsrvr, E_OUTOFMEMORY);
+
+ // set the signature handle and the app atom.
+ lpDDEsrvr->m_chk = chkDdeSrvr;
+ lpDDEsrvr->m_aClass = wGlobalAddAtom (lpclass);
+ lpDDEsrvr->m_clsid = rclsid; // Class ID (already TreatAs'd)
+ lpDDEsrvr->m_aOriginalClass = wDupAtom (aOriginalClass);
+ lpDDEsrvr->m_pClassFactory = NULL;
+ lpDDEsrvr->m_dwClassFactoryKey = lpDdeInfo->dwRegistrationKey;
+ lpDDEsrvr->m_aExe = aExe;
+ lpDDEsrvr->m_cnvtyp = cnvtyp;
+ lpDDEsrvr->m_fcfFlags = lpDdeInfo->dwFlags;
+
+ lpDDEsrvr->m_bTerminate = FALSE; // Set if we are terminating.
+ lpDDEsrvr->m_hcli = NULL; // handle to the first block of clients list
+ lpDDEsrvr->m_termNo = 0; // termination count
+ lpDDEsrvr->m_cSrvrClients= 0; // no of clients;
+ lpDDEsrvr->m_fDoNotDestroyWindow= 0;
+
+
+
+
+
+#ifdef FIREWALLS
+ AssertSz(lpDdeInfo.dwFlags <= REGCLS_MULTI_SEPARATE, "invalid server options");
+#endif
+
+ // Create the server window and do not show it.
+ //
+ // We are explicitly calling CreateWindowA here.
+ // The DDE tracking layer will attempt to convert hCommands to UNICODE
+ // if the two windows in the conversation are both UNICODE.
+ // This window is created as a child of the common server window for this
+ // thread. When this thread dies, the common server window is destroyed if
+ // it exists, which will cause all of the child windows to be destroyed also.
+ //
+ //
+ if (!(lpDDEsrvr->m_hwnd = DdeCreateWindowEx (0, gOleWindowClass,
+ szCDDEServer,
+ WS_OVERLAPPED | WS_CHILD,
+ 0,0,0,0,
+ (HWND)TLSGetDdeServer(),
+ NULL,
+ g_hinst, NULL)))
+ {
+ goto errReturn;
+ }
+
+ // fix up the WindowProc entry point.
+ SetWindowLong(lpDDEsrvr->m_hwnd, GWL_WNDPROC, (LONG)SrvrWndProc);
+
+ //
+ // The following will inform the class object in the class registration table
+ // that this window should be notified when the class object is revoked. This
+ // enables the window to shutdown properly.
+ //
+ // If there isn't a class factory, which happens for single instance servers
+ // which were launched with a filename, then m_dwClassFactory will be 0,
+ // in which case we don't make the set call.
+ //
+ if(lpDDEsrvr->m_dwClassFactoryKey != 0)
+ {
+ if(!SetDdeServerWindow(lpDDEsrvr->m_dwClassFactoryKey,lpDDEsrvr->m_hwnd))
+ {
+ intrDebugOut((DEB_IERROR,
+ "0 CDDEServer::Create unable to SetDdeServerWindow\n"));
+ goto errReturn;
+ }
+ }
+
+ intrDebugOut((DEB_DDE_INIT,
+ "DDE Server window for %ws created in task %x\n",
+ lpclass,GetCurrentThreadId()));
+
+ // save the ptr to the server struct in the window.
+ SetWindowLong (lpDDEsrvr->m_hwnd, 0, (LONG)lpDDEsrvr);
+
+ // Set the signature.
+ SetWindowWord (lpDDEsrvr->m_hwnd, WW_LE, WC_LE);
+
+ *phwnd = lpDDEsrvr->m_hwnd;
+
+
+ intrDebugOut((DEB_DDE_INIT,
+ "0 _OUT CDDEServer::Create returns %x\n",
+ NOERROR));
+ return NOERROR;
+
+errReturn:
+ AssertSz (0, "CDDEServer::Create errReturn");
+ if (lpDDEsrvr)
+ {
+ if (lpDDEsrvr->m_hwnd)
+ SSDestroyWindow (lpDDEsrvr->m_hwnd);
+
+ if (lpDDEsrvr->m_aClass)
+ GlobalDeleteAtom (lpDDEsrvr->m_aClass);
+
+ if (lpDDEsrvr->m_aExe)
+ GlobalDeleteAtom (lpDDEsrvr->m_aExe);
+ delete lpDDEsrvr;
+ }
+
+ intrDebugOut((DEB_IERROR,
+ "0 _OUT CDDEServer::Create returns %x\n",
+ E_OUTOFMEMORY));
+
+ return E_OUTOFMEMORY;
+}
+
+
+
+// ValidateSrvrClass checks whether the given server class is valid by
+// looking in the registration database.
+
+INTERNAL_(BOOL) ValidateSrvrClass (
+LPOLESTR lpclass,
+ATOM FAR * lpAtom
+)
+{
+ WCHAR buf[MAX_STR];
+ LONG cb = MAX_STR;
+ WCHAR key[MAX_STR];
+ LPOLESTR lptmp;
+ LPOLESTR lpbuf;
+ WCHAR ch;
+ CLSID clsid;
+
+ if (CLSIDFromProgID (lpclass, &clsid) != NOERROR)
+ {
+ // ProgId is not correctly registered in reg db
+ return FALSE;
+ }
+
+ lstrcpyW (key, lpclass);
+ lstrcatW (key, OLESTR("\\protocol\\StdFileEditing\\server"));
+
+ if (RegQueryValue (HKEY_CLASSES_ROOT, key, buf, &cb))
+ return TRUE;
+
+ if (!buf[0])
+ {
+ AssertSz (0, "ValidateSrvrClass failed.");
+ return FALSE;
+ }
+
+ // Get exe name without path and then get an atom for that
+ lptmp = lpbuf = buf;
+ while (ch = *lptmp)
+ {
+ lptmp++;
+ if (ch == '\\' || ch == ':')
+ lpbuf = lptmp;
+ }
+ *lpAtom = wGlobalAddAtom (lpbuf);
+
+ return TRUE;
+}
+
+
+
+INTERNAL RemDdeRevokeClassFactory
+ (LPSRVR lpsrvr)
+{
+ HRESULT hr;
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN RemDdeRevokeClassFactory(%x)\n",
+ lpsrvr));
+
+ ChkS(lpsrvr);
+ hr = lpsrvr->Revoke();
+ intrDebugOut((DEB_ITRACE,
+ "0 OUT RemDdeRevokeClassFactory(%x) %x\n",
+ lpsrvr,hr));
+ return(hr);
+}
+
+
+
+INTERNAL CDDEServer::Revoke ()
+{
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDDEServer::Revoke() m_cSrvrClients=%x\n",
+ this,
+ m_cSrvrClients));
+ HRESULT hr;
+
+ ChkS(this);
+
+ //
+ // Can't revoke if there are still clients. QueryRevokeCLassFactory
+ // determines if there are still clients attached.
+ //
+ if (!QueryRevokeClassFactory ())
+ {
+ intrDebugOut((DEB_IERROR,
+ "QueryRevokeClassFactory failed!"));
+ hr = RPC_E_DDE_REVOKE;
+ goto exitRtn;
+ }
+
+ if (m_cSrvrClients)
+ {
+ m_bTerminate = TRUE;
+ // if there are any clients connected to this classfactory,
+ // send terminates.
+ SendServerTerminateMsg ();
+ m_bTerminate = FALSE;
+ }
+
+ hr = FreeSrvrMem ();
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x OUT CDDEServer::Revoke(%x) hr = %x\n",
+ this, hr));
+ return hr;
+}
+
+INTERNAL_(void) CDDEServer::SendServerTerminateMsg ()
+{
+
+ HANDLE hcliPrev = NULL;
+ PCLILIST pcli;
+ HANDLE *phandle;
+ HANDLE hcli;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDDEServer::SendServerTerminateMsg\n",
+ this));
+
+ hcli = m_hcli;
+ while (hcli) {
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ {
+ Assert(0);
+ goto exitRtn;
+ }
+
+ phandle = (HANDLE *) (pcli->info);
+ while (phandle < (HANDLE *)(pcli + 1)) {
+ if (*phandle)
+ {
+ PostMessageToClientWithReply ((HWND)(*phandle), WM_DDE_TERMINATE,
+ (WPARAM) m_hwnd, NULL, WM_DDE_TERMINATE);
+ Assert (m_cSrvrClients);
+ m_cSrvrClients--;
+ }
+ phandle++;
+ phandle++;
+ }
+
+ hcliPrev = hcli;
+ hcli = pcli->hcliNext;
+ LocalUnlock (hcliPrev);
+ }
+
+exitRtn:
+ intrDebugOut((DEB_ITRACE,
+ "%x OUT CDDEServer::SendServerTerminateMsg\n",
+ this));
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDDEServer::FreeSrvrMem
+//
+// Synopsis: Free's up a CDDEServer.
+//
+// Effects:
+//
+// Arguments: [void] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 6-26-94 kevinro Commented
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL CDDEServer::FreeSrvrMem
+ (void)
+{
+ HRESULT hr;
+ // REVIEW: Not clear how this works in the synchronous mode
+ // Release for class factory is called only when everything is
+ // cleaned and srvr app can post WM_QUIT at this stage
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDDEServer::FreeSrvrMem\n",
+ this));
+
+ PCLILIST pcliPrev;
+ HANDLE hcli, hcliPrev;
+
+ if (m_bTerminate)
+ {
+ AssertSz (0, "terminate flag is not FALSE");
+ }
+
+
+ if (m_aExe)
+ {
+ GlobalDeleteAtom (m_aExe);
+ }
+
+
+ // We deliberately do not call this->Lock (FALSE)
+ // If the server has revoked his class object without
+ // waiting for his Lock count to go to zero, then
+ // presumably he doesn't need us to unlock him. In fact,
+ // doing such an unlock might confuse a server who then
+ // tries to call CoRevokeClassObject recursively.
+ if (m_pClassFactory)
+ {
+ m_pClassFactory->Release();
+ m_pClassFactory = NULL;
+ }
+
+ hcli = m_hcli;
+ while (hcli)
+ {
+ hcliPrev = hcli;
+ if (pcliPrev = (PCLILIST) LocalLock (hcliPrev))
+ {
+ hcli = pcliPrev->hcliNext;
+ }
+ else
+ {
+ AssertSz (0, "Corrupt internal data structure or out-of-memory");
+ hcli = NULL;
+ }
+ Verify (0==LocalUnlock (hcliPrev));
+ Verify (NULL==LocalFree (hcliPrev));
+ }
+
+ hr = DestroyDdeSrvrWindow(m_hwnd,m_aClass);
+ if (hr != NOERROR)
+ {
+ //
+ // Well now, if DestroyWindow fails, there isn't a whole heck of
+ // alot we can do about it. It could mean that the window was
+ // destroyed previously, or the parent window was destroyed during
+ // thread shutdown. We should still continue to cleanup
+ //
+ intrDebugOut((DEB_IERROR,
+ "%x CDDEServer::FreeSrvrMem DestroyDdeSrvrWindow failed %x\n",
+ this,
+ hr));
+ }
+
+ if (m_aClass)
+ {
+ GlobalDeleteAtom (m_aClass);
+ }
+
+ delete this;
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDDEServer::FreeSrvrMem\n",
+ this));
+ return NOERROR;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: SrvrHandleIncomingCall
+//
+// Synopsis: Setup and call the CallControl to dispatch a call to the server
+//
+// Effects: A call has been made from the client that requires us to call
+// into our server. This must be routed through the call control.
+// This routine sets up the appropriate data structures, and
+// calls into the CallControl. The CallControl will in turn
+// call SrvrDispatchIncomingCall to actuall process the call.
+//
+// This routine should only be called by the SrvrWndProc
+//
+//
+// Arguments: [lpsrvr] -- Points to the server
+// [hwnd] -- hwnd of server
+// [hdata] -- Handle to data
+// [wParam] -- hwnd of client
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-05-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL SrvrHandleIncomingCall(LPSRVR lpsrvr,
+ HWND hwnd,
+ HANDLE hdata,
+ HWND wParam)
+{
+ VDATEHEAP();
+ HRESULT hresult = NOERROR;
+ SRVRDISPATCHDATA srvrdispdata;
+ DISPATCHDATA dispatchdata;
+
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN SrvrHandleIncomingCall lpsrvr=%x hwnd=%x hdata=%x wParam=%x\n",
+ lpsrvr,
+ hwnd,
+ hdata,
+ wParam));
+
+ srvrdispdata.wDispFunc = DDE_DISP_SRVRWNDPROC;
+ srvrdispdata.hwnd = hwnd;
+ srvrdispdata.hData = hdata;
+ srvrdispdata.wParam = wParam;
+ srvrdispdata.lpsrvr = lpsrvr;
+
+ dispatchdata.pData = &srvrdispdata;
+
+ RPCOLEMESSAGE rpcMsg;
+ RPC_SERVER_INTERFACE RpcInterfaceInfo;
+ DWORD dwFault;
+
+ rpcMsg.iMethod = 0;
+ rpcMsg.Buffer = &dispatchdata;
+ rpcMsg.cbBuffer = sizeof(dispatchdata);
+ rpcMsg.reserved2[1] = &RpcInterfaceInfo;
+ *MSG_TO_IIDPTR(&rpcMsg) = GUID_NULL;
+
+
+ IRpcStubBuffer * pStub = &(lpsrvr->m_pCallMgr);
+ IRpcChannelBuffer * pChannel = &(lpsrvr->m_pCallMgr);
+ hresult = STAInvoke(&rpcMsg, CALLCAT_SYNCHRONOUS, pStub, pChannel, NULL, &dwFault);
+
+ intrDebugOut((DEB_ITRACE,
+ "0 _OUT SrvrHandleIncomingCall hresult=%x\n",
+ hresult));
+
+ return(hresult);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: SrvrDispatchIncomingCall
+//
+// Synopsis: Dispatch a call into the server.
+//
+// Effects: At the moment, the only incoming call that requires handling
+// by the server window is Execute. This routine dispatchs to it,
+// and returns.
+//
+// Arguments: [psdd] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-05-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL SrvrDispatchIncomingCall(PSRVRDISPATCHDATA psdd)
+{
+ VDATEHEAP();
+ HRESULT hr;
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN SrvrDispatchIncomingCall psdd(%x)\n",psdd));
+
+ hr = psdd->lpsrvr->SrvrExecute (psdd->hwnd,
+ psdd->hData,
+ (HWND)(psdd->wParam));
+
+ intrDebugOut((DEB_ITRACE,
+ "0 _OUT SrvrDispatchIncomingCall psdd(%x) hr =%x\n",
+ psdd,
+ hr));
+
+ return(hr);
+}
+
+
+// REVIEW: Revoking Class Factory will not be successful if
+// any clients are either connected to the classfactory
+// or to the object instances.
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SrvrWndProc
+//
+// Synopsis: This is the server window procedure.
+//
+// Effects:
+//
+// Arguments: [hwndIn] -- Window handle (may not be full. See note)
+// [msg] --
+// [wParam] --
+// [lParam] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 8-03-94 kevinro Created
+//
+// Notes:
+//
+// When running in a VDM, it is possible that this window was dispatched
+// without having a full window handle. This happens when the getmessage
+// was dispatched from 16-bit. Therefore, we need to convert the hwnd to
+// a full hwnd before doing any comparision functions.
+//
+//----------------------------------------------------------------------------
+STDAPI_(LRESULT) SrvrWndProc (
+HWND hwndIn,
+UINT msg,
+WPARAM wParam,
+LPARAM lParam
+)
+{
+ BOOL fRevoke=FALSE;
+ LPSRVR lpsrvr;
+ WORD status = NULL;
+ HANDLE hdata;
+ ATOM aItem;
+ HRESULT retval;
+
+ //
+ // The following hwnd variable is used to determine the full HWND, in the
+ // event we were dispatched in a 16 bit process.
+ //
+ HWND hwnd;
+
+#ifdef FIREWALLS
+ HWND hwndClient;
+#endif
+
+
+ switch (msg){
+
+ case WM_DDE_INITIATE:
+ VDATEHEAP();
+#ifdef FIREWALLS
+ AssertSz (lpsrvr, "No server window handle in server window");
+#endif
+ hwnd = ConvertToFullHWND(hwndIn);
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0);
+ if (lpsrvr->m_bTerminate){
+ // we are terminating, no more connections
+ break;
+ }
+
+ // class is not matching, so it is not definitely for us.
+ // for apps sending the EXE for initiate, do not allow if the app
+ // is mutiple instance (Bug fix for winworks).
+
+ if (!(lpsrvr->m_aClass == (ATOM)(LOWORD(lParam)) ||
+ (NOERROR==wCompatibleClasses (LOWORD(lParam), lpsrvr->m_aClass)) ||
+ (lpsrvr->m_aExe == (ATOM)(LOWORD(lParam)) && IsSingleServerInstance() )))
+ {
+ break;
+ }
+
+ intrDebugOut((DEB_DDE_INIT,"::SrvrWndProc INITIATE\n"));
+
+
+ if (!lpsrvr->HandleInitMsg (lParam))
+ {
+ if (!(aSysTopic == (ATOM)(HIWORD(lParam))))
+ {
+ //
+ // If this isn't a sys topic, then it must be a request for
+ // a specific document. Send a message to the
+ // children windows, asking for the document. If one of them
+ // may send an ACK to the client.
+ //
+
+ // if the server window is not the right window for
+ // DDE conversation, then try with the doc windows.
+ BOOL fAckSent = SendInitMsgToChildren (hwnd, msg, wParam, lParam);
+
+#ifdef KEVINRO_OLDCODE
+ The following code was removed, because I don't belive it is required
+ any longer. I am not 100% sure yet, so I have left it in. If you find it,
+ you can probably remove it.
+ It appears to be trying to claim the SINGLE_USE class factory from the class
+ factory table. It does this when a child document window sends an ACK to the
+ client, claiming to support the document being asked for. It really doesn't
+ make too much sense here, since a single use server would have already removed
+ its class factory if there was an open document.
+
+ Anyway, the 16-bit version had a direct hack into the class factory table. We
+ don't have that anymore, so this code wouldn't work anyway.
+
+ if (lpsrvr->m_fcfFlags==REGCLS_SINGLEUSE)
+ {
+ if (lpsrvr->m_pfAvail)
+ {
+ // Hide the entry in the class factory table so that no 2.0
+ // client can connect to the same server.
+ Assert (!IsBadWritePtr (lpsrvr->m_pfAvail, sizeof(BOOL)));
+ *(lpsrvr->m_pfAvail) = FALSE;
+ }
+ }
+#endif // KEVINRO_OLDCODE
+ intrDebugOut((DEB_DDE_INIT,"SrvrWndProc Child Init\n"));
+ return fAckSent;
+ }
+ break;
+ }
+
+ // We can enterain this client. Put him in our client list
+ // and acknowledge the initiate.
+
+ if (!AddClient ((LPHANDLE)&lpsrvr->m_hcli, (HWND)wParam,(HWND)/*fLocked*/FALSE))
+ {
+ break;
+ }
+
+ //
+ // Now its time to grab up the class factory from the class
+ // factory table. When this window was created, the class factory
+ // was available. However, it is possible that it has already
+ // been claimed by someone else. So, we try grabbing it (which
+ // normally should succeed). If it fails, then delete the client
+ // and don't acknowledge.
+ //
+
+ if (lpsrvr->m_pClassFactory == NULL)
+ {
+ DdeClassInfo ddeInfo;
+ ddeInfo.dwContextMask = CLSCTX_LOCAL_SERVER |
+ CLSCTX_INPROC_SERVER;
+ intrDebugOut((DEB_DDE_INIT,"SrvrWndProc getting class factory\n"));
+ //
+ // The following asks for control of the class
+ // factory in the case of a single use class
+ //
+ ddeInfo.fClaimFactory = TRUE;
+ ddeInfo.dwRegistrationKey = lpsrvr->m_dwClassFactoryKey;
+
+ if (GetClassInformationFromKey(&ddeInfo) == FALSE)
+ {
+ intrDebugOut((DEB_IERROR,"SrvrWndProc failed to get class factory\n"));
+ //
+ // Whoops, we were not able to grab the class factory
+ // Cleanup and hop out
+ if (!FindClient ((LPHANDLE)lpsrvr->m_hcli,(HWND)wParam, TRUE))
+ {
+ intrAssert(!"FindClient failed\n");
+ }
+ return(0);
+ }
+ lpsrvr->m_pClassFactory = (IClassFactory *)ddeInfo.punk;
+ lpsrvr->m_fcfFlags = ddeInfo.dwFlags;
+ }
+
+ intrAssert(lpsrvr->m_pClassFactory != NULL);
+
+ lpsrvr->m_cSrvrClients++;
+
+ lpsrvr->Lock (TRUE, (HWND)wParam);
+
+ // Post acknowledge
+ DuplicateAtom (LOWORD(lParam));
+ DuplicateAtom (HIWORD(lParam));
+ SSSendMessage ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, lParam);
+
+
+ return 1L; // fAckSent==TRUE
+ VDATEHEAP();
+ break;
+
+
+ case WM_DDE_EXECUTE:
+ VDATEHEAP();
+ hwnd = ConvertToFullHWND(hwndIn);
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0);
+
+ hdata = GET_WM_DDE_EXECUTE_HDATA(wParam,lParam);
+
+#ifdef FIREWALLS
+ AssertSz (lpsrvr, "No server handle in server window");
+#endif
+
+ intrDebugOut((DEB_ITRACE,"SrvrWndProc WM_DDE_EXECUTE\n"));
+
+#ifdef FIREWALLS
+ // find the client in the client list.
+ hwndClient = FindClient (lpsrvr->m_hcli, (HWND)wParam, FALSE);
+ AssertSz (hwndClient, "Client is missing from the server")
+#endif
+ // Are we terminating
+ if (lpsrvr->m_bTerminate) {
+ intrDebugOut((DEB_ITRACE,
+ "SrvrWndProc WM_DDE_EXECUTE ignored for TERMINATE\n"));
+ // !!! are we supposed to free the data
+ GlobalFree (hdata);
+ break;
+ }
+
+ retval = SrvrHandleIncomingCall(lpsrvr,hwnd,hdata,(HWND)wParam);
+
+ if (NOERROR!=retval)
+ {
+ intrDebugOut((DEB_IERROR,
+ "SrvrWndProc SrvrHandleIncomingCall fail %x\n",
+ retval));
+ }
+ SET_MSG_STATUS (retval, status)
+
+ if (!lpsrvr->m_bTerminate)
+ {
+ // REVIEW: We are making an assumption that, we will not be posting
+ // any DDE messages because of calling the SrvrExecute.
+ // If we post any messages, before we post the acknowledge
+ // we will be in trouble.
+
+ lParam = MAKE_DDE_LPARAM(WM_DDE_ACK,status,(UINT) hdata);
+
+ intrDebugOut((DEB_ITRACE,
+ "SrvrWndProc WM_DDE_EXECUTE sending %x for ack\n",status));
+
+ // Post the acknowledge to the client
+ if (!PostMessageToClient ((HWND) wParam,
+ WM_DDE_ACK, (UINT) hwnd, lParam)) {
+ // if the window died or post failed, delete the atom.
+ GlobalFree (hdata);
+ DDEFREE(WM_DDE_ACK,lParam);
+ }
+ }
+ VDATEHEAP();
+ break;
+
+
+
+ case WM_DDE_TERMINATE:
+ intrDebugOut((DEB_ITRACE,
+ "SrvrWndProc WM_DDE_TERMINATE\n"));
+
+ hwnd = ConvertToFullHWND(hwndIn);
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0);
+
+#ifdef FIREWALLS
+ // find the client in the client list.
+ hwndClient = FindClient (lpsrvr->m_hcli, (HWND)wParam, FALSE);
+ AssertSz (hwndClient, "Client is missing from the server")
+#endif
+ Putsi (lpsrvr->m_bTerminate);
+ if (lpsrvr->m_bTerminate)
+ {
+ AssertSz (0, "Unexpected code path");
+ }
+ else
+ {
+ // If client initiated the terminate. post matching terminate
+ PostMessageToClient ((HWND)wParam,
+ WM_DDE_TERMINATE,
+ (UINT) hwnd,
+ NULL);
+ --lpsrvr->m_cSrvrClients;
+ if (0==lpsrvr->m_cSrvrClients
+ && lpsrvr->QueryRevokeClassFactory())
+ {
+#ifdef KEVINRO_OLD_CODE
+ if (lpsrvr->m_phwndDde)
+ {
+ // Remove from class factory table
+ *(lpsrvr->m_phwndDde) = (HWND)0;
+ }
+#endif // KEVINRO_OLD_CODE
+ fRevoke = TRUE;
+ }
+
+ lpsrvr->Lock (FALSE, (HWND)wParam); // Unlock server
+ FindClient (lpsrvr->m_hcli, (HWND)wParam, /*fDelete*/TRUE);
+
+ if (fRevoke)
+ {
+ lpsrvr->Revoke();
+ }
+ }
+ break;
+
+
+ case WM_DDE_REQUEST:
+ aItem = GET_WM_DDE_REQUEST_ITEM(wParam,lParam);
+
+ hwnd = ConvertToFullHWND(hwndIn);
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0);
+
+ intrDebugOut((DEB_ITRACE,
+ "SrvrWndProc WM_DDE_REQUEST(aItem=%x)\n",aItem));
+
+ if (lpsrvr->m_bTerminate || !IsWindowValid ((HWND) wParam))
+ {
+ goto RequestErr;
+ }
+
+ if(RequestDataStd (aItem, (HANDLE FAR *)&hdata) != NOERROR)
+ {
+
+ lParam = MAKE_DDE_LPARAM(WM_DDE_ACK,0x8000,aItem);
+
+ // if request failed, then acknowledge with error.
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK,
+ (UINT) hwnd, lParam))
+ {
+ DDEFREE(WM_DDE_ACK,lParam);
+RequestErr:
+ if (aItem)
+ {
+ GlobalDeleteAtom (aItem);
+ }
+
+ }
+ }
+ else
+ {
+ lParam = MAKE_DDE_LPARAM(WM_DDE_REQUEST,
+ (UINT) hdata,(UINT) aItem);
+
+ // post the data message and we are not asking for any
+ // acknowledge.
+
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_DATA,
+ (UINT) hwnd, lParam))
+ {
+ GlobalFree (hdata);
+ DDEFREE(WM_DDE_REQUEST,lParam);
+ goto RequestErr;
+ }
+ }
+ break;
+
+ case WM_DONOTDESTROY:
+ intrDebugOut((DEB_ITRACE,
+ "SrvrWndProc WM_DONOTDESTROY %x\n",
+ wParam));
+
+ //
+ // This message is only sent by 32-bit code that has been
+ // given our full handle
+ //
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwndIn, 0);
+
+ //
+ // The WM_DONOTDESTROY message tells the server how to
+ // handle the following WM_USER message. If wParam is set,
+ // then the m_fDoNotDestroyWindow flag will be set, which
+ // keeps us from destroying the server window. If cleared,
+ // it will enable the destruction. This message is sent
+ // from the MaybeCreateDocWindow routine
+ //
+
+ lpsrvr->m_fDoNotDestroyWindow = wParam;
+ return 0;
+ break;
+
+ case WM_USER:
+ intrDebugOut((DEB_ITRACE,
+ "SrvrWndProc WM_USER\n"));
+ //
+ // This message is only sent by 32-bit code that has been
+ // given our full handle
+ //
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwndIn, 0);
+
+ // cftable.cpp sends a WM_USER message to destory the DDE
+ // server window when a 2.0 client has connected to a
+ // SDI 2.0 server (and no 1.0 client should be allowed to also
+ // connect.
+ // cftable.cpp cannot call RemDdeRevokeClassFactory directly
+ // becuase they may be in different processes.
+ //
+ // The m_fDoNotDestroyWindow flag is used by
+ // MaybeCreateDocWindow in the case that the server is a
+ // single use server, and revokes its class factory when
+ // an object is created. MaybeCreateDocWindow will set this
+ // flag, telling us to ignore the message.
+ //
+ // returning 0 means we did destroy, 1 means we did not.
+
+ if (!lpsrvr->m_fDoNotDestroyWindow)
+ {
+ RemDdeRevokeClassFactory(lpsrvr);
+ return(0);
+ }
+ return 1;
+ break;
+
+ default:
+ return SSDefWindowProc (hwndIn, msg, wParam, lParam);
+ }
+
+ return 0L;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDDEServer::HandleInitMsg
+//
+// Synopsis: Determine if we are going to handle the INITIATE message.
+//
+// Effects:
+//
+// Arguments: [lParam] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-28-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL_(BOOL) CDDEServer::HandleInitMsg(LPARAM lParam)
+{
+
+ // If it is not system or Ole, this is not the server.
+ if (!((aSysTopic == (ATOM)(HIWORD(lParam))) || (aOLE == (ATOM)(HIWORD(lParam)))))
+ {
+ return FALSE;
+ }
+ Assert (m_fcfFlags<=REGCLS_MULTI_SEPARATE);
+
+ // single instance MDI accept
+ if (m_fcfFlags != REGCLS_SINGLEUSE)
+ {
+ return TRUE;
+ }
+
+ // this server is multiple instance. So, check for any clients or docs.
+ if (!GetWindow (m_hwnd, GW_CHILD) && 0==m_cSrvrClients)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+
+// AddClient: Adds a client entry to the list.
+// Each client entry is a pair of handles; key handle
+// and data handle. Ecah list entry contains space for
+// MAX_LIST of pairs of handles.
+
+INTERNAL_(BOOL) AddClient
+(
+LPHANDLE lphead, // ptr to loc which contains the head handle
+HANDLE hkey, // key
+HANDLE hdata // hdata
+)
+{
+
+ HANDLE hcli = NULL;
+ HANDLE hcliPrev = NULL;
+ PCLILIST pcli;
+ HANDLE *phandle;
+
+
+ hcli = *lphead;
+
+ // if the entry is already present, return error.
+ if (hcli && FindClient (hcli, hkey, FALSE))
+ return FALSE;
+
+ while (hcli) {
+ if (hcliPrev)
+ LocalUnlock (hcliPrev);
+
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ return FALSE;
+
+ phandle = (HANDLE *) pcli->info;
+ while (phandle < (HANDLE *)(pcli + 1)) {
+ if (*phandle == NULL) {
+ *phandle++ = hkey;
+ *phandle++ = hdata;
+ LocalUnlock (hcli);
+ return TRUE;
+ }
+ phandle++;
+ phandle++;
+ }
+ hcliPrev = hcli;
+ hcli = pcli->hcliNext;
+ lphead = (LPHANDLE)&pcli->hcliNext;
+ }
+
+ // not in the list.
+ hcli = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (CLILIST));
+ if (hcli == NULL)
+ goto errRtn;
+
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ goto errRtn;
+
+ // set the link to this handle in the previous entry
+ *lphead = hcli;
+ if (hcliPrev)
+ LocalUnlock (hcliPrev);
+
+ phandle = (HANDLE *) pcli->info;
+ *phandle++ = hkey;
+ *phandle++ = hdata;
+ LocalUnlock (hcli);
+ return TRUE;
+
+errRtn:
+
+ if (hcliPrev)
+ LocalUnlock (hcliPrev);
+
+ if (hcli)
+ LocalFree (hcli);
+
+ return FALSE;
+
+}
+
+
+// FindClient: finds a client and deletes the client if necessary.
+INTERNAL_(HANDLE) FindClient
+(
+HANDLE hcli,
+HANDLE hkey,
+BOOL bDelete
+)
+{
+ HANDLE hcliPrev = NULL;
+ PCLILIST pcli;
+ HANDLE *phandle;
+ HANDLE hdata;
+
+ while (hcli) {
+ if ((pcli = (PCLILIST) LocalLock (hcli)) == NULL)
+ return FALSE;
+
+ phandle = (HANDLE *) pcli->info;
+ while (phandle < (HANDLE *)(pcli + 1)) {
+ if (*phandle == hkey) {
+ if (bDelete)
+ *phandle = NULL;
+
+ hdata = *++phandle;
+ LocalUnlock (hcli);
+ return hdata;
+ }
+ phandle++;
+ phandle++;
+ }
+ hcliPrev = hcli;
+ hcli = pcli->hcliNext;
+ LocalUnlock (hcliPrev);
+
+ }
+ return NULL;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDDEServer::SrvrExecute
+//
+// Synopsis: takes care of the WM_DDE_EXECUTE for the server.
+//
+// Effects: Parses the EXECUTE string, and determines what it should be
+// done.
+//
+// Arguments: [hwnd] -- Server window
+// [hdata] -- Handle to EXECUTE string
+// [hwndClient] -- Client window
+//
+// Requires:
+// hdata is an ANSI string. It was passed to us by a DDE client.
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 6-05-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL CDDEServer::SrvrExecute
+(
+HWND hwnd,
+HANDLE hdata,
+HWND hwndClient
+)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%x _IN CDDESrvr::SrvrExecute(hwnd=%x,hdata=%x,hwndClient=%x)\n",
+ this,
+ hwnd,
+ hdata,
+ hwndClient));
+
+ ATOM aCmd;
+ BOOL fActivate;
+
+ LPSTR lpdata = NULL;
+ HANDLE hdup = NULL;
+ HRESULT hresult = E_UNEXPECTED;
+
+ LPSTR lpdocname;
+ LPSTR lptemplate;
+ LPCLIENT lpdocClient = NULL;
+ LPSTR lpnextarg;
+ LPSTR lpclassname;
+ LPSTR lpitemname;
+ LPSTR lpopt;
+ CLSID clsid;
+ WORD wCmdType;
+ BOOL bCreateInst = FALSE;
+ LPUNKNOWN pUnk = NULL;
+
+ LPPERSISTSTORAGE pPersistStg=NULL;
+
+ // REVIEW: if any methods called on the objects genarate DDE messages
+ // before we return from Execute, we will be in trouble.
+
+
+ // REVIEW: this code can be lot simplified if we do the argument scanning
+ // seperately and return the ptrs to the args. Rewrite later on.
+
+ ErrZS (hdup = UtDupGlobal (hdata,GMEM_MOVEABLE), E_OUTOFMEMORY);
+
+ ErrZS (lpdata = (LPSTR)GlobalLock (hdup), E_OUTOFMEMORY);
+
+ intrDebugOut((DEB_ITRACE,
+ "CDDESrvr::SrvrExecute(lpdata = %s)\n",lpdata));
+
+ if (*lpdata++ != '[') // commands start with the left sqaure bracket
+ {
+ hresult = ResultFromScode (RPC_E_DDE_SYNTAX_EXECUTE);
+ goto errRtn;
+ }
+
+ hresult = ReportResult(0, RPC_E_DDE_SYNTAX_EXECUTE, 0, 0);
+ // scan upto the first arg
+ if (!(wCmdType = ScanCommand (lpdata, WT_SRVR, &lpdocname, &aCmd)))
+ goto errRtn;
+
+ if (wCmdType == NON_OLE_COMMAND)
+ {
+ if (!UtilQueryProtocol (m_aClass, PROTOCOL_EXECUTE))
+ hresult = ReportResult(0, RPC_E_DDE_PROTOCOL, 0, 0);
+ else {
+ // REVIEW: StdExecute has to be mapped on to the StdCommandProtocol
+ // What command do we map on to?
+
+ AssertSz (0, "StdExecute is being called for server");
+ }
+
+ goto errRtn1;
+ }
+
+ if (aCmd == aStdExit)
+ {
+ if (*lpdocname)
+ goto errRtn1;
+
+ hresult = NOERROR;
+ // REVIEW: Do we have to initiate any terminations from the
+ // the servr side? Check how this works with excel.
+ goto end2;
+ }
+
+ // scan the next argument.
+ if (!(lpnextarg = ScanArg(lpdocname)))
+ goto errRtn;
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdShowItem("docname", "itemname"[, "true"])]
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+ if (aCmd == aStdShowItem) {
+
+ // first find the documnet. If the doc does not exist, then
+ // blow it off.
+
+ if (!(lpdocClient = FindDocObj (lpdocname)))
+ goto errRtn1;
+
+ lpitemname = lpnextarg;
+
+ if( !(lpopt = ScanArg(lpitemname)))
+ goto errRtn1;
+
+ // scan for the optional parameter
+ // Optional can be only TRUE or FALSE.
+
+ fActivate = FALSE;
+ if (*lpopt) {
+
+ if( !(lpnextarg = ScanBoolArg (lpopt, (BOOL FAR *)&fActivate)))
+ goto errRtn1;
+
+ if (*lpnextarg)
+ goto errRtn1;
+
+ }
+
+
+ // scan it. But, igonre the arg.
+ hresult = lpdocClient->DocShowItem (lpitemname, !fActivate);
+ goto end2;
+
+
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdCloseDocument ("docname")]
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+ if (aCmd == aStdClose) {
+ if (!(lpdocClient = FindDocObj (lpdocname)))
+ goto errRtn1;
+
+ if (*lpnextarg)
+ goto errRtn1;
+
+ // REVIEW: Do we have to do anything for shutting down the
+ // the app? Is the client going to initiate the terminate?.
+ // if we need to initiate the terminates, make sure we post
+ // the ACK first.
+
+ lpdocClient->Revoke();
+ goto end2;
+ }
+
+
+ if (aCmd == aStdOpen)
+ {
+ // find if any doc level object is already registerd.
+ // if the object is registerd, then no need to call srvr app.
+ if (FindDocObj (lpdocname))
+ {
+ // A client has already opened the document or user opened the
+ // doc. We should do an addref to the docobj
+
+#ifdef TRY
+ if (m_cSrvrClients == 0)
+ // Why are we doing this?
+ hresult = lpdocClient->m_lpoleObj->AddRef();
+ else
+#endif
+ hresult = NOERROR;
+ goto end1;
+ }
+ }
+
+ if (aCmd == aStdCreate || aCmd == aStdCreateFromTemplate) {
+ lpclassname = lpdocname;
+ lpdocname = lpnextarg;
+ if( !(lpnextarg = ScanArg(lpdocname)))
+ goto errRtn1;
+
+ }
+
+ // check whether we can create/open more than one doc.
+
+ if ((m_fcfFlags == REGCLS_SINGLEUSE) &&
+ GetWindow (m_hwnd, GW_CHILD))
+ goto errRtn;
+
+
+ ErrZ (CLSIDFromAtom(m_aClass, &clsid));
+
+
+ //
+ // Generate a wide version of the name
+ //
+
+ WCHAR awcWideDocName[MAX_STR];
+
+ if (MultiByteToWideChar(CP_ACP,0,lpdocname,-1,awcWideDocName,MAX_STR) == FALSE)
+ {
+ Assert(!"Unable to convert characters");
+ hresult = E_UNEXPECTED;
+ goto errRtn;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdOpenDocument ("docname")]
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+ // Document does not exist.
+ if (aCmd == aStdOpen)
+ {
+ ErrRtnH (wClassesMatch (clsid, awcWideDocName));
+ ErrRtnH (wFileBind (awcWideDocName, &pUnk));
+ }
+
+
+ ErrRtnH (CreateInstance (clsid, awcWideDocName, lpdocname, pUnk, &lpdocClient, hwndClient));
+ bCreateInst = TRUE;
+
+ if (aCmd == aStdOpen)
+ {
+ // Temporary flag to indicate someone will INITIATE on this doc.
+ // The flag is reset after the INITITATE.
+ // This is Yet-Another-Excel-Hack. See ::QueryRevokeClassFactory
+ lpdocClient->m_fCreatedNotConnected = TRUE;
+ }
+ else
+ {
+ lpdocClient->m_fEmbed = TRUE;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdNewDocument ("classname", "docname")]
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+ if (aCmd == aStdCreate)
+ {
+ hresult = lpdocClient->DoInitNew();
+ lpdocClient->m_fCreatedNotConnected = TRUE;
+ goto end;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdNewFormTemplate ("classname", "docname". "templatename)]
+ //
+ //////////////////////////////////////////////////////////////////////////
+ if (aCmd == aStdCreateFromTemplate)
+ {
+ ErrRtnH (lpdocClient->DoInitNew());
+ lpdocClient->m_fCreatedNotConnected = TRUE;
+ IPersistFile FAR * lpPF;
+ lptemplate = lpnextarg;
+
+ if(!(lpnextarg = ScanArg(lpnextarg)))
+ {
+ goto errRtn;
+ }
+
+
+ hresult = lpdocClient->m_lpoleObj->QueryInterface(IID_IPersistFile,(LPLPVOID)&lpPF);
+ if (hresult == NOERROR)
+ {
+ WCHAR awcWideTemplate[MAX_STR];
+
+ if (MultiByteToWideChar(CP_ACP,0,lpdocname,-1,awcWideTemplate,MAX_STR) != FALSE)
+ {
+ hresult = lpPF->Load(awcWideTemplate, 0);
+ }
+ else
+ {
+ Assert(!"Unable to convert characters");
+ lpPF->Release();
+ hresult = E_UNEXPECTED;
+ goto end;
+ }
+
+ lpPF->Release();
+ lpdocClient->m_fEmbed = TRUE;
+ }
+ else
+ {
+ goto end;
+ }
+ }
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdEditDocument ("docname")]
+ //
+ //////////////////////////////////////////////////////////////////////////
+ // REVIEW: Do we have to call InitNew for editing an embedded object
+
+ if (aCmd == aStdEdit)
+ {
+ lpdocClient->m_fEmbed = TRUE;
+ lpdocClient->m_fGotEditNoPokeNativeYet = TRUE;
+ lpdocClient->m_fCreatedNotConnected = TRUE;
+ goto end;
+ }
+
+ intrDebugOut((DEB_IERROR,
+ "%x CDDESrvr::SrvrExecute Unknown command\n",
+ this));
+
+end:
+
+ if (hresult != NOERROR)
+ goto errRtn;
+end1:
+ // make sure that the srg string is indeed terminated by
+ // NULL.
+ if (*lpnextarg)
+ {
+ hresult = RPC_E_DDE_SYNTAX_EXECUTE;
+ }
+errRtn:
+
+ if ( hresult != NOERROR)
+ {
+ if (bCreateInst && lpdocClient)
+ {
+ lpdocClient->DestroyInstance ();
+ lpdocClient = NULL; //DestroyInstance invalidates the pointer
+ }
+ }
+
+end2:
+errRtn1:
+
+ if (lpdata)
+ GlobalUnlock (hdup);
+
+ if (hdup)
+ GlobalFree (hdup);
+ if (pUnk)
+ pUnk->Release();
+
+ if (pPersistStg)
+ pPersistStg->Release();
+
+ Assert (GetScode(hresult) != E_UNEXPECTED);
+
+ intrDebugOut((DEB_ITRACE,
+ "%x _OUT CDDESrvr::SrvrExecute hresult=%x\n",
+ this,
+ hresult));
+
+ return hresult;
+}
+
+
+
+
+// Maybe CreateDocWindow
+//
+// Return NOERROR only if a doc window was created and it sent an ACK.
+//
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: MaybeCreateDocWindow
+//
+// Synopsis: Determine if a DocWindow should be created
+//
+// Effects: Given a class, and a filename atom, determine if this thread
+// should be the server for this request.
+//
+// Arguments: [aClass] -- Class of object (PROGID)
+// [aFile] -- Filename (ATOM)
+// [hwndDdeServer] -- HWND of CDDEServer
+// [hwndSender] -- HWND of new requesting client
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-29-94 kevinro Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+ INTERNAL MaybeCreateDocWindow
+ (ATOM aClass,
+ ATOM aFile,
+ HWND hwndDdeServer,
+ HWND hwndSender)
+{
+ CLSID clsid = CLSID_NULL;
+ LPUNKNOWN pUnk = NULL;
+ HWND hwndClient = NULL;
+ ULONG fAckSent = FALSE;
+ LPSRVR pDdeSrvr = NULL;
+ WCHAR szFile [MAX_STR];
+ BOOL fTrue = TRUE;
+ BOOL fRunningInSDI = FALSE;
+ HRESULT hresult = NOERROR;
+ IClassFactory *pcf = NULL;
+ IPersistFile *ppf = NULL;
+ DdeClassInfo ddeClassInfo;
+
+ intrDebugOut((DEB_DDE_INIT,
+ "MaybeCreateDocWindow(aClass=%x(%ws),aFile=%x,"
+ "hwndDdeServer=%x,hwndSender=%x\n",
+ aClass,wAtomName(aClass),aFile,hwndDdeServer,hwndSender));
+
+ //
+ // If the window isn't valid, it would be very bad.
+ //
+ if (!IsWindowValid(hwndDdeServer))
+ {
+ intrDebugOut((DEB_DDE_INIT,
+ "MaybeCreateDocWindow: hwndDdeServer is invalid\n"));
+ hresult = E_UNEXPECTED;
+ goto exitRtn;
+ }
+
+ //
+ // We need the filename, which is passed in an Atom
+ //
+ Assert (IsFile (aFile));
+ if (GlobalGetAtomName(aFile,szFile,MAX_STR) == 0)
+ {
+ //
+ // The filename was not valid
+ //
+ hresult = S_FALSE;
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow Invalid file atom\n"));
+ goto exitRtn;
+ }
+
+ intrDebugOut((DEB_DDE_INIT,
+ "MaybeCreateDocWindow File=(%ws)\n",
+ WIDECHECK(szFile)));
+
+ //
+ // Get the class of the object. The class was passed as an atom
+ // in the INITIATE message.
+ //
+ if (CLSIDFromAtomWithTreatAs (&aClass, &clsid, NULL))
+ {
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow CLSIDFromAtom failed\n"));
+
+ hresult = S_FALSE;
+ goto exitRtn;
+ }
+
+ if (CoIsOle1Class(clsid))
+ {
+ // we shouldn't even be looking at this INIT message
+ hresult = S_FALSE;
+ intrDebugOut((DEB_DDE_INIT,
+ "MaybeCreateDocWindow Its an OLE 1.0 class\n"));
+ goto exitRtn;
+ }
+
+ //
+ // First of three cases is to see if the object is running in our
+ // local apartment. If it is, then this is the object we need to create
+ // a DDEServer for.
+ //
+ // Otherwise, We are going to try and load this file.
+ // Therefore, we need the class factory from the CFT.
+ //
+ // GetClassInformationForDde won't find a match if the class factory was
+ // single use, and is now hidden or invalid.
+ //
+ // If there was no class information available, then we are going to
+ // check to see if the object is in the local ROT. If it is in the
+ // local ROT, then we will use it, since it is registered and
+ // available for use by others
+ //
+
+ ddeClassInfo.dwContextMask = CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER;
+ ddeClassInfo.fClaimFactory = TRUE;
+
+ if ( GetLocalRunningObjectForDde(szFile, &pUnk) == NOERROR)
+ {
+ intrDebugOut((DEB_DDE_INIT,
+ "Found %ws in ROT\n",WIDECHECK(szFile)));
+ //
+ // Elsewhere in the code, we need to know if this is an SDI server.
+ // The old code determined this by detecting that there is a running
+ // object, and there was no class factory registered.
+ // This is sick, and obscene. Compatibilities says we need to get the
+ // class info anyway. However, we don't want to claim it.
+ //
+
+ ddeClassInfo.fClaimFactory = FALSE;
+ fRunningInSDI = !GetClassInformationForDde(clsid,&ddeClassInfo);
+ }
+ else if (!GetClassInformationForDde(clsid,&ddeClassInfo))
+ {
+ intrDebugOut((DEB_IERROR,
+ "No class registered for %ws\n",WIDECHECK(szFile)));
+
+ hresult = S_FALSE;
+ goto exitRtn;
+ }
+ else
+ {
+ //
+ // Otherwise, we are registered as the server for this class. This
+ // means we can create this object.
+ //
+ // A 1.0 client will have launched the server with a command line
+ // like server.exe -Embedding filename The server ignored the filename
+ // so now we must make it load the file by binding the moniker.
+ //
+ // KevinRo: The old code did a bind moniker here, on the filename,
+ // which went through the ROT, didn't find the object, so went for
+ // a server. This isn't terribly safe, since we could end up binding
+ // out of process when we really didn't mean to. So, I have made this
+ // routine just use the ClassFactory we retrieve from the
+ // local class factory table.
+ //
+
+ intrDebugOut((DEB_DDE_INIT,
+ "Found classinfo: Loading %ws\n",WIDECHECK(szFile)));
+
+
+ //
+ // Need to insure that the server doesn't go away on us. The following
+ // tells the server not to destroy itself.
+ //
+ SSSendMessage(hwndDdeServer,WM_DONOTDESTROY,TRUE,0);
+
+ intrAssert(ddeClassInfo.punk != NULL);
+ pcf = (IClassFactory *) ddeClassInfo.punk;
+
+ hresult = pcf->CreateInstance(NULL,IID_IUnknown,(void **)&pUnk);
+
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow CreateInstancefailed File=(%ws)\n",
+ WIDECHECK(szFile)));
+ goto sndMsg;
+ }
+
+ //
+ // Get the IPersistFile interface, and ask the object to load
+ // itself.
+ //
+ hresult = pUnk->QueryInterface(IID_IPersistFile,(void **)&ppf);
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow QI IPF failed File=(%ws)\n",
+ WIDECHECK(szFile)));
+ goto sndMsg;
+ }
+ //
+ // Attempt to load the object. The flags STGM_READWRITE are the
+ // same default values used by a standard bind context.
+ //
+ hresult = ppf->Load(szFile,STGM_READWRITE);
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow ppf->Load(%ws) failed %x\n",
+ WIDECHECK(szFile),
+ hresult));
+ goto sndMsg;
+ }
+sndMsg:
+ SSSendMessage(hwndDdeServer,WM_DONOTDESTROY,FALSE,0);
+ if (hresult != NOERROR)
+ {
+ goto exitRtn;
+
+ }
+ intrDebugOut((DEB_DDE_INIT,
+ "Loading %ws complete\n",WIDECHECK(szFile)));
+
+ }
+
+
+ intrAssert(IsWindowValid(hwndDdeServer));
+ intrAssert (pUnk);
+
+ pDdeSrvr = (LPSRVR) GetWindowLong (hwndDdeServer, 0);
+ if (pDdeSrvr == NULL)
+ {
+ intrAssert(pDdeSrvr != NULL);
+ hresult = E_UNEXPECTED;
+ goto exitRtn;
+ }
+
+ // This actually creates the doc window as a child of the server window
+ // Do not set the client site becuase this is a link.
+ hresult = CDefClient::Create (pDdeSrvr,
+ pUnk,
+ szFile,
+ /*fSetClientSite*/FALSE,
+ /*fDoAdvise*/TRUE,
+ fRunningInSDI,
+ &hwndClient);
+
+ if (hresult != NOERROR)
+ {
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow CDefClient::Create failed %x\n",
+ hresult));
+ goto exitRtn;
+ }
+
+ Assert (IsWindowValid (hwndClient));
+
+ //
+ // Pass along the original DDE_INIT to the newly created window.
+ // That window should respond by sending an ACK to the 1.0 client.
+ //
+ fAckSent = SSSendMessage (hwndClient,
+ WM_DDE_INITIATE,
+ (UINT) hwndSender,
+ MAKELONG(aClass, aFile));
+ if (!fAckSent)
+ {
+ intrDebugOut((DEB_IERROR,
+ "MaybeCreateDocWindow !fAckSent\n"));
+ hresult = CO_E_APPDIDNTREG;
+ }
+
+exitRtn:
+
+ if (ppf)
+ {
+ ppf->Release();
+ }
+ if (pUnk)
+ {
+ pUnk->Release();
+ }
+ if (pcf)
+ {
+ pcf->Release();
+ }
+
+ intrDebugOut((DEB_DDE_INIT,
+ "MaybeCreateDocWindow returns %x\n",
+ hresult));
+ return hresult;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SendMsgToChildren
+//
+// Synopsis: This routine sends the msg to all child windows.
+//
+// Arguments: [hwnd] -- Hwnd of parent window
+// [msg] -- Message and parameters to send
+// [wParam] --
+// [lParam] --
+//
+// Notes: This routine will stop on the first non-zero return code.
+//
+//----------------------------------------------------------------------------
+BOOL SendMsgToChildren (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ intrDebugOut((DEB_ITRACE,
+ "0 _IN SendMsgToChildren(hwnd=%x,msg=%x,wParam=%x,lParam=%x)\n",
+ hwnd,msg,wParam,lParam));
+
+ BOOL fAckSent = FALSE;
+
+ hwnd = GetWindow(hwnd, GW_CHILD);
+
+ //
+ // This routine is to be called only from one place, which is
+ // in the handling of WM_DDE_INITIATE. Because of that, we will terminate
+ // the loop on the first non-zero return code.
+ //
+ Assert (msg == WM_DDE_INITIATE);
+
+ while (hwnd)
+ {
+ intrDebugOut((DEB_ITRACE," SendMsgToChildren send to hwnd=%x\n",hwnd));
+
+ if (fAckSent = (1L==SSSendMessage (hwnd, msg, wParam, lParam)))
+ {
+ break;
+ }
+
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+
+ intrDebugOut((DEB_ITRACE,"0 OUT SendMsgToChildren returns %x\n",fAckSent));
+ return(fAckSent);
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SendInitMsgToChildren
+//
+// Synopsis: Sends an init message to all child windows of the hwnd
+//
+// Effects: This routine will send an init message to all children
+// of the given window. It is assuming that the lParam is
+// the atom that contains the topic (ie filename) of the
+// object being looked for.
+//
+// Arguments: [hwnd] -- hwnd of server window
+// [msg] -- MSG to send
+// [wParam] -- hwnd of client window
+// [lParam] -- HIWORD(lParam) is atom of filename
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: 6-28-94 kevinro Commented
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+BOOL SendInitMsgToChildren (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ intrDebugOut((DEB_DDE_INIT,
+ "0 _IN SendInitMsgToChildren(hwnd=%x,msg=%x,wParam=%x,lParam=%x)\n",
+ hwnd,msg,wParam,lParam));
+
+ BOOL fAckSent = FALSE;
+
+ fAckSent = SendMsgToChildren(hwnd,msg,wParam,lParam);
+
+ //
+ // If no windows acknowledged, then we might need to create a doc window
+ //
+ if (!fAckSent)
+ {
+ ATOM aTopic = HIWORD(lParam);
+ Assert (IsAtom(aTopic));
+
+ // if someone's trying to initiate on a filename, i.e., for a link
+ // then create the doc window on demand because 2.0 servers do not
+ // register doc windows. They don't even accept "-Embedding filename"
+ // on the command line
+ if (aTopic != aOLE && aTopic != aSysTopic && IsFile (aTopic))
+ {
+ intrDebugOut((DEB_DDE_INIT," Initiate for link %ws\n",wAtomName(aTopic)));
+ HRESULT hresult = MaybeCreateDocWindow (LOWORD(lParam), aTopic,
+ hwnd, (HWND)wParam);
+
+ fAckSent = (NOERROR==hresult);
+ }
+ }
+ intrDebugOut((DEB_DDE_INIT,
+ "0 _OUT SendInitMsgToChildren fAckSent=%x\n",fAckSent));
+ return fAckSent;
+}
+
+
+
+INTERNAL_(HRESULT) RequestDataStd
+(
+ATOM aItem,
+LPHANDLE lphdde
+)
+{
+
+
+ HANDLE hnew = NULL;
+
+ if (!aItem)
+ goto errRtn;
+
+ if (aItem == aEditItems){
+ hnew = MakeGlobal ("StdHostNames\tStdDocDimensions\tStdTargetDevice");
+ goto PostData;
+
+ }
+
+ if (aItem == aProtocols) {
+ hnew = MakeGlobal ("Embedding\tStdFileEditing");
+ goto PostData;
+ }
+
+ if (aItem == aTopics) {
+ hnew = MakeGlobal ("Doc");
+ goto PostData;
+ }
+
+ if (aItem == aFormats) {
+ hnew = MakeGlobal ("Picture\tBitmap");
+ goto PostData;
+ }
+
+ if (aItem == aStatus) {
+ hnew = MakeGlobal ("Ready");
+ goto PostData;
+ }
+
+ // format we do not understand.
+ goto errRtn;
+
+PostData:
+
+ // Duplicate the DDE data
+ if (MakeDDEData (hnew, CF_TEXT, lphdde, TRUE)){
+ // !!! why are we duplicating the atom.
+ DuplicateAtom (aItem);
+ return NOERROR;
+ }
+errRtn:
+ return ReportResult(0, S_FALSE, 0, 0);
+}
+
+
+//IsSingleServerInstance: returns true if the app is single server app else
+//false.
+
+INTERNAL_(BOOL) IsSingleServerInstance ()
+{
+ HWND hwnd;
+ WORD cnt = 0;
+ HTASK hTask;
+ DdeCHAR buf[MAX_STR];
+
+ hwnd = GetWindow (GetDesktopWindow(), GW_CHILD);
+ hTask = GetCurrentThreadId();
+
+ while (hwnd) {
+ if (hTask == ((HTASK) GetWindowThreadProcessId (hwnd,NULL))) {
+ DdeGetClassName (hwnd, buf, MAX_STR);
+ if (Ddelstrcmp (buf, SRVR_CLASS) == 0)
+ cnt++;
+ }
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+#ifdef FIREWALLS
+ AssertSz (cnt > 0, "srvr window instance count is zero");
+#endif
+ if (cnt == 1)
+ return TRUE;
+ else
+ return FALSE;
+
+}
+
+
+// QueryRevokeClassFactory: returns FALSE if there are clients
+// connected tothis class factory;
+INTERNAL_(BOOL) CDDEServer::QueryRevokeClassFactory ()
+{
+
+ HWND hwnd;
+ LPCLIENT lpclient;
+
+ Assert (IsWindow (m_hwnd));
+ hwnd = GetWindow (m_hwnd, GW_CHILD);
+ while (hwnd)
+ {
+ Assert (IsWindow (hwnd));
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+ if (lpclient->m_cClients != 0 || lpclient->m_fCreatedNotConnected)
+ return FALSE;
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+ return TRUE;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CDDEServer::CreateInstance
+//
+// Synopsis: Create an instance of a document
+//
+// Effects:
+//
+// Arguments: [lpclassName] --
+// [lpWidedocName] --
+// [lpdocName] --
+// [pUnk] --
+// [lplpdocClient] --
+// [hwndClient] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 5-30-94 kevinro Commented/cleaned
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+INTERNAL CDDEServer::CreateInstance
+(
+REFCLSID lpclassName,
+LPOLESTR lpWidedocName,
+LPSTR lpdocName,
+LPUNKNOWN pUnk,
+LPCLIENT FAR* lplpdocClient,
+HWND hwndClient)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%p _IN CDDEServer::CreateInstance(lpWidedocName=%ws,hwndClient=%x)\n",
+ this,
+ WIDECHECK(lpWidedocName),
+ hwndClient));
+
+
+ LPUNKNOWN pUnk2=NULL;
+ LPOLEOBJECT lpoleObj= NULL; // unknown object
+ HRESULT hresult;
+
+ ChkS(this);
+
+ if (NULL==pUnk)
+ {
+ Assert (m_pClassFactory);
+ hresult = m_pClassFactory->CreateInstance (NULL, IID_IUnknown, (LPLPVOID)&pUnk2);
+
+ if (hresult != NOERROR)
+ {
+ return hresult;
+ }
+
+ // Now that we have *used* the DDE server window, we can unlock
+ // the server.
+ // The OLE1 OleLockServer API opens a dummy DDE system channel
+ // and just leaves it open until OleunlockServer is called.
+ // Since we have now used this channel, we know it was not created
+ // for the purpose of locking the server.
+ this->Lock (FALSE, hwndClient);
+
+ // if it is an SDI app, we must revoke the ClassFactory after using it
+ // it is only good for "one-shot" createinstance call.
+ if (m_fcfFlags == REGCLS_SINGLEUSE)
+ {
+ m_pClassFactory->Release(); // done with the ClassFactory
+ Puts ("NULLing m_pCF\r\n");
+ m_pClassFactory = NULL;
+ }
+ }
+ else
+ {
+ pUnk2 = pUnk;
+ pUnk->AddRef();
+ }
+
+ hresult = CDefClient::Create ((LPSRVR)this,
+ pUnk2,
+ lpWidedocName,
+ /*fSetClientSite*/FALSE,
+ /*fDoAdvise*/pUnk!=NULL);
+
+ intrAssert (pUnk2 != NULL);
+ if (pUnk2 != NULL)
+ {
+ pUnk2->Release();
+ }
+
+ pUnk2 = NULL;
+
+ // REVIEW: error recovery
+ if (!(*lplpdocClient = FindDocObj (lpdocName)))
+ {
+ intrAssert(!"Document created but not found");
+ }
+ else
+ {
+ // set the server instance flag so that WM_DDE_INITIATE will not icrement
+ // the ref count. (EXCEL BUG)
+ (*lplpdocClient)->m_bCreateInst = TRUE;
+ }
+ intrDebugOut((DEB_ITRACE,
+ "%p _OUT CDDEServer::CreateInstance hresult=%x\n",
+ this,hresult));
+ return hresult;
+}
+
+
+INTERNAL_(void) CDDEServer::Lock
+ (BOOL fLock, // lock or unlock?
+ HWND hwndClient) // on behalf of which window?
+{
+ intrDebugOut((DEB_ITRACE,
+ "%p _IN CDDEServer::Lock(fLock=%x,hwndCient=%x)\n",
+ this,
+ fLock,
+ hwndClient));
+
+ VDATEHEAP();
+ BOOL fIsLocked = (BOOL) FindClient (m_hcli, hwndClient, /*fDelete*/FALSE);
+
+ if (fLock && !fIsLocked)
+ {
+ if (m_pClassFactory)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "%p ::Locking %x\n",
+ this,
+ m_pClassFactory));
+
+ m_pClassFactory->LockServer (TRUE);
+ // Only way to change the data associated with a client window
+ // is to delete it and re-add it with the new data.
+ FindClient (m_hcli, hwndClient, /*fDelete*/ TRUE);
+ AddClient (&m_hcli, hwndClient, (HANDLE) TRUE); // mark as locked
+ }
+ }
+ else if (!fLock && fIsLocked)
+ {
+ if (m_pClassFactory)
+ {
+ intrDebugOut((DEB_ITRACE,
+ "%p ::UnLocking %x\n",
+ this,
+ m_pClassFactory));
+ m_pClassFactory->LockServer (FALSE);
+ FindClient (m_hcli, hwndClient, /*fDelete*/ TRUE);
+ AddClient (&m_hcli, hwndClient, (HANDLE) FALSE); //mark as unlocked
+ }
+ }
+ VDATEHEAP();
+ intrDebugOut((DEB_ITRACE,
+ "%p _OUT CDDEServer::Lock(fLock=%x,hwndCient=%x)\n",
+ this,
+ fLock,
+ hwndClient));
+}
+
+
+
+
+
+INTERNAL CDefClient::DestroyInstance
+ (void)
+{
+ Puts ("DestroyInstance\r\n");
+ // We just created the instance. we ran into error.
+ // just call Release.
+ m_pUnkOuter->AddRef();
+ ReleaseObjPtrs();
+ Verify (0==m_pUnkOuter->Release());
+ // "this" should be deleted now
+ return NOERROR;
+}
+
+
+
+INTERNAL CDefClient::SetClientSite
+ (void)
+{
+ HRESULT hresult = m_lpoleObj->SetClientSite (&m_OleClientSite);
+ if (hresult==NOERROR)
+ {
+ m_fDidSetClientSite = TRUE;
+ }
+ else
+ {
+ Warn ("SetClientSite failed");
+ }
+ return hresult;
+}
+
+
+// implementations of IRpcStubBuffer methods
+STDMETHODIMP CDdeServerCallMgr::QueryInterface
+ ( REFIID iid, LPVOID * ppvObj )
+{
+ return S_OK;
+}
+
+STDMETHODIMP_(ULONG)CDdeServerCallMgr::AddRef ()
+{
+ return 1;
+}
+
+STDMETHODIMP_(ULONG)CDdeServerCallMgr::Release ()
+{
+ return 1;
+}
+
+
+STDMETHODIMP CDdeServerCallMgr::Connect
+ (IUnknown * pUnkServer )
+{
+ // do nothing
+ return S_OK;
+}
+
+STDMETHODIMP_(void) CDdeServerCallMgr::Disconnect
+ ()
+{
+ // do nothing
+}
+
+STDMETHODIMP_(IRpcStubBuffer*) CDdeServerCallMgr::IsIIDSupported
+ (REFIID riid)
+{
+ // do nothing
+ return NULL;
+}
+
+
+STDMETHODIMP_(ULONG) CDdeServerCallMgr::CountRefs
+ ()
+{
+ // do nothing
+ return 1;
+}
+
+STDMETHODIMP CDdeServerCallMgr::DebugServerQueryInterface
+ (void ** ppv )
+{
+ // do nothing
+ *ppv = NULL;
+ return S_OK;
+}
+
+
+STDMETHODIMP_(void) CDdeServerCallMgr::DebugServerRelease
+ (void * pv)
+{
+ // do nothing
+}
+
+STDMETHODIMP CDdeServerCallMgr::Invoke
+ (RPCOLEMESSAGE *_prpcmsg, IRpcChannelBuffer *_pRpcChannelBuffer)
+{
+ DISPATCHDATA *pdispdata = (PDISPATCHDATA) _prpcmsg->Buffer;
+ return DispatchCall( pdispdata );
+}
+
+
+// Provided IRpcChannelBuffer methods (for callback methods side)
+STDMETHODIMP CDdeServerCallMgr::GetBuffer(
+/* [in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+/* [in] */ REFIID riid)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CDdeServerCallMgr::SendReceive(
+/* [out][in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+/* [out] */ ULONG __RPC_FAR *pStatus)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CDdeServerCallMgr::FreeBuffer(
+/* [in] */ RPCOLEMESSAGE __RPC_FAR *pMessage)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CDdeServerCallMgr::GetDestCtx(
+/* [out] */ DWORD __RPC_FAR *pdwDestContext,
+/* [out] */ void __RPC_FAR *__RPC_FAR *ppvDestContext)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CDdeServerCallMgr::IsConnected( void)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CDdeServerCallMgr::SendReceive2(
+/* [out][in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
+/* [out] */ ULONG __RPC_FAR *pStatus)
+{
+ intrDebugOut((DEB_ITRACE,
+ "%p _IN CDdeServerCallMgr::SendReceive2(pMessage=%x,pStatus=%x)\n",
+ this,
+ pMessage,
+ pStatus));
+
+ DDECALLDATA *pCD = ((DDECALLDATA *) pMessage->Buffer);
+
+ if(!PostMessageToClient(pCD->hwndSvr,
+ pCD->wMsg,
+ pCD->wParam,
+ pCD->lParam))
+ {
+ intrDebugOut((DEB_ITRACE, "SendRecieve2(%x)PostMessageToClient failed", this));
+ return RPC_E_SERVER_DIED;
+ }
+
+
+ CAptCallCtrl *pCallCtrl = GetAptCallCtrl();
+
+ CCliModalLoop *pCML = pCallCtrl->GetTopCML();
+
+ HRESULT hres = S_OK;
+ BOOL fWait = !(m_pDefClient->m_CallState == SERVERCALLEX_ISHANDLED);
+
+ while (fWait)
+ {
+ HRESULT hr = OleModalLoopBlockFn(NULL, pCML, NULL);
+
+ if (m_pDefClient->m_CallState == SERVERCALLEX_ISHANDLED)
+ {
+ fWait = FALSE;
+ }
+ else if (hr != RPC_S_CALLPENDING)
+ {
+ fWait = FALSE;
+ hres = hr; // return result from OleModalLoopBlockFn()
+ }
+ }
+
+ if (FAILED(hres))
+ {
+ intrDebugOut((DEB_ITRACE, "**** CDdeServerCallMgr::SendReceive2 OleModalLoopBlockFn returned %x ***\n", hres));
+ }
+
+ intrDebugOut((DEB_ITRACE,
+ "%p _OUT CDdeServerCallMgr::SendReceive2(pMessage=%x,pStatus=%x)\n",
+ this,
+ pMessage,
+ pStatus));
+
+ return hres;
+}