Leaked source code of windows server 2003
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.

603 lines
19 KiB

  1. /***************************************************************************
  2. * msctls.c
  3. *
  4. * Utils library initialization code
  5. *
  6. ***************************************************************************/
  7. #include "ctlspriv.h"
  8. HINSTANCE g_hinst = 0;
  9. CRITICAL_SECTION g_csDll = {{0},0, 0, NULL, NULL, 0 };
  10. ATOM g_aCC32Subclass = 0;
  11. BOOL g_bRunOnNT5 = FALSE;
  12. BOOL g_bRemoteSession = FALSE;
  13. UINT g_uiACP = CP_ACP;
  14. // Is Mirroring enabled
  15. BOOL g_bMirroredOS = FALSE;
  16. #define PAGER //For Test Purposes
  17. //
  18. // Global DCs used during mirroring an Icon.
  19. //
  20. HDC g_hdc=NULL, g_hdcMask=NULL;
  21. // per process mem to store PlugUI information
  22. LANGID g_PUILangId = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
  23. BOOL PASCAL InitAnimateClass(HINSTANCE hInstance);
  24. BOOL ListView_Init(HINSTANCE hinst);
  25. BOOL TV_Init(HINSTANCE hinst);
  26. BOOL InitComboExClass(HINSTANCE hinst);
  27. BOOL PASCAL Header_Init(HINSTANCE hinst);
  28. BOOL PASCAL Tab_Init(HINSTANCE hinst);
  29. int InitIPAddr(HANDLE hInstance);
  30. #ifdef PAGER
  31. BOOL InitPager(HINSTANCE hinst);
  32. #endif
  33. BOOL InitNativeFontCtl(HINSTANCE hinst);
  34. void UnregisterClasses();
  35. #define DECLARE_DELAYED_FUNC(_ret, _fn, _args, _nargs) \
  36. _ret (__stdcall * g_pfn##_fn) _args = NULL; \
  37. _ret __stdcall _fn _args \
  38. { \
  39. if (!g_pfn##_fn) { \
  40. AssertMsg(g_pfn##_fn != NULL, TEXT("GetProcAddress failed")); \
  41. return 0; \
  42. } \
  43. return g_pfn##_fn _nargs; \
  44. }
  45. #define LOAD_DELAYED_FUNC(_ret, _fn, _args) \
  46. (*(FARPROC*)&(g_pfn##_fn) = GetProcAddress(hinst, #_fn))
  47. DECLARE_DELAYED_FUNC(BOOL, ImmNotifyIME, (HIMC himc, DWORD dw1, DWORD dw2, DWORD dw3), (himc, dw1, dw2, dw3));
  48. DECLARE_DELAYED_FUNC(HIMC, ImmAssociateContext, (HWND hwnd, HIMC himc), (hwnd, himc));
  49. DECLARE_DELAYED_FUNC(BOOL, ImmReleaseContext, (HWND hwnd, HIMC himc), (hwnd, himc));
  50. DECLARE_DELAYED_FUNC(HIMC, ImmGetContext, (HWND hwnd), (hwnd));
  51. DECLARE_DELAYED_FUNC(LONG, ImmGetCompositionStringA, (HIMC himc, DWORD dw1, LPVOID p1, DWORD dw2), (himc, dw1, p1, dw2) );
  52. DECLARE_DELAYED_FUNC(BOOL, ImmSetCompositionStringA, (HIMC himc, DWORD dw1, LPCVOID p1, DWORD dw2, LPCVOID p2, DWORD dw3), (himc, dw1, p1, dw2, p2, dw3));
  53. DECLARE_DELAYED_FUNC(LONG, ImmGetCompositionStringW, (HIMC himc, DWORD dw1, LPVOID p1, DWORD dw2), (himc, dw1, p1, dw2) );
  54. DECLARE_DELAYED_FUNC(BOOL, ImmSetCompositionStringW, (HIMC himc, DWORD dw1, LPCVOID p1, DWORD dw2, LPCVOID p2, DWORD dw3), (himc, dw1, p1, dw2, p2, dw3));
  55. DECLARE_DELAYED_FUNC(BOOL, ImmSetCandidateWindow, (HIMC himc, LPCANDIDATEFORM pcf), (himc, pcf));
  56. DECLARE_DELAYED_FUNC(HIMC, ImmCreateContext, (void), ());
  57. DECLARE_DELAYED_FUNC(BOOL, ImmDestroyContext, (HIMC himc), (himc));
  58. BOOL g_fDBCSEnabled = FALSE;
  59. BOOL g_fMEEnabled = FALSE;
  60. BOOL g_fDBCSInputEnabled = FALSE;
  61. #ifdef FONT_LINK
  62. BOOL g_bComplexPlatform = FALSE;
  63. #endif
  64. #if defined(FE_IME)
  65. void InitIme()
  66. {
  67. g_fMEEnabled = GetSystemMetrics(SM_MIDEASTENABLED);
  68. g_fDBCSEnabled = g_fDBCSInputEnabled = GetSystemMetrics(SM_DBCSENABLED);
  69. if (!g_fDBCSInputEnabled && g_bRunOnNT5)
  70. g_fDBCSInputEnabled = GetSystemMetrics(SM_IMMENABLED);
  71. // We load imm32.dll per process, but initialize proc pointers just once.
  72. // this is to solve two different problems.
  73. // 1) Debugging process on win95 would get our shared table trashed
  74. // if we rewrite proc address each time we get loaded.
  75. // 2) Some lotus application rely upon us to load imm32. They do not
  76. // load/link to imm yet they use imm(!)
  77. //
  78. if (g_fDBCSInputEnabled) {
  79. HANDLE hinst = LoadLibrary(TEXT("imm32.dll"));
  80. if (! g_pfnImmSetCandidateWindow &&
  81. (! hinst ||
  82. ! LOAD_DELAYED_FUNC(HIMC, ImmCreateContext, (void)) ||
  83. ! LOAD_DELAYED_FUNC(HIMC, ImmDestroyContext, (HIMC)) ||
  84. ! LOAD_DELAYED_FUNC(BOOL, ImmNotifyIME, (HIMC, DWORD, DWORD, DWORD)) ||
  85. ! LOAD_DELAYED_FUNC(HIMC, ImmAssociateContext, (HWND, HIMC)) ||
  86. ! LOAD_DELAYED_FUNC(BOOL, ImmReleaseContext, (HWND, HIMC)) ||
  87. ! LOAD_DELAYED_FUNC(HIMC, ImmGetContext, (HWND)) ||
  88. ! LOAD_DELAYED_FUNC(LONG, ImmGetCompositionStringA, (HIMC, DWORD, LPVOID, DWORD)) ||
  89. ! LOAD_DELAYED_FUNC(BOOL, ImmSetCompositionStringA, (HIMC, DWORD, LPCVOID, DWORD, LPCVOID, DWORD)) ||
  90. ! LOAD_DELAYED_FUNC(LONG, ImmGetCompositionStringW, (HIMC, DWORD, LPVOID, DWORD)) ||
  91. ! LOAD_DELAYED_FUNC(BOOL, ImmSetCompositionStringW, (HIMC, DWORD, LPCVOID, DWORD, LPCVOID, DWORD)) ||
  92. ! LOAD_DELAYED_FUNC(BOOL, ImmSetCandidateWindow, (HIMC, LPCANDIDATEFORM)))) {
  93. // if we were unable to load then bail on using IME.
  94. g_fDBCSEnabled = FALSE;
  95. g_fDBCSInputEnabled = FALSE;
  96. }
  97. }
  98. }
  99. #else
  100. #define InitIme() 0
  101. #endif
  102. #ifdef DEBUG
  103. // Verify that the localizers didn't accidentally change
  104. // DLG_PROPSHEET from a DIALOG to a DIALOGEX. _RealPropertySheet
  105. // relies on this (as well as any apps which parse the dialog template
  106. // in their PSCB_PRECREATE handler).
  107. BOOL IsSimpleDialog(LPCTSTR ptszDialog)
  108. {
  109. HRSRC hrsrc;
  110. LPDLGTEMPLATE pdlg;
  111. BOOL fSimple = FALSE;
  112. if ( (hrsrc = FindResource(HINST_THISDLL, ptszDialog, RT_DIALOG)) &&
  113. (pdlg = LoadResource(HINST_THISDLL, hrsrc)))
  114. {
  115. fSimple = HIWORD(pdlg->style) != 0xFFFF;
  116. }
  117. return fSimple;
  118. }
  119. //
  120. // For sublanguages to work, every language in our resources must contain
  121. // a SUBLANG_NEUTRAL variation so that (for example) Austria gets
  122. // German dialog boxes instead of English ones.
  123. //
  124. // The DPA is really a DSA of WORDs, but DPA's are easier to deal with.
  125. // We just collect all the languages into the DPA, and study them afterwards.
  126. //
  127. BOOL CALLBACK CheckLangProc(HINSTANCE hinst, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIdLang, LPARAM lparam)
  128. {
  129. HDPA hdpa = (HDPA)lparam;
  130. DPA_AppendPtr(hdpa, (LPVOID)(UINT_PTR)wIdLang);
  131. return TRUE;
  132. }
  133. void CheckResourceLanguages(void)
  134. {
  135. HDPA hdpa = DPA_Create(8);
  136. if (hdpa) {
  137. int i, j;
  138. EnumResourceLanguages(HINST_THISDLL, RT_DIALOG,
  139. MAKEINTRESOURCE(DLG_PROPSHEET), CheckLangProc,
  140. (LPARAM)hdpa);
  141. // Walk the language list. For each language we find, make sure
  142. // there is a SUBLANG_NEUTRAL version of it somewhere else
  143. // in the list. We use an O(n^2) algorithm because this is debug
  144. // only code and happens only at DLL load.
  145. for (i = 0; i < DPA_GetPtrCount(hdpa); i++) {
  146. UINT_PTR uLangI = (UINT_PTR)DPA_FastGetPtr(hdpa, i);
  147. BOOL fFound = FALSE;
  148. //
  149. // It is okay to have English (American) with no
  150. // English (Neutral) because Kernel32 uses English (American)
  151. // as its fallback, so we fall back to the correct language
  152. // after all.
  153. //
  154. if (uLangI == MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US))
  155. continue;
  156. //
  157. // If this language is already the Neutral one, then there's
  158. // no point looking for it - here it is!
  159. //
  160. if (SUBLANGID(uLangI) == SUBLANG_NEUTRAL)
  161. continue;
  162. //
  163. // Otherwise, this language is a dialect. See if there is
  164. // a Neutral version elsewhere in the table.
  165. //
  166. for (j = 0; j < DPA_GetPtrCount(hdpa); j++) {
  167. UINT_PTR uLangJ = (UINT_PTR)DPA_FastGetPtr(hdpa, j);
  168. if (PRIMARYLANGID(uLangI) == PRIMARYLANGID(uLangJ) &&
  169. SUBLANGID(uLangJ) == SUBLANG_NEUTRAL) {
  170. fFound = TRUE; break;
  171. }
  172. }
  173. //
  174. // If this assertion fires, it means that the localization team
  175. // added support for a new language but chose to specify the
  176. // language as a dialect instead of the Neutral version. E.g.,
  177. // specifying Romanian (Romanian) instead of Romanian (Neutral).
  178. // This means that people who live in Moldavia will see English
  179. // strings, even though Romanian (Romanian) would almost
  180. // certainly have been acceptable.
  181. //
  182. // If you want to support multiple dialects of a language
  183. // (e.g., Chinese), you should nominate one of the dialects
  184. // as the Neutral one. For example, we currently support
  185. // both Chinese (PRC) and Chinese (Taiwan), but the Taiwanese
  186. // version is marked as Chinese (Neutral), so people who live in
  187. // Singapore get Chinese instead of English. Sure, it's
  188. // Taiwanese Chinese, but at least it's Chinese.
  189. //
  190. AssertMsg(fFound, TEXT("Localization bug: No SUBLANG_NEUTRAL for language %04x"), uLangI);
  191. }
  192. DPA_Destroy(hdpa);
  193. }
  194. }
  195. #endif
  196. BOOL IsRunningIn16BitProcess()
  197. {
  198. NTSTATUS status;
  199. ULONG ulVDMFlags = 0;
  200. status = NtQueryInformationProcess(GetCurrentProcess(), ProcessWx86Information, &ulVDMFlags, sizeof(ulVDMFlags), NULL);
  201. return (NT_SUCCESS(status) && (ulVDMFlags != 0));
  202. }
  203. int _ProcessAttach(HANDLE hInstance)
  204. {
  205. g_hinst = hInstance;
  206. g_uiACP = GetACP();
  207. #ifdef DEBUG
  208. CcshellGetDebugFlags();
  209. g_dwBreakFlags = 0; // We do not want to break in comctl32 version 5 at ALL. Too many bad callers.
  210. #endif
  211. InitializeCriticalSection(&g_csDll);
  212. g_bRunOnNT5 = staticIsOS(OS_WIN2000ORGREATER);
  213. #ifdef FONT_LINK
  214. g_bComplexPlatform = BOOLFROMPTR(GetModuleHandle(TEXT("LPK.DLL")));
  215. #endif
  216. //
  217. // Check if the mirroring APIs exist on the current
  218. // platform.
  219. //
  220. g_bMirroredOS = IS_MIRRORING_ENABLED();
  221. //
  222. // Must detect Terminal Server before initializing global metrics
  223. // because we need to force some features off if running Terminal Server.
  224. //
  225. {
  226. typedef BOOL (__stdcall * PFNPROCESSIDTOSESSIONID)(DWORD, PDWORD);
  227. PFNPROCESSIDTOSESSIONID ProcessIdToSessionId =
  228. (PFNPROCESSIDTOSESSIONID)
  229. GetProcAddress(GetModuleHandle(TEXT("KERNEL32")),
  230. "ProcessIdToSessionId");
  231. DWORD dwSessionId;
  232. g_bRemoteSession = ProcessIdToSessionId &&
  233. ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId) &&
  234. dwSessionId != 0;
  235. }
  236. InitGlobalMetrics(0);
  237. InitGlobalColors();
  238. InitIme();
  239. #ifdef DEBUG
  240. ASSERT(IsSimpleDialog(MAKEINTRESOURCE(DLG_WIZARD)));
  241. ASSERT(IsSimpleDialog(MAKEINTRESOURCE(DLG_PROPSHEET)));
  242. CheckResourceLanguages();
  243. #endif
  244. if (IsRunningIn16BitProcess())
  245. {
  246. // This is a 16bit process. We need to artificially init the common controls
  247. INITCOMMONCONTROLSEX icce;
  248. icce.dwSize = sizeof(icce);
  249. icce.dwICC = ICC_WIN95_CLASSES;
  250. InitCommonControlsEx(&icce);
  251. }
  252. return TRUE;
  253. }
  254. void _ProcessDetach(HANDLE hInstance)
  255. {
  256. //
  257. // Cleanup cached DCs. No need to synchronize the following section of
  258. // code since it is only called in DLL_PROCESS_DETACH which is
  259. // synchronized by the OS Loader.
  260. //
  261. if (g_hdc)
  262. DeleteDC(g_hdc);
  263. if (g_hdcMask)
  264. DeleteDC(g_hdcMask);
  265. g_hdc = g_hdcMask = NULL;
  266. UnregisterClasses();
  267. DeleteCriticalSection(&g_csDll);
  268. }
  269. // DllEntryPoint
  270. STDAPI_(BOOL) DllMain(HANDLE hDll, DWORD dwReason, LPVOID pvReserverd)
  271. {
  272. switch(dwReason)
  273. {
  274. case DLL_PROCESS_ATTACH:
  275. DisableThreadLibraryCalls(hDll);
  276. return _ProcessAttach(hDll);
  277. case DLL_PROCESS_DETACH:
  278. _ProcessDetach(hDll);
  279. break;
  280. case DLL_THREAD_ATTACH:
  281. case DLL_THREAD_DETACH:
  282. default:
  283. break;
  284. }
  285. return TRUE;
  286. }
  287. /* Stub function to call if all you want to do is make sure this DLL is loaded
  288. */
  289. void WINAPI InitCommonControls(void)
  290. {
  291. }
  292. STDAPI_(void) FixupSubclassRecordsAfterLogoff();
  293. BOOL InitForWinlogon(HINSTANCE hInstance)
  294. {
  295. // Some people like to use comctl32 from inside winlogon, and
  296. // for C2 security reasons, all global atoms are nuked from the
  297. // window station when you log off.
  298. //
  299. // So the rule is that all winlogon clients of comctl32 must
  300. // call InitCommonControlsEx(ICC_WINLOGON_REINIT) immediately
  301. // before doing any common control things (creating windows
  302. // or property sheets/wizards) from winlogon.
  303. FixupSubclassRecordsAfterLogoff();
  304. InitGlobalMetrics(0);
  305. InitGlobalColors();
  306. return TRUE;
  307. }
  308. /* InitCommonControlsEx creates the classes. Only those classes requested are created!
  309. ** The process attach figures out if it's an old app and supplies ICC_WIN95_CLASSES.
  310. */
  311. typedef BOOL (PASCAL *PFNINIT)(HINSTANCE);
  312. typedef struct {
  313. PFNINIT pfnInit;
  314. LPCTSTR pszName;
  315. DWORD dwClassSet;
  316. BOOL fRegistered;
  317. } INITCOMMONCONTROLSINFO;
  318. #define MAKEICC(pfnInit, pszClass, dwFlags) { pfnInit, pszClass, dwFlags, FALSE }
  319. INITCOMMONCONTROLSINFO icc[] =
  320. {
  321. // Init function Class name Requested class sets which use this class
  322. MAKEICC(InitToolbarClass, TOOLBARCLASSNAME, ICC_BAR_CLASSES),
  323. MAKEICC(InitReBarClass, REBARCLASSNAME, ICC_COOL_CLASSES),
  324. MAKEICC(InitToolTipsClass, TOOLTIPS_CLASS, ICC_TREEVIEW_CLASSES|ICC_BAR_CLASSES|ICC_TAB_CLASSES),
  325. MAKEICC(InitStatusClass, STATUSCLASSNAME, ICC_BAR_CLASSES),
  326. MAKEICC(ListView_Init, WC_LISTVIEW, ICC_LISTVIEW_CLASSES),
  327. MAKEICC(Header_Init, WC_HEADER, ICC_LISTVIEW_CLASSES),
  328. MAKEICC(Tab_Init, WC_TABCONTROL, ICC_TAB_CLASSES),
  329. MAKEICC(TV_Init, WC_TREEVIEW, ICC_TREEVIEW_CLASSES),
  330. MAKEICC(InitTrackBar, TRACKBAR_CLASS, ICC_BAR_CLASSES),
  331. MAKEICC(InitUpDownClass, UPDOWN_CLASS, ICC_UPDOWN_CLASS),
  332. MAKEICC(InitProgressClass, PROGRESS_CLASS, ICC_PROGRESS_CLASS),
  333. MAKEICC(InitHotKeyClass, HOTKEY_CLASS, ICC_HOTKEY_CLASS),
  334. MAKEICC(InitAnimateClass, ANIMATE_CLASS, ICC_ANIMATE_CLASS),
  335. MAKEICC(InitDateClasses, DATETIMEPICK_CLASS,ICC_DATE_CLASSES),
  336. MAKEICC(InitDateClasses, MONTHCAL_CLASS, 0),
  337. MAKEICC(InitComboExClass, WC_COMBOBOXEX, ICC_USEREX_CLASSES),
  338. MAKEICC(InitIPAddr, WC_IPADDRESS, ICC_INTERNET_CLASSES),
  339. MAKEICC(InitPager, WC_PAGESCROLLER, ICC_PAGESCROLLER_CLASS),
  340. MAKEICC(InitNativeFontCtl, WC_NATIVEFONTCTL, ICC_NATIVEFNTCTL_CLASS),
  341. //
  342. // These aren't really classes. They're just goofy flags.
  343. //
  344. MAKEICC(InitForWinlogon, NULL, ICC_WINLOGON_REINIT),
  345. };
  346. //------------------------------------------------------------------------------
  347. //
  348. // Get the activation context associated with the .dll/.exe this
  349. // function is linked into -- that is, the activation context
  350. // that was active when it was loaded.
  351. //
  352. // This is a tiny wrapper around QueryActCtx.
  353. //
  354. // This context can also be gotten via
  355. // GetCurrentActCtx in DllMain(dll_process_attach).
  356. //
  357. BOOL GetModuleActCtx(OUT HANDLE *phActCtx)
  358. {
  359. ACTIVATION_CONTEXT_BASIC_INFORMATION actCtxBasicInfo = {0};
  360. BOOL fRet = QueryActCtxW(QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE|QUERY_ACTCTX_FLAG_NO_ADDREF,
  361. HINST_THISDLL,
  362. NULL,
  363. ActivationContextBasicInformation,
  364. &actCtxBasicInfo,
  365. sizeof(actCtxBasicInfo),
  366. NULL);
  367. if (fRet && phActCtx)
  368. {
  369. *phActCtx = actCtxBasicInfo.hActCtx;
  370. }
  371. return fRet;
  372. }
  373. //------------------------------------------------------------------------------
  374. BOOL ActivateModuleActCtx(OUT ULONG_PTR *pulCookie)
  375. {
  376. BOOL fRet = FALSE;
  377. HANDLE hActCtx = NULL;
  378. ASSERT(pulCookie != NULL);
  379. *pulCookie = 0;
  380. if (GetModuleActCtx(&hActCtx))
  381. {
  382. fRet = ActivateActCtx(hActCtx, pulCookie);
  383. }
  384. return fRet;
  385. }
  386. BOOL WINAPI InitCommonControlsEx(LPINITCOMMONCONTROLSEX picce)
  387. {
  388. int i;
  389. BOOL fRet = TRUE;
  390. ULONG_PTR ulCookie = 0;
  391. if (!picce ||
  392. (picce->dwSize != sizeof(INITCOMMONCONTROLSEX)) ||
  393. (picce->dwICC & ~ICC_ALL_VALID))
  394. {
  395. DebugMsg(DM_WARNING, TEXT("comctl32 - picce is bad"));
  396. return FALSE;
  397. }
  398. if (!ActivateModuleActCtx(&ulCookie))
  399. {
  400. return FALSE;
  401. }
  402. __try
  403. {
  404. for (i = 0; i < ARRAYSIZE(icc); i++)
  405. {
  406. if (picce->dwICC & icc[i].dwClassSet)
  407. {
  408. if (!icc[i].pfnInit(HINST_THISDLL))
  409. {
  410. fRet = FALSE;
  411. break;
  412. }
  413. else
  414. {
  415. icc[i].fRegistered = TRUE;
  416. }
  417. }
  418. }
  419. }
  420. __finally
  421. {
  422. DeactivateActCtx(0, ulCookie);
  423. }
  424. return fRet;
  425. }
  426. //
  427. // InitMUILanguage / GetMUILanguage implementation
  428. //
  429. // we have a per process PUI language setting. For NT it's just a global
  430. // initialized with LANG_NEUTRAL and SUBLANG_NEUTRAL
  431. // For Win95 it's DPA slot for the current process.
  432. // InitMUILanguage sets callers preferred language id for common control
  433. // GetMUILangauge returns what the caller has set to us
  434. //
  435. void WINAPI
  436. InitMUILanguage(LANGID wLang)
  437. {
  438. ENTERCRITICAL;
  439. g_PUILangId = wLang;
  440. LEAVECRITICAL;
  441. }
  442. LANGID WINAPI
  443. GetMUILanguage(void)
  444. {
  445. return g_PUILangId;
  446. }
  447. // end MUI functions
  448. //
  449. // Unlike Win9x, WinNT does not automatically unregister classes
  450. // when a DLL unloads. We have to do it manually. Leaving the
  451. // class lying around means that if an app loads our DLL, then
  452. // unloads it, then reloads it at a different address, all our
  453. // leftover RegisterClass()es will point the WndProc at the wrong
  454. // place and we fault at the next CreateWindow().
  455. //
  456. // This is not purely theoretical - NT4/FE hit this bug.
  457. //
  458. void UnregisterClasses()
  459. {
  460. int i;
  461. for (i=0 ; i < ARRAYSIZE(icc) ; i++)
  462. {
  463. if (icc[i].pszName && icc[i].fRegistered)
  464. {
  465. UnregisterClass(icc[i].pszName, HINST_THISDLL);
  466. }
  467. }
  468. }
  469. #if defined(DEBUG)
  470. LRESULT WINAPI SendMessageD(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  471. {
  472. ASSERTNONCRITICAL;
  473. return SendMessageW(hWnd, Msg, wParam, lParam);
  474. }
  475. #endif // defined(DEBUG)
  476. #define COMPILE_MULTIMON_STUBS
  477. #include "multimon.h"
  478. BOOL WINAPI RegisterClassNameW(LPCWSTR pszClass)
  479. {
  480. int i;
  481. BOOL fRet = FALSE;
  482. for (i = 0; i < ARRAYSIZE(icc) ; i++)
  483. {
  484. if (lstrcmpi(icc[i].pszName, pszClass) == 0)
  485. {
  486. if (icc[i].pfnInit(HINST_THISDLL))
  487. {
  488. icc[i].fRegistered = TRUE;
  489. fRet = TRUE;
  490. }
  491. break;
  492. }
  493. }
  494. return fRet;
  495. }