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.

516 lines
18 KiB

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