Source code of Windows XP (NT5)
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.

609 lines
18 KiB

  1. //#define DONT_USE_ATL
  2. #include "priv.h"
  3. #define ATL_ENABLED
  4. #include "atl.h"
  5. #include "sccls.h"
  6. #include <ntverp.h>
  7. #include <shlobj.h> // for CLSID_ACLMRU
  8. #include <schedule.h>
  9. #include "shbrows2.h" // CWinInetNotify_szWindowClass
  10. #include "desktop.h" // DESKTOPPROXYCLASS
  11. #include "mluisupp.h"
  12. #define DECL_CRTFREE
  13. #include <crtfree.h>
  14. #include "shfusion.h"
  15. STDAPI_(void) InitURLIDs(UINT uPlatform); // from shdocfl.cpp
  16. STDAPI SHIsThereASystemScheduler(void); // from schedule.cpp
  17. STDAPI SHFreeSystemScheduler(void);
  18. //
  19. // Downlevel delay load support (we forward to shlwapi)
  20. //
  21. #include <delayimp.h>
  22. PfnDliHook __pfnDliFailureHook;
  23. HANDLE BaseDllHandle;
  24. LONG g_cRefThisDll = 0; // per-instance
  25. CRITICAL_SECTION g_csDll = {0}; // per-instance
  26. HINSTANCE g_hinst = NULL;
  27. HANDLE g_hMutexHistory = NULL;
  28. BOOL g_fNashInNewProcess = FALSE; // Are we running in a separate process
  29. BOOL g_fRunningOnNT = FALSE;
  30. BOOL g_bRunOnNT5 = FALSE;
  31. BOOL g_fRunOnWhistler = FALSE;
  32. BOOL g_bRunOnMemphis = FALSE;
  33. BOOL g_fRunOnFE = FALSE;
  34. DWORD g_dwStopWatchMode = 0; // Shell perf automation
  35. HANDLE g_hCabStateChange = NULL;
  36. BOOL g_fIE = FALSE;
  37. // Is Mirroring enabled
  38. BOOL g_bMirroredOS = FALSE;
  39. HPALETTE g_hpalHalftone = NULL;
  40. void DestroyZoneIconNameCache(void);
  41. //
  42. // This array holds information needed for ClassFacory.
  43. // OLEMISC_ flags are used by shembed and shocx.
  44. //
  45. // PERF: this table should be ordered in most-to-least used order
  46. //
  47. CF_TABLE_BEGIN(g_ObjectInfo)
  48. CF_TABLE_ENTRY(&CLSID_InternetToolbar, CInternetToolbar_CreateInstance,
  49. COCREATEONLY),
  50. CF_TABLE_ENTRY(&CLSID_BrandBand, CBrandBand_CreateInstance,
  51. COCREATEONLY),
  52. CF_TABLE_ENTRY(&CLSID_MenuBandSite, CMenuBandSite_CreateInstance,
  53. COCREATEONLY),
  54. CF_TABLE_ENTRY(&CLSID_MenuDeskBar, CMenuDeskBar_CreateInstance,
  55. COCREATEONLY),
  56. CF_TABLE_ENTRY(&CLSID_AugmentedShellFolder, CAugmentedISF_CreateInstance,
  57. COCREATEONLY),
  58. CF_TABLE_ENTRY(&CLSID_AugmentedShellFolder2, CAugmentedISF2_CreateInstance,
  59. COCREATEONLY),
  60. CF_TABLE_ENTRY(&CLSID_AddressBand, CAddressBand_CreateInstance,
  61. COCREATEONLY),
  62. CF_TABLE_ENTRY(&CLSID_AddressEditBox, CAddressEditBox_CreateInstance,
  63. COCREATEONLY),
  64. CF_TABLE_ENTRY(&CLSID_BandProxy, CBandProxy_CreateInstance,
  65. COCREATEONLY),
  66. CF_TABLE_ENTRY_NOFLAGS( &CLSID_RebarBandSite, CBandSite_CreateInstance,
  67. COCREATEONLY_NOFLAGS, OIF_ALLOWAGGREGATION),
  68. CF_TABLE_ENTRY(&CLSID_DeskBarApp, CDeskBarApp_CreateInstance,
  69. COCREATEONLY),
  70. CF_TABLE_ENTRY(&CLSID_DeskBar, CDeskBar_CreateInstance,
  71. COCREATEONLY),
  72. CF_TABLE_ENTRY(&CLSID_AutoComplete, CAutoComplete_CreateInstance,
  73. COCREATEONLY),
  74. CF_TABLE_ENTRY(&CLSID_ACLHistory, CACLHistory_CreateInstance,
  75. COCREATEONLY),
  76. CF_TABLE_ENTRY(&CLSID_ACListISF, CACLIShellFolder_CreateInstance,
  77. COCREATEONLY),
  78. CF_TABLE_ENTRY(&CLSID_ACLMRU, CACLMRU_CreateInstance,
  79. COCREATEONLY),
  80. CF_TABLE_ENTRY(&CLSID_ACLMulti, CACLMulti_CreateInstance,
  81. COCREATEONLY),
  82. CF_TABLE_ENTRY_NOFLAGS( &CLSID_CCommonBrowser, CCommonBrowser_CreateInstance,
  83. COCREATEONLY_NOFLAGS, OIF_ALLOWAGGREGATION),
  84. CF_TABLE_ENTRY(&CLSID_CDockingBarPropertyBag, CDockingBarPropertyBag_CreateInstance,
  85. COCREATEONLY),
  86. CF_TABLE_ENTRY(&CLSID_CRegTreeOptions, CRegTreeOptions_CreateInstance,
  87. COCREATEONLY),
  88. CF_TABLE_ENTRY(&CLSID_BrowserBand, CBrowserBand_CreateInstance,
  89. COCREATEONLY),
  90. CF_TABLE_ENTRY(&CLSID_SearchBand, CSearchBand_CreateInstance,
  91. COCREATEONLY),
  92. CF_TABLE_ENTRY(&CLSID_MediaBand, CMediaBand_CreateInstance,
  93. COCREATEONLY),
  94. CF_TABLE_ENTRY(&CLSID_CommBand, CCommBand_CreateInstance,
  95. COCREATEONLY),
  96. CF_TABLE_ENTRY(&CLSID_BandSiteMenu, CBandSiteMenu_CreateInstance,
  97. COCREATEONLY),
  98. CF_TABLE_ENTRY(&CLSID_ComCatCacheTask, CComCatCacheTask_CreateInstance,
  99. COCREATEONLY),
  100. CF_TABLE_ENTRY(&CLSID_ComCatConditionalCacheTask,CComCatConditionalCacheTask_CreateInstance,
  101. COCREATEONLY),
  102. CF_TABLE_ENTRY(&CLSID_ImgCtxThumbnailExtractor, CImgCtxThumb_CreateInstance,
  103. COCREATEONLY),
  104. CF_TABLE_ENTRY(&CLSID_ImageListCache, CImageListCache_CreateInstance,
  105. COCREATEONLY),
  106. CF_TABLE_ENTRY(&CLSID_ShellTaskScheduler, CShellTaskScheduler_CreateInstance,
  107. COCREATEONLY),
  108. CF_TABLE_ENTRY(&CLSID_SharedTaskScheduler, CSharedTaskScheduler_CreateInstance,
  109. COCREATEONLY),
  110. CF_TABLE_ENTRY(&CLSID_BrowseuiPreloader, CBitmapPreload_CreateInstance,
  111. COCREATEONLY),
  112. CF_TABLE_ENTRY(&CLSID_ShellSearchExt, CShellSearchExt_CreateInstance,
  113. COCREATEONLY),
  114. CF_TABLE_ENTRY(&CLSID_WebSearchExt, CWebSearchExt_CreateInstance,
  115. COCREATEONLY),
  116. CF_TABLE_ENTRY(&CLSID_OrderListExport, COrderList_CreateInstance,
  117. COCREATEONLY),
  118. CF_TABLE_ENTRY(&CLSID_UserAssist, CUserAssist_CreateInstance,
  119. COCREATEONLY),
  120. CF_TABLE_ENTRY(&CLSID_GlobalFolderSettings, CGlobalFolderSettings_CreateInstance,
  121. COCREATEONLY),
  122. CF_TABLE_ENTRY(&CLSID_ProgressDialog, CProgressDialog_CreateInstance,
  123. COCREATEONLY),
  124. CF_TABLE_ENTRY(&CLSID_ACLCustomMRU, CACLCustomMRU_CreateInstance,
  125. COCREATEONLY),
  126. CF_TABLE_ENTRY(&CLSID_AddressBarParser, CShellUrl_CreateInstance,
  127. COCREATEONLY),
  128. CF_TABLE_ENTRY_NOFLAGS( &CLSID_MenuBand, CMenuBand_CreateInstance,
  129. COCREATEONLY_NOFLAGS, OIF_DONTIECREATE), // legacy component, dont default to browseui's impl
  130. CF_TABLE_ENTRY_NOFLAGS( &CLSID_QuickLinks, CQuickLinks_CreateInstance,
  131. COCREATEONLY_NOFLAGS, OIF_DONTIECREATE), // legacy component, dont default to browseui's impl
  132. CF_TABLE_ENTRY_NOFLAGS( &CLSID_ISFBand, CISFBand_CreateInstance,
  133. COCREATEONLY_NOFLAGS, OIF_DONTIECREATE), // legacy component, dont default to browseui's impl
  134. CF_TABLE_ENTRY_NOFLAGS( &CLSID_Thumbnail, CThumbnail_CreateInstance,
  135. COCREATEONLY_NOFLAGS, OIF_DONTIECREATE), // legacy component, dont default to browseui's impl
  136. CF_TABLE_ENTRY_NOFLAGS(&CLSID_TrackShellMenu, CTrackShellMenu_CreateInstance,
  137. COCREATEONLY_NOFLAGS, OIF_DONTIECREATE), // legacy component, dont default to browseui's impl
  138. CF_TABLE_END(g_ObjectInfo)
  139. // constructor for CObjectInfo.
  140. CObjectInfo::CObjectInfo(CLSID const* pclsidin, LPFNCREATEOBJINSTANCE pfnCreatein, IID const* piidIn,
  141. IID const* piidEventsIn, long lVersionIn, DWORD dwOleMiscFlagsIn,
  142. DWORD dwClassFactFlagsIn)
  143. {
  144. pclsid = pclsidin;
  145. pfnCreateInstance = pfnCreatein;
  146. piid = piidIn;
  147. piidEvents = piidEventsIn;
  148. lVersion = lVersionIn;
  149. dwOleMiscFlags = dwOleMiscFlagsIn;
  150. dwClassFactFlags = dwClassFactFlagsIn;
  151. }
  152. // static class factory (no allocs!)
  153. STDMETHODIMP CClassFactory::QueryInterface(REFIID riid, void **ppvObj)
  154. {
  155. if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
  156. {
  157. *ppvObj = (void *)GET_ICLASSFACTORY(this);
  158. DllAddRef();
  159. return NOERROR;
  160. }
  161. *ppvObj = NULL;
  162. return E_NOINTERFACE;
  163. }
  164. STDMETHODIMP_(ULONG) CClassFactory::AddRef()
  165. {
  166. DllAddRef();
  167. return 2;
  168. }
  169. STDMETHODIMP_(ULONG) CClassFactory::Release()
  170. {
  171. DllRelease();
  172. return 1;
  173. }
  174. STDMETHODIMP CClassFactory::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  175. {
  176. *ppv = NULL;
  177. if (punkOuter && !IsEqualIID(riid, IID_IUnknown))
  178. {
  179. // It is technically illegal to aggregate an object and request
  180. // any interface other than IUnknown. Enforce this.
  181. //
  182. return CLASS_E_NOAGGREGATION;
  183. }
  184. else
  185. {
  186. LPOBJECTINFO pthisobj = (LPOBJECTINFO)this;
  187. if (punkOuter && !(pthisobj->dwClassFactFlags & OIF_ALLOWAGGREGATION))
  188. return CLASS_E_NOAGGREGATION;
  189. IUnknown *punk;
  190. HRESULT hres = pthisobj->pfnCreateInstance(punkOuter, &punk, pthisobj);
  191. if (SUCCEEDED(hres))
  192. {
  193. hres = punk->QueryInterface(riid, ppv);
  194. punk->Release();
  195. }
  196. ASSERT(FAILED(hres) ? *ppv == NULL : TRUE);
  197. return hres;
  198. }
  199. }
  200. STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
  201. {
  202. if (fLock)
  203. DllAddRef();
  204. else
  205. DllRelease();
  206. TraceMsg(DM_TRACE, "sccls: LockServer(%s) to %d", fLock ? TEXT("LOCK") : TEXT("UNLOCK"), g_cRefThisDll);
  207. return S_OK;
  208. }
  209. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
  210. {
  211. TraceMsg(TF_SHDLIFE, "DllGetClassObject called with riid=%x (%x)", riid, &riid);
  212. if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
  213. {
  214. for (LPCOBJECTINFO pcls = g_ObjectInfo; pcls->pclsid; pcls++)
  215. {
  216. if (IsEqualGUID(rclsid, *(pcls->pclsid)))
  217. {
  218. *ppv = (void*)pcls;
  219. DllAddRef(); // class factory holds DLL ref count
  220. return NOERROR;
  221. }
  222. }
  223. #ifdef ATL_ENABLED
  224. // Try the ATL class factory
  225. if (SUCCEEDED(AtlGetClassObject(rclsid, riid, ppv)))
  226. return NOERROR;
  227. #endif
  228. }
  229. *ppv = NULL;
  230. return CLASS_E_CLASSNOTAVAILABLE;
  231. }
  232. STDAPI DllCanUnloadNow(void)
  233. {
  234. #ifndef UNIX
  235. // special case for the system scheduler we hang onto
  236. if ( g_cRefThisDll == 1 && SHIsThereASystemScheduler() == S_OK )
  237. {
  238. // this will drop the ref count by one to zero....
  239. SHFreeSystemScheduler();
  240. }
  241. #ifdef ATL_ENABLED
  242. if (0 != g_cRefThisDll || 0 != AtlGetLockCount())
  243. return S_FALSE;
  244. #else
  245. if (0 != g_cRefThisDll)
  246. return S_FALSE;
  247. #endif
  248. #else
  249. if (g_cRefThisDll)
  250. return S_FALSE;
  251. #endif
  252. TraceMsg(DM_TRACE, "DllCanUnloadNow returning S_OK (bye, bye...)");
  253. return S_OK;
  254. }
  255. // DllGetVersion
  256. //
  257. // All we have to do is declare this puppy and CCDllGetVersion does the rest
  258. //
  259. DLLVER_SINGLEBINARY(VER_PRODUCTVERSION_DW, VER_PRODUCTBUILD_QFE);
  260. UINT g_msgMSWheel;
  261. #ifdef DEBUG
  262. EXTERN_C DWORD g_TlsMem = 0xffffffff;
  263. #endif
  264. // imports from isfband.cpp
  265. STDAPI_(void) CLogoBase_Initialize( void );
  266. STDAPI_(void) CLogoBase_Cleanup( void );
  267. //
  268. // Table of all window classes we register so we can unregister them
  269. // at DLL unload.
  270. //
  271. const LPCTSTR c_rgszClasses[] = {
  272. TEXT("BaseBar"), // basebar.cpp
  273. TEXT("MenuSite"), // menusite.cpp
  274. DESKTOPPROXYCLASS, // proxy.cpp
  275. c_szExploreClass, // shbrows2.cpp
  276. c_szIExploreClass, // shbrows2.cpp
  277. c_szCabinetClass, // shbrows2.cpp
  278. c_szAutoSuggestClass, // autocomp.cpp
  279. TEXT("MediaPane"), //Mediaband.cpp
  280. TEXT("MediaPopupPane"), //Mediaband.cpp
  281. TEXT("MediaLayoutPane") //Mediaband.cpp
  282. };
  283. //
  284. // Since we are single-binary, we have to play it safe and do
  285. // this cleanup (needed only on NT, but harmless on Win95).
  286. //
  287. #define UnregisterWindowClasses() \
  288. SHUnregisterClasses(HINST_THISDLL, c_rgszClasses, ARRAYSIZE(c_rgszClasses))
  289. void InitNFCtl()
  290. {
  291. INITCOMMONCONTROLSEX icc;
  292. icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
  293. icc.dwICC = ICC_NATIVEFNTCTL_CLASS;
  294. InitCommonControlsEx(&icc);
  295. }
  296. const LPCTSTR s_aryExplorerFileName[] =
  297. {
  298. TEXT("iexplore.exe"),
  299. };
  300. BOOL IsRootExeExplorer(void)
  301. {
  302. TCHAR szApp[MAX_PATH];
  303. LPCTSTR pszApp;
  304. GetModuleFileName(NULL, szApp, ARRAYSIZE(szApp));
  305. pszApp = PathFindFileName(szApp);
  306. if (pszApp)
  307. {
  308. for (int i = 0; i < ARRAYSIZE(s_aryExplorerFileName); i++)
  309. {
  310. if (!lstrcmpi(pszApp, s_aryExplorerFileName[i]))
  311. return TRUE;
  312. }
  313. }
  314. return FALSE;
  315. }
  316. //
  317. // we use shlwapi as our delayload error handler.
  318. // NOTE: this only works if we are statically linked to shlwapi!
  319. //
  320. void SetupDelayloadErrorHandler()
  321. {
  322. BaseDllHandle = GetModuleHandleA("shlwapi.dll");
  323. ASSERTMSG(BaseDllHandle != NULL, "BROWSEUI must be statically linked to shlwapi.dll for delayload failure handling to work!");
  324. __pfnDliFailureHook = (PfnDliHook)GetProcAddress((HMODULE)BaseDllHandle, "DelayLoadFailureHook");
  325. }
  326. STDAPI_(BOOL) DllMain(HINSTANCE hDll, DWORD dwReason, void *fProcessUnload)
  327. {
  328. if (dwReason == DLL_PROCESS_ATTACH)
  329. {
  330. SHFusionInitializeFromModule(hDll);
  331. SetupDelayloadErrorHandler();
  332. #ifdef ATL_ENABLED
  333. AtlInit(hDll);
  334. #endif
  335. DisableThreadLibraryCalls(hDll); // perf
  336. g_hinst = hDll;
  337. InitializeCriticalSection(&g_csDll);
  338. g_msgMSWheel = RegisterWindowMessage(TEXT("MSWHEEL_ROLLMSG"));
  339. MLLoadResources(g_hinst, TEXT("browselc.dll"));
  340. g_fIE = IsRootExeExplorer();
  341. if (g_fIE)
  342. InitMUILanguage(MLGetUILanguage());
  343. // Don't put it under #ifdef DEBUG
  344. CcshellGetDebugFlags();
  345. #ifdef DEBUG
  346. g_TlsMem = TlsAlloc();
  347. if (IsFlagSet(g_dwBreakFlags, BF_ONLOADED))
  348. {
  349. TraceMsg(TF_ALWAYS, "DllMain() - SHDOCVW.DLL has just loaded");
  350. DEBUG_BREAK;
  351. }
  352. #endif
  353. g_fRunningOnNT = IsOS(OS_NT);
  354. if (g_fRunningOnNT)
  355. {
  356. g_bRunOnNT5 = IsOS(OS_WIN2000ORGREATER);
  357. g_fRunOnWhistler = IsOS(OS_WHISTLERORGREATER);
  358. }
  359. else
  360. g_bRunOnMemphis = IsOS(OS_WIN98ORGREATER);
  361. g_fRunOnFE = GetSystemMetrics(SM_DBCSENABLED);
  362. g_bMirroredOS = IS_MIRRORING_ENABLED();
  363. InitNFCtl();
  364. // See if perfmode is enabled
  365. g_dwStopWatchMode = StopWatchMode();
  366. // Cache a palette handle for use throughout shdocvw
  367. g_hpalHalftone = SHCreateShellPalette( NULL );
  368. CLogoBase_Initialize( );
  369. }
  370. else if (dwReason == DLL_PROCESS_DETACH)
  371. {
  372. #ifdef ATL_ENABLED
  373. AtlTerm();
  374. #endif
  375. CBrandBand_CleanUp();
  376. CInternetToolbar_CleanUp();
  377. CUserAssist_CleanUp(dwReason, fProcessUnload);
  378. CLogoBase_Cleanup();
  379. // let go of the resource DLL...
  380. MLFreeResources(g_hinst);
  381. ENTERCRITICAL;
  382. DESTROY_OBJ_WITH_HANDLE(g_hpalHalftone, DeletePalette);
  383. DESTROY_OBJ_WITH_HANDLE(g_hCabStateChange, SHGlobalCounterDestroy);
  384. DESTROY_OBJ_WITH_HANDLE(g_hMutexHistory, CloseHandle);
  385. DestroyZoneIconNameCache();
  386. UnregisterWindowClasses();
  387. LEAVECRITICAL;
  388. DeleteCriticalSection(&g_csDll);
  389. SHFusionUninitialize();
  390. }
  391. return TRUE;
  392. }
  393. STDAPI_(void) DllAddRef(void)
  394. {
  395. InterlockedIncrement(&g_cRefThisDll);
  396. }
  397. STDAPI_(void) DllRelease(void)
  398. {
  399. InterlockedDecrement(&g_cRefThisDll);
  400. ASSERT(g_cRefThisDll >= 0); // don't underflow
  401. }
  402. // IEUNIX
  403. // CoCreateInstance is #defined as IECreateInstance #ifdef __cplusplus,
  404. // so I #undef it here to prevent the recursive call.
  405. // On Windows it works, because this file is C file.
  406. #ifdef CoCreateInstance
  407. #undef CoCreateInstance
  408. #endif
  409. HRESULT IECreateInstance(REFCLSID rclsid, IUnknown *pUnkOuter,
  410. DWORD dwClsContext, REFIID riid, void **ppv)
  411. {
  412. #ifndef NO_MARSHALLING
  413. if (dwClsContext == CLSCTX_INPROC_SERVER)
  414. #else
  415. if (dwClsContext & CLSCTX_INPROC_SERVER)
  416. #endif
  417. {
  418. LPCOBJECTINFO pcls;
  419. for (pcls = g_ObjectInfo; pcls->pclsid; pcls++)
  420. {
  421. // Note that we do pointer comparison (instead of IsEuqalGUID)
  422. if ((&rclsid == pcls->pclsid) && !(pcls->dwClassFactFlags & OIF_DONTIECREATE))
  423. {
  424. // const -> non-const expclit casting (this is OK)
  425. IClassFactory* pcf = GET_ICLASSFACTORY(pcls);
  426. return pcf->CreateInstance(pUnkOuter, riid, ppv);
  427. }
  428. }
  429. }
  430. // Use SHCoCreateInstanceAC to go through the app compat layer
  431. return SHCoCreateInstanceAC(rclsid, pUnkOuter, dwClsContext, riid, ppv);
  432. }
  433. #ifdef DEBUG
  434. //
  435. // In DEBUG, make sure every class we register lives in the c_rgszClasses
  436. // table so we can clean up properly at DLL unload. NT does not automatically
  437. // unregister classes when a DLL unloads, so we have to do it manually.
  438. //
  439. STDAPI_(BOOL) SHRegisterClassD(CONST WNDCLASS *pwc)
  440. {
  441. for (int i = 0; i < ARRAYSIZE(c_rgszClasses); i++)
  442. {
  443. if (lstrcmpi(c_rgszClasses[i], pwc->lpszClassName) == 0)
  444. {
  445. return RealSHRegisterClass(pwc);
  446. }
  447. }
  448. AssertMsg(0, TEXT("Class %s needs to be added to the c_rgszClasses list"), pwc->lpszClassName);
  449. return 0;
  450. }
  451. STDAPI_(ATOM) RegisterClassD(CONST WNDCLASS *pwc)
  452. {
  453. for (int i = 0; i < ARRAYSIZE(c_rgszClasses); i++)
  454. {
  455. if (lstrcmpi(c_rgszClasses[i], pwc->lpszClassName) == 0)
  456. {
  457. return RealRegisterClass(pwc);
  458. }
  459. }
  460. AssertMsg(0, TEXT("Class %s needs to be added to the c_rgszClasses list"), pwc->lpszClassName);
  461. return 0;
  462. }
  463. //
  464. // In DEBUG, send FindWindow through a wrapper that ensures that the
  465. // critical section is not taken. FindWindow'ing for a window title
  466. // sends inter-thread WM_GETTEXT messages, which is not obvious.
  467. //
  468. STDAPI_(HWND) FindWindowD(LPCTSTR lpClassName, LPCTSTR lpWindowName)
  469. {
  470. return FindWindowExD(NULL, NULL, lpClassName, lpWindowName);
  471. }
  472. STDAPI_(HWND) FindWindowExD(HWND hwndParent, HWND hwndChildAfter, LPCTSTR lpClassName, LPCTSTR lpWindowName)
  473. {
  474. if (lpWindowName)
  475. {
  476. ASSERTNONCRITICAL;
  477. }
  478. return RealFindWindowEx(hwndParent, hwndChildAfter, lpClassName, lpWindowName);
  479. }
  480. #endif // DEBUG