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.

1059 lines
27 KiB

  1. /*
  2. * tweakui - User interface customization
  3. */
  4. #include "tweakui.h"
  5. #include <string.h>
  6. /*
  7. * Because prsht.h doesn't define it.
  8. */
  9. typedef struct _PROPSHEETPAGE_V1 {
  10. DWORD dwSize;
  11. DWORD dwFlags;
  12. HINSTANCE hInstance;
  13. union {
  14. LPCSTR pszTemplate;
  15. LPCDLGTEMPLATE pResource;
  16. } DUMMYUNIONNAME;
  17. union {
  18. HICON hIcon;
  19. LPCSTR pszIcon;
  20. } DUMMYUNIONNAME2;
  21. LPCTSTR pszTitle;
  22. DLGPROC pfnDlgProc;
  23. LPARAM lParam;
  24. LPFNPSPCALLBACK pfnCallback;
  25. UINT FAR * pcRefParent;
  26. } PROPSHEETPAGE_V0, *LPPROPSHEETPAGE_V0;
  27. #pragma BEGIN_CONST_DATA
  28. HKEY CODESEG c_hkCR = hkCR;
  29. HKEY CODESEG c_hkCU = hkCU;
  30. HKEY CODESEG c_hkLM = hkLM;
  31. KL const c_klNoRegedit = { &g_hkCUSMWCV, c_tszPoliciesSystem, c_tszNoRegedit };
  32. KL const c_klIEVersion = { &g_hkLMSMIE, NULL, c_tszVersion };
  33. #pragma END_CONST_DATA
  34. /*
  35. * Globals
  36. */
  37. TCH g_tszName[80]; /* Program name goes here */
  38. TCH g_tszMsdosSys[] = TEXT("@:\\MSDOS.SYS"); /* Boot file */
  39. TCH g_tszPathShell32[MAX_PATH]; /* Full path to shell32.dll */
  40. TCH g_tszPathMe[MAX_PATH]; /* Full path to myself */
  41. PSF psfDesktop; /* Desktop IShellFolder */
  42. HKEY g_hkLMSMWCV; /* HKLM\Software\MS\Win\CurrentVer */
  43. HKEY g_hkCUSMWCV; /* HKCU\Software\MS\Win\CurrentVer */
  44. HKEY g_hkLMSMIE; /* HKLM\Software\MS\IE */
  45. HKEY g_hkCUSMIE; /* HKCU\Software\MS\IE */
  46. HKEY g_hkLMSMWNTCV; /* HKLM\Software\MS\Win (NT)?\CurrentVer */
  47. HINSTANCE hinstCur;
  48. DWORD g_dwShellVer;
  49. UINT g_flWeirdStuff; /* What components are weird */
  50. #define MIT_Item(a, b) b, /* Emit the ordinal and tag */
  51. /*
  52. * LOWORD(c_umit[iit]) == ordinal to obtain
  53. * HIWORD(c_umit[iit]) == 1 if we can survive without the function
  54. */
  55. const DWORD c_umit[] = {
  56. MIT_Contents
  57. };
  58. #undef MIT_Item
  59. MIT mit;
  60. /*
  61. * Instanced
  62. */
  63. CDII cdii;
  64. /*****************************************************************************
  65. *
  66. * iFromPtsz
  67. *
  68. * Parse an integer out of a string, skipping leading spaces.
  69. * Returns iErr on error.
  70. *
  71. *****************************************************************************/
  72. int PASCAL
  73. iFromPtsz(LPTSTR ptsz)
  74. {
  75. int i;
  76. int sign;
  77. while (*ptsz == ' ') ptsz++;
  78. if (*ptsz == '-') {
  79. sign = -1;
  80. ptsz++;
  81. } else {
  82. sign = 1;
  83. }
  84. for (i = 0; (unsigned)(*ptsz - '0') < 10; ptsz++) {
  85. i = i * 10 + (*ptsz - '0');
  86. if (i < 0) return iErr;
  87. }
  88. return sign * i;
  89. }
  90. /*****************************************************************************
  91. *
  92. * StrChr
  93. *
  94. * Return the first occurrence of ch in psz, or 0 if none.
  95. *
  96. *****************************************************************************/
  97. LPTSTR PASCAL
  98. ptszStrChr(LPCTSTR ptsz, TCH tch)
  99. {
  100. for ( ; *ptsz; ptsz = CharNext(ptsz)) {
  101. if (*ptsz == tch) return (LPTSTR)ptsz;
  102. }
  103. return 0;
  104. }
  105. /*****************************************************************************
  106. *
  107. * ParseIconSpec
  108. *
  109. * Given an icon spec of the form "DLL,icon", parse out the icon
  110. * index and return it, changing the comma to a null, so that the
  111. * remaining stuff is a valid DLL name.
  112. *
  113. * If no comma is found, then the entire string is a DLL name,
  114. * and the icon index is zero.
  115. *
  116. *****************************************************************************/
  117. int PASCAL
  118. ParseIconSpec(LPTSTR ptszSrc)
  119. {
  120. LPTSTR ptsz = ptszStrChr(ptszSrc, ',');
  121. if (ptsz) {
  122. *ptsz = '\0';
  123. return iFromPtsz(ptsz+1);
  124. } else {
  125. return 0;
  126. }
  127. }
  128. /*****************************************************************************
  129. *
  130. * LoadIconId
  131. *
  132. * Load an icon by identifier.
  133. *
  134. *****************************************************************************/
  135. HICON PASCAL
  136. LoadIconId(UINT id)
  137. {
  138. return LoadIcon(hinstCur, MAKEINTRESOURCE(id));
  139. }
  140. /*****************************************************************************
  141. *
  142. * SafeDestroyIcon
  143. *
  144. * DestroyIcon, except it doesn't try to destroy the null icon.
  145. *
  146. *****************************************************************************/
  147. void PASCAL
  148. SafeDestroyIcon(HICON hicon)
  149. {
  150. if (hicon) {
  151. DestroyIcon(hicon);
  152. }
  153. }
  154. /*****************************************************************************
  155. *
  156. * InitOpenFileName
  157. *
  158. * Initialize a COFN structure.
  159. *
  160. *****************************************************************************/
  161. void PASCAL
  162. InitOpenFileName(HWND hwnd, PCOFN pcofn, UINT ids, LPCSTR pszInit)
  163. {
  164. int itchMax;
  165. TCH tch;
  166. ZeroMemory(&pcofn->ofn, sizeof(pcofn->ofn));
  167. pcofn->ofn.lStructSize |= sizeof(pcofn->ofn);
  168. pcofn->ofn.hwndOwner = hwnd;
  169. pcofn->ofn.lpstrFilter = pcofn->tszFilter;
  170. pcofn->ofn.lpstrFile = pcofn->tsz;
  171. pcofn->ofn.nMaxFile = MAX_PATH;
  172. pcofn->ofn.Flags |= OFN_HIDEREADONLY;
  173. /* Get the filter string */
  174. itchMax = LoadString(hinstCur, ids, pcofn->tszFilter, cA(pcofn->tszFilter));
  175. if (itchMax) {
  176. /* Marker character must not be DBCS */
  177. tch = pcofn->tszFilter[itchMax-1];
  178. LPTSTR ptsz = pcofn->tszFilter;
  179. while (ptsz < &pcofn->tszFilter[itchMax]) {
  180. if (*ptsz == tch) *ptsz++ = '\0';
  181. else ptsz = CharNext(ptsz);
  182. }
  183. }
  184. /* Set the initial value */
  185. lstrcpyn(pcofn->tsz, pszInit, cA(pcofn->tsz));
  186. }
  187. /*****************************************************************************
  188. *
  189. * MessageBoxId
  190. *
  191. * Wrapper for MessageBox that uses an id instead of a string.
  192. *
  193. *****************************************************************************/
  194. int PASCAL
  195. MessageBoxId(HWND hwnd, UINT id, LPCSTR pszTitle, UINT fl)
  196. {
  197. char szBuf[256];
  198. LoadString(hinstCur, id, szBuf, cA(szBuf));
  199. return MessageBox(hwnd, szBuf, pszTitle, fl);
  200. }
  201. /*****************************************************************************
  202. *
  203. * TweakUi_TrimTrailingBs
  204. *
  205. * Bs stands for backslash. Returns pointer to trailing 0.
  206. *
  207. *****************************************************************************/
  208. PTSTR PASCAL
  209. TweakUi_TrimTrailingBs(LPTSTR ptsz)
  210. {
  211. ptsz = ptszFilenameCqn(ptsz);
  212. if (ptsz[0] == TEXT('\0')) {
  213. *--ptsz = TEXT('\0');
  214. } else {
  215. ptsz += lstrlen(ptsz);
  216. }
  217. return ptsz;
  218. }
  219. /*****************************************************************************
  220. *
  221. * TweakUi_BuildPathToFile
  222. *
  223. * Callback procedure (GetWindowsDirectory or GetSystemDirectory)
  224. * generates the base directory. Then we cat the file to the path.
  225. *
  226. * ptszOut must be MAX_PATH bytes in length.
  227. *
  228. *****************************************************************************/
  229. typedef UINT (CALLBACK *PATHPROC)(LPTSTR, UINT);
  230. void PASCAL
  231. TweakUi_BuildPathToFile(PTSTR ptszOut, PATHPROC pfn, LPCTSTR ptszFile)
  232. {
  233. pfn(ptszOut, MAX_PATH);
  234. Path_Append(ptszOut, ptszFile);
  235. }
  236. /*****************************************************************************
  237. *
  238. * BuildRundll
  239. *
  240. * ptszOut must be 1024 bytes in length.
  241. *
  242. * ptszInUn is "I" for DefaultInstall, and "Uni" for DefaultUninstall.
  243. *
  244. * Builds the string
  245. *
  246. * "<windir>\rundll.exe setupx.dll,InstallHinfSection Default<x>nstall 4 "
  247. *
  248. * Returns a pointer to the terminating null, so you can put the
  249. * inf file name into place.
  250. *
  251. *****************************************************************************/
  252. LPTSTR PASCAL
  253. BuildRundll(LPTSTR ptszOut, LPCTSTR ptszInUn)
  254. {
  255. TCH tszWindir[MAX_PATH];
  256. TweakUi_BuildPathToFile(tszWindir, GetWindowsDirectory, c_tszNil);
  257. return ptszOut + wsprintf(ptszOut, g_fNT ?
  258. c_tszFormatRundllNT : c_tszFormatRundll, tszWindir, ptszInUn);
  259. }
  260. /*****************************************************************************
  261. *
  262. * RunShellInf
  263. *
  264. * Re-run the shell.inf file to fix the registry.
  265. *
  266. * The bad news is that CtlGetLdidPath is 16-bit, and we aren't.
  267. *
  268. * The "good" news is that there is currently no override to
  269. * put the Inf directory anywhere other than Windows\Inf, so we
  270. * can hard-code the Inf subdirectory name.
  271. *
  272. *****************************************************************************/
  273. void PASCAL
  274. RunShellInf(HWND hwnd)
  275. {
  276. TCH tszOut[1024];
  277. TweakUi_BuildPathToFile(BuildRundll(tszOut, c_tszI), GetWindowsDirectory,
  278. c_tszInfBsShellInf);
  279. WinExec(tszOut, SW_NORMAL);
  280. }
  281. /*****************************************************************************
  282. *
  283. * InitPpspDidDp
  284. *
  285. * Initialize a single PROPSHEETPAGE to load the dialog resource did
  286. * with dialog procedure dp.
  287. *
  288. * We must use the original property sheet page structure because
  289. * we need to run on Win95 Golden, which has the old comctl32.
  290. *
  291. * In particular, we cannot use DS_SHELLFONT because the old comctl32
  292. * does not support DIALOGEX, which DS_SHELLFONT requires.
  293. *
  294. *****************************************************************************/
  295. void PASCAL
  296. InitPpspResDp(LPPROPSHEETHEADER ppsh, LPCTSTR ptszDlg, DLGPROC dp)
  297. {
  298. LPPROPSHEETPAGE_V0 ppsp;
  299. #ifdef DEBUG
  300. if (ppsh->nPages >= MAX_TWEAKUIPAGES) {
  301. DebugBreak();
  302. }
  303. {
  304. HRSRC hrsrc = FindResource(hinstCur, ptszDlg, RT_DIALOG);
  305. LPDLGTEMPLATE pdt = (LPDLGTEMPLATE)LoadResource(hinstCur, hrsrc);
  306. if (pdt && HIWORD(pdt->style) != 0xFFFF) {
  307. /* Template is okay */
  308. } else {
  309. /* ERROR! Win95 Golden does not support DIALOGEX */
  310. DebugBreak();
  311. }
  312. }
  313. #endif
  314. ppsp = (LPPROPSHEETPAGE_V0)ppsh->ppsp;
  315. ppsp = &ppsp[ppsh->nPages++];
  316. ppsp->dwSize = sizeof(PROPSHEETPAGE_V0);
  317. ppsp->dwFlags = PSP_DEFAULT;
  318. ppsp->hInstance = hinstCur;
  319. ppsp->pszTemplate = ptszDlg;
  320. ppsp->pfnDlgProc = dp;
  321. /* ppsp->lParam = ??; */ /* No refdata needed */
  322. }
  323. #define InitPpspDidDp(ppsh, did, dp) \
  324. InitPpspResDp(ppsh, MAKEINTRESOURCE(did), dp)
  325. /*****************************************************************************
  326. *
  327. * Open
  328. *
  329. * Start the show.
  330. *
  331. *****************************************************************************/
  332. void PASCAL
  333. Open(HWND hwnd)
  334. {
  335. PROPSHEETPAGE_V0 rgpsp[MAX_TWEAKUIPAGES];
  336. PROPSHEETHEADER psh;
  337. /*
  338. * Make us Alt+Tab'able by removing WS_EX_TOOLWINDOW from our
  339. * parent's extended window style.
  340. */
  341. SetWindowLong(hwnd, GWL_EXSTYLE,
  342. (LONG)(GetWindowExStyle(hwnd) & ~WS_EX_TOOLWINDOW));
  343. /*
  344. * Give our hidden parent an icon so the user can Alt+Tab to it.
  345. */
  346. SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)
  347. LoadIcon(hinstCur, MAKEINTRESOURCE(IDI_DEFAULT)));
  348. /* Init our cached pidls */
  349. pcdii->pidlTemplates = NULL;
  350. SHGetSpecialFolderLocation(0, CSIDL_TEMPLATES, &pcdii->pidlTemplates);
  351. psh.dwSize = PROPSHEETHEADER_V1_SIZE;
  352. psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK;
  353. psh.hwndParent = hwnd;
  354. psh.pszCaption = g_tszName;
  355. psh.nPages = 0;
  356. psh.nStartPage = 0;
  357. psh.ppsp = (PROPSHEETPAGE*)rgpsp;
  358. psh.pfnCallback = Prsht_PropertySheetCallback;
  359. InitPpspDidDp(&psh, IDD_MOUSE, Mouse_DlgProc);
  360. InitPpspDidDp(&psh, IDD_GENERAL, General_DlgProc);
  361. InitPpspDidDp(&psh, IDD_EXPLORER, Explorer_DlgProc);
  362. /*
  363. * Display IE4 only if IE4 is installed.
  364. */
  365. if (g_fIE4) {
  366. InitPpspDidDp(&psh, IDD_IE4, IE4_DlgProc);
  367. }
  368. /*
  369. * Display CMD only if NT5 is installed.
  370. */
  371. if (g_fNT5) {
  372. InitPpspDidDp(&psh, IDD_CMD, Cmd_DlgProc);
  373. }
  374. InitPpspDidDp(&psh, IDD_DESKTOP, Desktop_DlgProc);
  375. /*
  376. * Display My Computer only if the user has permission to
  377. * edit the appropriate registry key.
  378. */
  379. if (RegCanModifyKey(g_hkCUSMWCV, c_tszRestrictions)) {
  380. InitPpspDidDp(&psh, IDD_MYCOMP, MyComp_DlgProc);
  381. }
  382. InitPpspDidDp(&psh, IDD_CONTROL, Control_DlgProc);
  383. /*
  384. * Display Network only if the user has permission to
  385. * edit the appropriate registry key.
  386. */
  387. if (RegCanModifyKey(g_hkLMSMWNTCV, c_tszWinlogon)) {
  388. InitPpspDidDp(&psh, IDD_NETWORK, Network_DlgProc);
  389. }
  390. if (pcdii->pidlTemplates) {
  391. InitPpspDidDp(&psh, IDD_TOOLS, Template_DlgProc);
  392. }
  393. /*
  394. * Add/Remove Programs on NT5 is completely different.
  395. */
  396. if (!g_fNT5) {
  397. InitPpspDidDp(&psh, IDD_ADDREMOVE, AddRm_DlgProc);
  398. }
  399. #ifdef _X86_
  400. if (g_tszMsdosSys[0] && !g_fNT && !g_fMillennium) {
  401. InitPpspDidDp(&psh, IDD_BOOT, Boot_DlgProc);
  402. }
  403. #endif
  404. InitPpspDidDp(&psh, IDD_REPAIR, Repair_DlgProc);
  405. InitPpspDidDp(&psh, IDD_PARANOIA, Paranoia_DlgProc);
  406. /*
  407. * Common dialog features.
  408. */
  409. if (RegCanModifyKey(g_hkCUSMWCV, TEXT("Policies")) &&
  410. GetProcAddress(GetModuleHandle("COMDLG32"), "PrintDlgExA"))
  411. {
  412. InitPpspDidDp(&psh, IDD_COMDLG32, Comdlg32_DlgProc);
  413. }
  414. pcdii->hmenu = LoadMenu(hinstCur, MAKEINTRESOURCE(IDM_MAIN));
  415. _RegOpenKey(HKEY_CLASSES_ROOT, c_tszClsid, &pcdii->hkClsid);
  416. pcdii->himlState = ImageList_LoadImage(hinstCur, MAKEINTRESOURCE(IDB_CHECK),
  417. 0, 2, CLR_NONE, IMAGE_BITMAP, LR_LOADTRANSPARENT);
  418. pcdii->fRunShellInf = 0;
  419. #ifndef DEBUG
  420. /* Reinstall our run key in case somebody nuked it */
  421. SetRegStr(g_hkLMSMWCV, c_tszRun, g_tszName, c_tszFixLink);
  422. #endif
  423. #if defined(PRERELEASE) || defined(PUBLIC_PRERELEASE)
  424. if (!IsExpired(hwnd))
  425. #endif
  426. switch (PropertySheet(&psh)) {
  427. case ID_PSRESTARTWINDOWS:
  428. if (pcdii->fRunShellInf) {
  429. RunShellInf(hwnd);
  430. }
  431. MessageBoxId(hwnd, IDS_LOGONOFF, g_tszName, MB_OK);
  432. break;
  433. }
  434. RegCloseKey(pcdii->hkClsid);
  435. if (pcdii->hmenu)
  436. DestroyMenu(pcdii->hmenu);
  437. /* Now free them cached shell things */
  438. Ole_Free(pcdii->pidlTemplates);
  439. }
  440. /*****************************************************************************
  441. *
  442. * TweakUi_OnBadRun
  443. *
  444. * Somebody double-clicked our icon, but we aren't being run as
  445. * a control panel. Offer to install.
  446. *
  447. *****************************************************************************/
  448. void PASCAL
  449. TweakUi_OnBadRun(HWND hwnd)
  450. {
  451. if (MessageBoxId(hwnd, IDS_BADRUN, g_tszName, MB_YESNO) == IDYES) {
  452. TCH tszOut[1024];
  453. PTSTR ptsz;
  454. ptsz = BuildRundll(tszOut, c_tszI);
  455. lstrcpy(ptsz, g_tszPathMe);
  456. PTSTR ptszExt = ptszStrRChr(ptsz, TEXT('.'));
  457. if (ptszExt) {
  458. strcpy(ptszExt, c_tszDotInf);
  459. if (GetFileAttributes(ptsz) != (DWORD)-1) {
  460. WinExec(tszOut, SW_NORMAL);
  461. } else {
  462. MessageBoxId(hwnd, IDS_CANTINSTALL, g_tszName, MB_OK);
  463. }
  464. } else {
  465. MessageBoxId(hwnd, IDS_CANTINSTALL, g_tszName, MB_OK);
  466. }
  467. }
  468. }
  469. /*****************************************************************************
  470. *
  471. * CriticalInit
  472. *
  473. * Here is where we put the stuff to impede reverse-engineering.
  474. *
  475. * 1. All of our strings are encoded. Decode them now.
  476. *
  477. * 2. Get the shell32 internal entry points via GetProcAddress
  478. * so that a "hdr" won't see them.
  479. *
  480. *****************************************************************************/
  481. HRESULT PASCAL
  482. CriticalInit(void)
  483. {
  484. int itch;
  485. int iit;
  486. HINSTANCE hinst;
  487. itch = cA(c_rgtchCommon)-1;
  488. do {
  489. c_rgtchCommon[itch] ^= c_rgtchCommon[itch-1];
  490. } while (--itch);
  491. hinst = GetModuleHandle(c_tszShell32Dll);
  492. for (iit = 0; iit < sizeof(mit) / sizeof(LPCSTR); iit++) {
  493. DWORD dwOrd = c_umit[iit];
  494. ((FARPROC *)&mit)[iit] = GetProcAddress(hinst, MAKEINTRESOURCE(dwOrd));
  495. if (((FARPROC *)&mit)[iit] == 0 && !HIWORD(dwOrd)) {
  496. return E_FAIL;
  497. }
  498. }
  499. return Ole_Init();
  500. }
  501. /*****************************************************************************
  502. *
  503. * GetObjectBuild
  504. *
  505. * Get the build number on the specified module, in the form
  506. *
  507. * 0xMMmmbbbb
  508. *
  509. * MM = major
  510. * mm = minor
  511. * bbbb = build
  512. *
  513. * The input parameter is either an OSVERSIONINFO or a DLLVERSIONINFO.
  514. * Fortunately, the two are the same in the places we care about.
  515. *
  516. *****************************************************************************/
  517. DWORD PASCAL
  518. GetObjectBuild(LPOSVERSIONINFO posv)
  519. {
  520. return MAKELONG(LOWORD(posv->dwBuildNumber),
  521. MAKEWORD(posv->dwMinorVersion,
  522. posv->dwMajorVersion));
  523. }
  524. /*****************************************************************************
  525. *
  526. * GetModuleBuild
  527. *
  528. * Get the build number on the specified module, in the form
  529. *
  530. * 0xMMmmbbbb
  531. *
  532. * MM = major
  533. * mm = minor
  534. * bbbb = build
  535. *
  536. * Returns 0 if DLL does not have DllGetVersion.
  537. *
  538. *****************************************************************************/
  539. DWORD PASCAL
  540. GetModuleBuild(LPCTSTR ptszDll)
  541. {
  542. HINSTANCE hinst = GetModuleHandle(ptszDll);
  543. DLLGETVERSIONPROC DllGetVersion;
  544. DWORD dwRc;
  545. DllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinst, "DllGetVersion");
  546. if (DllGetVersion) {
  547. DLLVERSIONINFO dvi;
  548. dvi.cbSize = sizeof(dvi);
  549. if (SUCCEEDED(DllGetVersion(&dvi))) {
  550. dwRc = GetObjectBuild((LPOSVERSIONINFO)&dvi);
  551. } else {
  552. dwRc = 0;
  553. }
  554. } else {
  555. dwRc = 0;
  556. }
  557. return dwRc;
  558. }
  559. /*****************************************************************************
  560. *
  561. * CheckWin95Versions
  562. *
  563. * Determine whether we're on Win95 OPK2 or later. We already know
  564. * that we're not Windows NT.
  565. *
  566. *****************************************************************************/
  567. void PASCAL
  568. CheckWin95Versions(void)
  569. {
  570. BOOL fRc;
  571. OSVERSIONINFO osv;
  572. osv.dwOSVersionInfoSize = sizeof(osv);
  573. if (GetVersionEx(&osv)) {
  574. DWORD dwBuild = GetObjectBuild(&osv);
  575. if (dwBuild >= MAKELONG(1045, 0x0400)) {
  576. g_flWeirdStuff |= flbsOPK2;
  577. if (dwBuild >= MAKELONG(0, 0x040A)) {
  578. g_flWeirdStuff |= flbsMemphis;
  579. if (dwBuild >= MAKELONG(0, 0x045A)) {
  580. g_flWeirdStuff |= flbsMillennium;
  581. }
  582. }
  583. }
  584. }
  585. }
  586. /*****************************************************************************
  587. *
  588. * LibMain
  589. *
  590. * Initialize globals.
  591. *
  592. * Get our own name.
  593. *
  594. * Get our own path.
  595. *
  596. * Build path to shell32.dll.
  597. *
  598. *****************************************************************************/
  599. BOOL FAR PASCAL LibMain(HINSTANCE hinst)
  600. {
  601. if (SUCCEEDED(CriticalInit())) {
  602. DWORD dwBuild;
  603. DWORD dwVersion;
  604. RegCreateKey(HKEY_LOCAL_MACHINE, c_tszSMWCV, &g_hkLMSMWCV);
  605. RegCreateKey(HKEY_CURRENT_USER, c_tszSMWCV, &g_hkCUSMWCV);
  606. RegCreateKey(g_hkLMSMWCV, c_tszExplorer, &pcdii->hkLMExplorer);
  607. RegCreateKey(g_hkCUSMWCV, c_tszExplorer, &pcdii->hkCUExplorer);
  608. RegOpenKey(hkLM, c_tszSMWIE, &g_hkLMSMIE);
  609. RegOpenKey(hkCU, c_tszSMWIE, &g_hkCUSMIE);
  610. hinstCur = hinst;
  611. LoadString(hinst, IDS_NAME, g_tszName, cA(g_tszName));
  612. dwBuild = GetModuleBuild(c_tszComCtl32Dll);
  613. if (dwBuild == 0) {
  614. g_flWeirdStuff |= flbsComCtl32;
  615. }
  616. if (dwBuild >= MAKELONG(0, 0x447)) { /* 4.71 */
  617. g_flWeirdStuff |= flbsSmoothScroll;
  618. }
  619. dwVersion = GetVersion();
  620. if ((LONG)dwVersion >= 0) {
  621. g_flWeirdStuff |= flbsNT;
  622. if (LOBYTE(dwVersion) >= 5) {
  623. g_flWeirdStuff |= flbsNT5;
  624. }
  625. } else {
  626. CheckWin95Versions();
  627. }
  628. g_dwShellVer = dwBuild = GetModuleBuild(c_tszShell32Dll);
  629. if (dwBuild || g_fNT) {
  630. g_flWeirdStuff |= flbsShellSz;
  631. }
  632. /*
  633. * Some things need to be turned off if IE5. Go figure.
  634. * Borrow g_tszPathMe for scratch space.
  635. */
  636. if (GetStrPkl(g_tszPathMe, cA(g_tszPathMe), &c_klIEVersion) &&
  637. iFromPtsz(g_tszPathMe) >= 5) {
  638. g_flWeirdStuff |= flbsIE5;
  639. }
  640. GetModuleFileName(hinst, g_tszPathMe, cA(g_tszPathMe));
  641. /*
  642. * Check if we're being run from the proper directory.
  643. */
  644. TweakUi_BuildPathToFile(g_tszPathShell32, GetSystemDirectory,
  645. c_tszTweakUICpl);
  646. if (lstrcmpi(g_tszPathMe, g_tszPathShell32)) {
  647. #ifndef DEBUG
  648. g_flWeirdStuff |= flbsBadRun; /* Nope */
  649. #endif
  650. }
  651. /*
  652. * Stash the location of shell32.
  653. */
  654. TweakUi_BuildPathToFile(g_tszPathShell32, GetSystemDirectory,
  655. c_tszShell32Dll);
  656. /* See if we have an msdos.sys file to tweak */
  657. #if defined(_X86_)
  658. Boot_FindMsdosSys();
  659. #endif
  660. /*
  661. * Build the platform-sensitive base key.
  662. */
  663. RegCreateKey(hkLM, g_fNT ? c_tszSMWNTCV : c_tszSMWCV, &g_hkLMSMWNTCV);
  664. InitCommonControls();
  665. return 1;
  666. } else {
  667. return 0;
  668. }
  669. }
  670. /*****************************************************************************
  671. *
  672. * LibExit
  673. *
  674. * Clean up globals.
  675. *
  676. *****************************************************************************/
  677. void PASCAL
  678. LibExit(void)
  679. {
  680. if (g_hkCUSMIE) {
  681. RegCloseKey(g_hkCUSMIE);
  682. }
  683. if (g_hkLMSMIE) {
  684. RegCloseKey(g_hkLMSMIE);
  685. }
  686. RegCloseKey(pcdii->hkCUExplorer);
  687. RegCloseKey(pcdii->hkLMExplorer);
  688. RegCloseKey(g_hkLMSMWCV);
  689. RegCloseKey(g_hkLMSMWNTCV);
  690. RegCloseKey(g_hkCUSMWCV);
  691. Ole_Term();
  692. }
  693. /*****************************************************************************
  694. *
  695. * _DllMainCRTStartup
  696. *
  697. * Hi.
  698. *
  699. *****************************************************************************/
  700. STDAPI_(BOOL)
  701. Entry32(HINSTANCE hinst, DWORD dwReason, LPVOID lpReserved)
  702. {
  703. if (dwReason == DLL_PROCESS_ATTACH) {
  704. return LibMain(hinst);
  705. } else if (dwReason == DLL_PROCESS_DETACH) {
  706. LibExit();
  707. }
  708. return TRUE;
  709. }
  710. /*****************************************************************************
  711. *
  712. * CPlApplet
  713. *
  714. * Control panel entry point.
  715. *
  716. *****************************************************************************/
  717. LRESULT EXPORT
  718. CPlApplet(HWND hwnd, UINT wm, LPARAM lp1, LPARAM lp2)
  719. {
  720. switch (wm) {
  721. case CPL_INIT: return 1; /* Yes I'm here */
  722. case CPL_GETCOUNT: return 1; /* I provide one icon */
  723. case CPL_INQUIRE:
  724. if (lp1 == 0) { /* For the zero'th icon... */
  725. LPCPLINFO lpci = (LPCPLINFO)lp2;
  726. lpci->idIcon = IDI_DEFAULT;
  727. lpci->idName = IDS_NAME;
  728. lpci->idInfo = IDS_DESCRIPTION;
  729. /* lpci->lData = 0; */ /* Garbage doesn't hurt */
  730. return 1;
  731. } else {
  732. return 0; /* Huh? */
  733. }
  734. /*
  735. * Note! Do not open if registry tools have been disabled.
  736. *
  737. * This is particularly important for the Network page, which
  738. * lets the user view passwords!
  739. *
  740. * Make this check *before* checking for a bad run, so a
  741. * user can't do an end-run by just double-clicking the CPL.
  742. */
  743. case CPL_DBLCLK: /* Hey, somebody's knocking */
  744. if (GetDwordPkl(&c_klNoRegedit, 0)) {
  745. MessageBoxId(hwnd, IDS_RESTRICTED, g_tszName, MB_OK);
  746. } else if (!g_fBadRun) {
  747. Open(hwnd);
  748. } else {
  749. TweakUi_OnBadRun(hwnd);
  750. }
  751. break;
  752. }
  753. return 0;
  754. }
  755. /*****************************************************************************
  756. *
  757. * WithSelector
  758. *
  759. * Call the callback after creating a particular selector alias to a
  760. * chunk of memory. The memory block is confirmed for read access,
  761. * or for write access if fWrite is set.
  762. *
  763. * Note that the validation doesn't work in Win16 if the data crosses
  764. * a page boundary, so be careful.
  765. *
  766. *****************************************************************************/
  767. BOOL PASCAL
  768. WithSelector(DWORD_PTR lib, UINT cb, WITHPROC wp, LPVOID pvRef, BOOL fWrite)
  769. {
  770. BOOL fRc;
  771. #ifdef WIN32
  772. #define lpv (LPVOID)lib
  773. #else
  774. UINT sel = AllocSelector((UINT)hinstCur);
  775. if (sel) {
  776. SetSelectorBase(sel, lib);
  777. SetSelectorLimit(sel, cb);
  778. #define lpv MAKELP(sel, 0)
  779. #endif
  780. if (!IsBadReadPtr(lpv, cb) && !(fWrite && IsBadWritePtr(lpv, cb))) {
  781. fRc = wp(lpv, pvRef);
  782. } else {
  783. fRc = 0;
  784. }
  785. #undef lpv
  786. #ifndef WIN32
  787. FreeSelector(sel);
  788. } else {
  789. fRc = 0;
  790. }
  791. #endif
  792. return fRc;
  793. }
  794. /*****************************************************************************
  795. *
  796. * TweakUi_OnLogon
  797. *
  798. * This hacks around two bugs.
  799. *
  800. * The first is a bug in Shell32, where a bad comparison causes the
  801. * Link registry key not to be restored properly. So we patch the
  802. * correct value into the registry for them.
  803. *
  804. * The second is a bug in commctrl where it gets confused by overlay
  805. * bitmaps with no pixels.
  806. *
  807. * And then we do the paranoia stuff.
  808. *
  809. *****************************************************************************/
  810. void PASCAL
  811. TweakUi_OnLogon(void)
  812. {
  813. UINT cxIcon;
  814. /*
  815. * This shell bug was fixed sometime before July 1997, though I
  816. * can't tell exactly when. Definitely fixed before the ShellSz
  817. * support was added, so let's just use that.
  818. */
  819. if (!g_fShellSz && !Link_GetShortcutTo()) {
  820. Link_SetShortcutTo(1);
  821. Link_SetShortcutTo(0);
  822. }
  823. /*
  824. * If the shell icon size is wacked out for some bizarre reason,
  825. * then unwack it. This is theoretically impossible, but somehow
  826. * it happens, so we fix it ex post facto.
  827. */
  828. cxIcon = Misc_GetShellIconSize();
  829. if (((cxIcon + 1) & 0x1F) == 0) {
  830. Misc_SetShellIconSize(cxIcon + 1);
  831. }
  832. Explorer_HackPtui();
  833. Paranoia_CoverTracks();
  834. }
  835. /*****************************************************************************
  836. *
  837. * TweakUi_OnInstall
  838. *
  839. * Upgrade the previous version of Tweak UI.
  840. *
  841. * 1. Fix the LinkOverlay gizmo. If we have a buggy ComCtl32 and the
  842. * overlay is set to IDI_BLANK - 1, then set HackPtui.
  843. *
  844. #ifdef UPGRADE_V1_ICON
  845. * 2. Rebuild the icon cache, to work around a bug in the control panel,
  846. * where it doesn't update its cached image properly when the cpl changes.
  847. #endif
  848. *
  849. *****************************************************************************/
  850. void PASCAL
  851. TweakUi_OnInstall(void)
  852. {
  853. TCHAR tsz[MAX_PATH];
  854. if (g_fBuggyComCtl32 &&
  855. Explorer_GetIconSpecFromRegistry(tsz) == IDI_BLANK - 1 &&
  856. lstrcmpi(tsz, g_tszPathMe) == 0) {
  857. SetIntPkl(1, &c_klHackPtui);
  858. }
  859. #ifdef UPGRADE_V1_ICON
  860. /*
  861. * We no longer try to upgrade the V1 icon because it tickles
  862. * the shell icon cache in a way that may expose pre-existing
  863. * corruption.
  864. */
  865. Misc_RebuildIcoCache();
  866. #endif
  867. }
  868. /*****************************************************************************
  869. *
  870. * TweakUi_OnFix
  871. *
  872. * Put our Uninstall script back into the registry.
  873. *
  874. *****************************************************************************/
  875. #pragma BEGIN_CONST_DATA
  876. KL const c_klDisplayName =
  877. { &g_hkLMSMWCV, c_tszUninstallTweakUI, c_tszDisplayName };
  878. KL const c_klUninstallString =
  879. { &g_hkLMSMWCV, c_tszUninstallTweakUI, c_tszUninstallString };
  880. #pragma END_CONST_DATA
  881. void EXPORT
  882. TweakUi_OnFix(HWND hwnd, BOOL fVerbose)
  883. {
  884. TCH tszOut[1024];
  885. SetStrPkl(&c_klDisplayName, g_tszName);
  886. TweakUi_BuildPathToFile(BuildRundll(tszOut, c_tszUni), GetWindowsDirectory,
  887. c_tszInfBsTweakuiInf);
  888. SetStrPkl(&c_klUninstallString, tszOut);
  889. if (fVerbose) {
  890. MessageBoxId(hwnd, IDS_FIXED, g_tszName, MB_OK);
  891. }
  892. }
  893. /*****************************************************************************
  894. *
  895. * TweakMeUp
  896. *
  897. * Rundll entry point.
  898. *
  899. * The command line tells us what we're trying to do.
  900. *
  901. * Null command line - User has just logged on; do logon stuff.
  902. *
  903. * '0' - We've just been installed; upgrade the previous version.
  904. * Since unisntalling on NT is different from on Win95, we fall
  905. * through to...
  906. *
  907. * '1' - The user wants to restore the Uninstall string.
  908. *
  909. *****************************************************************************/
  910. void EXPORT
  911. TweakMeUp(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
  912. {
  913. switch (lpszCmdLine[0]) {
  914. case '\0': TweakUi_OnLogon(); break;
  915. case '0': TweakUi_OnInstall(); TweakUi_OnFix(hwnd, 0); break;
  916. case '1': TweakUi_OnFix(hwnd, 1); break;
  917. }
  918. }