extern "C" HRESULT DAPI ShelGetKnownFolder( __out_z LPWSTR* psczFolderPath, __in REFKNOWNFOLDERID rfidFolder ) { HRESULT hr = S_OK; HMODULE hShell32Dll = NULL; PFN_SHGetKnownFolderPath pfn = NULL; LPWSTR pwzPath = NULL; hr = LoadSystemLibrary(L"shell32.dll", &hShell32Dll); if (E_MODNOTFOUND == hr) { TraceError(hr, "Failed to load shell32.dll"); ExitFunction1(hr = E_NOTIMPL); } ExitOnFailure(hr, "Failed to load shell32.dll."); pfn = reinterpret_cast<PFN_SHGetKnownFolderPath>(::GetProcAddress(hShell32Dll, "SHGetKnownFolderPath")); ExitOnNull(pfn, hr, E_NOTIMPL, "Failed to find SHGetKnownFolderPath entry point."); hr = pfn(rfidFolder, KF_FLAG_CREATE, NULL, &pwzPath); ExitOnFailure(hr, "Failed to get known folder path."); hr = StrAllocString(psczFolderPath, pwzPath, 0); ExitOnFailure1(hr, "Failed to copy shell folder path: %ls", pwzPath); hr = PathBackslashTerminate(psczFolderPath); ExitOnFailure1(hr, "Failed to backslash terminate shell folder path: %ls", *psczFolderPath); LExit: if (pwzPath) { ::CoTaskMemFree(pwzPath); } if (hShell32Dll) { ::FreeLibrary(hShell32Dll); } return hr; }
/******************************************************************** ShelGetFolder() - gets a folder by CSIDL. *******************************************************************/ extern "C" HRESULT DAPI ShelGetFolder( __out_z LPWSTR* psczFolderPath, __in int csidlFolder ) { HRESULT hr = S_OK; WCHAR wzPath[MAX_PATH]; hr = ::SHGetFolderPathW(NULL, csidlFolder | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, wzPath); ExitOnFailure1(hr, "Failed to get folder path for CSIDL: %d", csidlFolder); hr = StrAllocString(psczFolderPath, wzPath, 0); ExitOnFailure1(hr, "Failed to copy shell folder path: %ls", wzPath); hr = PathBackslashTerminate(psczFolderPath); ExitOnFailure1(hr, "Failed to backslash terminate shell folder path: %ls", *psczFolderPath); LExit: return hr; }
static HRESULT DeleteEmptyDirectoryChildren( __in_z LPCWSTR wzPath ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; WIN32_FIND_DATAW wfd = { }; HANDLE hFind = NULL; LPWSTR sczSubDirWithWildcard = NULL; LPWSTR sczPath = NULL; hr = PathConcat(wzPath, L"*", &sczSubDirWithWildcard); ExitOnFailure(hr, "Failed to concatenate wildcard character to directory name for search"); hFind = ::FindFirstFileW(sczSubDirWithWildcard, &wfd); if (INVALID_HANDLE_VALUE == hFind) { er = ::GetLastError(); hr = HRESULT_FROM_WIN32(er); if (E_PATHNOTFOUND == hr) { ExitFunction(); } ExitWithLastError(hr, "Failed to find first file with query: %ls", sczSubDirWithWildcard); } do { // Safety / silence code analysis tools wfd.cFileName[MAX_PATH - 1] = L'\0'; // Don't use "." or ".." if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, wfd.cFileName, -1, L".", -1)) { continue; } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, wfd.cFileName, -1, L"..", -1)) { continue; } hr = PathConcat(wzPath, wfd.cFileName, &sczPath); ExitOnFailure(hr, "Failed to concat filename '%ls' to directory: %ls", wfd.cFileName, wzPath); // If we found a directory, recurse! if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { hr = PathBackslashTerminate(&sczPath); ExitOnFailure(hr, "Failed to ensure path is backslash terminated: %ls", sczPath); hr = DeleteEmptyDirectoryChildren(sczPath); if (HRESULT_FROM_WIN32(ERROR_DIR_NOT_EMPTY) == hr) { hr = S_OK; } else { ExitOnFailure(hr, "Failed to recurse to directory: %ls", sczPath); hr = DirEnsureDelete(sczPath, FALSE, FALSE); if (HRESULT_FROM_WIN32(ERROR_DIR_NOT_EMPTY) == hr) { hr = S_OK; } ExitOnFailure(hr, "Failed to delete directory: %ls", sczPath); } } else { continue; } } while (::FindNextFileW(hFind, &wfd)); er = ::GetLastError(); if (ERROR_NO_MORE_FILES == er) { hr = S_OK; } else { ExitWithLastError(hr, "Failed while looping through files in directory: %ls", wzPath); } LExit: // There was nothing to read, it's still success if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) { hr = S_OK; } if (NULL != hFind) { FindClose(hFind); } ReleaseStr(sczSubDirWithWildcard); ReleaseStr(sczPath); return hr; }
extern "C" UINT WINAPI WixRemoveFoldersEx( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug WixRemoveFoldersEx"); HRESULT hr = S_OK; PMSIHANDLE hView; PMSIHANDLE hRec; LPWSTR sczId = NULL; LPWSTR sczComponent = NULL; LPWSTR sczProperty = NULL; LPWSTR sczPath = NULL; LPWSTR sczExpandedPath = NULL; int iMode = 0; DWORD dwCounter = 0; DWORD_PTR cchLen = 0; MSIHANDLE hTable = NULL; MSIHANDLE hColumns = NULL; hr = WcaInitialize(hInstall, "WixRemoveFoldersEx"); ExitOnFailure(hr, "Failed to initialize WixRemoveFoldersEx."); // anything to do? if (S_OK != WcaTableExists(L"WixRemoveFolderEx")) { WcaLog(LOGMSG_STANDARD, "WixRemoveFolderEx table doesn't exist, so there are no folders to remove."); ExitFunction(); } // query and loop through all the remove folders exceptions hr = WcaOpenExecuteView(vcsRemoveFolderExQuery, &hView); ExitOnFailure(hr, "Failed to open view on WixRemoveFolderEx table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { hr = WcaGetRecordString(hRec, rfqId, &sczId); ExitOnFailure(hr, "Failed to get remove folder identity."); hr = WcaGetRecordString(hRec, rfqComponent, &sczComponent); ExitOnFailure(hr, "Failed to get remove folder component."); hr = WcaGetRecordString(hRec, rfqProperty, &sczProperty); ExitOnFailure(hr, "Failed to get remove folder property."); hr = WcaGetRecordInteger(hRec, feqMode, &iMode); ExitOnFailure(hr, "Failed to get remove folder mode"); hr = WcaGetProperty(sczProperty, &sczPath); ExitOnFailure2(hr, "Failed to resolve remove folder property: %S for row: %S", sczProperty, sczId); // fail early if the property isn't set as you probably don't want your installers trying to delete SystemFolder // StringCchLengthW succeeds only if the string is zero characters plus 1 for the terminating null hr = ::StringCchLengthW(sczPath, 1, reinterpret_cast<UINT_PTR*>(&cchLen)); if (SUCCEEDED(hr)) { ExitOnFailure2(hr = E_INVALIDARG, "Missing folder property: %S for row: %S", sczProperty, sczId); } hr = PathExpand(&sczExpandedPath, sczPath, PATH_EXPAND_ENVIRONMENT); ExitOnFailure2(hr, "Failed to expand path: %S for row: %S", sczPath, sczId); hr = PathBackslashTerminate(&sczExpandedPath); ExitOnFailure1(hr, "Failed to backslash-terminate path: %S", sczExpandedPath); WcaLog(LOGMSG_STANDARD, "Recursing path: %S for row: %S.", sczExpandedPath, sczId); hr = RecursePath(sczExpandedPath, sczId, sczComponent, sczProperty, iMode, &dwCounter, &hTable, &hColumns); ExitOnFailure2(hr, "Failed while navigating path: %S for row: %S", sczPath, sczId); } // reaching the end of the list is actually a good thing, not an error if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "Failure occured while processing WixRemoveFolderEx table"); LExit: if (hColumns) { ::MsiCloseHandle(hColumns); } if (hTable) { ::MsiCloseHandle(hTable); } ReleaseStr(sczExpandedPath); ReleaseStr(sczPath); ReleaseStr(sczProperty); ReleaseStr(sczComponent); ReleaseStr(sczId); DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
static HRESULT ReadRegKeyWriteLegacyDb( __in CFGDB_STRUCT *pcdb, __in LEGACY_SYNC_PRODUCT_SESSION *pSyncProductSession, __in LEGACY_REGISTRY_KEY *pRegKey, __in_z LPCWSTR wzSubKey ) { HRESULT hr = S_OK; HKEY hkKey = NULL; DWORD dwType = 0; DWORD dwIndex = 0; LPWSTR sczValueName = NULL; LPWSTR sczSubkeyName = NULL; LPWSTR sczSubkeyPath = NULL; hr = RegOpen(ManifestConvertToRootKey(pRegKey->dwRoot), wzSubKey, KEY_READ, &hkKey); if (E_FILENOTFOUND == hr) { ExitFunction1(hr = S_OK); } ExitOnFailure(hr, "Failed to open regkey: %ls", wzSubKey); dwIndex = 0; while (E_NOMOREITEMS != (hr = RegValueEnum(hkKey, dwIndex, &sczValueName, &dwType))) { ExitOnFailure(hr, "Failed to enumerate value %u", dwIndex); hr = ReadRegValueWriteLegacyDb(pcdb, pSyncProductSession, pRegKey, hkKey, wzSubKey, sczValueName, dwType); ExitOnFailure(hr, "Failed to write registry value setting: %ls", sczValueName); ++dwIndex; } // Recurse and handle subkeys as well dwIndex = 0; while (E_NOMOREITEMS != (hr = RegKeyEnum(hkKey, dwIndex, &sczSubkeyName))) { ExitOnFailure(hr, "Failed to enumerate key %u", dwIndex); hr = StrAllocString(&sczSubkeyPath, wzSubKey, 0); ExitOnFailure(hr, "Failed to allocate copy of subkey name"); hr = PathBackslashTerminate(&sczSubkeyPath); ExitOnFailure(hr, "Failed to ensure path is terminated with a backslash"); hr = StrAllocConcat(&sczSubkeyPath, sczSubkeyName, 0); ExitOnFailure(hr, "Failed to concatenate subkey name to subkey path"); hr = ReadRegKeyWriteLegacyDb(pcdb, pSyncProductSession, pRegKey, sczSubkeyPath); ExitOnFailure(hr, "Failed to read regkey and write settings for root: %u, subkey: %ls", pRegKey->dwRoot, sczSubkeyPath); ++dwIndex; } if (E_NOMOREITEMS == hr) { hr = S_OK; } LExit: ReleaseRegKey(hkKey); ReleaseStr(sczValueName); ReleaseStr(sczSubkeyName); ReleaseStr(sczSubkeyPath); return hr; }