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.

436 lines
12 KiB

  1. /*
  2. * control - Dialog box property sheet for "control panel"
  3. */
  4. #include "tweakui.h"
  5. /*
  6. * cchFriendlyMax is used to hold control panel file descriptions.
  7. */
  8. #define cchFriendlyMax 256
  9. typedef struct CPL { /* control panel */
  10. TCHAR tszFile[MAX_PATH]; /* File name */
  11. } CPL, *PCPL;
  12. #define icplPlvi(plvi) ((UINT)(plvi)->lParam)
  13. #define pcplIcpl(icpl) (&pcpii->pcpl[icpl])
  14. #define pcplPlvi(plvi) pcplIcpl(icplPlvi(plvi))
  15. typedef struct CPII {
  16. Declare_Gxa(CPL, cpl);
  17. } CPII, *PCPII;
  18. CPII cpii;
  19. #define pcpii (&cpii)
  20. TCHAR g_tszBoring[64];
  21. #pragma BEGIN_CONST_DATA
  22. const static DWORD CODESEG rgdwHelp[] = {
  23. 0, 0,
  24. };
  25. /*****************************************************************************
  26. *
  27. * Control_VerQueryDescription
  28. *
  29. * pull out the file description if we have one.
  30. *
  31. *****************************************************************************/
  32. BOOL PASCAL
  33. Control_VerQueryDescription(LPVOID pvData, UINT uiLang, UINT uiCharSet,
  34. LPTSTR ptszBuf, UINT ctch)
  35. {
  36. TCHAR tsz[128];
  37. LPWSTR pwsz;
  38. BOOL fRc;
  39. UINT cb;
  40. wsprintf(tsz, TEXT("\\StringFileInfo\\%04X%04X\\")
  41. TEXT("FileDescription"), uiLang, uiCharSet);
  42. fRc = VerQueryValue(pvData, tsz, (LPVOID *)&pwsz, &cb);
  43. if (fRc && cb > 0) {
  44. #ifdef UNICODE
  45. lstrcpyn(ptszBuf, pwsz, ctch);
  46. #else
  47. WideCharToMultiByte(CP_ACP, 0, pwsz, cb / cbX(WCHAR),
  48. ptszBuf, MAX_PATH, NULL, NULL);
  49. lstrcpyn(ptszBuf, (LPSTR)pwsz, ctch);
  50. #endif
  51. }
  52. return fRc;
  53. }
  54. /*****************************************************************************
  55. *
  56. * Control_GetFileDescription
  57. *
  58. * pull out the file description if we have one.
  59. *
  60. *****************************************************************************/
  61. void PASCAL
  62. Control_GetFileDescription(LPTSTR ptszFile, LPTSTR ptszBuf, UINT ctch)
  63. {
  64. DWORD dwHandle;
  65. UINT cb;
  66. /*
  67. * Assume it doesn't work.
  68. */
  69. ptszBuf[0] = TEXT('\0');
  70. cb = GetFileVersionInfoSize(ptszFile, &dwHandle);
  71. if (cb) {
  72. LPVOID pvData = lAlloc(cb);
  73. if (pvData) {
  74. LPWORD rgwTrans;
  75. UINT uiSize;
  76. if (GetFileVersionInfo(ptszFile, dwHandle, cb, pvData) &&
  77. VerQueryValue(pvData, TEXT("\\VarFileInfo\\Translation"),
  78. (LPVOID *)&rgwTrans, &uiSize)) {
  79. if (Control_VerQueryDescription(pvData,
  80. rgwTrans[0], rgwTrans[1],
  81. ptszBuf, ctch) ||
  82. /*
  83. * Lots of people forget to set the language properly,
  84. * so we will try English/USA regardless. And if that
  85. * doesn't work, try English/NULL because some people
  86. * do that too.
  87. */
  88. Control_VerQueryDescription(pvData,
  89. 0x0409, 0x040E,
  90. ptszBuf, ctch) ||
  91. Control_VerQueryDescription(pvData,
  92. 0x0409, 0x0000,
  93. ptszBuf, ctch)) {
  94. }
  95. }
  96. lFree(pvData);
  97. }
  98. }
  99. }
  100. /*****************************************************************************
  101. *
  102. * Control_GetShowState
  103. *
  104. * Determine whether a *.CPL file is currently shown in the
  105. * Control Panel.
  106. *
  107. *****************************************************************************/
  108. BOOL PASCAL
  109. Control_GetShowState(LPCTSTR ptszName)
  110. {
  111. TCHAR tsz[10];
  112. GetPrivateProfileString(c_tszDontLoad, ptszName,
  113. c_tszNil, tsz, cA(tsz), c_tszControlIni);
  114. return tsz[0] ? FALSE : TRUE;
  115. }
  116. /*****************************************************************************
  117. *
  118. * Control_SetShowState
  119. *
  120. * Set the registry/INI flag that tells us to hide/show the *.CPL file.
  121. *
  122. *****************************************************************************/
  123. void PASCAL
  124. Control_SetShowState(LPCTSTR ptszName, BOOL fShow)
  125. {
  126. WritePrivateProfileString(c_tszDontLoad, ptszName,
  127. fShow ? NULL : c_tszNo, c_tszControlIni);
  128. }
  129. /*****************************************************************************
  130. *
  131. * Control_AddCpl
  132. *
  133. * Add a single *.CPL to the list.
  134. *
  135. * The display name is the CPL filename, followed by an optional
  136. * parenthesized version description string. For control panels
  137. * that ship with Windows 95 whose version strings isn't very good, we substitute
  138. * our own.
  139. *
  140. *****************************************************************************/
  141. #pragma BEGIN_CONST_DATA
  142. LPCTSTR c_rgpszCpl[] = {
  143. c_tszAppWizCpl,
  144. c_tszDeskCpl,
  145. c_tszIntlCpl,
  146. c_tszMainCpl,
  147. c_tszTimeDateCpl,
  148. };
  149. int PASCAL
  150. Control_AddCpl(HWND hwnd, LPTSTR ptszName)
  151. {
  152. //
  153. // On Windows 2000, ncpa.cpl is a stub that exists only for legacy
  154. // purposes. It does exactly the same thing as the "Network
  155. // Connections" icon that already exists in the Control Panel.
  156. //
  157. if (g_fNT5 && lstrcmpi(ptszName, TEXT("ncpa.cpl")) == 0) {
  158. return -1;
  159. }
  160. PCPL pcpl = (PCPL)Misc_AllocPx(&pcpii->gxa);
  161. TCHAR tszDesc[MAX_PATH];
  162. TCHAR tszFull[MAX_PATH + 3 + MAX_PATH]; /* 3 = " - " */
  163. if (pcpl) {
  164. lstrcpy(pcpl->tszFile, ptszFilenameCqn(ptszName));
  165. CharLower(pcpl->tszFile);
  166. Control_GetFileDescription(ptszName, tszDesc, MAX_PATH);
  167. /*
  168. * Now clean up various weird cases.
  169. */
  170. if (lstrcmpi(tszDesc, g_tszBoring) == 0) {
  171. int i;
  172. for (i = 0; i < cA(c_rgpszCpl); i++) {
  173. if (lstrcmpi(pcpl->tszFile, c_rgpszCpl[i]) == 0) {
  174. LoadString(hinstCur, IDS_CPL_ADDRM + i, tszDesc, cA(tszDesc));
  175. break;
  176. }
  177. }
  178. }
  179. wsprintf(tszFull, TEXT("%s - %s"), pcpl->tszFile, tszDesc);
  180. return LV_AddItem(hwnd, pcpii->ccpl++, tszFull, -1,
  181. Control_GetShowState(pcpl->tszFile));
  182. } else {
  183. return -1;
  184. }
  185. }
  186. /*****************************************************************************
  187. *
  188. * Control_InitControls2
  189. *
  190. * Enumerate all the special DLLs in the MMCPL section and add them
  191. * to the list. Note that the buffer sizes are exactly the same sizes
  192. * that SHELL32 uses, so we won't miss anything that the shell itself
  193. * doesn't.
  194. *
  195. *****************************************************************************/
  196. void PASCAL
  197. Control_InitControls2(HWND hwnd)
  198. {
  199. LPTSTR ptsz;
  200. TCHAR tszKeys[512];
  201. TCHAR tszName[64];
  202. GetPrivateProfileString(TEXT("MMCPL"), NULL, c_tszNil,
  203. tszKeys, cA(tszKeys), c_tszControlIni);
  204. for (ptsz = tszKeys; ptsz[0]; ptsz += lstrlen(ptsz) + 1) {
  205. /*
  206. * Some legacy keys to ignore:
  207. *
  208. * NumApps= <number of applets>
  209. * H= <height>
  210. * W= <width>
  211. * X= <x coordinate>
  212. * Y= <y coordinate>
  213. */
  214. if (lstrcmpi(ptsz, TEXT("NumApps")) == 0) {
  215. continue;
  216. }
  217. if (ptsz[1] == TEXT('\0')) {
  218. switch (ptsz[0]) {
  219. case 'H':
  220. case 'W':
  221. case 'X':
  222. case 'Y': continue;
  223. }
  224. }
  225. /*
  226. * End of wacky legacy keys.
  227. */
  228. GetPrivateProfileString(TEXT("MMCPL"), ptsz, c_tszNil,
  229. tszName, cA(tszName), c_tszControlIni);
  230. Control_AddCpl(hwnd, tszName);
  231. }
  232. }
  233. /*****************************************************************************
  234. *
  235. * Control_InitControls3
  236. *
  237. * Enumerate all the *.CPL files in the System folder
  238. * and add them to the list.
  239. *
  240. *****************************************************************************/
  241. void PASCAL
  242. Control_InitControls3(HWND hwnd)
  243. {
  244. WIN32_FIND_DATA wfd;
  245. HANDLE h;
  246. TCHAR tszSystemDir[MAX_PATH];
  247. TCHAR tszPrevDir[MAX_PATH];
  248. if (GetCurrentDirectory(cA(tszPrevDir), tszPrevDir) && /* For restore */
  249. GetSystemDirectory(tszSystemDir, MAX_PATH) &&
  250. SetCurrentDirectory(tszSystemDir)) {
  251. h = FindFirstFile(c_tszStarCpl, &wfd);
  252. if (h != INVALID_HANDLE_VALUE) {
  253. do {
  254. Control_AddCpl(hwnd, wfd.cFileName);
  255. } while (FindNextFile(h, &wfd)) ;
  256. FindClose(h);
  257. }
  258. SetCurrentDirectory(tszPrevDir);
  259. }
  260. }
  261. /*****************************************************************************
  262. *
  263. * Control_OnInitDialog
  264. *
  265. * Enumerate all the *.CPL files and add them to the list.
  266. *
  267. *****************************************************************************/
  268. BOOL PASCAL
  269. Control_OnInitDialog(HWND hwnd)
  270. {
  271. HCURSOR hcurPrev = GetCursor();
  272. SetCursor(LoadCursor(0, IDC_WAIT));
  273. ZeroMemory(pcpii, cbX(*pcpii));
  274. LoadString(hinstCur, IDS_CPL_BORING, g_tszBoring, cA(g_tszBoring));
  275. if (Misc_InitPgxa(&pcpii->gxa, cbX(CPL))) {
  276. Control_InitControls2(hwnd);
  277. Control_InitControls3(hwnd);
  278. }
  279. SetCursor(hcurPrev);
  280. return 1;
  281. }
  282. /*****************************************************************************
  283. *
  284. * Control_OnDestroy
  285. *
  286. * Free the memory we allocated.
  287. *
  288. *****************************************************************************/
  289. void PASCAL
  290. Control_OnDestroy(HWND hdlg)
  291. {
  292. Misc_FreePgxa(&pcpii->gxa);
  293. }
  294. /*****************************************************************************
  295. *
  296. * Control_LV_Dirtify
  297. *
  298. * Mark this item as having been changed during the property sheet
  299. * page's lifetime.
  300. *
  301. *****************************************************************************/
  302. void PASCAL
  303. Control_LV_Dirtify(LPARAM icpl)
  304. {
  305. // pcpii->pcpl[icpl].cplfl |= cplflEdited;
  306. }
  307. /*****************************************************************************
  308. *
  309. * Control_OnApply
  310. *
  311. * Write the changes out.
  312. *
  313. *****************************************************************************/
  314. void PASCAL
  315. Control_OnApply(HWND hdlg)
  316. {
  317. HWND hwnd = GetDlgItem(hdlg, IDC_ICONLV);
  318. int cItems = ListView_GetItemCount(hwnd);
  319. BOOL fChanged = 0;
  320. LV_ITEM lvi;
  321. for (lvi.iItem = 0; lvi.iItem < cItems; lvi.iItem++) {
  322. PCPL pcpl;
  323. lvi.stateMask = LVIS_STATEIMAGEMASK;
  324. Misc_LV_GetItemInfo(hwnd, &lvi, lvi.iItem, LVIF_PARAM | LVIF_STATE);
  325. pcpl = pcplPlvi(&lvi);
  326. if (Control_GetShowState(pcpl->tszFile) != LV_IsChecked(&lvi)) {
  327. fChanged = 1;
  328. Control_SetShowState(pcpl->tszFile, LV_IsChecked(&lvi));
  329. }
  330. }
  331. if (fChanged) {
  332. ChangeNotifyCsidl(hdlg, CSIDL_CONTROLS, SHCNE_UPDATEDIR);
  333. }
  334. }
  335. /*****************************************************************************
  336. *
  337. * Oh yeah, we need this too.
  338. *
  339. *****************************************************************************/
  340. #pragma BEGIN_CONST_DATA
  341. LVV lvvControl = {
  342. 0, /* Control_OnCommand */
  343. 0, /* Control_LV_OnInitContextMenu */
  344. Control_LV_Dirtify,
  345. 0, /* Control_LV_GetIcon */
  346. Control_OnInitDialog,
  347. Control_OnApply,
  348. Control_OnDestroy,
  349. 0, /* Control_OnSelChange */
  350. 7, /* iMenu */
  351. rgdwHelp,
  352. 0, /* Double-click action */
  353. lvvflCanCheck, /* We need check boxes */
  354. NULL,
  355. };
  356. #pragma END_CONST_DATA
  357. /*****************************************************************************
  358. *
  359. * Our window procedure.
  360. *
  361. *****************************************************************************/
  362. INT_PTR EXPORT
  363. Control_DlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam)
  364. {
  365. return LV_DlgProc(&lvvControl, hdlg, wm, wParam, lParam);
  366. }