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.

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