#include #include #include #include "CleanupWiz.h" #include "resource.h" #include "priv.h" #include "dblnul.h" #include 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()); }