windows-nt/Source/XPSP1/NT/sdktools/tweakui/repair.cpp

822 lines
20 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*
* 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 */
}