/* * repair - Dialog box property sheet for "Repair" */ #include "tweakui.h" #pragma BEGIN_CONST_DATA KL const c_klRegView = { &g_hkCUSMWCV, c_tszRegedit, c_tszView }; const static DWORD CODESEG rgdwHelp[] = { IDC_REPAIRCOMBO, IDH_REPAIR, IDC_REPAIRNOW, IDH_REPAIR, IDC_REPAIRHELP, IDH_REPAIR, IDC_REPAIRTEXT, IDH_REPAIR, IDC_REPAIRICON, IDH_REPAIR, 0, 0, }; typedef UINT (PASCAL *REPAIRPATHPROC)(HWND hdlg, LPTSTR ptszBuf); /***************************************************************************** * * _Repair_FileFromResource * * Given a resource ID and a file name, extract the c_tszExe resource * into that file. * *****************************************************************************/ BOOL PASCAL _Repair_FileFromResource(UINT idx, LPCTSTR ptszFileName) { BOOL fRc; HRSRC hrsrc = FindResource(hinstCur, (LPCTSTR)IntToPtr(idx), c_tszExe); if (hrsrc) { HGLOBAL hglob = LoadResource(hinstCur, hrsrc); if (hglob) { PV pv = LockResource(hglob); if (pv) { HFILE hf = _lcreat(ptszFileName, 0); if (hf != HFILE_ERROR) { UINT cb = SizeofResource(hinstCur, hrsrc); fRc = _lwrite(hf, (char *)pv, cb) == cb; _lclose(hf); if (fRc) { } else { DeleteFile(ptszFileName); } } else { fRc = 0; } } else { fRc = 0; } } else { fRc = 0; } } else { fRc = 0; } return fRc; } /***************************************************************************** * * Repair_RunSetupCqn * * Put the Setup program into the specified directory and run it. * WithTempDirectory will clean up the file when we return. * *****************************************************************************/ BOOL PASCAL Repair_RunSetupCqn(LPCTSTR cqn, LPVOID pv) { BOOL fRc; fRc = _Repair_FileFromResource(IDX_SETUP, c_tszSetupExe); if (fRc) { STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); fRc = CreateProcess(0, c_tszSetupExe, 0, 0, 0, 0, 0, 0, &si, &pi); if (fRc) { CloseHandle(pi.hThread); WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); } } return fRc; } #ifdef _X86_ /***************************************************************************** * * Repair_MoveFileExWininit * * Rename a file via wininit.ini. * *****************************************************************************/ #pragma BEGIN_CONST_DATA TCHAR c_tszPercentSEqualsPercentS[] = TEXT("%s=%s"); #pragma END_CONST_DATA void PASCAL Repair_MoveFileExWininit(LPCTSTR ptszDst, LPCTSTR ptszSrc) { TCHAR tszWininit[MAX_PATH]; DWORD cb; LPSTR pszBuf; WIN32_FIND_DATA wfd; HANDLE h; if (GetWindowsDirectory(tszWininit, cA(tszWininit))) { lstrcatnBs(tszWininit, c_tszWininit, MAX_PATH); /* INI files are always in ANSI */ h = FindFirstFile(ptszSrc, &wfd); if (h != INVALID_HANDLE_VALUE) { FindClose(h); } else { wfd.nFileSizeLow = 0; } cb = wfd.nFileSizeLow + MAX_PATH + 1 + MAX_PATH + 3; pszBuf = (LPSTR)lAlloc(cb); if (pszBuf) { LPSTR psz; if (!GetPrivateProfileSection(c_tszRename, pszBuf, cb, tszWininit)) { /* No such section; create one */ /* Already done by LocalAlloc (zero-init) */ } for (psz = pszBuf; psz[0]; psz += lstrlenA(psz) + 1); psz += wsprintf(psz, c_tszPercentSEqualsPercentS, ptszDst, ptszSrc); psz[1] = '\0'; WritePrivateProfileSection(c_tszRename, pszBuf, tszWininit); lFree(pszBuf); } } } #endif /***************************************************************************** * * Repair_MoveFileEx * * Try to rename the file from existing.dll to existing.bak, * using MoveFileEx or wininit.ini as necessary. * * Note that we must use the short name because that's all that * wininit.ini understands. * *****************************************************************************/ void PASCAL Repair_MoveFileEx(LPTSTR ptszSrc) { TCHAR tszDst[MAX_PATH]; GetShortPathName(ptszSrc, ptszSrc, MAX_PATH); lstrcpy(tszDst, ptszSrc); lstrcpy(tszDst + lstrlen(tszDst) - 4, c_tszDotBak); DeleteFile(tszDst); if (MoveFile(ptszSrc, tszDst)) { /* All done */ } else if (MoveFileEx(ptszSrc, tszDst, MOVEFILE_DELAY_UNTIL_REBOOT)) { /* All done */ #ifdef _X86_ } else if (g_fNT) { /* I did my best */ } else { /* wininit.ini for Windows 95 */ Repair_MoveFileExWininit(tszDst, ptszSrc); #endif } } /***************************************************************************** * * _Repair_RunSetup * * Check if there are any hidden DLLs on the desktop. * * Extract the tiny little "setup" program attached via our resources, * run it, delete it, then tell the user they she may need to restart * the computer for the full effect to kick in. * *****************************************************************************/ #pragma BEGIN_CONST_DATA TCHAR c_tszStarDotDll[] = TEXT("*.DLL"); #pragma END_CONST_DATA UINT PASCAL _Repair_RunSetup(HWND hdlg, REPAIRPATHPROC GetRepairPath) { PIDL pidl; if (SUCCEEDED(SHGetSpecialFolderLocation(hdlg, CSIDL_DESKTOPDIRECTORY, &pidl))) { HANDLE h; TCHAR tszDesktop[MAX_PATH]; TCHAR tszSrc[MAX_PATH]; WIN32_FIND_DATA wfd; SHGetPathFromIDList(pidl, tszDesktop); lstrcpy(tszSrc, tszDesktop); lstrcatnBsA(tszSrc, c_tszStarDotDll); h = FindFirstFile(tszSrc, &wfd); if (h != INVALID_HANDLE_VALUE) { do { lstrcpy(tszSrc, tszDesktop); lstrcatnBsA(tszSrc, wfd.cFileName); Repair_MoveFileEx(tszSrc); } while (FindNextFile(h, &wfd)); FindClose(h); } Ole_Free(pidl); } WithTempDirectory(Repair_RunSetupCqn, 0); return IDS_MAYBEREBOOT; } /***************************************************************************** * * _Repair_GetFontPath * * Obtain the path to the Fonts folder. * *****************************************************************************/ UINT PASCAL _Repair_GetFontPath(HWND hdlg, LPTSTR ptszBuf) { PIDL pidlFonts; if (SUCCEEDED(SHGetSpecialFolderLocation(hdlg, CSIDL_FONTS, &pidlFonts))) { SHGetPathFromIDListA(pidlFonts, ptszBuf); Ole_Free(pidlFonts); } return IDX_FONTFOLDER; } /***************************************************************************** * * _Repair_GetIEPath * * Obtain the path to some IE special folder. * * If we can't get it from the registry, then it's just * "%windir%\ptszSubdir". * *****************************************************************************/ void PASCAL _Repair_GetIEPath(LPTSTR ptszBuf, LPCTSTR ptszKey, LPCTSTR ptszSubdir) { HKEY hk; ptszBuf[0] = TEXT('\0'); if (RegOpenKeyEx(g_hkLMSMWCV, ptszKey, 0, KEY_QUERY_VALUE, &hk) == ERROR_SUCCESS) { DWORD cb = cbCtch(MAX_PATH); DWORD dwType; RegQueryValueEx(hk, c_tszDirectory, 0, &dwType, (LPBYTE)ptszBuf, &cb); RegCloseKey(hk); if (dwType == REG_EXPAND_SZ) { LPTSTR ptszTemp; cb = ExpandEnvironmentStrings(ptszBuf, NULL, 0); ptszTemp = (LPTSTR)LocalAlloc(LPTR, cb * sizeof(TCHAR)); if (ptszTemp) { if (ExpandEnvironmentStrings(ptszBuf, ptszTemp, cb)) { lstrcpyn(ptszBuf, ptszTemp, MAX_PATH); } LocalFree(ptszTemp); } } } if (ptszBuf[0] == TEXT('\0') && GetWindowsDirectory(ptszBuf, MAX_PATH - lstrlen(ptszSubdir) - 1)) { ptszBuf = TweakUi_TrimTrailingBs(ptszBuf); *ptszBuf++ = TEXT('\\'); lstrcpy(ptszBuf, ptszSubdir); } } /***************************************************************************** * * _Repair_GetHistoryPath * * Obtain the path to the URL History folder. * * If we can't get it from the registry, then it's just * "%windir%\History". * *****************************************************************************/ UINT PASCAL _Repair_GetHistoryPath(HWND hdlg, LPTSTR ptszBuf) { _Repair_GetIEPath(ptszBuf, c_tszUrlHist, c_tszHistory); return IDX_HISTORY; } /***************************************************************************** * * _Repair_GetCachePath * * Obtain the path to the Temporary Internet Files folder. * * If we can't get it from the registry, then it's just * "%windir%\Temporary Internet Files". * *****************************************************************************/ UINT PASCAL _Repair_GetCachePath(HWND hdlg, LPTSTR ptszBuf) { _Repair_GetIEPath(ptszBuf, c_tszIECache, c_tszTempInet); return IDX_TEMPINET; } /***************************************************************************** * * _Repair_RepairJunction * * Hack at a junction to make it magic again. * *****************************************************************************/ UINT PASCAL _Repair_RepairJunction(HWND hdlg, REPAIRPATHPROC GetRepairPath) { PIDL pidlFonts; TCHAR tsz[MAX_PATH]; UINT ids; tsz[0] = TEXT('\0'); ids = GetRepairPath(hdlg, tsz); if (ids && tsz[0]) { /* Ignore error; might already exist */ CreateDirectory(tsz, 0); /* Ignore error; might not have permission to change attributes */ SetFileAttributes(tsz, FILE_ATTRIBUTE_SYSTEM); lstrcpy(TweakUi_TrimTrailingBs(tsz), c_tszBSDesktopIni); _Repair_FileFromResource(ids, tsz); } return IDS_MAYBEREBOOT; } /***************************************************************************** * * _Repair_RepairFontFolder * * The font folder is special in that if we can find a * DllRegisterServer, we will call it as well. * *****************************************************************************/ typedef HRESULT (CALLBACK *DLLREGISTERSERVER)(void); UINT PASCAL _Repair_RepairFontFolder(HWND hdlg, REPAIRPATHPROC GetRepairPath) { UINT ids = _Repair_RepairJunction(hdlg, GetRepairPath); /* * Do this after we do the default repair so fontext has a chance * to override whatever we did. */ HINSTANCE hinst = LoadLibrary("fontext.dll"); if (hinst) { DLLREGISTERSERVER _DllRegisterServer = (DLLREGISTERSERVER)GetProcAddress(hinst, "DllRegisterServer"); if (_DllRegisterServer) { _DllRegisterServer(); } FreeLibrary(hinst); } return ids; } /***************************************************************************** * * _Repair_RepairIconCache * * Rebuild the icon cache. * *****************************************************************************/ UINT PASCAL _Repair_RepairIconCache(HWND hdlg, REPAIRPATHPROC GetRepairPath) { Misc_RebuildIcoCache(); return 0; } /***************************************************************************** * * _Repair_RepairRegedit * * Nuke the saved view goo so Regedit won't be hosed. * *****************************************************************************/ UINT PASCAL _Repair_RepairRegedit(HWND hdlg, REPAIRPATHPROC GetRepairPath) { DelPkl(&c_klRegView); return 0; } /***************************************************************************** * * _Repair_RepairAssociations * * Rebuild the associations. * *****************************************************************************/ UINT PASCAL _Repair_RepairAssociations(HWND hdlg, REPAIRPATHPROC GetRepairPath) { if (MessageBoxId(hdlg, IDS_DESKTOPRESETOK, g_tszName, MB_YESNO + MB_DEFBUTTON2) == IDYES) { pcdii->fRunShellInf = 1; Common_NeedLogoff(hdlg); PropSheet_Apply(GetParent(hdlg)); } return 0; } /***************************************************************************** * * _Repair_RepairHotkeys * * Rebuild the Start Menu hotkey list. * *****************************************************************************/ UINT PASCAL _Repair_RepairHotkeys(HWND hdlg, REPAIRPATHPROC GetRepairPath) { SetRegStr(g_hkCUSMWCV, TEXT("RunOnce"), TEXT("TweakUI_RepairHotkeys"), TEXT("RUNDLL32.EXE TWEAKUI.CPL,RepairHotkeys")); MessageBoxId(hdlg, IDS_REPAIRLOGONOFF, g_tszName, MB_OK); return 0; } /***************************************************************************** * * RepairHotkeys * * Rundll entry point. * * This must be run during RunOnce because it has to do its work while * the tray does not exist. The tray loads settings when it is created, * and it saves them when it is destroyed. So if you try to clean up * the hotkeys * *****************************************************************************/ void EXPORT RepairHotkeys(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { RegDeleteKey(pcdii->hkCUExplorer, TEXT("Hotkeys")); } /***************************************************************************** * * Repair_IsWin95 * * Nonzero if we are on Windows 95. * *****************************************************************************/ BOOL PASCAL Repair_IsWin95(void) { return !g_fNT; } /***************************************************************************** * * Repair_IsIE3 * * Nonzero if we are on IE3 or better. * *****************************************************************************/ BOOL PASCAL Repair_IsIE3(void) { return g_hkCUSMIE ? TRUE : FALSE; } /***************************************************************************** * * Repair_IsIE3or4 * * Nonzero if we are on IE3 or IE4, but not IE5. * *****************************************************************************/ BOOL PASCAL Repair_IsIE3or4(void) { return g_hkCUSMIE && !g_fIE5 ? TRUE : FALSE; } /***************************************************************************** * * REPAIRINFO * *****************************************************************************/ typedef struct REPAIRINFO { BOOL (PASCAL *CanRepair)(void); UINT (PASCAL *Repair)(HWND hdlg, REPAIRPATHPROC GetRepairPath); REPAIRPATHPROC GetRepairPath; } REPAIRINFO, *PREPAIRINFO; /* * Note that this needs to be in sync with the IDS_REPAIR strings. */ struct REPAIRINFO c_rgri[] = { { 0, _Repair_RepairIconCache, 0, }, /* Rebuild Icons */ { 0, _Repair_RepairFontFolder, _Repair_GetFontPath, }, /* Repair Font Folder */ { Repair_IsWin95, _Repair_RunSetup, 0, }, /* Repair System Files */ { 0, _Repair_RepairRegedit, 0, }, /* Rebuild Regedit */ { Repair_IsWin95, _Repair_RepairAssociations, 0, }, /* Repair Associations */ { Repair_IsIE3or4, // Busted on IE5 _Repair_RepairJunction, _Repair_GetHistoryPath, }, /* Repair URL History */ { Repair_IsIE3, _Repair_RepairJunction, _Repair_GetCachePath, }, /* Repair Temporary Internet Files */ { 0, _Repair_RepairHotkeys, 0, }, /* Repair hotkeys */ }; #pragma END_CONST_DATA /***************************************************************************** * * Repair_GetCurSelIndex * * Get the index of the selected item. * *****************************************************************************/ INT_PTR PASCAL Repair_GetCurSelIndex(HWND hdlg) { HWND hwnd = GetDlgItem(hdlg, IDC_REPAIRCOMBO); INT_PTR iItem = ComboBox_GetCurSel(hwnd); if (iItem >= 0) { return ComboBox_GetItemData(hwnd, iItem); } else { return iItem; } } /***************************************************************************** * * Repair_OnSelChange * * Ooh, the selection changed. * *****************************************************************************/ void PASCAL Repair_OnSelChange(HWND hdlg) { HWND hwnd = GetDlgItem(hdlg, IDC_REPAIRCOMBO); int dids = (int)Repair_GetCurSelIndex(hdlg); if (dids >= 0) { TCHAR tsz[1024]; LoadString(hinstCur, IDS_REPAIRHELP+dids, tsz, cA(tsz)); SetDlgItemText(hdlg, IDC_REPAIRHELP, tsz); } } /***************************************************************************** * * Repair_OnInitDialog * * Disable the shell.inf thing on NT, because NT doesn't have one. * *****************************************************************************/ BOOL PASCAL Repair_OnInitDialog(HWND hdlg) { HWND hwnd = GetDlgItem(hdlg, IDC_REPAIRCOMBO); int dids; for (dids = 0; dids < cA(c_rgri); dids++) { if (c_rgri[dids].CanRepair == 0 || c_rgri[dids].CanRepair()) { TCHAR tsz[MAX_PATH]; int iItem; LoadString(hinstCur, IDS_REPAIR+dids, tsz, cA(tsz)); iItem = ComboBox_AddString(hwnd, tsz); ComboBox_SetItemData(hwnd, iItem, dids); } } ComboBox_SetCurSel(hwnd, 0); Repair_OnSelChange(hdlg); return 1; } /***************************************************************************** * * Repair_OnRepairNow * * Ooh, go repair something. * *****************************************************************************/ void PASCAL Repair_OnRepairNow(HWND hdlg) { HWND hwnd = GetDlgItem(hdlg, IDC_REPAIRCOMBO); int dids = (int)Repair_GetCurSelIndex(hdlg); if (dids >= 0) { UINT ids = c_rgri[dids].Repair(hdlg, c_rgri[dids].GetRepairPath); if (ids) { MessageBoxId(hdlg, ids, g_tszName, MB_OK); } } } /***************************************************************************** * * Repair_OnCommand * * Ooh, we got a command. * *****************************************************************************/ BOOL PASCAL Repair_OnCommand(HWND hdlg, int id, UINT codeNotify) { switch (id) { case IDC_REPAIRCOMBO: if (codeNotify == CBN_SELCHANGE) { Repair_OnSelChange(hdlg); } break; case IDC_REPAIRNOW: if (codeNotify == BN_CLICKED) { Repair_OnRepairNow(hdlg); } } #if 0 switch (id) { case IDC_REBUILDCACHE: if (codeNotify == BN_CLICKED) { Misc_RebuildIcoCache(); MessageBoxId(hdlg, IDS_ICONSREBUILT, g_tszName, MB_OK); } break; case IDC_REPAIRFONTFLD: if (codeNotify == BN_CLICKED) { if (_Repair_RepairFontFolder(hdlg)) { MessageBoxId(hdlg, IDS_MAYBEREBOOT, g_tszName, MB_OK); } } break; case IDC_REPAIRREGEDIT: if (codeNotify == BN_CLICKED) { DelPkl(&c_klRegView); } break; case IDC_REPAIRASSOC: if (codeNotify == BN_CLICKED) { if (MessageBoxId(hdlg, IDS_DESKTOPRESETOK, g_tszName, MB_YESNO + MB_DEFBUTTON2) == IDYES) { pcdii->fRunShellInf = 1; Common_NeedLogoff(hdlg); PropSheet_Apply(GetParent(hdlg)); } } break; case IDC_REPAIRDLLS: if (codeNotify == BN_CLICKED) { if (_Repair_RunSetup(hdlg)) { MessageBoxId(hdlg, IDS_MAYBEREBOOT, g_tszName, MB_OK); } } break; } #endif return 0; } #if 0 /***************************************************************************** * * Repair_OnNotify * * Ooh, we got a notification. * *****************************************************************************/ BOOL PASCAL Repair_OnNotify(HWND hdlg, NMHDR FAR *pnm) { switch (pnm->code) { case PSN_APPLY: Repair_Apply(hdlg); break; } return 0; } #endif /***************************************************************************** * * Our window procedure. * *****************************************************************************/ /* * The HANDLE_WM_* macros weren't designed to be used from a dialog * proc, so we need to handle the messages manually. (But carefully.) */ INT_PTR EXPORT Repair_DlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam) { switch (wm) { case WM_INITDIALOG: return Repair_OnInitDialog(hdlg); case WM_COMMAND: return Repair_OnCommand(hdlg, (int)GET_WM_COMMAND_ID(wParam, lParam), (UINT)GET_WM_COMMAND_CMD(wParam, lParam)); #if 0 case WM_NOTIFY: return Repair_OnNotify(hdlg, (NMHDR FAR *)lParam); #endif case WM_HELP: Common_OnHelp(lParam, &rgdwHelp[0]); break; case WM_CONTEXTMENU: Common_OnContextMenu(wParam, &rgdwHelp[0]); break; default: return 0; /* Unhandled */ } return 1; /* Handled */ }