windows-nt/Source/XPSP1/NT/shell/applets/cleanup/fldrclnr/silent.cpp
2020-09-26 16:20:57 +08:00

505 lines
15 KiB
C++

#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include "CleanupWiz.h"
#include "resource.h"
#include "priv.h"
#include "dblnul.h"
#include <shlwapi.h>
extern HINSTANCE g_hInst;
//#define SILENTMODE_LOGGING
#ifdef SILENTMODE_LOGGING
HANDLE g_hLogFile;
void StartLogging(LPTSTR pszFolderPath)
{
TCHAR szLogFile[MAX_PATH];
StrCpyN(szLogFile, pszFolderPath, ARRAYSIZE(szLogFile));
PathAppend(szLogFile, TEXT("log.txt"));
g_hLogFile = CreateFile(szLogFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
}
void StopLogging()
{
if (INVALID_HANDLE_VALUE != g_hLogFile)
{
CloseHandle(g_hLogFile);
}
}
void WriteLog(LPCTSTR pszTemplate, LPCTSTR pszParam1, LPCTSTR pszParam2)
{
if (INVALID_HANDLE_VALUE != g_hLogFile)
{
TCHAR szBuffer[1024];
DWORD cbWritten;
wnsprintf(szBuffer, ARRAYSIZE(szBuffer), pszTemplate, pszParam1, pszParam2);
if (WriteFile(g_hLogFile, szBuffer, sizeof(TCHAR) * lstrlen(szBuffer), &cbWritten, NULL))
{
FlushFileBuffers(g_hLogFile);
}
}
}
#define STARTLOGGING(psz) StartLogging(psz)
#define STOPLOGGING StopLogging()
#define WRITELOG(pszTemplate, psz1, psz2) WriteLog(pszTemplate, psz1, psz2)
#else
#define STARTLOGGING(psz)
#define STOPLOGGING
#define WRITELOG(pszTemplate, psz1, psz2)
#endif
DWORD CCleanupWiz::_LoadUnloadHive(HKEY hKey, LPCTSTR pszSubKey, LPCTSTR pszHive)
{
DWORD dwErr;
BOOLEAN bWasEnabled;
NTSTATUS status;
status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &bWasEnabled);
if ( NT_SUCCESS(status) )
{
if (pszHive)
{
dwErr = RegLoadKey(hKey, pszSubKey, pszHive);
}
else
{
dwErr = RegUnLoadKey(hKey, pszSubKey);
}
RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, bWasEnabled, FALSE, &bWasEnabled);
}
else
{
dwErr = RtlNtStatusToDosError(status);
}
return dwErr;
}
HRESULT CCleanupWiz::_HideRegItemsFromNameSpace(LPCTSTR pszDestPath, HKEY hkey)
{
DWORD dwIndex = 0;
TCHAR szCLSID[39];
while (ERROR_SUCCESS == RegEnumKey(hkey, dwIndex++, szCLSID, ARRAYSIZE(szCLSID)))
{
CLSID clsid;
GUIDFromString(szCLSID, &clsid);
if (CLSID_MyComputer != clsid &&
CLSID_MyDocuments != clsid &&
CLSID_NetworkPlaces != clsid &&
CLSID_RecycleBin != clsid)
{
BOOL fWasVisible;
_HideRegItem(&clsid, TRUE, &fWasVisible);
if (fWasVisible)
{
HKEY hkeyCLSID;
if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, TEXT("CLSID"), &hkeyCLSID))
{
HKEY hkeySub;
if (ERROR_SUCCESS == RegOpenKey(hkeyCLSID, szCLSID, &hkeySub))
{
TCHAR szName[260];
LONG cbName = sizeof(szName);
if (ERROR_SUCCESS == RegQueryValue(hkeySub, NULL, szName, &cbName))
{
_CreateFakeRegItem(pszDestPath, szName, szCLSID);
}
RegCloseKey(hkeySub);
}
RegCloseKey(hkeyCLSID);
}
}
}
}
return S_OK;
}
HRESULT CCleanupWiz::_GetDesktopFolderBySid(LPCTSTR pszDestPath, LPCTSTR pszSid, LPTSTR pszBuffer, DWORD cchBuffer)
{
TCHAR szKey[MAX_PATH];
TCHAR szProfilePath[MAX_PATH];
DWORD dwSize;
DWORD dwErr;
// Start by getting the user's ProfilePath from the registry
StrCpyN(szKey, REGSTR_PROFILELIST, ARRAYSIZE(szKey));
StrCatBuff(szKey, pszSid, ARRAYSIZE(szKey));
dwSize = sizeof(szProfilePath);
dwErr = SHGetValue(HKEY_LOCAL_MACHINE,
szKey,
TEXT("ProfileImagePath"),
NULL,
szProfilePath,
&dwSize);
if ( ERROR_SUCCESS == dwErr)
{
// Load the user's hive
PathAppend(szProfilePath, TEXT("ntuser.dat"));
dwErr = _LoadUnloadHive(HKEY_USERS, pszSid, szProfilePath);
if ( dwErr == ERROR_SUCCESS || ERROR_SHARING_VIOLATION == dwErr) // sharing violation means the hive is already open
{
HKEY hkey;
StrCpyN(szKey, pszSid, ARRAYSIZE(szKey));
PathAppend(szKey, REGSTR_SHELLFOLDERS);
dwErr = RegOpenKeyEx(HKEY_USERS,
szKey,
0,
KEY_QUERY_VALUE,
&hkey);
if ( dwErr == ERROR_SUCCESS )
{
dwSize = cchBuffer;
dwErr = RegQueryValueEx(hkey, REGSTR_DESKTOP, NULL, NULL, (LPBYTE)pszBuffer, &dwSize);
if ( dwErr == ERROR_SUCCESS )
{
// todo: confirm that this doesn't overflow
PathAppend(pszBuffer, TEXT("*"));
}
RegCloseKey(hkey);
}
StrCpyN(szKey, pszSid, ARRAYSIZE(szKey));
PathAppend(szKey, REGSTR_DESKTOPNAMESPACE);
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_USERS, szKey, 0, KEY_READ, &hkey))
{
_HideRegItemsFromNameSpace(pszDestPath, hkey);
RegCloseKey(hkey);
}
_LoadUnloadHive(HKEY_USERS, pszSid, NULL);
}
}
return HRESULT_FROM_WIN32(dwErr);
}
HRESULT CCleanupWiz::_AppendDesktopFolderName(LPTSTR pszBuffer)
{
TCHAR szDesktop[MAX_PATH];
if (SHGetSpecialFolderPath(NULL, szDesktop, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE))
{
PathStripPath(szDesktop); // get just the localized word "Desktop"
PathAppend(pszBuffer, szDesktop);
}
else
{
PathAppend(pszBuffer, DESKTOP_DIR); // default to "Desktop"
}
return S_OK;
}
HRESULT CCleanupWiz::_GetDesktopFolderByRegKey(LPCTSTR pszRegKey, LPCTSTR pszRegValue, LPTSTR szBuffer, DWORD cchBuffer)
{
HRESULT hr = E_FAIL;
DWORD cb = cchBuffer * sizeof(TCHAR);
if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, pszRegKey, REGSTR_PROFILESDIR, NULL, (void*)szBuffer, &cb))
{
TCHAR szAppend[MAX_PATH];
cb = sizeof(szAppend);
if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, pszRegKey, pszRegValue, NULL, (void*)szAppend, &cb))
{
PathAppend(szBuffer, szAppend);
_AppendDesktopFolderName(szBuffer);
PathAppend(szBuffer, TEXT("*"));
hr = S_OK;
}
}
return hr;
}
HRESULT CCleanupWiz::_MoveDesktopItems(LPCTSTR pszFrom, LPCTSTR pszTo)
{
WRITELOG(TEXT("**** MoveDesktopItems: %s %s **** "), pszFrom, pszTo);
SHFILEOPSTRUCT fo;
fo.hwnd = NULL;
fo.wFunc = FO_MOVE;
fo.pFrom = pszFrom;
fo.pTo = pszTo;
fo.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NOCOPYSECURITYATTRIBS | FOF_NOERRORUI | FOF_RENAMEONCOLLISION;
int iRet = SHFileOperation(&fo);
return HRESULT_FROM_WIN32(iRet);
}
HRESULT CCleanupWiz::_SilentProcessUserBySid(LPCTSTR pszDestPath, LPCTSTR pszSid)
{
WRITELOG(TEXT("**** SilentProcessUserBySid: %s **** "), pszSid, TEXT(""));
HRESULT hr;
if (!pszSid || !*pszSid || !pszDestPath || !*pszDestPath)
{
return E_INVALIDARG;
}
TCHAR szTo[MAX_PATH + 1];
TCHAR szFrom[MAX_PATH + 1];
StrCpyN(szTo, pszDestPath, ARRAYSIZE(szTo) - 1);
hr = _GetDesktopFolderBySid(pszDestPath, pszSid, szFrom, ARRAYSIZE(szFrom));
if (SUCCEEDED(hr))
{
szFrom[lstrlen(szFrom) + 1] = 0;
szTo[lstrlen(szTo) + 1] = 0;
hr = _MoveDesktopItems(szFrom, szTo);
}
return hr;
}
HRESULT CCleanupWiz::_SilentProcessUserByRegKey(LPCTSTR pszDestPath, LPCTSTR pszRegKey, LPCTSTR pszRegValue)
{
HRESULT hr;
if (!pszRegKey || !*pszRegKey || !pszRegValue || !*pszRegValue || !pszDestPath || !*pszDestPath)
{
return E_INVALIDARG;
}
TCHAR szTo[MAX_PATH + 1];
TCHAR szFrom[MAX_PATH + 1];
StrCpyN(szTo, pszDestPath, ARRAYSIZE(szTo) - 1);
hr = _GetDesktopFolderByRegKey(pszRegKey, pszRegValue, szFrom, ARRAYSIZE(szFrom));
if (SUCCEEDED(hr))
{
szFrom[lstrlen(szFrom) + 1] = 0;
szTo[lstrlen(szTo) + 1] = 0;
hr = _MoveDesktopItems(szFrom, szTo);
}
return hr;
}
HRESULT CCleanupWiz::_SilentProcessUsers(LPCTSTR pszDestPath)
{
HRESULT hr = E_FAIL;
HKEY hkey;
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"), &hkey))
{
TCHAR szSid[MAX_PATH];
DWORD dwIndex = 0;
while (ERROR_SUCCESS == RegEnumKey(hkey, dwIndex++, szSid, ARRAYSIZE(szSid)))
{
_SilentProcessUserBySid(pszDestPath, szSid);
}
RegCloseKey(hkey);
hr = S_OK;
}
return hr;
}
HRESULT CCleanupWiz::_RunSilent()
{
// if we're in silent mode, try to get the special folder name out of the registry, else default to normal name
DWORD dwType = REG_SZ;
DWORD cb = sizeof(_szFolderName);
if (ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_OEM_PATH, REGSTR_OEM_TITLEVAL, &dwType, _szFolderName, &cb))
{
LoadString(g_hInst, IDS_ARCHIVEFOLDER_FIRSTBOOT, _szFolderName, MAX_PATH);
}
// assemble the name of the directory we should write to
TCHAR szPath[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, szPath);
PathAppend(szPath, _szFolderName);
// Create the directory
SHCreateDirectoryEx(NULL, szPath, NULL);
STARTLOGGING(szPath);
// Move regitems of All Users
HKEY hkey;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_DESKTOPNAMESPACE, 0, KEY_READ, &hkey))
{
_HideRegItemsFromNameSpace(szPath, hkey);
RegCloseKey(hkey);
}
// Move desktop items of All Users
_SilentProcessUserByRegKey(szPath, REGSTR_PROFILELIST, REGSTR_ALLUSERS);
// move desktop items of Default User
_SilentProcessUserByRegKey(szPath, REGSTR_PROFILELIST, REGSTR_DEFAULTUSER);
// Move desktop items of each normal users
_SilentProcessUsers(szPath);
STOPLOGGING;
return S_OK;
}
BOOL _ShouldPlaceIEDesktopIcon()
{
BOOL fRetVal = TRUE;
DWORD dwData;
DWORD cbData = sizeof(dwData);
if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_OCMANAGER, REGSTR_IEACCESS, NULL, &dwData, &cbData)) &&
(dwData == 0))
{
fRetVal = FALSE;
}
return fRetVal;
}
BOOL _ShouldUseMSNInternetAccessIcon()
{
BOOL fRetVal = FALSE;
TCHAR szBuffer[4];
DWORD cch = sizeof(szBuffer);
if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_MSNCODES, REGSTR_MSN_IAONLY, NULL, szBuffer, &cch)) &&
(!StrCmpI(szBuffer, TEXT("yes"))))
{
fRetVal = TRUE;
}
return fRetVal;
}
HRESULT _AddIEIconToDesktop()
{
DWORD dwData = 0;
TCHAR szCLSID[MAX_GUID_STRING_LEN];
TCHAR szBuffer[MAX_PATH];
HRESULT hr = SHStringFromGUID(CLSID_Internet, szCLSID, ARRAYSIZE(szCLSID));
if (SUCCEEDED(hr))
{
for (int i = 0; i < 2; i ++)
{
wsprintf(szBuffer, REGSTR_PATH_HIDDEN_DESKTOP_ICONS, (i == 0) ? REGSTR_VALUE_STARTPANEL : REGSTR_VALUE_CLASSICMENU);
SHRegSetUSValue(szBuffer, szCLSID, REG_DWORD, &dwData, sizeof(DWORD), SHREGSET_FORCE_HKLM);
}
}
return hr;
}
HRESULT _AddWMPIconToDesktop()
{
// first set this registry value so if the WMP shortcut creator kicks in after us (it may not, due to timing concerns) it will not delete our shortcut
SHRegSetUSValue(REGSTR_WMP_PATH_SETUP, REGSTR_WMP_REGVALUE, REG_SZ, REGSTR_YES, sizeof(TCHAR) * (ARRAYSIZE(REGSTR_YES) + 1), SHREGSET_FORCE_HKLM);
HRESULT hr;
TCHAR szBuffer[MAX_PATH];
TCHAR szSourcePath[MAX_PATH];
TCHAR szDestPath[MAX_PATH];
// we get docs and settings\all users\start menu\programs
hr = SHGetSpecialFolderPath(NULL, szSourcePath, CSIDL_COMMON_PROGRAMS, FALSE);
if (SUCCEEDED(hr))
{
// strip it down to docs and settings\all users, using szDestPath as a temp buffer
StrCpyN(szDestPath, szSourcePath, ARRAYSIZE(szDestPath));
PathRemoveFileSpec(szSourcePath); // remove Programs
PathRemoveFileSpec(szSourcePath); // remove Start Menu
// now copy "start menu\programs" to szBuffer
StrCpyN(szBuffer, szDestPath + lstrlen(szSourcePath), ARRAYSIZE(szBuffer));
// load "Default user" into szDestPath
LoadString(g_hInst, IDS_DEFAULTUSER, szDestPath, ARRAYSIZE(szDestPath));
PathRemoveFileSpec(szSourcePath); // remove All Users
// now szSourcePath is docs and settings
PathAppend(szSourcePath, szDestPath);
// now szSourcePath is docs and settings\Default User
// sanity check, localizers may have inappropriately localized Default User on a system where it shouldn't be localized
if (!PathIsDirectory(szSourcePath))
{
PathRemoveFileSpec(szSourcePath);
PathAppend(szSourcePath, DEFAULT_USER); // if so, remove what they gave us and just add the English "Default User", which is what it is on most machines
}
PathAppend(szSourcePath, szBuffer);
// now szSourcePath is docs and settings\Default User\start menu\programs
hr = SHGetSpecialFolderPath(NULL, szDestPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
if (SUCCEEDED(hr))
{
LoadString(g_hInst, IDS_WMP, szBuffer, ARRAYSIZE(szBuffer));
PathAppend(szSourcePath, szBuffer);
PathAppend(szDestPath, szBuffer);
CopyFile(szSourcePath, szDestPath, TRUE);
}
}
return hr;
}
HRESULT _AddMSNIconToDesktop(BOOL fUseMSNExplorerIcon)
{
HRESULT hr = E_FAIL;
TCHAR szBuffer[MAX_PATH];
TCHAR szSourcePath[MAX_PATH];
TCHAR szDestPath[MAX_PATH];
if ((SUCCEEDED(SHGetSpecialFolderPath(NULL, szSourcePath, CSIDL_COMMON_PROGRAMS, FALSE))) &&
(SUCCEEDED(SHGetSpecialFolderPath(NULL, szDestPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE))))
{
if (fUseMSNExplorerIcon)
{
LoadString(g_hInst, IDS_MSN, szBuffer, ARRAYSIZE(szBuffer)); // MSN Explorer
}
else
{
LoadString(g_hInst, IDS_MSN_ALT, szBuffer, ARRAYSIZE(szBuffer)); // Get Online With MSN
}
PathAppend(szSourcePath, szBuffer);
PathAppend(szDestPath, szBuffer);
CopyFile(szSourcePath, szDestPath, TRUE);
hr = S_OK;
}
return hr;
}
void CreateDesktopIcons()
{
BOOL fIEDesktopIcon = _ShouldPlaceIEDesktopIcon();
_AddWMPIconToDesktop();
if (fIEDesktopIcon)
{
_AddIEIconToDesktop();
}
_AddMSNIconToDesktop(fIEDesktopIcon || !_ShouldUseMSNInternetAccessIcon());
}