/* * tweakui - User interface customization */ #include "tweakui.h" #include /* * Because prsht.h doesn't define it. */ typedef struct _PROPSHEETPAGE_V1 { DWORD dwSize; DWORD dwFlags; HINSTANCE hInstance; union { LPCSTR pszTemplate; LPCDLGTEMPLATE pResource; } DUMMYUNIONNAME; union { HICON hIcon; LPCSTR pszIcon; } DUMMYUNIONNAME2; LPCTSTR pszTitle; DLGPROC pfnDlgProc; LPARAM lParam; LPFNPSPCALLBACK pfnCallback; UINT FAR * pcRefParent; } PROPSHEETPAGE_V0, *LPPROPSHEETPAGE_V0; #pragma BEGIN_CONST_DATA HKEY CODESEG c_hkCR = hkCR; HKEY CODESEG c_hkCU = hkCU; HKEY CODESEG c_hkLM = hkLM; KL const c_klNoRegedit = { &g_hkCUSMWCV, c_tszPoliciesSystem, c_tszNoRegedit }; KL const c_klIEVersion = { &g_hkLMSMIE, NULL, c_tszVersion }; #pragma END_CONST_DATA /* * Globals */ TCH g_tszName[80]; /* Program name goes here */ TCH g_tszMsdosSys[] = TEXT("@:\\MSDOS.SYS"); /* Boot file */ TCH g_tszPathShell32[MAX_PATH]; /* Full path to shell32.dll */ TCH g_tszPathMe[MAX_PATH]; /* Full path to myself */ PSF psfDesktop; /* Desktop IShellFolder */ HKEY g_hkLMSMWCV; /* HKLM\Software\MS\Win\CurrentVer */ HKEY g_hkCUSMWCV; /* HKCU\Software\MS\Win\CurrentVer */ HKEY g_hkLMSMIE; /* HKLM\Software\MS\IE */ HKEY g_hkCUSMIE; /* HKCU\Software\MS\IE */ HKEY g_hkLMSMWNTCV; /* HKLM\Software\MS\Win (NT)?\CurrentVer */ HINSTANCE hinstCur; DWORD g_dwShellVer; UINT g_flWeirdStuff; /* What components are weird */ #define MIT_Item(a, b) b, /* Emit the ordinal and tag */ /* * LOWORD(c_umit[iit]) == ordinal to obtain * HIWORD(c_umit[iit]) == 1 if we can survive without the function */ const DWORD c_umit[] = { MIT_Contents }; #undef MIT_Item MIT mit; /* * Instanced */ CDII cdii; /***************************************************************************** * * iFromPtsz * * Parse an integer out of a string, skipping leading spaces. * Returns iErr on error. * *****************************************************************************/ int PASCAL iFromPtsz(LPTSTR ptsz) { int i; int sign; while (*ptsz == ' ') ptsz++; if (*ptsz == '-') { sign = -1; ptsz++; } else { sign = 1; } for (i = 0; (unsigned)(*ptsz - '0') < 10; ptsz++) { i = i * 10 + (*ptsz - '0'); if (i < 0) return iErr; } return sign * i; } /***************************************************************************** * * StrChr * * Return the first occurrence of ch in psz, or 0 if none. * *****************************************************************************/ LPTSTR PASCAL ptszStrChr(LPCTSTR ptsz, TCH tch) { for ( ; *ptsz; ptsz = CharNext(ptsz)) { if (*ptsz == tch) return (LPTSTR)ptsz; } return 0; } /***************************************************************************** * * ParseIconSpec * * Given an icon spec of the form "DLL,icon", parse out the icon * index and return it, changing the comma to a null, so that the * remaining stuff is a valid DLL name. * * If no comma is found, then the entire string is a DLL name, * and the icon index is zero. * *****************************************************************************/ int PASCAL ParseIconSpec(LPTSTR ptszSrc) { LPTSTR ptsz = ptszStrChr(ptszSrc, ','); if (ptsz) { *ptsz = '\0'; return iFromPtsz(ptsz+1); } else { return 0; } } /***************************************************************************** * * LoadIconId * * Load an icon by identifier. * *****************************************************************************/ HICON PASCAL LoadIconId(UINT id) { return LoadIcon(hinstCur, MAKEINTRESOURCE(id)); } /***************************************************************************** * * SafeDestroyIcon * * DestroyIcon, except it doesn't try to destroy the null icon. * *****************************************************************************/ void PASCAL SafeDestroyIcon(HICON hicon) { if (hicon) { DestroyIcon(hicon); } } /***************************************************************************** * * InitOpenFileName * * Initialize a COFN structure. * *****************************************************************************/ void PASCAL InitOpenFileName(HWND hwnd, PCOFN pcofn, UINT ids, LPCSTR pszInit) { int itchMax; TCH tch; ZeroMemory(&pcofn->ofn, sizeof(pcofn->ofn)); pcofn->ofn.lStructSize |= sizeof(pcofn->ofn); pcofn->ofn.hwndOwner = hwnd; pcofn->ofn.lpstrFilter = pcofn->tszFilter; pcofn->ofn.lpstrFile = pcofn->tsz; pcofn->ofn.nMaxFile = MAX_PATH; pcofn->ofn.Flags |= OFN_HIDEREADONLY; /* Get the filter string */ itchMax = LoadString(hinstCur, ids, pcofn->tszFilter, cA(pcofn->tszFilter)); if (itchMax) { /* Marker character must not be DBCS */ tch = pcofn->tszFilter[itchMax-1]; LPTSTR ptsz = pcofn->tszFilter; while (ptsz < &pcofn->tszFilter[itchMax]) { if (*ptsz == tch) *ptsz++ = '\0'; else ptsz = CharNext(ptsz); } } /* Set the initial value */ lstrcpyn(pcofn->tsz, pszInit, cA(pcofn->tsz)); } /***************************************************************************** * * MessageBoxId * * Wrapper for MessageBox that uses an id instead of a string. * *****************************************************************************/ int PASCAL MessageBoxId(HWND hwnd, UINT id, LPCSTR pszTitle, UINT fl) { char szBuf[256]; LoadString(hinstCur, id, szBuf, cA(szBuf)); return MessageBox(hwnd, szBuf, pszTitle, fl); } /***************************************************************************** * * TweakUi_TrimTrailingBs * * Bs stands for backslash. Returns pointer to trailing 0. * *****************************************************************************/ PTSTR PASCAL TweakUi_TrimTrailingBs(LPTSTR ptsz) { ptsz = ptszFilenameCqn(ptsz); if (ptsz[0] == TEXT('\0')) { *--ptsz = TEXT('\0'); } else { ptsz += lstrlen(ptsz); } return ptsz; } /***************************************************************************** * * TweakUi_BuildPathToFile * * Callback procedure (GetWindowsDirectory or GetSystemDirectory) * generates the base directory. Then we cat the file to the path. * * ptszOut must be MAX_PATH bytes in length. * *****************************************************************************/ typedef UINT (CALLBACK *PATHPROC)(LPTSTR, UINT); void PASCAL TweakUi_BuildPathToFile(PTSTR ptszOut, PATHPROC pfn, LPCTSTR ptszFile) { pfn(ptszOut, MAX_PATH); Path_Append(ptszOut, ptszFile); } /***************************************************************************** * * BuildRundll * * ptszOut must be 1024 bytes in length. * * ptszInUn is "I" for DefaultInstall, and "Uni" for DefaultUninstall. * * Builds the string * * "\rundll.exe setupx.dll,InstallHinfSection Defaultnstall 4 " * * Returns a pointer to the terminating null, so you can put the * inf file name into place. * *****************************************************************************/ LPTSTR PASCAL BuildRundll(LPTSTR ptszOut, LPCTSTR ptszInUn) { TCH tszWindir[MAX_PATH]; TweakUi_BuildPathToFile(tszWindir, GetWindowsDirectory, c_tszNil); return ptszOut + wsprintf(ptszOut, g_fNT ? c_tszFormatRundllNT : c_tszFormatRundll, tszWindir, ptszInUn); } /***************************************************************************** * * RunShellInf * * Re-run the shell.inf file to fix the registry. * * The bad news is that CtlGetLdidPath is 16-bit, and we aren't. * * The "good" news is that there is currently no override to * put the Inf directory anywhere other than Windows\Inf, so we * can hard-code the Inf subdirectory name. * *****************************************************************************/ void PASCAL RunShellInf(HWND hwnd) { TCH tszOut[1024]; TweakUi_BuildPathToFile(BuildRundll(tszOut, c_tszI), GetWindowsDirectory, c_tszInfBsShellInf); WinExec(tszOut, SW_NORMAL); } /***************************************************************************** * * InitPpspDidDp * * Initialize a single PROPSHEETPAGE to load the dialog resource did * with dialog procedure dp. * * We must use the original property sheet page structure because * we need to run on Win95 Golden, which has the old comctl32. * * In particular, we cannot use DS_SHELLFONT because the old comctl32 * does not support DIALOGEX, which DS_SHELLFONT requires. * *****************************************************************************/ void PASCAL InitPpspResDp(LPPROPSHEETHEADER ppsh, LPCTSTR ptszDlg, DLGPROC dp) { LPPROPSHEETPAGE_V0 ppsp; #ifdef DEBUG if (ppsh->nPages >= MAX_TWEAKUIPAGES) { DebugBreak(); } { HRSRC hrsrc = FindResource(hinstCur, ptszDlg, RT_DIALOG); LPDLGTEMPLATE pdt = (LPDLGTEMPLATE)LoadResource(hinstCur, hrsrc); if (pdt && HIWORD(pdt->style) != 0xFFFF) { /* Template is okay */ } else { /* ERROR! Win95 Golden does not support DIALOGEX */ DebugBreak(); } } #endif ppsp = (LPPROPSHEETPAGE_V0)ppsh->ppsp; ppsp = &ppsp[ppsh->nPages++]; ppsp->dwSize = sizeof(PROPSHEETPAGE_V0); ppsp->dwFlags = PSP_DEFAULT; ppsp->hInstance = hinstCur; ppsp->pszTemplate = ptszDlg; ppsp->pfnDlgProc = dp; /* ppsp->lParam = ??; */ /* No refdata needed */ } #define InitPpspDidDp(ppsh, did, dp) \ InitPpspResDp(ppsh, MAKEINTRESOURCE(did), dp) /***************************************************************************** * * Open * * Start the show. * *****************************************************************************/ void PASCAL Open(HWND hwnd) { PROPSHEETPAGE_V0 rgpsp[MAX_TWEAKUIPAGES]; PROPSHEETHEADER psh; /* * Make us Alt+Tab'able by removing WS_EX_TOOLWINDOW from our * parent's extended window style. */ SetWindowLong(hwnd, GWL_EXSTYLE, (LONG)(GetWindowExStyle(hwnd) & ~WS_EX_TOOLWINDOW)); /* * Give our hidden parent an icon so the user can Alt+Tab to it. */ SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) LoadIcon(hinstCur, MAKEINTRESOURCE(IDI_DEFAULT))); /* Init our cached pidls */ pcdii->pidlTemplates = NULL; SHGetSpecialFolderLocation(0, CSIDL_TEMPLATES, &pcdii->pidlTemplates); psh.dwSize = PROPSHEETHEADER_V1_SIZE; psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK; psh.hwndParent = hwnd; psh.pszCaption = g_tszName; psh.nPages = 0; psh.nStartPage = 0; psh.ppsp = (PROPSHEETPAGE*)rgpsp; psh.pfnCallback = Prsht_PropertySheetCallback; InitPpspDidDp(&psh, IDD_MOUSE, Mouse_DlgProc); InitPpspDidDp(&psh, IDD_GENERAL, General_DlgProc); InitPpspDidDp(&psh, IDD_EXPLORER, Explorer_DlgProc); /* * Display IE4 only if IE4 is installed. */ if (g_fIE4) { InitPpspDidDp(&psh, IDD_IE4, IE4_DlgProc); } /* * Display CMD only if NT5 is installed. */ if (g_fNT5) { InitPpspDidDp(&psh, IDD_CMD, Cmd_DlgProc); } InitPpspDidDp(&psh, IDD_DESKTOP, Desktop_DlgProc); /* * Display My Computer only if the user has permission to * edit the appropriate registry key. */ if (RegCanModifyKey(g_hkCUSMWCV, c_tszRestrictions)) { InitPpspDidDp(&psh, IDD_MYCOMP, MyComp_DlgProc); } InitPpspDidDp(&psh, IDD_CONTROL, Control_DlgProc); /* * Display Network only if the user has permission to * edit the appropriate registry key. */ if (RegCanModifyKey(g_hkLMSMWNTCV, c_tszWinlogon)) { InitPpspDidDp(&psh, IDD_NETWORK, Network_DlgProc); } if (pcdii->pidlTemplates) { InitPpspDidDp(&psh, IDD_TOOLS, Template_DlgProc); } /* * Add/Remove Programs on NT5 is completely different. */ if (!g_fNT5) { InitPpspDidDp(&psh, IDD_ADDREMOVE, AddRm_DlgProc); } #ifdef _X86_ if (g_tszMsdosSys[0] && !g_fNT && !g_fMillennium) { InitPpspDidDp(&psh, IDD_BOOT, Boot_DlgProc); } #endif InitPpspDidDp(&psh, IDD_REPAIR, Repair_DlgProc); InitPpspDidDp(&psh, IDD_PARANOIA, Paranoia_DlgProc); /* * Common dialog features. */ if (RegCanModifyKey(g_hkCUSMWCV, TEXT("Policies")) && GetProcAddress(GetModuleHandle("COMDLG32"), "PrintDlgExA")) { InitPpspDidDp(&psh, IDD_COMDLG32, Comdlg32_DlgProc); } pcdii->hmenu = LoadMenu(hinstCur, MAKEINTRESOURCE(IDM_MAIN)); _RegOpenKey(HKEY_CLASSES_ROOT, c_tszClsid, &pcdii->hkClsid); pcdii->himlState = ImageList_LoadImage(hinstCur, MAKEINTRESOURCE(IDB_CHECK), 0, 2, CLR_NONE, IMAGE_BITMAP, LR_LOADTRANSPARENT); pcdii->fRunShellInf = 0; #ifndef DEBUG /* Reinstall our run key in case somebody nuked it */ SetRegStr(g_hkLMSMWCV, c_tszRun, g_tszName, c_tszFixLink); #endif #if defined(PRERELEASE) || defined(PUBLIC_PRERELEASE) if (!IsExpired(hwnd)) #endif switch (PropertySheet(&psh)) { case ID_PSRESTARTWINDOWS: if (pcdii->fRunShellInf) { RunShellInf(hwnd); } MessageBoxId(hwnd, IDS_LOGONOFF, g_tszName, MB_OK); break; } RegCloseKey(pcdii->hkClsid); if (pcdii->hmenu) DestroyMenu(pcdii->hmenu); /* Now free them cached shell things */ Ole_Free(pcdii->pidlTemplates); } /***************************************************************************** * * TweakUi_OnBadRun * * Somebody double-clicked our icon, but we aren't being run as * a control panel. Offer to install. * *****************************************************************************/ void PASCAL TweakUi_OnBadRun(HWND hwnd) { if (MessageBoxId(hwnd, IDS_BADRUN, g_tszName, MB_YESNO) == IDYES) { TCH tszOut[1024]; PTSTR ptsz; ptsz = BuildRundll(tszOut, c_tszI); lstrcpy(ptsz, g_tszPathMe); PTSTR ptszExt = ptszStrRChr(ptsz, TEXT('.')); if (ptszExt) { strcpy(ptszExt, c_tszDotInf); if (GetFileAttributes(ptsz) != (DWORD)-1) { WinExec(tszOut, SW_NORMAL); } else { MessageBoxId(hwnd, IDS_CANTINSTALL, g_tszName, MB_OK); } } else { MessageBoxId(hwnd, IDS_CANTINSTALL, g_tszName, MB_OK); } } } /***************************************************************************** * * CriticalInit * * Here is where we put the stuff to impede reverse-engineering. * * 1. All of our strings are encoded. Decode them now. * * 2. Get the shell32 internal entry points via GetProcAddress * so that a "hdr" won't see them. * *****************************************************************************/ HRESULT PASCAL CriticalInit(void) { int itch; int iit; HINSTANCE hinst; itch = cA(c_rgtchCommon)-1; do { c_rgtchCommon[itch] ^= c_rgtchCommon[itch-1]; } while (--itch); hinst = GetModuleHandle(c_tszShell32Dll); for (iit = 0; iit < sizeof(mit) / sizeof(LPCSTR); iit++) { DWORD dwOrd = c_umit[iit]; ((FARPROC *)&mit)[iit] = GetProcAddress(hinst, MAKEINTRESOURCE(dwOrd)); if (((FARPROC *)&mit)[iit] == 0 && !HIWORD(dwOrd)) { return E_FAIL; } } return Ole_Init(); } /***************************************************************************** * * GetObjectBuild * * Get the build number on the specified module, in the form * * 0xMMmmbbbb * * MM = major * mm = minor * bbbb = build * * The input parameter is either an OSVERSIONINFO or a DLLVERSIONINFO. * Fortunately, the two are the same in the places we care about. * *****************************************************************************/ DWORD PASCAL GetObjectBuild(LPOSVERSIONINFO posv) { return MAKELONG(LOWORD(posv->dwBuildNumber), MAKEWORD(posv->dwMinorVersion, posv->dwMajorVersion)); } /***************************************************************************** * * GetModuleBuild * * Get the build number on the specified module, in the form * * 0xMMmmbbbb * * MM = major * mm = minor * bbbb = build * * Returns 0 if DLL does not have DllGetVersion. * *****************************************************************************/ DWORD PASCAL GetModuleBuild(LPCTSTR ptszDll) { HINSTANCE hinst = GetModuleHandle(ptszDll); DLLGETVERSIONPROC DllGetVersion; DWORD dwRc; DllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinst, "DllGetVersion"); if (DllGetVersion) { DLLVERSIONINFO dvi; dvi.cbSize = sizeof(dvi); if (SUCCEEDED(DllGetVersion(&dvi))) { dwRc = GetObjectBuild((LPOSVERSIONINFO)&dvi); } else { dwRc = 0; } } else { dwRc = 0; } return dwRc; } /***************************************************************************** * * CheckWin95Versions * * Determine whether we're on Win95 OPK2 or later. We already know * that we're not Windows NT. * *****************************************************************************/ void PASCAL CheckWin95Versions(void) { BOOL fRc; OSVERSIONINFO osv; osv.dwOSVersionInfoSize = sizeof(osv); if (GetVersionEx(&osv)) { DWORD dwBuild = GetObjectBuild(&osv); if (dwBuild >= MAKELONG(1045, 0x0400)) { g_flWeirdStuff |= flbsOPK2; if (dwBuild >= MAKELONG(0, 0x040A)) { g_flWeirdStuff |= flbsMemphis; if (dwBuild >= MAKELONG(0, 0x045A)) { g_flWeirdStuff |= flbsMillennium; } } } } } /***************************************************************************** * * LibMain * * Initialize globals. * * Get our own name. * * Get our own path. * * Build path to shell32.dll. * *****************************************************************************/ BOOL FAR PASCAL LibMain(HINSTANCE hinst) { if (SUCCEEDED(CriticalInit())) { DWORD dwBuild; DWORD dwVersion; RegCreateKey(HKEY_LOCAL_MACHINE, c_tszSMWCV, &g_hkLMSMWCV); RegCreateKey(HKEY_CURRENT_USER, c_tszSMWCV, &g_hkCUSMWCV); RegCreateKey(g_hkLMSMWCV, c_tszExplorer, &pcdii->hkLMExplorer); RegCreateKey(g_hkCUSMWCV, c_tszExplorer, &pcdii->hkCUExplorer); RegOpenKey(hkLM, c_tszSMWIE, &g_hkLMSMIE); RegOpenKey(hkCU, c_tszSMWIE, &g_hkCUSMIE); hinstCur = hinst; LoadString(hinst, IDS_NAME, g_tszName, cA(g_tszName)); dwBuild = GetModuleBuild(c_tszComCtl32Dll); if (dwBuild == 0) { g_flWeirdStuff |= flbsComCtl32; } if (dwBuild >= MAKELONG(0, 0x447)) { /* 4.71 */ g_flWeirdStuff |= flbsSmoothScroll; } dwVersion = GetVersion(); if ((LONG)dwVersion >= 0) { g_flWeirdStuff |= flbsNT; if (LOBYTE(dwVersion) >= 5) { g_flWeirdStuff |= flbsNT5; } } else { CheckWin95Versions(); } g_dwShellVer = dwBuild = GetModuleBuild(c_tszShell32Dll); if (dwBuild || g_fNT) { g_flWeirdStuff |= flbsShellSz; } /* * Some things need to be turned off if IE5. Go figure. * Borrow g_tszPathMe for scratch space. */ if (GetStrPkl(g_tszPathMe, cA(g_tszPathMe), &c_klIEVersion) && iFromPtsz(g_tszPathMe) >= 5) { g_flWeirdStuff |= flbsIE5; } GetModuleFileName(hinst, g_tszPathMe, cA(g_tszPathMe)); /* * Check if we're being run from the proper directory. */ TweakUi_BuildPathToFile(g_tszPathShell32, GetSystemDirectory, c_tszTweakUICpl); if (lstrcmpi(g_tszPathMe, g_tszPathShell32)) { #ifndef DEBUG g_flWeirdStuff |= flbsBadRun; /* Nope */ #endif } /* * Stash the location of shell32. */ TweakUi_BuildPathToFile(g_tszPathShell32, GetSystemDirectory, c_tszShell32Dll); /* See if we have an msdos.sys file to tweak */ #if defined(_X86_) Boot_FindMsdosSys(); #endif /* * Build the platform-sensitive base key. */ RegCreateKey(hkLM, g_fNT ? c_tszSMWNTCV : c_tszSMWCV, &g_hkLMSMWNTCV); InitCommonControls(); return 1; } else { return 0; } } /***************************************************************************** * * LibExit * * Clean up globals. * *****************************************************************************/ void PASCAL LibExit(void) { if (g_hkCUSMIE) { RegCloseKey(g_hkCUSMIE); } if (g_hkLMSMIE) { RegCloseKey(g_hkLMSMIE); } RegCloseKey(pcdii->hkCUExplorer); RegCloseKey(pcdii->hkLMExplorer); RegCloseKey(g_hkLMSMWCV); RegCloseKey(g_hkLMSMWNTCV); RegCloseKey(g_hkCUSMWCV); Ole_Term(); } /***************************************************************************** * * _DllMainCRTStartup * * Hi. * *****************************************************************************/ STDAPI_(BOOL) Entry32(HINSTANCE hinst, DWORD dwReason, LPVOID lpReserved) { if (dwReason == DLL_PROCESS_ATTACH) { return LibMain(hinst); } else if (dwReason == DLL_PROCESS_DETACH) { LibExit(); } return TRUE; } /***************************************************************************** * * CPlApplet * * Control panel entry point. * *****************************************************************************/ LRESULT EXPORT CPlApplet(HWND hwnd, UINT wm, LPARAM lp1, LPARAM lp2) { switch (wm) { case CPL_INIT: return 1; /* Yes I'm here */ case CPL_GETCOUNT: return 1; /* I provide one icon */ case CPL_INQUIRE: if (lp1 == 0) { /* For the zero'th icon... */ LPCPLINFO lpci = (LPCPLINFO)lp2; lpci->idIcon = IDI_DEFAULT; lpci->idName = IDS_NAME; lpci->idInfo = IDS_DESCRIPTION; /* lpci->lData = 0; */ /* Garbage doesn't hurt */ return 1; } else { return 0; /* Huh? */ } /* * Note! Do not open if registry tools have been disabled. * * This is particularly important for the Network page, which * lets the user view passwords! * * Make this check *before* checking for a bad run, so a * user can't do an end-run by just double-clicking the CPL. */ case CPL_DBLCLK: /* Hey, somebody's knocking */ if (GetDwordPkl(&c_klNoRegedit, 0)) { MessageBoxId(hwnd, IDS_RESTRICTED, g_tszName, MB_OK); } else if (!g_fBadRun) { Open(hwnd); } else { TweakUi_OnBadRun(hwnd); } break; } return 0; } /***************************************************************************** * * WithSelector * * Call the callback after creating a particular selector alias to a * chunk of memory. The memory block is confirmed for read access, * or for write access if fWrite is set. * * Note that the validation doesn't work in Win16 if the data crosses * a page boundary, so be careful. * *****************************************************************************/ BOOL PASCAL WithSelector(DWORD_PTR lib, UINT cb, WITHPROC wp, LPVOID pvRef, BOOL fWrite) { BOOL fRc; #ifdef WIN32 #define lpv (LPVOID)lib #else UINT sel = AllocSelector((UINT)hinstCur); if (sel) { SetSelectorBase(sel, lib); SetSelectorLimit(sel, cb); #define lpv MAKELP(sel, 0) #endif if (!IsBadReadPtr(lpv, cb) && !(fWrite && IsBadWritePtr(lpv, cb))) { fRc = wp(lpv, pvRef); } else { fRc = 0; } #undef lpv #ifndef WIN32 FreeSelector(sel); } else { fRc = 0; } #endif return fRc; } /***************************************************************************** * * TweakUi_OnLogon * * This hacks around two bugs. * * The first is a bug in Shell32, where a bad comparison causes the * Link registry key not to be restored properly. So we patch the * correct value into the registry for them. * * The second is a bug in commctrl where it gets confused by overlay * bitmaps with no pixels. * * And then we do the paranoia stuff. * *****************************************************************************/ void PASCAL TweakUi_OnLogon(void) { UINT cxIcon; /* * This shell bug was fixed sometime before July 1997, though I * can't tell exactly when. Definitely fixed before the ShellSz * support was added, so let's just use that. */ if (!g_fShellSz && !Link_GetShortcutTo()) { Link_SetShortcutTo(1); Link_SetShortcutTo(0); } /* * If the shell icon size is wacked out for some bizarre reason, * then unwack it. This is theoretically impossible, but somehow * it happens, so we fix it ex post facto. */ cxIcon = Misc_GetShellIconSize(); if (((cxIcon + 1) & 0x1F) == 0) { Misc_SetShellIconSize(cxIcon + 1); } Explorer_HackPtui(); Paranoia_CoverTracks(); } /***************************************************************************** * * TweakUi_OnInstall * * Upgrade the previous version of Tweak UI. * * 1. Fix the LinkOverlay gizmo. If we have a buggy ComCtl32 and the * overlay is set to IDI_BLANK - 1, then set HackPtui. * #ifdef UPGRADE_V1_ICON * 2. Rebuild the icon cache, to work around a bug in the control panel, * where it doesn't update its cached image properly when the cpl changes. #endif * *****************************************************************************/ void PASCAL TweakUi_OnInstall(void) { TCHAR tsz[MAX_PATH]; if (g_fBuggyComCtl32 && Explorer_GetIconSpecFromRegistry(tsz) == IDI_BLANK - 1 && lstrcmpi(tsz, g_tszPathMe) == 0) { SetIntPkl(1, &c_klHackPtui); } #ifdef UPGRADE_V1_ICON /* * We no longer try to upgrade the V1 icon because it tickles * the shell icon cache in a way that may expose pre-existing * corruption. */ Misc_RebuildIcoCache(); #endif } /***************************************************************************** * * TweakUi_OnFix * * Put our Uninstall script back into the registry. * *****************************************************************************/ #pragma BEGIN_CONST_DATA KL const c_klDisplayName = { &g_hkLMSMWCV, c_tszUninstallTweakUI, c_tszDisplayName }; KL const c_klUninstallString = { &g_hkLMSMWCV, c_tszUninstallTweakUI, c_tszUninstallString }; #pragma END_CONST_DATA void EXPORT TweakUi_OnFix(HWND hwnd, BOOL fVerbose) { TCH tszOut[1024]; SetStrPkl(&c_klDisplayName, g_tszName); TweakUi_BuildPathToFile(BuildRundll(tszOut, c_tszUni), GetWindowsDirectory, c_tszInfBsTweakuiInf); SetStrPkl(&c_klUninstallString, tszOut); if (fVerbose) { MessageBoxId(hwnd, IDS_FIXED, g_tszName, MB_OK); } } /***************************************************************************** * * TweakMeUp * * Rundll entry point. * * The command line tells us what we're trying to do. * * Null command line - User has just logged on; do logon stuff. * * '0' - We've just been installed; upgrade the previous version. * Since unisntalling on NT is different from on Win95, we fall * through to... * * '1' - The user wants to restore the Uninstall string. * *****************************************************************************/ void EXPORT TweakMeUp(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { switch (lpszCmdLine[0]) { case '\0': TweakUi_OnLogon(); break; case '0': TweakUi_OnInstall(); TweakUi_OnFix(hwnd, 0); break; case '1': TweakUi_OnFix(hwnd, 1); break; } }