Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

757 lines
18 KiB

/*
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 szOLE_CLASSA = "Ole2WndClass 0x######## ";
LPSTR szSRVR_CLASSA = "SrvrWndClass 0x######## ";
LPSTR szDdeServerWindow = "DDE Server Window";
#define szDdeCommonWindowClass szCOMMONCLASSA
#else
const LPOLESTR szDdeServerWindow = OLESTR("DDE Server Window");
const LPOLESTR szDdeCommonWindowClass = OLESTR("DdeCommonWindowClass");
#endif
//+---------------------------------------------------------------------------
//
// Function: CreateDdeSrvrWindow
//
// Synopsis: When CoRegisterClassObject is called, this function
// is called to create a DDE window to listen for DDE messages
// from a 1.0 client.
//
// Effects:
//
// Arguments: [clsid] --
// [aClass] --
// [phwnd] --
// [fIsRunning] --
// [aOriginalClass] --
// [cnvtyp] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 5-27-94 kevinro Commented/cleaned
// 13-Jul-94 BruceMa Make register/unregister dde window class
// thread safe
//
// Notes:
//
//----------------------------------------------------------------------------
INTERNAL CreateDdeSrvrWindow
(REFCLSID clsid,
ATOM aClass,
HWND FAR* phwnd, // optional out parm: created window
BOOL fIsRunning, // Is the item atom a file in the ROT?
ATOM aOriginalClass, // for TreatAs/ConvertTo case
CNVTYP cnvtyp)
{
intrDebugOut((DEB_DDE_INIT,"0 _IN CreateDdeSrvrWindow\n"));
VDATEHEAP();
HWND hwnd = NULL;
HRESULT hresult = NOERROR;
DdeClassInfo ddeClassInfo;
ddeClassInfo.dwContextMask = CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER;
ddeClassInfo.fClaimFactory = FALSE;
// Null out parameter in case of error
if (phwnd)
{
*phwnd = NULL;
}
intrAssert (wIsValidAtom (aClass));
//
// See if this process is registered as a class server for
// the requested class. If it isn't, then check for a running
// object.
//
if (GetClassInformationForDde(clsid,&ddeClassInfo) == FALSE)
{
intrDebugOut((DEB_DDE_INIT,
"CreateDdeSrvrWindow No class information available\n"));
//
// The ClassObject was not found in the table.
//
if (fIsRunning)
{
// Link case.
// An SDI app was launched by the user (without "-Embedding").
// It did not register its class factory. (It never does.)
// Meanwhile, a DDE_INIT with a filename as an item atom was
// broadcasted.
// We are in the task of the SDI app that loaded that filename,
// so this function was called.
// So we need to create the window even though no class factory
// was registered.
// Call CDDEServer::Create with a lot of NULLs.
// Once the DDE_INIT is passed along to the server window, it
// should immediately cause a doc window to be created.
// Must be SDI or we wouldn't have this problem.
//
// This works because we are going to attempt to 'bind' to the
// object which is the subject of the link. If the link object
// was registered as running, we will find it. Otherwise, the
// attempt to create via the class factory will fail, since the
// class factory doesn't exist.
//
intrDebugOut((DEB_DDE_INIT,
"::CreateDdeServerWindow fIsRunning - override dwFlags\n"));
//
// NULL out the entire structure, then set only the flags
//
memset(&ddeClassInfo,0,sizeof(ddeClassInfo));
ddeClassInfo.dwFlags = REGCLS_SINGLEUSE;
}
else
{
intrDebugOut((DEB_DDE_INIT,
"CreateDdeServerWindow Returning FALSE\n"));
hresult = S_FALSE;
goto errRtn;
}
}
intrDebugOut((DEB_DDE_INIT,
"::CreateDdeServerWindow found class\n"));
// Create() does the real work: creates a CDDEServer and the window.
WCHAR szClass[MAX_STR];
lstrcpyW (szClass, wAtomName (aClass));
Assert (szClass[0]);
hresult = CDDEServer::Create(szClass,
clsid,
&ddeClassInfo,
&hwnd,
aOriginalClass,
cnvtyp);
if (hresult != NOERROR)
{
intrDebugOut((DEB_IERROR,
"CreateDdeServerWindow CDDEServer::Create returns %x\n",
hresult));
goto errRtn;
}
Assert (IsWindowValid(hwnd));
// Fill in out parameter
if (phwnd)
{
*phwnd = hwnd;
}
errRtn:
VDATEHEAP();
intrDebugOut((DEB_DDE_INIT,
"0 _OUT CreateDdeSrvrWindow %x\n",
hresult));
return hresult;
}
//+---------------------------------------------------------------------------
//
// Function: DestroyDdeSrvrWindow
//
// Synopsis: Destroy a DDE server window
//
// Effects:
//
// Arguments: [hwnd] -- Window to destroy
// [aClass] -- Class for server
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 6-24-94 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
INTERNAL DestroyDdeSrvrWindow
(HWND hwnd,
ATOM aClass)
{
intrDebugOut((DEB_ITRACE,
"0 _IN DestroyDdeSrvrWindow\n"));
VDATEHEAP();
Assert (IsAtom (aClass));
// Make sure it is a server window
RetZ (IsWindowValid (hwnd));
RetZ (GetWindowWord (hwnd, WW_LE) == WC_LE);
// Get the Common window for this task.
HWND hwndCommonServer = (HWND)TLSGetDdeServer();
if (hwndCommonServer == NULL)
{
intrDebugOut((DEB_IERROR,"hwndCommonServer != NULL\n"));
return(E_UNEXPECTED);
}
if (!IsWindow(hwndCommonServer))
{
intrAssert(IsWindow(hwndCommonServer));
return(E_UNEXPECTED);
}
// Get the map from the common window
CMapUintPtr FAR *pmapClassToHwnd;
Assert (sizeof (CMapUintPtr FAR *)==sizeof(LONG));
pmapClassToHwnd = (CMapUintPtr FAR *) GetWindowLong (hwndCommonServer, 0);
Assert (pmapClassToHwnd);
// Make sure the window we're deleting is the server window for this class
void *hwndSrvr;
RetZ (pmapClassToHwnd->Lookup (aClass,hwndSrvr) && hwndSrvr == hwnd);
RetZ (SSDestroyWindow (hwnd));
// Remove this window from the map
pmapClassToHwnd->RemoveKey (aClass);
VDATEHEAP();
intrDebugOut((DEB_ITRACE,
"0 _OUT DestroyDdeSrvrWindow\n"));
return NOERROR;
}
//+---------------------------------------------------------------------------
//
// Function: DdeCommonWndProc
//
// Synopsis: Window proc for the common dde server window that
// listens for all WM_DDE_INITIATEs
//
// Effects: When a DDE_INITIATE comes in, this routine will determine
// the class of the object being requested. If the class is
// served by this thread, then it will create a window to
// converse with the server.
//
// Arguments: [hWnd] -- hWnd of Common DDE
// [wMsg] -- msg
// [wParam] -- Return Window to converse with
// [lParam] -- HIWORD(aItem) LOWORD(aClass)
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 5-27-94 kevinro Commented/cleaned
//
// Notes:
//
// When running in a VDM, it is possible that this window was dispatched
// without having a full window handle. This happens when the getmessage
// was dispatched from 16-bit. Therefore, we need to convert the hwnd to
// a full hwnd before doing any comparision functions.
//
//----------------------------------------------------------------------------
STDAPI_(LRESULT)
DdeCommonWndProc(HWND hwndIn, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
switch (wMsg)
{
case WM_DDE_INITIATE:
{
VDATEHEAP();
ATOM aClass = LOWORD(lParam);
ATOM aItem = HIWORD(lParam);
HWND hwnd;
CNVTYP cnvtyp = cnvtypNone;
BOOL fIsFile= FALSE; // Must initialize
BOOL fIsRunning= FALSE; // Must initialize
BOOL fUnsavedDoc = FALSE; // Is the "file" really an unsaved doc
HWND hwndServer;
HRESULT hresult;
//
// From this point forward, we need to insure we are using a
// FULL hwnd.
//
hwnd = ConvertToFullHWND(hwndIn);
//
// The following should already be initialized
//
intrAssert (aOLE != NULL);
intrAssert (aSysTopic != NULL);
if (aItem==aOLE || aItem==aSysTopic
|| (fIsFile=IsFile (aItem, &fUnsavedDoc)))
{
intrDebugOut((DEB_DDE_INIT,
"DdeCommonWndProc:hWnd(%x) DDE_INITIATE cls(%ws)\n",
hwnd,
wAtomName(aClass)));
//
// Get the ClassToHwnd map for this thread
//
CMapUintPtr FAR *pmapClassToHwnd;
Assert (sizeof (CMapUintPtr FAR *)==sizeof(LONG));
pmapClassToHwnd = (CMapUintPtr FAR *) GetWindowLong (hwnd, 0);
Assert (pmapClassToHwnd);
// Convert atom to CLSID, taking into account
// TreatAs and AutoConvert.
CLSID clsid;
ATOM aOriginalClass = aClass;
if (CLSIDFromAtomWithTreatAs (&aClass, &clsid, &cnvtyp) != NOERROR)
{
intrDebugOut((DEB_IERROR,"Could not get clsid for this class\n"));
return 0L;
}
void *pServerTmp;
if (TRUE == pmapClassToHwnd->Lookup (aClass, pServerTmp))
{
//
// Since a server window for this class already exists, but is a child window
// of ours, we will send it this message directly.
//
intrDebugOut((DEB_DDE_INIT,
"DdeCommonWndProc Server cls exists. Forwarding to %x\n",
pServerTmp));
return SSSendMessage ((HWND)pServerTmp, WM_DDE_INITIATE, wParam,lParam);
}
if (CoIsOle1Class (clsid))
{
// We have no business intercepting Initiates sent
// to 1.0 servers
intrDebugOut((DEB_DDE_INIT,
"DdeCommonWndProc: Its a OLE 1.0 class\n"));
return 0L;
}
if (fIsFile)
{
// Link case
WCHAR szFile[MAX_STR];
WORD cb=GlobalGetAtomName (aItem, szFile, MAX_STR);
Assert (cb>0 && cb < MAX_STR-1);
intrDebugOut((DEB_DDE_INIT,
"Looking for file %ws\n",szFile));
IsRunningInThisTask (szFile, &fIsRunning);
}
// If it's not a file, it can't be running, obviously.
intrAssert (fIsFile || !fIsRunning);
if (NOERROR == (hresult=(CreateDdeSrvrWindow (clsid,
aClass,
&hwndServer,
fIsRunning,
aOriginalClass,
cnvtyp))))
{
// Indicate that we have created a server window
// for this class. We could have used any value in
// place of hwndServer_. It's just a flag.
// REVIEW jasonful: how to handle OOM?
pmapClassToHwnd->SetAt (wDupAtom(aClass), hwndServer);
#if DBG == 1
// Verify the SetAt we just did.
void FAR* pv;
Verify (pmapClassToHwnd->Lookup(aClass, pv));
Assert (pv == hwndServer);
#endif
// Pass the INITIATE along to the real,
// newly-created server window and forge
// the sender's hwnd to be whoever called
// the common server window.
// SendMessage should return 1L is doc is running,
// indicating an ACK was sent.
Assert (IsWindowValid (hwndServer));
SSSendMessage (hwndServer, WM_DDE_INITIATE, wParam,lParam);
intrDebugOut((DEB_DDE_INIT,
"DdeCommonWndProc:hWnd(%x) DDE_INITIATE complete(%ws)\n",
hwnd,
wAtomName(aClass)));
VDATEHEAP();
}
else
{
if (S_FALSE!=GetScode(hresult))
{
intrDebugOut((DEB_IERROR,
"DCWP: CreateDdeSrvrWindow failed %x\n",
hresult));
}
}
}
else
{
//
// We have a DDE_INITIATE message that needs to be forwarded to our
// child window.
//
return SendMsgToChildren(hwnd,wMsg,wParam,lParam);
}
return 0L;
}
break;
case WM_DESTROY:
{
//
// When this window is destroyed, we cleanup the
// windows attached data.
//
CMapUintPtr FAR *pmapClassToHwnd;
pmapClassToHwnd = (CMapUintPtr FAR *) GetWindowLong (hwndIn, 0);
//
// Make sure there are no server windows
// created by this common window still extant. If there are, print out
// a message on a debug build. Otherwise, there really isn't much we
// can do about it. We are already closing down. The DDE emulation layer
// will send appropriate terminate messages.
//
#if DBG == 1
if (pmapClassToHwnd && !pmapClassToHwnd->IsEmpty())
{
intrDebugOut((DEB_ERROR,
"DCDW Leaking active OLE 1.0 clients\n"));
intrDebugOut((DEB_ERROR,
"There were active OLE 1.0 connections at shutdown\n"));
}
#endif
delete pmapClassToHwnd;
return(0);
}
default:
return SSDefWindowProc (hwndIn, wMsg, wParam, lParam);
}
}
//+---------------------------------------------------------------------------
//
// Function: CreateCommonDdeWindow
//
// Synopsis: Creates a DDE window for initiating conversations with this
// threads objects.
//
// Effects: Creates a window that responds to DDE_INITIATE messages, and
// determines if it needs to respond to the INITIATE. This
// routine is called by OleInitializeEx()
//
// The handle to the created window is placed in the TLS
// structure.
//
// Arguments: [void] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 5-27-94 kevinro Converted to OLE32
//
// Notes:
//
//----------------------------------------------------------------------------
INTERNAL CreateCommonDdeWindow
(void)
{
intrDebugOut((DEB_ITRACE,"%p _IN CreateCommonDdeWindow\n",0));
HRESULT hr = NOERROR;
HWND hwndDdeServer;
COleTls tls;
if (tls->dwFlags & OLETLS_DISABLE_OLE1DDE)
{
// If DDE use is disabled we shouldn't have gotten here.
//
Assert(!"Executing CreateCommonDdeWindow when DDE is disabled");
hr = CO_E_OLE1DDE_DISABLED;
goto exitRtn;
}
//
// If a DdeServer window already exists, then return NOERROR.
// If Com has been initialized but Ole has not, then we dont
// create a window, we just return NOERROR. This way, COM-only
// servers dont start serving OLE1 clients.
//
if (tls->hwndDdeServer != NULL || tls->cOleInits == 0)
{
goto exitRtn;
}
if (!(hwndDdeServer = DdeCreateWindowEx(0, gOleWindowClass,
szDdeServerWindow,
WS_POPUP,0,0,0,0,
NULL,NULL,
g_hmodOLE2, NULL)))
{
intrDebugOut((DEB_IERROR,
"CreateCommonDocWindow() has failed %x\n",
GetLastError()));
hr = E_OUTOFMEMORY;
goto exitRtn;
}
// fix up the WindowProc entry point.
SetWindowLong(hwndDdeServer, GWL_WNDPROC, (LONG)DdeCommonWndProc);
intrDebugOut((DEB_ITRACE,
"CreateCommonDocWindow() hwndDdeServer=%x\n",
hwndDdeServer));
// Give the common window a map from classes to server windows
CMapUintPtr FAR *pmapClassToHwnd;
Assert (sizeof(LONG)==sizeof (CMapUintPtr FAR*));
if ((pmapClassToHwnd = new CMapUintPtr) == NULL)
{
intrDebugOut((DEB_ERROR,"pmapClassToHwnd != NULL\n"));
hr = E_OUTOFMEMORY;
goto errRtn;
}
SetWindowLong (hwndDdeServer, 0, (LONG)pmapClassToHwnd);
//
// Set the pointer to the server in the TLS data
//
tls->hwndDdeServer = hwndDdeServer;
exitRtn:
intrDebugOut((DEB_ITRACE,"%p _OUT CreateCommonDocWindow (%x)\n",0,hr));
return(hr);
//
// In the error case, if the hwnDdeServer != NULL, then destroy it
//
errRtn:
if (hwndDdeServer != NULL)
{
SSDestroyWindow(hwndDdeServer);
}
goto exitRtn;
}
//+---------------------------------------------------------------------------
//
// Function: DestroyCommonDdeWindow
//
// Synopsis: Destroys the common DDE Server window
//
// Effects:
//
// Arguments: [void] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 5-27-94 kevinro Commented/cleaned
//
// Notes:
//
//----------------------------------------------------------------------------
INTERNAL DestroyCommonDdeWindow
(void)
{
intrDebugOut((DEB_ITRACE,"%p _IN DestroyCommonDdeWindow\n",0));
HRESULT hr = S_OK;
COleTls tls;
HWND hwndDdeServer = tls->hwndDdeServer;
if (hwndDdeServer == NULL)
{
goto errRtn;
}
//
// The map from the common window got deleted in DdeCommonWndProc
//
//
// If destroying this window fails, there isn't much we can
// do about it.
//
if(!SSDestroyWindow (hwndDdeServer))
{
hr = E_UNEXPECTED;
}
// NULL out the TLS
tls->hwndDdeServer = NULL;
errRtn:
intrDebugOut((DEB_ITRACE,"%p _OUT DestroyCommonDdeWindow %x\n",0,hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: IsRunningInThisTask
//
// Synopsis: Determine if the given file is running in the current task
//
// Effects: Calls a special function in the ROT to determine if the
// file szFile is loaded as a moniker in the current task
//
// Arguments: [szFile] -- Filename
// [pf] -- Points to a BOOL. Returned TRUE if running
//
// History: 6-29-94 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
INTERNAL IsRunningInThisTask(LPOLESTR szFileIn,BOOL FAR* pf) // out parm
{
HRESULT hresult;
intrDebugOut((DEB_DDE_INIT,
"IsRunninginThisTask szFileIn=%ws\n",
WIDECHECK(szFileIn)));
//
// The RunningObjectTable always stores LONG filenames, therefore we
// need to convert this name to the long name for the lookup.
//
WCHAR szFile[MAX_PATH];
if ((lstrlenW(szFileIn) == 0) || (GetLongPathNameW(szFileIn,szFile,MAX_PATH) == 0))
{
//
// Unable to determine a long path for this object. Use whatever we were
// handed.
//
intrDebugOut((DEB_DDE_INIT,"No conversion to long path. Copy szFileIn\n"));
lstrcpyW(szFile,szFileIn);
}
intrDebugOut((DEB_DDE_INIT,"Long file szFile(%ws)\n",szFile));
hresult = GetLocalRunningObjectForDde(szFile,NULL);
*pf = (hresult == S_OK);
intrDebugOut((DEB_DDE_INIT,
"IsRunninginThisTask szFile=%ws returns %s\n",
WIDECHECK(szFile),
*pf?"TRUE":"FALSE"));
return NOERROR;
}