#include #include #include #include #include "CleanupWiz.h" #include "resource.h" #include "dblnul.h" extern HINSTANCE g_hInst; //#define SILENTMODE_LOGGING #ifdef SILENTMODE_LOGGING HANDLE g_hLogFile = INVALID_HANDLE_VALUE; void StartLogging(LPTSTR pszFolderPath) { TCHAR szLogFile[MAX_PATH]; if (SUCCEEDED(StringCchCopy(szLogFile, ARRAYSIZE(szLogFile), pszFolderPath)) && 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); g_hLogFile = INVALID_HANDLE_VALUE; } } void WriteLog(LPCTSTR pszTemplate, LPCTSTR pszParam1, LPCTSTR pszParam2) { if (INVALID_HANDLE_VALUE != g_hLogFile) { TCHAR szBuffer[1024]; DWORD cbWritten; if (SUCCEEDED(StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), pszTemplate, pszParam1, pszParam2)) && 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 // copied from shell\ext\shgina\cenumusers.cpp 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; if (GUIDFromString(szCLSID, &clsid) && CLSID_MyComputer != clsid && CLSID_MyDocuments != clsid && CLSID_NetworkPlaces != clsid && CLSID_RecycleBin != clsid) { BOOL fWasVisible; if (SUCCEEDED(_HideRegItem(&clsid, TRUE, &fWasVisible)) && fWasVisible) { HKEY hkeyCLSID; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_READ, &hkeyCLSID)) { HKEY hkeySub; if (ERROR_SUCCESS == RegOpenKeyEx(hkeyCLSID, szCLSID, 0, KEY_READ, &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) { ASSERT(cchBuffer >= MAX_PATH); // because we do PathAppend on it HRESULT hr; TCHAR szKey[MAX_PATH]; TCHAR szProfilePath[MAX_PATH]; DWORD dwSize; DWORD dwErr; // Start by getting the user's ProfilePath from the registry hr = StringCchCopy(szKey, ARRAYSIZE(szKey), c_szRegStrPROFILELIST); if (SUCCEEDED(hr)) { if (!PathAppend(szKey, pszSid)) { hr = E_FAIL; } else { dwSize = sizeof(szProfilePath); dwErr = SHGetValue(HKEY_LOCAL_MACHINE, szKey, TEXT("ProfileImagePath"), NULL, szProfilePath, &dwSize); if (ERROR_SUCCESS != dwErr || !PathAppend(szProfilePath, TEXT("ntuser.dat"))) { hr = E_FAIL; } else { dwErr = _LoadUnloadHive(HKEY_USERS, pszSid, szProfilePath); if (ERROR_SUCCESS != dwErr && ERROR_SHARING_VIOLATION != dwErr) // sharing violation means the hive is already open { hr = HRESULT_FROM_WIN32(dwErr); } else { HKEY hkey; hr = StringCchCopy(szKey, ARRAYSIZE(szKey), pszSid); if (SUCCEEDED(hr)) { if (!PathAppend(szKey, c_szRegStrSHELLFOLDERS)) { hr = E_FAIL; } else { dwErr = RegOpenKeyEx(HKEY_USERS, szKey, 0, KEY_QUERY_VALUE, &hkey); if ( dwErr != ERROR_SUCCESS ) { hr = HRESULT_FROM_WIN32(dwErr); } else { dwSize = cchBuffer; dwErr = RegQueryValueEx(hkey, c_szRegStrDESKTOP, NULL, NULL, (LPBYTE)pszBuffer, &dwSize); if ( dwErr == ERROR_SUCCESS ) { if (!PathAppend(pszBuffer, TEXT("*"))) { hr = E_FAIL; } } RegCloseKey(hkey); } if (SUCCEEDED(hr)) { hr = StringCchCopy(szKey, ARRAYSIZE(szKey), pszSid); if (SUCCEEDED(hr)) { if (!PathAppend(szKey, c_szRegStrDESKTOPNAMESPACE)) { hr = E_FAIL; } else { if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_USERS, szKey, 0, KEY_READ, &hkey)) { _HideRegItemsFromNameSpace(pszDestPath, hkey); RegCloseKey(hkey); } } } } } } _LoadUnloadHive(HKEY_USERS, pszSid, NULL); } } } } return hr; } HRESULT CCleanupWiz::_AppendDesktopFolderName(LPTSTR pszBuffer) { TCHAR szDesktopPath[MAX_PATH]; LPTSTR pszDesktopName; if (SHGetSpecialFolderPath(NULL, szDesktopPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE)) { pszDesktopName = PathFindFileName(szDesktopPath); } else { pszDesktopName = c_szDESKTOP_DIR; } return PathAppend(pszBuffer, pszDesktopName) ? S_OK : E_FAIL; } 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, c_szRegStrPROFILESDIR, NULL, (void*)szBuffer, &cb)) { TCHAR szAppend[MAX_PATH]; cb = sizeof(szAppend); if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, pszRegKey, pszRegValue, NULL, (void*)szAppend, &cb)) { if (PathAppend(szBuffer, szAppend)) { if (SUCCEEDED(_AppendDesktopFolderName(szBuffer))) { if (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) { ASSERT(pszDestPath && *pszDestPath && pszSid && *pszSid); HRESULT hr; WRITELOG(TEXT("**** SilentProcessUserBySid: %s **** "), pszSid, TEXT("")); TCHAR szTo[MAX_PATH + 1]; TCHAR szFrom[MAX_PATH + 1]; hr = StringCchCopy(szTo, ARRAYSIZE(szTo) - 1, pszDestPath); if (SUCCEEDED(hr)) { 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) { ASSERT(pszRegKey && *pszRegKey && pszRegValue && *pszRegValue && pszDestPath && *pszDestPath); HRESULT hr; TCHAR szTo[MAX_PATH + 1]; TCHAR szFrom[MAX_PATH + 1]; hr = StringCchCopy(szTo, ARRAYSIZE(szTo) - 1, pszDestPath); if (SUCCEEDED(hr)) { 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 == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegStrPROFILELIST, 0, KEY_READ, &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() { HRESULT hr; // 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, c_szOEM_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]; hr = SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, szPath); if (SUCCEEDED(hr)) { if (!PathAppend(szPath, _szFolderName)) { hr = E_FAIL; } else { SHCreateDirectoryEx(NULL, szPath, NULL); if (!PathIsDirectory(szPath)) { hr = E_FAIL; } else { hr = S_OK; STARTLOGGING(szPath); // Move regitems of All Users HKEY hkey; if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegStrDESKTOPNAMESPACE, 0, KEY_READ, &hkey)) { hr = E_FAIL; } else { _HideRegItemsFromNameSpace(szPath, hkey); RegCloseKey(hkey); } // Move desktop items of All Users if (FAILED(_SilentProcessUserByRegKey(szPath, c_szRegStrPROFILELIST, c_szRegStrALLUSERS))) { hr = E_FAIL; } // move desktop items of Default User if (FAILED(_SilentProcessUserByRegKey(szPath, c_szRegStrPROFILELIST, c_szRegStrDEFAULTUSER))) { hr = E_FAIL; } // Move desktop items of each normal users if (FAILED(_SilentProcessUsers(szPath))) { hr = E_FAIL; } STOPLOGGING; } } } return hr; } BOOL _ShouldPlaceIEDesktopIcon() { BOOL fRetVal = TRUE; DWORD dwData; DWORD cbData = sizeof(dwData); if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, c_szRegStrPATH_OCMANAGER, c_szRegStrIEACCESS, NULL, &dwData, &cbData)) && (dwData == 0)) { fRetVal = FALSE; } return fRetVal; } BOOL _ShouldUseMSNInternetAccessIcon() { BOOL fRetVal = FALSE; TCHAR szBuffer[4]; DWORD cbBuffer = sizeof(szBuffer); if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, c_szRegStrMSNCODES, c_szRegStrMSN_IAONLY, NULL, szBuffer, &cbBuffer)) && (!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 ++) { hr = StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), REGSTR_PATH_HIDDEN_DESKTOP_ICONS, (i == 0) ? c_szVALUE_STARTPANEL : c_szVALUE_CLASSICMENU); if (SUCCEEDED(hr)) { 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(c_szRegStrWMP_PATH_SETUP, c_szRegStrWMP_REGVALUE, REG_SZ, c_szRegStrYES, sizeof(TCHAR) * (ARRAYSIZE(c_szRegStrYES) + 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 hr = StringCchCopy(szDestPath, ARRAYSIZE(szDestPath), szSourcePath); if (SUCCEEDED(hr)) { if (!PathRemoveFileSpec(szSourcePath) || // remove Programs !PathRemoveFileSpec(szSourcePath)) // remove Start Menu { hr = E_FAIL; } else { hr = StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), szDestPath + lstrlen(szSourcePath)); if (SUCCEEDED(hr)) { // load "Default user" into szDestPath LoadString(g_hInst, IDS_DEFAULTUSER, szDestPath, ARRAYSIZE(szDestPath)); if (!PathRemoveFileSpec(szSourcePath) || // remove All Users, now szSourcePath is "docs and settings" !PathAppend(szSourcePath, szDestPath)) // now szSourcePath is "docs and settings\Default User" { hr = E_FAIL; } else { // sanity check, localizers may have inappropriately localized Default User on a system where it shouldn't be localized if (!PathIsDirectory(szSourcePath)) { // if so, remove what they gave us and just add the English "Default User", which is what it is on most machines if (!PathRemoveFileSpec(szSourcePath) || !PathAppend(szSourcePath, c_szRegStrDEFAULTUSER)) { hr = E_FAIL; } } if (SUCCEEDED(hr)) { if (!PathAppend(szSourcePath, szBuffer)) { hr = E_FAIL; } else { // 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)); if (!PathAppend(szSourcePath, szBuffer) || !PathAppend(szDestPath, szBuffer) || !CopyFileEx(szSourcePath, szDestPath, 0, 0, 0, COPY_FILE_FAIL_IF_EXISTS)) { hr = E_FAIL; } else { hr = S_OK; } } } } } } } } } 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 } if (PathAppend(szSourcePath, szBuffer) && PathAppend(szDestPath, szBuffer)) { if (CopyFileEx(szSourcePath, szDestPath, 0, 0, 0, COPY_FILE_FAIL_IF_EXISTS)) { hr = S_OK; } } } return hr; } void CreateDesktopIcons() { BOOL fIEDesktopIcon = _ShouldPlaceIEDesktopIcon(); _AddWMPIconToDesktop(); if (fIEDesktopIcon) { _AddIEIconToDesktop(); } _AddMSNIconToDesktop(fIEDesktopIcon || !_ShouldUseMSNInternetAccessIcon()); }