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.

732 lines
21 KiB

  1. /***************************************************************************
  2. * msctls.c
  3. *
  4. * Utils library initialization code
  5. *
  6. ***************************************************************************/
  7. #include "ctlspriv.h"
  8. HINSTANCE g_hinst = 0;
  9. #ifndef UNIX
  10. CRITICAL_SECTION g_csDll = {{0},0, 0, NULL, NULL, 0 };
  11. #else
  12. /* IEUNIX: MainWin uses DllMain as an entry point (Ref: mwdip) */
  13. #define LibMain DllMain
  14. #include "mwversion.h"
  15. #if defined(MW_STRUCTINIT_SUPPORTED)
  16. CRITICAL_SECTION g_csDll = {{0},0, 0, NULL, NULL, 0 };
  17. #else
  18. CRITICAL_SECTION g_csDll;
  19. #endif
  20. #endif /* UNIX */
  21. ATOM g_aCC32Subclass = 0;
  22. #ifdef WINNT
  23. BOOL g_bRunOnNT5 = FALSE;
  24. BOOL g_bRemoteSession = FALSE;
  25. #else
  26. BOOL g_bRunOnMemphis = FALSE;
  27. BOOL g_bRunOnBiDiWin95Loc = FALSE;
  28. int g_cProcesses = 0;
  29. #endif
  30. UINT g_uiACP = CP_ACP;
  31. // Is Mirroring enabled
  32. BOOL g_bMirroredOS = FALSE;
  33. #define PAGER //For Test Purposes
  34. //
  35. // Global DCs used during mirroring an Icon.
  36. //
  37. HDC g_hdc=NULL, g_hdcMask=NULL;
  38. // per process mem to store PlugUI information
  39. #ifdef WINNT
  40. LANGID g_PUILangId = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
  41. #else
  42. HDPA g_hdpaPUI = NULL;
  43. void InitPUI();
  44. void DeInitPUI(int cProcesses);
  45. #endif
  46. BOOL PASCAL InitAnimateClass(HINSTANCE hInstance);
  47. BOOL ListView_Init(HINSTANCE hinst);
  48. BOOL TV_Init(HINSTANCE hinst);
  49. BOOL InitComboExClass(HINSTANCE hinst);
  50. BOOL PASCAL Header_Init(HINSTANCE hinst);
  51. BOOL PASCAL Tab_Init(HINSTANCE hinst);
  52. int InitIPAddr(HANDLE hInstance);
  53. #if !defined(WINNT) && defined(FONT_LINK)
  54. void InitMLANG();
  55. void DeinitMLANG(int cProcesses);
  56. #endif
  57. #ifdef PAGER
  58. BOOL InitPager(HINSTANCE hinst);
  59. #endif
  60. BOOL InitNativeFontCtl(HINSTANCE hinst);
  61. void UnregisterClasses();
  62. void Mem_Terminate();
  63. #define DECLARE_DELAYED_FUNC(_ret, _fn, _args, _nargs) \
  64. _ret (__stdcall * g_pfn##_fn) _args = NULL; \
  65. _ret __stdcall _fn _args \
  66. { \
  67. if (!g_pfn##_fn) { \
  68. AssertMsg(g_pfn##_fn != NULL, TEXT("GetProcAddress failed")); \
  69. return 0; \
  70. } \
  71. return g_pfn##_fn _nargs; \
  72. }
  73. #define LOAD_DELAYED_FUNC(_ret, _fn, _args) \
  74. (*(FARPROC*)&(g_pfn##_fn) = GetProcAddress(hinst, #_fn))
  75. DECLARE_DELAYED_FUNC(BOOL, ImmNotifyIME, (HIMC himc, DWORD dw1, DWORD dw2, DWORD dw3), (himc, dw1, dw2, dw3));
  76. DECLARE_DELAYED_FUNC(HIMC, ImmAssociateContext, (HWND hwnd, HIMC himc), (hwnd, himc));
  77. DECLARE_DELAYED_FUNC(BOOL, ImmReleaseContext, (HWND hwnd, HIMC himc), (hwnd, himc));
  78. DECLARE_DELAYED_FUNC(HIMC, ImmGetContext, (HWND hwnd), (hwnd));
  79. DECLARE_DELAYED_FUNC(LONG, ImmGetCompositionStringA, (HIMC himc, DWORD dw1, LPVOID p1, DWORD dw2), (himc, dw1, p1, dw2) );
  80. DECLARE_DELAYED_FUNC(BOOL, ImmSetCompositionStringA, (HIMC himc, DWORD dw1, LPCVOID p1, DWORD dw2, LPCVOID p2, DWORD dw3), (himc, dw1, p1, dw2, p2, dw3));
  81. #ifndef UNICODE_WIN9x
  82. DECLARE_DELAYED_FUNC(LONG, ImmGetCompositionStringW, (HIMC himc, DWORD dw1, LPVOID p1, DWORD dw2), (himc, dw1, p1, dw2) );
  83. DECLARE_DELAYED_FUNC(BOOL, ImmSetCompositionStringW, (HIMC himc, DWORD dw1, LPCVOID p1, DWORD dw2, LPCVOID p2, DWORD dw3), (himc, dw1, p1, dw2, p2, dw3));
  84. #endif
  85. DECLARE_DELAYED_FUNC(BOOL, ImmSetCandidateWindow, (HIMC himc, LPCANDIDATEFORM pcf), (himc, pcf));
  86. DECLARE_DELAYED_FUNC(HIMC, ImmCreateContext, (void), ());
  87. DECLARE_DELAYED_FUNC(BOOL, ImmDestroyContext, (HIMC himc), (himc));
  88. BOOL g_fDBCSEnabled = FALSE;
  89. BOOL g_fMEEnabled = FALSE;
  90. BOOL g_fDBCSInputEnabled = FALSE;
  91. #ifdef FONT_LINK
  92. BOOL g_bComplexPlatform = FALSE;
  93. #endif
  94. #if defined(FE_IME) || !defined(WINNT)
  95. void InitIme()
  96. {
  97. g_fMEEnabled = GetSystemMetrics(SM_MIDEASTENABLED);
  98. g_fDBCSEnabled = g_fDBCSInputEnabled = GetSystemMetrics(SM_DBCSENABLED);
  99. if (!g_fDBCSInputEnabled && g_bRunOnNT5)
  100. g_fDBCSInputEnabled = GetSystemMetrics(SM_IMMENABLED);
  101. // We load imm32.dll per process, but initialize proc pointers just once.
  102. // this is to solve two different problems.
  103. // 1) Debugging process on win95 would get our shared table trashed
  104. // if we rewrite proc address each time we get loaded.
  105. // 2) Some lotus application rely upon us to load imm32. They do not
  106. // load/link to imm yet they use imm(!)
  107. //
  108. if (g_fDBCSInputEnabled) {
  109. HANDLE hinst = LoadLibrary(TEXT("imm32.dll"));
  110. if (! g_pfnImmSetCandidateWindow &&
  111. (! hinst ||
  112. ! LOAD_DELAYED_FUNC(HIMC, ImmCreateContext, (void)) ||
  113. ! LOAD_DELAYED_FUNC(HIMC, ImmDestroyContext, (HIMC)) ||
  114. ! LOAD_DELAYED_FUNC(BOOL, ImmNotifyIME, (HIMC, DWORD, DWORD, DWORD)) ||
  115. ! LOAD_DELAYED_FUNC(HIMC, ImmAssociateContext, (HWND, HIMC)) ||
  116. ! LOAD_DELAYED_FUNC(BOOL, ImmReleaseContext, (HWND, HIMC)) ||
  117. ! LOAD_DELAYED_FUNC(HIMC, ImmGetContext, (HWND)) ||
  118. ! LOAD_DELAYED_FUNC(LONG, ImmGetCompositionStringA, (HIMC, DWORD, LPVOID, DWORD)) ||
  119. ! LOAD_DELAYED_FUNC(BOOL, ImmSetCompositionStringA, (HIMC, DWORD, LPCVOID, DWORD, LPCVOID, DWORD)) ||
  120. #ifndef UNICODE_WIN9x
  121. ! LOAD_DELAYED_FUNC(LONG, ImmGetCompositionStringW, (HIMC, DWORD, LPVOID, DWORD)) ||
  122. ! LOAD_DELAYED_FUNC(BOOL, ImmSetCompositionStringW, (HIMC, DWORD, LPCVOID, DWORD, LPCVOID, DWORD)) ||
  123. #endif
  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. #if defined(MAINWIN)
  234. MwSet3dLook(TRUE);
  235. #endif
  236. #ifdef DEBUG
  237. CcshellGetDebugFlags();
  238. g_dwBreakFlags = 0; // We do not want to break in comctl32 version 5 at ALL. Too many bad callers.
  239. #endif
  240. #ifdef WINNT
  241. InitializeCriticalSection(&g_csDll);
  242. g_bRunOnNT5 = staticIsOS(OS_WIN2000ORGREATER);
  243. #ifdef FONT_LINK
  244. g_bComplexPlatform = BOOLFROMPTR(GetModuleHandle(TEXT("LPK.DLL")));
  245. #endif
  246. #else
  247. ReinitializeCriticalSection(&g_csDll);
  248. #ifdef FONT_LINK
  249. g_bComplexPlatform = ((g_uiACP == CP_ARABIC) || (g_uiACP == CP_HEBREW) || (g_uiACP == CP_THAI));
  250. #endif
  251. g_bRunOnMemphis = staticIsOS(OS_WIN98ORGREATER);
  252. g_bRunOnBiDiWin95Loc = IsBiDiLocalizedWin95(FALSE);
  253. g_cProcesses++;
  254. {
  255. // HACK: we are intentionally incrementing the refcount on this atom
  256. // WE DO NOT WANT IT TO GO BACK DOWN so we will not delete it in process
  257. // detach (see comments for g_aCC32Subclass in subclass.c for more info)
  258. // on Win95 doe this as early as possible to avoid getting
  259. // a trashed atom.
  260. ATOM a = GlobalAddAtom(c_szCC32Subclass);
  261. if (a != 0)
  262. g_aCC32Subclass = a; // in case the old atom got nuked
  263. }
  264. #endif
  265. //
  266. // Check if the mirroring APIs exist on the current
  267. // platform.
  268. //
  269. g_bMirroredOS = IS_MIRRORING_ENABLED();
  270. #ifdef WINNT
  271. //
  272. // Must detect Terminal Server before initializing global metrics
  273. // because we need to force some features off if running Terminal Server.
  274. //
  275. {
  276. typedef BOOL (__stdcall * PFNPROCESSIDTOSESSIONID)(DWORD, PDWORD);
  277. PFNPROCESSIDTOSESSIONID ProcessIdToSessionId =
  278. (PFNPROCESSIDTOSESSIONID)
  279. GetProcAddress(GetModuleHandle(TEXT("KERNEL32")),
  280. "ProcessIdToSessionId");
  281. DWORD dwSessionId;
  282. g_bRemoteSession = ProcessIdToSessionId &&
  283. ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId) &&
  284. dwSessionId != 0;
  285. }
  286. #endif
  287. InitGlobalMetrics(0);
  288. InitGlobalColors();
  289. InitIme();
  290. #ifndef WINNT
  291. #ifdef FONT_LINK
  292. InitMLANG();
  293. #endif
  294. InitPUI();
  295. #endif
  296. #ifdef DEBUG
  297. ASSERT(IsSimpleDialog(MAKEINTRESOURCE(DLG_WIZARD)));
  298. ASSERT(IsSimpleDialog(MAKEINTRESOURCE(DLG_PROPSHEET)));
  299. CheckResourceLanguages();
  300. #endif
  301. // BUGBUG: only do this for GetProcessVersion apps <= 0x40000
  302. // Newer apps MUST use InitCommonControlsEx.
  303. icce.dwSize = sizeof(icce);
  304. icce.dwICC = ICC_ALL_CLASSES;
  305. return InitCommonControlsEx(&icce);
  306. }
  307. void _ProcessDetach(HANDLE hInstance)
  308. {
  309. //
  310. // Cleanup cached DCs. No need to synchronize the following section of
  311. // code since it is only called in DLL_PROCESS_DETACH which is
  312. // synchronized by the OS Loader.
  313. //
  314. #ifdef WINNT
  315. if (g_hdc)
  316. DeleteDC(g_hdc);
  317. if (g_hdcMask)
  318. DeleteDC(g_hdcMask);
  319. g_hdc = g_hdcMask = NULL;
  320. #endif
  321. #ifdef WINNT
  322. UnregisterClasses();
  323. DeleteCriticalSection(&g_csDll);
  324. #else
  325. ENTERCRITICAL;
  326. #ifdef FONT_LINK
  327. DeinitMLANG(g_cProcesses);
  328. #endif
  329. DeInitPUI(g_cProcesses);
  330. if (--g_cProcesses == 0)
  331. {
  332. if (g_hdc)
  333. DeleteDC(g_hdc);
  334. if (g_hdcMask)
  335. DeleteDC(g_hdcMask);
  336. g_hdc = g_hdcMask = NULL;
  337. Mem_Terminate(); // shared heap cleanup... all calls after this will die!
  338. }
  339. LEAVECRITICAL;
  340. #endif
  341. }
  342. STDAPI_(BOOL) LibMain(HANDLE hDll, DWORD dwReason, LPVOID pv)
  343. {
  344. #ifndef WINNT
  345. STDAPI_(BOOL) Cctl1632_ThunkConnect32(LPCSTR pszDll16,LPCSTR pszDll32,HANDLE hIinst,DWORD dwReason);
  346. if (!Cctl1632_ThunkConnect32("commctrl.dll", "comctl32.dll", hDll, dwReason))
  347. return FALSE;
  348. #endif
  349. switch(dwReason) {
  350. case DLL_PROCESS_ATTACH:
  351. DisableThreadLibraryCalls(hDll);
  352. return _ProcessAttach(hDll);
  353. case DLL_PROCESS_DETACH:
  354. _ProcessDetach(hDll);
  355. break;
  356. case DLL_THREAD_ATTACH:
  357. case DLL_THREAD_DETACH:
  358. default:
  359. break;
  360. } // end switch()
  361. return TRUE;
  362. } // end DllEntryPoint()
  363. /* Stub function to call if all you want to do is make sure this DLL is loaded
  364. */
  365. void WINAPI InitCommonControls(void)
  366. {
  367. }
  368. #ifdef WINNT
  369. BOOL InitForWinlogon(HINSTANCE hInstance)
  370. {
  371. // Some people like to use comctl32 from inside winlogon, and
  372. // for C2 security reasons, all global atoms are nuked from the
  373. // window station when you log off.
  374. //
  375. // So the rule is that all winlogon clients of comctl32 must
  376. // call InitCommonControlsEx(ICC_WINLOGON_REINIT) immediately
  377. // before doing any common control things (creating windows
  378. // or property sheets/wizards) from winlogon.
  379. ATOM a = GlobalAddAtom(c_szCC32Subclass);
  380. if (a)
  381. g_aCC32Subclass = a;
  382. InitGlobalMetrics(0);
  383. InitGlobalColors();
  384. return TRUE;
  385. }
  386. #endif
  387. /* InitCommonControlsEx creates the classes. Only those classes requested are created!
  388. ** The process attach figures out if it's an old app and supplies ICC_WIN95_CLASSES.
  389. */
  390. typedef BOOL (PASCAL *PFNINIT)(HINSTANCE);
  391. typedef struct {
  392. PFNINIT pfnInit;
  393. #ifdef WINNT
  394. LPCTSTR pszName;
  395. #endif
  396. DWORD dw;
  397. } INITCOMMONCONTROLSINFO;
  398. #ifdef WINNT
  399. #define MAKEICC(pfnInit, pszClass, dwFlags) { pfnInit, pszClass, dwFlags }
  400. #else
  401. #define MAKEICC(pfnInit, pszClass, dwFlags) { pfnInit, dwFlags }
  402. #endif
  403. const INITCOMMONCONTROLSINFO icc[] =
  404. {
  405. // Init function Class name Requested class sets which use this class
  406. MAKEICC(InitToolbarClass, TOOLBARCLASSNAME, ICC_BAR_CLASSES),
  407. MAKEICC(InitReBarClass, REBARCLASSNAME, ICC_COOL_CLASSES),
  408. MAKEICC(InitToolTipsClass, TOOLTIPS_CLASS, ICC_TREEVIEW_CLASSES|ICC_BAR_CLASSES|ICC_TAB_CLASSES),
  409. MAKEICC(InitStatusClass, STATUSCLASSNAME, ICC_BAR_CLASSES),
  410. MAKEICC(ListView_Init, WC_LISTVIEW, ICC_LISTVIEW_CLASSES),
  411. MAKEICC(Header_Init, WC_HEADER, ICC_LISTVIEW_CLASSES),
  412. MAKEICC(Tab_Init, WC_TABCONTROL, ICC_TAB_CLASSES),
  413. MAKEICC(TV_Init, WC_TREEVIEW, ICC_TREEVIEW_CLASSES),
  414. MAKEICC(InitTrackBar, TRACKBAR_CLASS, ICC_BAR_CLASSES),
  415. MAKEICC(InitUpDownClass, UPDOWN_CLASS, ICC_UPDOWN_CLASS),
  416. MAKEICC(InitProgressClass, PROGRESS_CLASS, ICC_PROGRESS_CLASS),
  417. MAKEICC(InitHotKeyClass, HOTKEY_CLASS, ICC_HOTKEY_CLASS),
  418. MAKEICC(InitAnimateClass, ANIMATE_CLASS, ICC_ANIMATE_CLASS),
  419. MAKEICC(InitDateClasses, DATETIMEPICK_CLASS,ICC_DATE_CLASSES),
  420. MAKEICC(InitComboExClass, WC_COMBOBOXEX, ICC_USEREX_CLASSES),
  421. MAKEICC(InitIPAddr, WC_IPADDRESS, ICC_INTERNET_CLASSES),
  422. #ifdef PAGER
  423. MAKEICC(InitPager, WC_PAGESCROLLER, ICC_PAGESCROLLER_CLASS),
  424. #endif
  425. MAKEICC(InitNativeFontCtl, WC_NATIVEFONTCTL, ICC_NATIVEFNTCTL_CLASS),
  426. //
  427. // These aren't really classes. They're just goofy flags.
  428. //
  429. #ifdef WINNT
  430. MAKEICC(InitForWinlogon, NULL, ICC_WINLOGON_REINIT),
  431. #endif
  432. };
  433. BOOL WINAPI InitCommonControlsEx(LPINITCOMMONCONTROLSEX picce)
  434. {
  435. int i;
  436. #ifdef UNIX
  437. if (MwIsInitLite())
  438. return (TRUE);
  439. #endif
  440. if (!picce ||
  441. (picce->dwSize != sizeof(INITCOMMONCONTROLSEX)) ||
  442. (picce->dwICC & ~ICC_ALL_VALID))
  443. {
  444. DebugMsg(DM_WARNING, TEXT("comctl32 - picce is bad"));
  445. return(FALSE);
  446. }
  447. for (i=0 ; i < ARRAYSIZE(icc) ; i++)
  448. if (picce->dwICC & icc[i].dw)
  449. if (!icc[i].pfnInit(HINST_THISDLL))
  450. return(FALSE);
  451. return(TRUE);
  452. }
  453. //
  454. // InitMUILanguage / GetMUILanguage implementation
  455. //
  456. // we have a per process PUI language setting. For NT it's just a global
  457. // initialized with LANG_NEUTRAL and SUBLANG_NEUTRAL
  458. // For Win95 it's DPA slot for the current process.
  459. // InitMUILanguage sets callers preferred language id for common control
  460. // GetMUILangauge returns what the caller has set to us
  461. //
  462. #ifdef WINNT
  463. LANGID PUIGetLangId(void)
  464. {
  465. return g_PUILangId;
  466. }
  467. #else // WIN95
  468. typedef struct tagPUIPROCSLOT
  469. {
  470. DWORD dwPID;
  471. LANGID wLangId;
  472. } PUIPROCSLOT, *PPUIPROCSLOT;
  473. PPUIPROCSLOT PUICreateProcSlot(void)
  474. {
  475. PPUIPROCSLOT pSlot = (PPUIPROCSLOT)Alloc(sizeof(PUIPROCSLOT));
  476. if (pSlot)
  477. {
  478. pSlot->dwPID = GetCurrentProcessId();
  479. pSlot->wLangId = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
  480. }
  481. return pSlot;
  482. }
  483. int PUIGetProcIdx(DWORD dwProcessId)
  484. {
  485. int i, cSlot = 0;
  486. ASSERTCRITICAL;
  487. if (g_hdpaPUI)
  488. cSlot = DPA_GetPtrCount(g_hdpaPUI);
  489. for (i = 0; i < cSlot; i++)
  490. {
  491. PPUIPROCSLOT pSlot = (PPUIPROCSLOT)DPA_FastGetPtr(g_hdpaPUI, i);
  492. if (pSlot && pSlot->dwPID == dwProcessId)
  493. return i;
  494. }
  495. return -1;
  496. }
  497. void InitPUI(void)
  498. {
  499. if (NULL == g_hdpaPUI)
  500. {
  501. ENTERCRITICAL;
  502. if (NULL == g_hdpaPUI)
  503. g_hdpaPUI= DPA_Create(4);
  504. LEAVECRITICAL;
  505. }
  506. }
  507. void DeInitPUI(int cProcesses)
  508. {
  509. int i = PUIGetProcIdx(GetCurrentProcessId());
  510. ASSERTCRITICAL;
  511. if (0 <= i)
  512. {
  513. Free((PPUIPROCSLOT)DPA_FastGetPtr(g_hdpaPUI, i));
  514. DPA_DeletePtr(g_hdpaPUI, i);
  515. }
  516. if (g_hdpaPUI&& 1 == cProcesses) // This is last process detach
  517. {
  518. DPA_Destroy(g_hdpaPUI);
  519. g_hdpaPUI= NULL;
  520. }
  521. }
  522. PPUIPROCSLOT PUIGetProcSlot(void)
  523. {
  524. PPUIPROCSLOT pSlot = NULL;
  525. int i;
  526. ENTERCRITICAL;
  527. i = PUIGetProcIdx(GetCurrentProcessId());
  528. if (0 <= i)
  529. {
  530. pSlot = (PPUIPROCSLOT)DPA_FastGetPtr(g_hdpaPUI, i);
  531. }
  532. else
  533. {
  534. pSlot = PUICreateProcSlot();
  535. if (pSlot)
  536. DPA_AppendPtr(g_hdpaPUI, pSlot);
  537. }
  538. LEAVECRITICAL;
  539. return pSlot;
  540. }
  541. LANGID PUIGetLangId(void)
  542. {
  543. PPUIPROCSLOT pSlot = PUIGetProcSlot();
  544. LANGID wLang;
  545. if (pSlot)
  546. wLang = pSlot->wLangId;
  547. else
  548. wLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
  549. return wLang;
  550. }
  551. #endif // !WINNT
  552. void WINAPI
  553. InitMUILanguage(LANGID wLang)
  554. {
  555. #ifdef WINNT
  556. ENTERCRITICAL;
  557. g_PUILangId = wLang;
  558. LEAVECRITICAL;
  559. #else
  560. PPUIPROCSLOT pSlot = PUIGetProcSlot();
  561. if(pSlot)
  562. pSlot->wLangId = wLang;
  563. #endif
  564. }
  565. LANGID WINAPI
  566. GetMUILanguage(void)
  567. {
  568. #ifdef WINNT
  569. return g_PUILangId;
  570. #else
  571. return PUIGetLangId();
  572. #endif
  573. }
  574. // end MUI functions
  575. #ifdef WINNT
  576. //
  577. // Unlike Win9x, WinNT does not automatically unregister classes
  578. // when a DLL unloads. We have to do it manually. Leaving the
  579. // class lying around means that if an app loads our DLL, then
  580. // unloads it, then reloads it at a different address, all our
  581. // leftover RegisterClass()es will point the WndProc at the wrong
  582. // place and we fault at the next CreateWindow().
  583. //
  584. // This is not purely theoretical - NT4/FE hit this bug.
  585. //
  586. void UnregisterClasses()
  587. {
  588. WNDCLASS wc;
  589. int i;
  590. for (i=0 ; i < ARRAYSIZE(icc) ; i++)
  591. {
  592. if (icc[i].pszName &&
  593. GetClassInfo(HINST_THISDLL, icc[i].pszName, &wc))
  594. {
  595. UnregisterClass(icc[i].pszName, HINST_THISDLL);
  596. }
  597. }
  598. }
  599. #endif
  600. #if defined(DEBUG)
  601. LRESULT WINAPI SendMessageD(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  602. {
  603. ASSERTNONCRITICAL;
  604. #ifdef UNICODE
  605. return SendMessageW(hWnd, Msg, wParam, lParam);
  606. #else
  607. return SendMessageA(hWnd, Msg, wParam, lParam);
  608. #endif
  609. }
  610. #endif // defined(DEBUG)
  611. #define COMPILE_MULTIMON_STUBS
  612. #include "multimon.h"