diff options
Diffstat (limited to '')
41 files changed, 1890 insertions, 392 deletions
diff --git a/src/burn/engine/approvedexe.cpp b/src/burn/engine/approvedexe.cpp index 2a96868e..d8bd956b 100644 --- a/src/burn/engine/approvedexe.cpp +++ b/src/burn/engine/approvedexe.cpp | |||
| @@ -148,6 +148,7 @@ extern "C" HRESULT ApprovedExesLaunch( | |||
| 148 | LPWSTR sczCommand = NULL; | 148 | LPWSTR sczCommand = NULL; |
| 149 | LPWSTR sczCommandObfuscated = NULL; | 149 | LPWSTR sczCommandObfuscated = NULL; |
| 150 | LPWSTR sczExecutableDirectory = NULL; | 150 | LPWSTR sczExecutableDirectory = NULL; |
| 151 | size_t cchExecutableDirectory = 0; | ||
| 151 | STARTUPINFOW si = { }; | 152 | STARTUPINFOW si = { }; |
| 152 | PROCESS_INFORMATION pi = { }; | 153 | PROCESS_INFORMATION pi = { }; |
| 153 | 154 | ||
| @@ -177,9 +178,17 @@ extern "C" HRESULT ApprovedExesLaunch( | |||
| 177 | // Try to get the directory of the executable so we can set the current directory of the process to help those executables | 178 | // Try to get the directory of the executable so we can set the current directory of the process to help those executables |
| 178 | // that expect stuff to be relative to them. Best effort only. | 179 | // that expect stuff to be relative to them. Best effort only. |
| 179 | hr = PathGetDirectory(pLaunchApprovedExe->sczExecutablePath, &sczExecutableDirectory); | 180 | hr = PathGetDirectory(pLaunchApprovedExe->sczExecutablePath, &sczExecutableDirectory); |
| 181 | if (SUCCEEDED(hr)) | ||
| 182 | { | ||
| 183 | // CreateProcessW has undocumented MAX_PATH restriction for lpCurrentDirectory even when long path support is enabled. | ||
| 184 | hr = ::StringCchLengthW(sczExecutableDirectory, MAX_PATH - 1, &cchExecutableDirectory); | ||
| 185 | } | ||
| 186 | |||
| 180 | if (FAILED(hr)) | 187 | if (FAILED(hr)) |
| 181 | { | 188 | { |
| 182 | ReleaseNullStr(sczExecutableDirectory); | 189 | ReleaseNullStr(sczExecutableDirectory); |
| 190 | |||
| 191 | hr = S_OK; | ||
| 183 | } | 192 | } |
| 184 | 193 | ||
| 185 | LogId(REPORT_STANDARD, MSG_LAUNCHING_APPROVED_EXE, pLaunchApprovedExe->sczExecutablePath, sczCommandObfuscated); | 194 | LogId(REPORT_STANDARD, MSG_LAUNCHING_APPROVED_EXE, pLaunchApprovedExe->sczExecutablePath, sczCommandObfuscated); |
diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp index cf9de1c3..eb5cc508 100644 --- a/src/burn/engine/cache.cpp +++ b/src/burn/engine/cache.cpp | |||
| @@ -174,7 +174,7 @@ extern "C" HRESULT CacheInitialize( | |||
| 174 | 174 | ||
| 175 | // Cache paths are initialized once so they cannot be changed while the engine is caching payloads. | 175 | // Cache paths are initialized once so they cannot be changed while the engine is caching payloads. |
| 176 | // Always construct the default machine package cache path so we can determine if we're redirected. | 176 | // Always construct the default machine package cache path so we can determine if we're redirected. |
| 177 | hr = PathGetKnownFolder(CSIDL_COMMON_APPDATA, &sczAppData); | 177 | hr = ShelGetFolder(&sczAppData, CSIDL_COMMON_APPDATA); |
| 178 | ExitOnFailure(hr, "Failed to find local %hs appdata directory.", "per-machine"); | 178 | ExitOnFailure(hr, "Failed to find local %hs appdata directory.", "per-machine"); |
| 179 | 179 | ||
| 180 | hr = PathConcat(sczAppData, PACKAGE_CACHE_FOLDER_NAME, &pCache->sczDefaultMachinePackageCache); | 180 | hr = PathConcat(sczAppData, PACKAGE_CACHE_FOLDER_NAME, &pCache->sczDefaultMachinePackageCache); |
| @@ -210,7 +210,7 @@ extern "C" HRESULT CacheInitialize( | |||
| 210 | pCache->fCustomMachinePackageCache = !fPathEqual; | 210 | pCache->fCustomMachinePackageCache = !fPathEqual; |
| 211 | 211 | ||
| 212 | 212 | ||
| 213 | hr = PathGetKnownFolder(CSIDL_LOCAL_APPDATA, &sczAppData); | 213 | hr = ShelGetFolder(&sczAppData, CSIDL_LOCAL_APPDATA); |
| 214 | ExitOnFailure(hr, "Failed to find local %hs appdata directory.", "per-user"); | 214 | ExitOnFailure(hr, "Failed to find local %hs appdata directory.", "per-user"); |
| 215 | 215 | ||
| 216 | hr = PathConcat(sczAppData, PACKAGE_CACHE_FOLDER_NAME, &pCache->sczDefaultUserPackageCache); | 216 | hr = PathConcat(sczAppData, PACKAGE_CACHE_FOLDER_NAME, &pCache->sczDefaultUserPackageCache); |
| @@ -1469,7 +1469,7 @@ static HRESULT CalculateWorkingFolders( | |||
| 1469 | HRESULT hr = S_OK; | 1469 | HRESULT hr = S_OK; |
| 1470 | LPWSTR sczBaseAcquisitionPath = NULL; | 1470 | LPWSTR sczBaseAcquisitionPath = NULL; |
| 1471 | 1471 | ||
| 1472 | hr = PathGetTempPath(&sczBaseAcquisitionPath); | 1472 | hr = PathGetTempPath(&sczBaseAcquisitionPath, NULL); |
| 1473 | ExitOnFailure(hr, "Failed to get temp folder path for acquisition folder base."); | 1473 | ExitOnFailure(hr, "Failed to get temp folder path for acquisition folder base."); |
| 1474 | 1474 | ||
| 1475 | hr = PathBackslashTerminate(&sczBaseAcquisitionPath); | 1475 | hr = PathBackslashTerminate(&sczBaseAcquisitionPath); |
diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp index 7fca1141..13075497 100644 --- a/src/burn/engine/engine.cpp +++ b/src/burn/engine/engine.cpp | |||
| @@ -486,7 +486,7 @@ static HRESULT RunUntrusted( | |||
| 486 | 486 | ||
| 487 | si.cb = sizeof(si); | 487 | si.cb = sizeof(si); |
| 488 | si.wShowWindow = static_cast<WORD>(pEngineState->command.nCmdShow); | 488 | si.wShowWindow = static_cast<WORD>(pEngineState->command.nCmdShow); |
| 489 | if (!::CreateProcessW(wzCleanRoomBundlePath, sczFullCommandLine, NULL, NULL, TRUE, 0, 0, NULL, &si, &pi)) | 489 | if (!::CreateProcessW(wzCleanRoomBundlePath, sczFullCommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) |
| 490 | { | 490 | { |
| 491 | ExitWithLastError(hr, "Failed to launch clean room process: %ls", sczFullCommandLine); | 491 | ExitWithLastError(hr, "Failed to launch clean room process: %ls", sczFullCommandLine); |
| 492 | } | 492 | } |
diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp index f7be082d..701adb74 100644 --- a/src/burn/engine/exeengine.cpp +++ b/src/burn/engine/exeengine.cpp | |||
| @@ -695,6 +695,7 @@ extern "C" HRESULT ExeEngineRunProcess( | |||
| 695 | BOOL fDelayedCancel = FALSE; | 695 | BOOL fDelayedCancel = FALSE; |
| 696 | BOOL fFireAndForget = BURN_PACKAGE_TYPE_EXE == pPackage->type && pPackage->Exe.fFireAndForget; | 696 | BOOL fFireAndForget = BURN_PACKAGE_TYPE_EXE == pPackage->type && pPackage->Exe.fFireAndForget; |
| 697 | BOOL fInheritHandles = BURN_PACKAGE_TYPE_BUNDLE == pPackage->type; | 697 | BOOL fInheritHandles = BURN_PACKAGE_TYPE_BUNDLE == pPackage->type; |
| 698 | size_t cchCachedDirectory = 0; | ||
| 698 | 699 | ||
| 699 | // Always add user supplied arguments last. | 700 | // Always add user supplied arguments last. |
| 700 | if (wzUserArgs) | 701 | if (wzUserArgs) |
| @@ -703,6 +704,12 @@ extern "C" HRESULT ExeEngineRunProcess( | |||
| 703 | ExitOnFailure(hr, "Failed to append user args."); | 704 | ExitOnFailure(hr, "Failed to append user args."); |
| 704 | } | 705 | } |
| 705 | 706 | ||
| 707 | // CreateProcessW has undocumented MAX_PATH restriction for lpCurrentDirectory even when long path support is enabled. | ||
| 708 | if (wzCachedDirectory && FAILED(::StringCchLengthW(wzCachedDirectory, MAX_PATH - 1, &cchCachedDirectory))) | ||
| 709 | { | ||
| 710 | wzCachedDirectory = NULL; | ||
| 711 | } | ||
| 712 | |||
| 706 | // Make the cache location of the executable the current directory to help those executables | 713 | // Make the cache location of the executable the current directory to help those executables |
| 707 | // that expect stuff to be relative to them. | 714 | // that expect stuff to be relative to them. |
| 708 | si.cb = sizeof(si); | 715 | si.cb = sizeof(si); |
diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp index 1020d01f..68f0c35b 100644 --- a/src/burn/engine/logging.cpp +++ b/src/burn/engine/logging.cpp | |||
| @@ -211,7 +211,7 @@ extern "C" void LoggingOpenFailed() | |||
| 211 | LPCWSTR* lpStrings = const_cast<LPCWSTR*>(&LOG_FAILED_EVENT_LOG_MESSAGE); | 211 | LPCWSTR* lpStrings = const_cast<LPCWSTR*>(&LOG_FAILED_EVENT_LOG_MESSAGE); |
| 212 | WORD wNumStrings = 1; | 212 | WORD wNumStrings = 1; |
| 213 | 213 | ||
| 214 | hr = LogOpen(NULL, L"Setup", L"_Failed", L"txt", FALSE, FALSE, NULL); | 214 | hr = LogOpen(NULL, L"Setup", L"_Failed", L"log", FALSE, FALSE, NULL); |
| 215 | if (SUCCEEDED(hr)) | 215 | if (SUCCEEDED(hr)) |
| 216 | { | 216 | { |
| 217 | ExitFunction(); | 217 | ExitFunction(); |
| @@ -965,19 +965,14 @@ static HRESULT GetNonSessionSpecificTempFolder( | |||
| 965 | ) | 965 | ) |
| 966 | { | 966 | { |
| 967 | HRESULT hr = S_OK; | 967 | HRESULT hr = S_OK; |
| 968 | WCHAR wzTempFolder[MAX_PATH] = { }; | 968 | LPWSTR sczTempFolder = NULL; |
| 969 | SIZE_T cchTempFolder = 0; | 969 | SIZE_T cchTempFolder = 0; |
| 970 | DWORD dwSessionId = 0; | 970 | DWORD dwSessionId = 0; |
| 971 | LPWSTR sczSessionId = 0; | 971 | LPWSTR sczSessionId = 0; |
| 972 | SIZE_T cchSessionId = 0; | 972 | SIZE_T cchSessionId = 0; |
| 973 | 973 | ||
| 974 | if (!::GetTempPathW(countof(wzTempFolder), wzTempFolder)) | 974 | hr = PathGetTempPath(&sczTempFolder, &cchTempFolder); |
| 975 | { | 975 | ExitOnFailure(hr, "Failed to get temp folder."); |
| 976 | ExitWithLastError(hr, "Failed to get temp folder."); | ||
| 977 | } | ||
| 978 | |||
| 979 | hr = ::StringCchLengthW(wzTempFolder, countof(wzTempFolder), reinterpret_cast<size_t*>(&cchTempFolder)); | ||
| 980 | ExitOnFailure(hr, "Failed to get length of temp folder."); | ||
| 981 | 976 | ||
| 982 | // If our session id is in the TEMP path then remove that part so we get the non-session | 977 | // If our session id is in the TEMP path then remove that part so we get the non-session |
| 983 | // specific temporary folder. | 978 | // specific temporary folder. |
| @@ -989,17 +984,18 @@ static HRESULT GetNonSessionSpecificTempFolder( | |||
| 989 | hr = ::StringCchLengthW(sczSessionId, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cchSessionId)); | 984 | hr = ::StringCchLengthW(sczSessionId, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cchSessionId)); |
| 990 | ExitOnFailure(hr, "Failed to get length of session id string."); | 985 | ExitOnFailure(hr, "Failed to get length of session id string."); |
| 991 | 986 | ||
| 992 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzTempFolder + cchTempFolder - cchSessionId, static_cast<DWORD>(cchSessionId), sczSessionId, static_cast<DWORD>(cchSessionId))) | 987 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, sczTempFolder + cchTempFolder - cchSessionId, static_cast<DWORD>(cchSessionId), sczSessionId, static_cast<DWORD>(cchSessionId))) |
| 993 | { | 988 | { |
| 994 | cchTempFolder -= cchSessionId; | 989 | cchTempFolder -= cchSessionId; |
| 995 | } | 990 | } |
| 996 | } | 991 | } |
| 997 | 992 | ||
| 998 | hr = StrAllocString(psczNonSessionTempFolder, wzTempFolder, cchTempFolder); | 993 | hr = StrAllocString(psczNonSessionTempFolder, sczTempFolder, cchTempFolder); |
| 999 | ExitOnFailure(hr, "Failed to copy temp folder."); | 994 | ExitOnFailure(hr, "Failed to copy temp folder."); |
| 1000 | 995 | ||
| 1001 | LExit: | 996 | LExit: |
| 1002 | ReleaseStr(sczSessionId); | 997 | ReleaseStr(sczSessionId); |
| 998 | ReleaseStr(sczTempFolder); | ||
| 1003 | 999 | ||
| 1004 | return hr; | 1000 | return hr; |
| 1005 | } | 1001 | } |
diff --git a/src/burn/engine/msuengine.cpp b/src/burn/engine/msuengine.cpp index 1b051165..400fdc92 100644 --- a/src/burn/engine/msuengine.cpp +++ b/src/burn/engine/msuengine.cpp | |||
| @@ -269,7 +269,6 @@ extern "C" HRESULT MsuEngineExecutePackage( | |||
| 269 | HRESULT hr = S_OK; | 269 | HRESULT hr = S_OK; |
| 270 | LPWSTR sczCachedDirectory = NULL; | 270 | LPWSTR sczCachedDirectory = NULL; |
| 271 | LPWSTR sczMsuPath = NULL; | 271 | LPWSTR sczMsuPath = NULL; |
| 272 | LPWSTR sczWindowsPath = NULL; | ||
| 273 | LPWSTR sczSystemPath = NULL; | 272 | LPWSTR sczSystemPath = NULL; |
| 274 | LPWSTR sczWusaPath = NULL; | 273 | LPWSTR sczWusaPath = NULL; |
| 275 | LPWSTR sczCommand = NULL; | 274 | LPWSTR sczCommand = NULL; |
| @@ -294,15 +293,12 @@ extern "C" HRESULT MsuEngineExecutePackage( | |||
| 294 | // get wusa.exe path | 293 | // get wusa.exe path |
| 295 | if (fUseSysNativePath) | 294 | if (fUseSysNativePath) |
| 296 | { | 295 | { |
| 297 | hr = PathGetKnownFolder(CSIDL_WINDOWS, &sczWindowsPath); | 296 | hr = PathSystemWindowsSubdirectory(L"SysNative\\", &sczSystemPath); |
| 298 | ExitOnFailure(hr, "Failed to find Windows directory."); | ||
| 299 | |||
| 300 | hr = PathConcat(sczWindowsPath, L"SysNative\\", &sczSystemPath); | ||
| 301 | ExitOnFailure(hr, "Failed to append SysNative directory."); | 297 | ExitOnFailure(hr, "Failed to append SysNative directory."); |
| 302 | } | 298 | } |
| 303 | else | 299 | else |
| 304 | { | 300 | { |
| 305 | hr = PathGetKnownFolder(CSIDL_SYSTEM, &sczSystemPath); | 301 | hr = PathGetSystemDirectory(&sczSystemPath); |
| 306 | ExitOnFailure(hr, "Failed to find System32 directory."); | 302 | ExitOnFailure(hr, "Failed to find System32 directory."); |
| 307 | } | 303 | } |
| 308 | 304 | ||
| @@ -390,7 +386,6 @@ LExit: | |||
| 390 | ReleaseStr(sczCachedDirectory); | 386 | ReleaseStr(sczCachedDirectory); |
| 391 | ReleaseStr(sczMsuPath); | 387 | ReleaseStr(sczMsuPath); |
| 392 | ReleaseStr(sczSystemPath); | 388 | ReleaseStr(sczSystemPath); |
| 393 | ReleaseStr(sczWindowsPath); | ||
| 394 | ReleaseStr(sczWusaPath); | 389 | ReleaseStr(sczWusaPath); |
| 395 | ReleaseStr(sczCommand); | 390 | ReleaseStr(sczCommand); |
| 396 | ReleaseStr(sczEscapedKB); | 391 | ReleaseStr(sczEscapedKB); |
diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp index a97234ef..6f84caba 100644 --- a/src/burn/engine/userexperience.cpp +++ b/src/burn/engine/userexperience.cpp | |||
| @@ -99,6 +99,7 @@ extern "C" HRESULT UserExperienceLoad( | |||
| 99 | HRESULT hr = S_OK; | 99 | HRESULT hr = S_OK; |
| 100 | BOOTSTRAPPER_CREATE_ARGS args = { }; | 100 | BOOTSTRAPPER_CREATE_ARGS args = { }; |
| 101 | BOOTSTRAPPER_CREATE_RESULTS results = { }; | 101 | BOOTSTRAPPER_CREATE_RESULTS results = { }; |
| 102 | LPCWSTR wzPath = pUserExperience->payloads.rgPayloads[0].sczLocalFilePath; | ||
| 102 | 103 | ||
| 103 | args.cbSize = sizeof(BOOTSTRAPPER_CREATE_ARGS); | 104 | args.cbSize = sizeof(BOOTSTRAPPER_CREATE_ARGS); |
| 104 | args.pCommand = pCommand; | 105 | args.pCommand = pCommand; |
| @@ -109,8 +110,8 @@ extern "C" HRESULT UserExperienceLoad( | |||
| 109 | results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); | 110 | results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); |
| 110 | 111 | ||
| 111 | // Load BA DLL. | 112 | // Load BA DLL. |
| 112 | pUserExperience->hUXModule = ::LoadLibraryExW(pUserExperience->payloads.rgPayloads[0].sczLocalFilePath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); | 113 | pUserExperience->hUXModule = ::LoadLibraryExW(wzPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); |
| 113 | ExitOnNullWithLastError(pUserExperience->hUXModule, hr, "Failed to load BA DLL."); | 114 | ExitOnNullWithLastError(pUserExperience->hUXModule, hr, "Failed to load BA DLL: %ls", wzPath); |
| 114 | 115 | ||
| 115 | // Get BootstrapperApplicationCreate entry-point. | 116 | // Get BootstrapperApplicationCreate entry-point. |
| 116 | PFN_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = (PFN_BOOTSTRAPPER_APPLICATION_CREATE)::GetProcAddress(pUserExperience->hUXModule, "BootstrapperApplicationCreate"); | 117 | PFN_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = (PFN_BOOTSTRAPPER_APPLICATION_CREATE)::GetProcAddress(pUserExperience->hUXModule, "BootstrapperApplicationCreate"); |
diff --git a/src/burn/engine/variable.cpp b/src/burn/engine/variable.cpp index c96e9d95..8d208a66 100644 --- a/src/burn/engine/variable.cpp +++ b/src/burn/engine/variable.cpp | |||
| @@ -1947,18 +1947,18 @@ static HRESULT InitializeVariableTempFolder( | |||
| 1947 | UNREFERENCED_PARAMETER(dwpData); | 1947 | UNREFERENCED_PARAMETER(dwpData); |
| 1948 | 1948 | ||
| 1949 | HRESULT hr = S_OK; | 1949 | HRESULT hr = S_OK; |
| 1950 | WCHAR wzPath[MAX_PATH] = { }; | 1950 | LPWSTR sczPath = NULL; |
| 1951 | 1951 | ||
| 1952 | if (!::GetTempPathW(MAX_PATH, wzPath)) | 1952 | hr = PathGetTempPath(&sczPath, NULL); |
| 1953 | { | 1953 | ExitOnFailure(hr, "Failed to get temp path."); |
| 1954 | ExitWithLastError(hr, "Failed to get temp path."); | ||
| 1955 | } | ||
| 1956 | 1954 | ||
| 1957 | // set value | 1955 | // set value |
| 1958 | hr = BVariantSetString(pValue, wzPath, 0, FALSE); | 1956 | hr = BVariantSetString(pValue, sczPath, 0, FALSE); |
| 1959 | ExitOnFailure(hr, "Failed to set variant value."); | 1957 | ExitOnFailure(hr, "Failed to set variant value."); |
| 1960 | 1958 | ||
| 1961 | LExit: | 1959 | LExit: |
| 1960 | ReleaseStr(sczPath); | ||
| 1961 | |||
| 1962 | return hr; | 1962 | return hr; |
| 1963 | } | 1963 | } |
| 1964 | 1964 | ||
| @@ -1969,7 +1969,7 @@ static HRESULT InitializeVariableSystemFolder( | |||
| 1969 | { | 1969 | { |
| 1970 | HRESULT hr = S_OK; | 1970 | HRESULT hr = S_OK; |
| 1971 | BOOL f64 = (BOOL)dwpData; | 1971 | BOOL f64 = (BOOL)dwpData; |
| 1972 | WCHAR wzSystemFolder[MAX_PATH + 2] = { }; | 1972 | LPWSTR sczSystemFolder = NULL; |
| 1973 | 1973 | ||
| 1974 | #if !defined(_WIN64) | 1974 | #if !defined(_WIN64) |
| 1975 | BOOL fIsWow64 = FALSE; | 1975 | BOOL fIsWow64 = FALSE; |
| @@ -1979,57 +1979,43 @@ static HRESULT InitializeVariableSystemFolder( | |||
| 1979 | { | 1979 | { |
| 1980 | if (f64) | 1980 | if (f64) |
| 1981 | { | 1981 | { |
| 1982 | if (!::GetSystemDirectoryW(wzSystemFolder, countof(wzSystemFolder))) | 1982 | hr = PathGetSystemDirectory(&sczSystemFolder); |
| 1983 | { | 1983 | ExitOnFailure(hr, "Failed to get 64-bit system folder."); |
| 1984 | ExitWithLastError(hr, "Failed to get 64-bit system folder."); | ||
| 1985 | } | ||
| 1986 | } | 1984 | } |
| 1987 | else | 1985 | else |
| 1988 | { | 1986 | { |
| 1989 | if (!::GetSystemWow64DirectoryW(wzSystemFolder, countof(wzSystemFolder))) | 1987 | hr = PathGetSystemWow64Directory(&sczSystemFolder); |
| 1990 | { | 1988 | ExitOnFailure(hr, "Failed to get 32-bit system folder."); |
| 1991 | ExitWithLastError(hr, "Failed to get 32-bit system folder."); | ||
| 1992 | } | ||
| 1993 | } | 1989 | } |
| 1994 | } | 1990 | } |
| 1995 | else | 1991 | else |
| 1996 | { | 1992 | { |
| 1997 | if (!f64) | 1993 | if (!f64) |
| 1998 | { | 1994 | { |
| 1999 | if (!::GetSystemDirectoryW(wzSystemFolder, countof(wzSystemFolder))) | 1995 | hr = PathGetSystemDirectory(&sczSystemFolder); |
| 2000 | { | 1996 | ExitOnFailure(hr, "Failed to get 32-bit system folder."); |
| 2001 | ExitWithLastError(hr, "Failed to get 32-bit system folder."); | ||
| 2002 | } | ||
| 2003 | } | 1997 | } |
| 2004 | } | 1998 | } |
| 2005 | #else | 1999 | #else |
| 2006 | if (f64) | 2000 | if (f64) |
| 2007 | { | 2001 | { |
| 2008 | if (!::GetSystemDirectoryW(wzSystemFolder, countof(wzSystemFolder))) | 2002 | hr = PathGetSystemDirectory(&sczSystemFolder); |
| 2009 | { | 2003 | ExitOnFailure(hr, "Failed to get 64-bit system folder."); |
| 2010 | ExitWithLastError(hr, "Failed to get 64-bit system folder."); | ||
| 2011 | } | ||
| 2012 | } | 2004 | } |
| 2013 | else | 2005 | else |
| 2014 | { | 2006 | { |
| 2015 | if (!::GetSystemWow64DirectoryW(wzSystemFolder, countof(wzSystemFolder))) | 2007 | hr = PathGetSystemWow64Directory(&sczSystemFolder); |
| 2016 | { | 2008 | ExitOnFailure(hr, "Failed to get 32-bit system folder."); |
| 2017 | ExitWithLastError(hr, "Failed to get 32-bit system folder."); | ||
| 2018 | } | ||
| 2019 | } | 2009 | } |
| 2020 | #endif | 2010 | #endif |
| 2021 | 2011 | ||
| 2022 | if (*wzSystemFolder) | ||
| 2023 | { | ||
| 2024 | hr = PathFixedBackslashTerminate(wzSystemFolder, countof(wzSystemFolder)); | ||
| 2025 | ExitOnFailure(hr, "Failed to backslash terminate system folder."); | ||
| 2026 | } | ||
| 2027 | |||
| 2028 | // set value | 2012 | // set value |
| 2029 | hr = BVariantSetString(pValue, wzSystemFolder, 0, FALSE); | 2013 | hr = BVariantSetString(pValue, sczSystemFolder, 0, FALSE); |
| 2030 | ExitOnFailure(hr, "Failed to set system folder variant value."); | 2014 | ExitOnFailure(hr, "Failed to set system folder variant value."); |
| 2031 | 2015 | ||
| 2032 | LExit: | 2016 | LExit: |
| 2017 | ReleaseStr(sczSystemFolder); | ||
| 2018 | |||
| 2033 | return hr; | 2019 | return hr; |
| 2034 | } | 2020 | } |
| 2035 | 2021 | ||
| @@ -2041,26 +2027,25 @@ static HRESULT InitializeVariableWindowsVolumeFolder( | |||
| 2041 | UNREFERENCED_PARAMETER(dwpData); | 2027 | UNREFERENCED_PARAMETER(dwpData); |
| 2042 | 2028 | ||
| 2043 | HRESULT hr = S_OK; | 2029 | HRESULT hr = S_OK; |
| 2044 | WCHAR wzWindowsPath[MAX_PATH] = { }; | 2030 | LPWSTR sczWindowsPath = NULL; |
| 2045 | WCHAR wzVolumePath[MAX_PATH] = { }; | 2031 | LPWSTR sczVolumePath = NULL; |
| 2046 | 2032 | ||
| 2047 | // get windows directory | 2033 | // get windows directory |
| 2048 | if (!::GetWindowsDirectoryW(wzWindowsPath, countof(wzWindowsPath))) | 2034 | hr = PathSystemWindowsSubdirectory(NULL, &sczWindowsPath); |
| 2049 | { | 2035 | ExitOnFailure(hr, "Failed to get windows directory."); |
| 2050 | ExitWithLastError(hr, "Failed to get windows directory."); | ||
| 2051 | } | ||
| 2052 | 2036 | ||
| 2053 | // get volume path name | 2037 | // get volume path name |
| 2054 | if (!::GetVolumePathNameW(wzWindowsPath, wzVolumePath, MAX_PATH)) | 2038 | hr = PathGetVolumePathName(sczWindowsPath, &sczVolumePath); |
| 2055 | { | 2039 | ExitOnFailure(hr, "Failed to get volume path name."); |
| 2056 | ExitWithLastError(hr, "Failed to get volume path name."); | ||
| 2057 | } | ||
| 2058 | 2040 | ||
| 2059 | // set value | 2041 | // set value |
| 2060 | hr = BVariantSetString(pValue, wzVolumePath, 0, FALSE); | 2042 | hr = BVariantSetString(pValue, sczVolumePath, 0, FALSE); |
| 2061 | ExitOnFailure(hr, "Failed to set variant value."); | 2043 | ExitOnFailure(hr, "Failed to set variant value."); |
| 2062 | 2044 | ||
| 2063 | LExit: | 2045 | LExit: |
| 2046 | ReleaseStr(sczWindowsPath); | ||
| 2047 | ReleaseStr(sczVolumePath); | ||
| 2048 | |||
| 2064 | return hr; | 2049 | return hr; |
| 2065 | } | 2050 | } |
| 2066 | 2051 | ||
diff --git a/src/burn/test/BurnUnitTest/RegistrationTest.cpp b/src/burn/test/BurnUnitTest/RegistrationTest.cpp index 883b9cc8..aa3bd34b 100644 --- a/src/burn/test/BurnUnitTest/RegistrationTest.cpp +++ b/src/burn/test/BurnUnitTest/RegistrationTest.cpp | |||
| @@ -108,8 +108,8 @@ namespace Bootstrapper | |||
| 108 | TestThrowOnFailure(hr, L"Failed to register bundle."); | 108 | TestThrowOnFailure(hr, L"Failed to register bundle."); |
| 109 | 109 | ||
| 110 | // verify that registration was created | 110 | // verify that registration was created |
| 111 | Assert::True(Directory::Exists(cacheDirectory)); | 111 | Assert::True(Directory::Exists(cacheDirectory), "Cache directory didn't exist."); |
| 112 | Assert::True(File::Exists(Path::Combine(cacheDirectory, gcnew String(L"setup.exe")))); | 112 | Assert::True(File::Exists(Path::Combine(cacheDirectory, gcnew String(L"setup.exe"))), "Bundle exe wasn't cached."); |
| 113 | 113 | ||
| 114 | this->ValidateUninstallKeyResume(Int32(BURN_RESUME_MODE_ACTIVE)); | 114 | this->ValidateUninstallKeyResume(Int32(BURN_RESUME_MODE_ACTIVE)); |
| 115 | this->ValidateRunOnceKeyEntry(cacheExePath); | 115 | this->ValidateRunOnceKeyEntry(cacheExePath); |
| @@ -119,7 +119,7 @@ namespace Bootstrapper | |||
| 119 | TestThrowOnFailure(hr, L"Failed to unregister bundle."); | 119 | TestThrowOnFailure(hr, L"Failed to unregister bundle."); |
| 120 | 120 | ||
| 121 | // verify that registration was removed | 121 | // verify that registration was removed |
| 122 | Assert::False(Directory::Exists(cacheDirectory)); | 122 | Assert::False(Directory::Exists(cacheDirectory), "Cache directory wasn't removed."); |
| 123 | 123 | ||
| 124 | this->ValidateUninstallKeyNull(L"Resume"); | 124 | this->ValidateUninstallKeyNull(L"Resume"); |
| 125 | this->ValidateRunOnceKeyString(TEST_BUNDLE_ID, nullptr); | 125 | this->ValidateRunOnceKeyString(TEST_BUNDLE_ID, nullptr); |
diff --git a/src/internal/WixBuildTools.TestSupport/ExternalExecutable.cs b/src/internal/WixBuildTools.TestSupport/ExternalExecutable.cs index eb07aa13..4a932645 100644 --- a/src/internal/WixBuildTools.TestSupport/ExternalExecutable.cs +++ b/src/internal/WixBuildTools.TestSupport/ExternalExecutable.cs | |||
| @@ -2,11 +2,16 @@ | |||
| 2 | 2 | ||
| 3 | namespace WixBuildTools.TestSupport | 3 | namespace WixBuildTools.TestSupport |
| 4 | { | 4 | { |
| 5 | using System; | ||
| 5 | using System.Collections.Concurrent; | 6 | using System.Collections.Concurrent; |
| 6 | using System.Collections.Generic; | 7 | using System.Collections.Generic; |
| 8 | using System.ComponentModel; | ||
| 7 | using System.Diagnostics; | 9 | using System.Diagnostics; |
| 8 | using System.IO; | 10 | using System.IO; |
| 11 | using System.Runtime.InteropServices; | ||
| 9 | using System.Text; | 12 | using System.Text; |
| 13 | using System.Threading.Tasks; | ||
| 14 | using Microsoft.Win32.SafeHandles; | ||
| 10 | 15 | ||
| 11 | public abstract class ExternalExecutable | 16 | public abstract class ExternalExecutable |
| 12 | { | 17 | { |
| @@ -19,6 +24,125 @@ namespace WixBuildTools.TestSupport | |||
| 19 | 24 | ||
| 20 | protected ExternalExecutableResult Run(string args, bool mergeErrorIntoOutput = false, string workingDirectory = null) | 25 | protected ExternalExecutableResult Run(string args, bool mergeErrorIntoOutput = false, string workingDirectory = null) |
| 21 | { | 26 | { |
| 27 | // https://github.com/dotnet/runtime/issues/58492 | ||
| 28 | // Process.Start doesn't currently support starting a process with a long path, | ||
| 29 | // but the way to support long paths doesn't support searching for the executable if it was a relative path. | ||
| 30 | // Avoid the managed way of doing this even if the target isn't a long path to help verify that the native way works. | ||
| 31 | if (!Path.IsPathRooted(this.exePath)) | ||
| 32 | { | ||
| 33 | return this.RunManaged(args, mergeErrorIntoOutput, workingDirectory); | ||
| 34 | } | ||
| 35 | |||
| 36 | // https://web.archive.org/web/20150331190801/https://support.microsoft.com/en-us/kb/190351 | ||
| 37 | var commandLine = $"\"{this.exePath}\" {args}"; | ||
| 38 | var currentDirectory = workingDirectory ?? Path.GetDirectoryName(this.exePath); | ||
| 39 | if (String.IsNullOrEmpty(currentDirectory)) | ||
| 40 | { | ||
| 41 | currentDirectory = null; | ||
| 42 | } | ||
| 43 | var processInfo = new PROCESS_INFORMATION(); | ||
| 44 | var startInfo = new STARTUPINFOW | ||
| 45 | { | ||
| 46 | cb = Marshal.SizeOf(typeof(STARTUPINFOW)), | ||
| 47 | dwFlags = StartupInfoFlags.STARTF_FORCEOFFFEEDBACK | StartupInfoFlags.STARTF_USESTDHANDLES, | ||
| 48 | hStdInput = GetStdHandle(StdHandleType.STD_INPUT_HANDLE), | ||
| 49 | }; | ||
| 50 | SafeFileHandle hStdOutputParent = null; | ||
| 51 | SafeFileHandle hStdErrorParent = null; | ||
| 52 | |||
| 53 | try | ||
| 54 | { | ||
| 55 | CreatePipeForProcess(out hStdOutputParent, out startInfo.hStdOutput); | ||
| 56 | |||
| 57 | if (!mergeErrorIntoOutput) | ||
| 58 | { | ||
| 59 | CreatePipeForProcess(out hStdErrorParent, out startInfo.hStdError); | ||
| 60 | } | ||
| 61 | else | ||
| 62 | { | ||
| 63 | if (!DuplicateHandle(GetCurrentProcess(), startInfo.hStdOutput, GetCurrentProcess(), out startInfo.hStdError, 0, true, DuplicateHandleOptions.DUPLICATE_SAME_ACCESS)) | ||
| 64 | { | ||
| 65 | throw new Win32Exception(); | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | if (!CreateProcessW(this.exePath, commandLine, IntPtr.Zero, IntPtr.Zero, true, CreateProcessFlags.CREATE_NO_WINDOW, IntPtr.Zero, | ||
| 70 | currentDirectory, ref startInfo, ref processInfo)) | ||
| 71 | { | ||
| 72 | throw new Win32Exception(); | ||
| 73 | } | ||
| 74 | |||
| 75 | startInfo.Dispose(); | ||
| 76 | |||
| 77 | return GetResultFromNative(mergeErrorIntoOutput, hStdOutputParent, hStdErrorParent, processInfo.hProcess, this.exePath, args); | ||
| 78 | } | ||
| 79 | finally | ||
| 80 | { | ||
| 81 | hStdErrorParent?.Dispose(); | ||
| 82 | hStdOutputParent?.Dispose(); | ||
| 83 | |||
| 84 | startInfo.Dispose(); | ||
| 85 | processInfo.Dispose(); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | private static ExternalExecutableResult GetResultFromNative(bool mergeErrorIntoOutput, SafeFileHandle hStdOutputParent, SafeFileHandle hStdErrorParent, IntPtr hProcess, string fileName, string args) | ||
| 90 | { | ||
| 91 | using (var outputStream = new StreamReader(new FileStream(hStdOutputParent, FileAccess.Read))) | ||
| 92 | using (var errorStream = mergeErrorIntoOutput ? null : new StreamReader(new FileStream(hStdErrorParent, FileAccess.Read))) | ||
| 93 | { | ||
| 94 | var outputTask = Task.Run(() => ReadProcessStreamLines(outputStream)); | ||
| 95 | var errorTask = Task.Run(() => ReadProcessStreamLines(errorStream)); | ||
| 96 | |||
| 97 | while (!outputTask.Wait(100) || !errorTask.Wait(100)) { Task.Yield(); } | ||
| 98 | var standardOutput = outputTask.Result; | ||
| 99 | var standardError = errorTask.Result; | ||
| 100 | |||
| 101 | if (WaitForSingleObject(hProcess, -1) != 0) | ||
| 102 | { | ||
| 103 | throw new Win32Exception(); | ||
| 104 | } | ||
| 105 | |||
| 106 | if (!GetExitCodeProcess(hProcess, out var exitCode)) | ||
| 107 | { | ||
| 108 | throw new Win32Exception(); | ||
| 109 | } | ||
| 110 | |||
| 111 | return new ExternalExecutableResult | ||
| 112 | { | ||
| 113 | ExitCode = exitCode, | ||
| 114 | StandardError = standardError, | ||
| 115 | StandardOutput = standardOutput, | ||
| 116 | FileName = fileName, | ||
| 117 | Arguments = args, | ||
| 118 | }; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | private static string[] ReadProcessStreamLines(StreamReader streamReader) | ||
| 123 | { | ||
| 124 | if (streamReader == null) | ||
| 125 | { | ||
| 126 | return null; | ||
| 127 | } | ||
| 128 | |||
| 129 | var lines = new List<string>(); | ||
| 130 | while (true) | ||
| 131 | { | ||
| 132 | var line = streamReader.ReadLine(); | ||
| 133 | if (line == null) | ||
| 134 | { | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | |||
| 138 | lines.Add(line); | ||
| 139 | } | ||
| 140 | |||
| 141 | return lines.ToArray(); | ||
| 142 | } | ||
| 143 | |||
| 144 | protected ExternalExecutableResult RunManaged(string args, bool mergeErrorIntoOutput = false, string workingDirectory = null) | ||
| 145 | { | ||
| 22 | var startInfo = new ProcessStartInfo(this.exePath, args) | 146 | var startInfo = new ProcessStartInfo(this.exePath, args) |
| 23 | { | 147 | { |
| 24 | CreateNoWindow = true, | 148 | CreateNoWindow = true, |
| @@ -48,7 +172,8 @@ namespace WixBuildTools.TestSupport | |||
| 48 | ExitCode = process.ExitCode, | 172 | ExitCode = process.ExitCode, |
| 49 | StandardError = mergeErrorIntoOutput ? null : standardError.ToArray(), | 173 | StandardError = mergeErrorIntoOutput ? null : standardError.ToArray(), |
| 50 | StandardOutput = standardOutput.ToArray(), | 174 | StandardOutput = standardOutput.ToArray(), |
| 51 | StartInfo = startInfo, | 175 | FileName = this.exePath, |
| 176 | Arguments = args, | ||
| 52 | }; | 177 | }; |
| 53 | } | 178 | } |
| 54 | } | 179 | } |
| @@ -84,5 +209,166 @@ namespace WixBuildTools.TestSupport | |||
| 84 | 209 | ||
| 85 | return sb.ToString(); | 210 | return sb.ToString(); |
| 86 | } | 211 | } |
| 212 | |||
| 213 | private static void CreatePipeForProcess(out SafeFileHandle hReadPipe, out IntPtr hWritePipe) | ||
| 214 | { | ||
| 215 | var securityAttributes = new SECURITY_ATTRIBUTES | ||
| 216 | { | ||
| 217 | nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES)), | ||
| 218 | bInheritHandle = true, | ||
| 219 | }; | ||
| 220 | |||
| 221 | if (!CreatePipe(out var hReadTemp, out hWritePipe, ref securityAttributes, 0)) | ||
| 222 | { | ||
| 223 | throw new Win32Exception(); | ||
| 224 | } | ||
| 225 | |||
| 226 | // Only the handle passed to the process should be inheritable, so have to duplicate the other handle to get an uninheritable one. | ||
| 227 | if (!DuplicateHandle(GetCurrentProcess(), hReadTemp, GetCurrentProcess(), out var hReadPipePtr, 0, false, DuplicateHandleOptions.DUPLICATE_CLOSE_SOURCE | DuplicateHandleOptions.DUPLICATE_SAME_ACCESS)) | ||
| 228 | { | ||
| 229 | throw new Win32Exception(); | ||
| 230 | } | ||
| 231 | |||
| 232 | hReadPipe = new SafeFileHandle(hReadPipePtr, true); | ||
| 233 | } | ||
| 234 | |||
| 235 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 236 | private extern static IntPtr GetStdHandle(StdHandleType nStdHandle); | ||
| 237 | |||
| 238 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 239 | [return: MarshalAs(UnmanagedType.Bool)] | ||
| 240 | private extern static bool CreatePipe(out IntPtr hReadPipe, out IntPtr hWritePipe, ref SECURITY_ATTRIBUTES lpPipeAttributes, int nSize); | ||
| 241 | |||
| 242 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 243 | [return: MarshalAs(UnmanagedType.Bool)] | ||
| 244 | private extern static bool CreateProcessW( | ||
| 245 | string lpApplicationName, | ||
| 246 | string lpCommandLine, | ||
| 247 | IntPtr lpProcessAttributes, | ||
| 248 | IntPtr lpThreadAttributes, | ||
| 249 | [MarshalAs(UnmanagedType.Bool)] bool bInheritHandles, | ||
| 250 | CreateProcessFlags dwCreationFlags, | ||
| 251 | IntPtr lpEnvironment, | ||
| 252 | string lpCurrentDirectory, | ||
| 253 | ref STARTUPINFOW lpStartupInfo, | ||
| 254 | ref PROCESS_INFORMATION lpProcessInformation); | ||
| 255 | |||
| 256 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] | ||
| 257 | private extern static IntPtr GetCurrentProcess(); | ||
| 258 | |||
| 259 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 260 | [return: MarshalAs(UnmanagedType.Bool)] | ||
| 261 | private extern static bool GetExitCodeProcess(IntPtr hHandle, out int lpExitCode); | ||
| 262 | |||
| 263 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 264 | private extern static int WaitForSingleObject(IntPtr hHandle, int dwMilliseconds); | ||
| 265 | |||
| 266 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 267 | [return: MarshalAs(UnmanagedType.Bool)] | ||
| 268 | private extern static bool CloseHandle(IntPtr hObject); | ||
| 269 | |||
| 270 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 271 | [return: MarshalAs(UnmanagedType.Bool)] | ||
| 272 | private extern static bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, int dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, DuplicateHandleOptions dwOptions); | ||
| 273 | |||
| 274 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] | ||
| 275 | private struct SECURITY_ATTRIBUTES | ||
| 276 | { | ||
| 277 | public int nLength; | ||
| 278 | public IntPtr lpSecurityDescriptor; | ||
| 279 | [MarshalAs(UnmanagedType.Bool)] | ||
| 280 | public bool bInheritHandle; | ||
| 281 | } | ||
| 282 | |||
| 283 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] | ||
| 284 | private struct STARTUPINFOW | ||
| 285 | { | ||
| 286 | public int cb; | ||
| 287 | public string lpReserved; | ||
| 288 | public string lpDesktop; | ||
| 289 | public string lpTitle; | ||
| 290 | public int dwX; | ||
| 291 | public int dwY; | ||
| 292 | public int dwXSize; | ||
| 293 | public int dwYSize; | ||
| 294 | public int dwXCountChars; | ||
| 295 | public int dwYCountChars; | ||
| 296 | public int dwFillAttribute; | ||
| 297 | public StartupInfoFlags dwFlags; | ||
| 298 | public short wShowWindow; | ||
| 299 | public short cbReserved2; | ||
| 300 | public IntPtr lpReserved2; | ||
| 301 | public IntPtr hStdInput; | ||
| 302 | public IntPtr hStdOutput; | ||
| 303 | public IntPtr hStdError; | ||
| 304 | |||
| 305 | public void Dispose() | ||
| 306 | { | ||
| 307 | // This makes assumptions based on how it's used above. | ||
| 308 | if (this.hStdError != IntPtr.Zero) | ||
| 309 | { | ||
| 310 | CloseHandle(this.hStdError); | ||
| 311 | this.hStdError = IntPtr.Zero; | ||
| 312 | } | ||
| 313 | |||
| 314 | if (this.hStdOutput != IntPtr.Zero) | ||
| 315 | { | ||
| 316 | CloseHandle(this.hStdOutput); | ||
| 317 | this.hStdOutput = IntPtr.Zero; | ||
| 318 | } | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] | ||
| 323 | private struct PROCESS_INFORMATION | ||
| 324 | { | ||
| 325 | public IntPtr hProcess; | ||
| 326 | public IntPtr hThread; | ||
| 327 | public int dwProcessId; | ||
| 328 | public int dwThreadId; | ||
| 329 | |||
| 330 | public void Dispose() | ||
| 331 | { | ||
| 332 | if (this.hProcess != IntPtr.Zero) | ||
| 333 | { | ||
| 334 | CloseHandle(this.hProcess); | ||
| 335 | this.hProcess = IntPtr.Zero; | ||
| 336 | } | ||
| 337 | |||
| 338 | if (this.hThread != IntPtr.Zero) | ||
| 339 | { | ||
| 340 | CloseHandle(this.hThread); | ||
| 341 | this.hThread = IntPtr.Zero; | ||
| 342 | } | ||
| 343 | } | ||
| 344 | } | ||
| 345 | |||
| 346 | private enum StdHandleType | ||
| 347 | { | ||
| 348 | STD_INPUT_HANDLE = -10, | ||
| 349 | STD_OUTPUT_HANDLE = -11, | ||
| 350 | STD_ERROR_HANDLE = -12, | ||
| 351 | } | ||
| 352 | |||
| 353 | [Flags] | ||
| 354 | private enum CreateProcessFlags | ||
| 355 | { | ||
| 356 | None = 0x0, | ||
| 357 | CREATE_NO_WINDOW = 0x08000000, | ||
| 358 | } | ||
| 359 | |||
| 360 | [Flags] | ||
| 361 | private enum StartupInfoFlags | ||
| 362 | { | ||
| 363 | None = 0x0, | ||
| 364 | STARTF_FORCEOFFFEEDBACK = 0x80, | ||
| 365 | STARTF_USESTDHANDLES = 0x100, | ||
| 366 | } | ||
| 367 | |||
| 368 | private enum DuplicateHandleOptions | ||
| 369 | { | ||
| 370 | DUPLICATE_CLOSE_SOURCE = 1, | ||
| 371 | DUPLICATE_SAME_ACCESS = 2, | ||
| 372 | } | ||
| 87 | } | 373 | } |
| 88 | } | 374 | } |
diff --git a/src/internal/WixBuildTools.TestSupport/ExternalExecutableResult.cs b/src/internal/WixBuildTools.TestSupport/ExternalExecutableResult.cs index 19b5183b..950ee4bd 100644 --- a/src/internal/WixBuildTools.TestSupport/ExternalExecutableResult.cs +++ b/src/internal/WixBuildTools.TestSupport/ExternalExecutableResult.cs | |||
| @@ -12,6 +12,8 @@ namespace WixBuildTools.TestSupport | |||
| 12 | 12 | ||
| 13 | public string[] StandardOutput { get; set; } | 13 | public string[] StandardOutput { get; set; } |
| 14 | 14 | ||
| 15 | public ProcessStartInfo StartInfo { get; set; } | 15 | public string FileName { get; set; } |
| 16 | |||
| 17 | public string Arguments { get; set; } | ||
| 16 | } | 18 | } |
| 17 | } | 19 | } |
diff --git a/src/internal/WixBuildTools.TestSupport/TestDataFolderFileSystem.cs b/src/internal/WixBuildTools.TestSupport/TestDataFolderFileSystem.cs index 8d670bf0..15b7631d 100644 --- a/src/internal/WixBuildTools.TestSupport/TestDataFolderFileSystem.cs +++ b/src/internal/WixBuildTools.TestSupport/TestDataFolderFileSystem.cs | |||
| @@ -33,7 +33,7 @@ namespace WixBuildTools.TestSupport | |||
| 33 | RobocopyFolder(sourceDirectoryPath, this.BaseFolder); | 33 | RobocopyFolder(sourceDirectoryPath, this.BaseFolder); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | private static ExternalExecutableResult RobocopyFolder(string sourceFolderPath, string destinationFolderPath) | 36 | public static ExternalExecutableResult RobocopyFolder(string sourceFolderPath, string destinationFolderPath) |
| 37 | { | 37 | { |
| 38 | var args = $"\"{sourceFolderPath}\" \"{destinationFolderPath}\" /E /R:1 /W:1"; | 38 | var args = $"\"{sourceFolderPath}\" \"{destinationFolderPath}\" /E /R:1 /W:1"; |
| 39 | return RobocopyRunner.Execute(args); | 39 | return RobocopyRunner.Execute(args); |
diff --git a/src/libs/dutil/WixToolset.DUtil/apputil.cpp b/src/libs/dutil/WixToolset.DUtil/apputil.cpp index b70c8cfb..9e75082a 100644 --- a/src/libs/dutil/WixToolset.DUtil/apputil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/apputil.cpp | |||
| @@ -87,31 +87,27 @@ DAPI_(HRESULT) LoadSystemLibraryWithPath( | |||
| 87 | ) | 87 | ) |
| 88 | { | 88 | { |
| 89 | HRESULT hr = S_OK; | 89 | HRESULT hr = S_OK; |
| 90 | DWORD cch = 0; | 90 | LPWSTR sczDirectory = NULL; |
| 91 | WCHAR wzPath[MAX_PATH] = { }; | 91 | LPWSTR sczPath = NULL; |
| 92 | 92 | ||
| 93 | cch = ::GetSystemDirectoryW(wzPath, MAX_PATH); | 93 | hr = PathGetSystemDirectory(&sczDirectory); |
| 94 | AppExitOnNullWithLastError(cch, hr, "Failed to get the Windows system directory."); | 94 | AppExitOnFailure(hr, "Failed to get the Windows system directory."); |
| 95 | 95 | ||
| 96 | if (L'\\' != wzPath[cch - 1]) | 96 | hr = StrAllocFormatted(&sczPath, L"%ls%ls", sczDirectory, wzModuleName); |
| 97 | { | 97 | AppExitOnFailure(hr, "Failed to create the fully-qualified path to %ls.", wzModuleName); |
| 98 | hr = ::StringCchCatNW(wzPath, MAX_PATH, L"\\", 1); | ||
| 99 | AppExitOnRootFailure(hr, "Failed to terminate the string with a backslash."); | ||
| 100 | } | ||
| 101 | 98 | ||
| 102 | hr = ::StringCchCatW(wzPath, MAX_PATH, wzModuleName); | 99 | *phModule = ::LoadLibraryExW(sczPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); |
| 103 | AppExitOnRootFailure(hr, "Failed to create the fully-qualified path to %ls.", wzModuleName); | 100 | AppExitOnNullWithLastError(*phModule, hr, "Failed to load the library %ls.", sczPath); |
| 104 | |||
| 105 | *phModule = ::LoadLibraryExW(wzPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); | ||
| 106 | AppExitOnNullWithLastError(*phModule, hr, "Failed to load the library %ls.", wzModuleName); | ||
| 107 | 101 | ||
| 108 | if (psczPath) | 102 | if (psczPath) |
| 109 | { | 103 | { |
| 110 | hr = StrAllocString(psczPath, wzPath, MAX_PATH); | 104 | *psczPath = sczPath; |
| 111 | AppExitOnFailure(hr, "Failed to copy the path to library."); | 105 | sczPath = NULL; |
| 112 | } | 106 | } |
| 113 | 107 | ||
| 114 | LExit: | 108 | LExit: |
| 109 | ReleaseStr(sczDirectory); | ||
| 110 | |||
| 115 | return hr; | 111 | return hr; |
| 116 | } | 112 | } |
| 117 | 113 | ||
diff --git a/src/libs/dutil/WixToolset.DUtil/cabcutil.cpp b/src/libs/dutil/WixToolset.DUtil/cabcutil.cpp index d1edc54d..294669af 100644 --- a/src/libs/dutil/WixToolset.DUtil/cabcutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/cabcutil.cpp | |||
| @@ -89,8 +89,8 @@ struct CABC_DATA | |||
| 89 | 89 | ||
| 90 | STRINGDICT_HANDLE shDictHandle; | 90 | STRINGDICT_HANDLE shDictHandle; |
| 91 | 91 | ||
| 92 | WCHAR wzCabinetPath[MAX_PATH]; | 92 | LPWSTR sczCabinetPath; |
| 93 | WCHAR wzEmptyFile[MAX_PATH]; | 93 | LPWSTR sczEmptyFile; |
| 94 | HANDLE hEmptyFile; | 94 | HANDLE hEmptyFile; |
| 95 | DWORD dwLastFileIndex; | 95 | DWORD dwLastFileIndex; |
| 96 | 96 | ||
| @@ -197,33 +197,17 @@ extern "C" HRESULT DAPI CabCBegin( | |||
| 197 | 197 | ||
| 198 | HRESULT hr = S_OK; | 198 | HRESULT hr = S_OK; |
| 199 | CABC_DATA *pcd = NULL; | 199 | CABC_DATA *pcd = NULL; |
| 200 | WCHAR wzTempPath[MAX_PATH] = { }; | ||
| 201 | 200 | ||
| 202 | C_ASSERT(sizeof(MSIFILEHASHINFO) == 20); | 201 | C_ASSERT(sizeof(MSIFILEHASHINFO) == 20); |
| 203 | 202 | ||
| 204 | WCHAR wzPathBuffer [MAX_PATH] = L""; | 203 | LPWSTR pwzPathBuffer = NULL; |
| 205 | size_t cchPathBuffer; | ||
| 206 | if (wzCabDir) | 204 | if (wzCabDir) |
| 207 | { | 205 | { |
| 208 | hr = ::StringCchLengthW(wzCabDir, MAX_PATH, &cchPathBuffer); | 206 | hr = StrAllocString(&pwzPathBuffer, wzCabDir, 0); |
| 209 | CabcExitOnFailure(hr, "Failed to get length of cab directory"); | ||
| 210 | |||
| 211 | // Need room to terminate with L'\\' and L'\0' | ||
| 212 | if((MAX_PATH - 1) <= cchPathBuffer || 0 == cchPathBuffer) | ||
| 213 | { | ||
| 214 | hr = E_INVALIDARG; | ||
| 215 | CabcExitOnFailure(hr, "Cab directory had invalid length: %u", cchPathBuffer); | ||
| 216 | } | ||
| 217 | |||
| 218 | hr = ::StringCchCopyW(wzPathBuffer, countof(wzPathBuffer), wzCabDir); | ||
| 219 | CabcExitOnFailure(hr, "Failed to copy cab directory to buffer"); | 207 | CabcExitOnFailure(hr, "Failed to copy cab directory to buffer"); |
| 220 | 208 | ||
| 221 | if (L'\\' != wzPathBuffer[cchPathBuffer - 1]) | 209 | hr = PathBackslashTerminate(&pwzPathBuffer); |
| 222 | { | 210 | CabcExitOnFailure(hr, "Failed to cat \\ to end of buffer"); |
| 223 | hr = ::StringCchCatW(wzPathBuffer, countof(wzPathBuffer), L"\\"); | ||
| 224 | CabcExitOnFailure(hr, "Failed to cat \\ to end of buffer"); | ||
| 225 | ++cchPathBuffer; | ||
| 226 | } | ||
| 227 | } | 211 | } |
| 228 | 212 | ||
| 229 | pcd = static_cast<CABC_DATA*>(MemAlloc(sizeof(CABC_DATA), TRUE)); | 213 | pcd = static_cast<CABC_DATA*>(MemAlloc(sizeof(CABC_DATA), TRUE)); |
| @@ -290,33 +274,23 @@ extern "C" HRESULT DAPI CabCBegin( | |||
| 290 | CabcExitWithLastError(hr, "failed to convert cab name to multi-byte"); | 274 | CabcExitWithLastError(hr, "failed to convert cab name to multi-byte"); |
| 291 | } | 275 | } |
| 292 | 276 | ||
| 293 | if (0 == ::WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wzPathBuffer, -1, pcd->ccab.szCabPath, sizeof(pcd->ccab.szCab), NULL, NULL)) | 277 | if (0 == ::WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pwzPathBuffer, -1, pcd->ccab.szCabPath, sizeof(pcd->ccab.szCab), NULL, NULL)) |
| 294 | { | 278 | { |
| 295 | CabcExitWithLastError(hr, "failed to convert cab dir to multi-byte"); | 279 | CabcExitWithLastError(hr, "failed to convert cab dir to multi-byte"); |
| 296 | } | 280 | } |
| 297 | 281 | ||
| 298 | // Remember the path to the cabinet. | 282 | // Remember the path to the cabinet. |
| 299 | hr= ::StringCchCopyW(pcd->wzCabinetPath, countof(pcd->wzCabinetPath), wzPathBuffer); | 283 | hr = PathConcat(pwzPathBuffer, wzCab, &pcd->sczCabinetPath); |
| 300 | CabcExitOnFailure(hr, "Failed to copy cabinet path from path: %ls", wzPathBuffer); | ||
| 301 | |||
| 302 | hr = ::StringCchCatW(pcd->wzCabinetPath, countof(pcd->wzCabinetPath), wzCab); | ||
| 303 | CabcExitOnFailure(hr, "Failed to concat to cabinet path cabinet name: %ls", wzCab); | 284 | CabcExitOnFailure(hr, "Failed to concat to cabinet path cabinet name: %ls", wzCab); |
| 304 | 285 | ||
| 305 | // Get the empty file to use as the blank marker for duplicates. | 286 | // Get the empty file to use as the blank marker for duplicates. |
| 306 | if (!::GetTempPathW(countof(wzTempPath), wzTempPath)) | 287 | hr = DirCreateTempPath(L"WSC", &pcd->sczEmptyFile); |
| 307 | { | 288 | CabcExitOnFailure(hr, "Failed to create a temp file name."); |
| 308 | CabcExitWithLastError(hr, "Failed to get temp path."); | ||
| 309 | } | ||
| 310 | |||
| 311 | if (!::GetTempFileNameW(wzTempPath, L"WSC", 0, pcd->wzEmptyFile)) | ||
| 312 | { | ||
| 313 | CabcExitWithLastError(hr, "Failed to create a temp file name."); | ||
| 314 | } | ||
| 315 | 289 | ||
| 316 | // Try to open the newly created empty file (remember, GetTempFileName() is kind enough to create a file for us) | 290 | // Try to open the newly created empty file (remember, GetTempFileName() is kind enough to create a file for us) |
| 317 | // with a handle to automatically delete the file on close. Ignore any failure that might happen, since the worst | 291 | // with a handle to automatically delete the file on close. Ignore any failure that might happen, since the worst |
| 318 | // case is we'll leave a zero byte file behind in the temp folder. | 292 | // case is we'll leave a zero byte file behind in the temp folder. |
| 319 | pcd->hEmptyFile = ::CreateFileW(pcd->wzEmptyFile, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); | 293 | pcd->hEmptyFile = ::CreateFileW(pcd->sczEmptyFile, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); |
| 320 | 294 | ||
| 321 | hr = DictCreateWithEmbeddedKey(&pcd->shDictHandle, dwMaxFiles, reinterpret_cast<void **>(&pcd->prgFiles), offsetof(CABC_FILE, pwzSourcePath), DICT_FLAG_CASEINSENSITIVE); | 295 | hr = DictCreateWithEmbeddedKey(&pcd->shDictHandle, dwMaxFiles, reinterpret_cast<void **>(&pcd->prgFiles), offsetof(CABC_FILE, pwzSourcePath), DICT_FLAG_CASEINSENSITIVE); |
| 322 | CabcExitOnFailure(hr, "Failed to create dictionary to keep track of duplicate files"); | 296 | CabcExitOnFailure(hr, "Failed to create dictionary to keep track of duplicate files"); |
| @@ -358,6 +332,8 @@ extern "C" HRESULT DAPI CabCBegin( | |||
| 358 | *phContext = pcd; | 332 | *phContext = pcd; |
| 359 | 333 | ||
| 360 | LExit: | 334 | LExit: |
| 335 | ReleaseStr(pwzPathBuffer); | ||
| 336 | |||
| 361 | if (FAILED(hr) && pcd && pcd->hfci) | 337 | if (FAILED(hr) && pcd && pcd->hfci) |
| 362 | { | 338 | { |
| 363 | ::FCIDestroy(pcd->hfci); | 339 | ::FCIDestroy(pcd->hfci); |
| @@ -527,7 +503,7 @@ extern "C" HRESULT DAPI CabCFinish( | |||
| 527 | // files point at the same path (the empty file) so there is no point in tracking them with | 503 | // files point at the same path (the empty file) so there is no point in tracking them with |
| 528 | // their path. | 504 | // their path. |
| 529 | fileInfo.wzSourcePath = pcd->prgDuplicates[dwDupeArrayFileIndex].pwzSourcePath; | 505 | fileInfo.wzSourcePath = pcd->prgDuplicates[dwDupeArrayFileIndex].pwzSourcePath; |
| 530 | fileInfo.wzEmptyPath = pcd->wzEmptyFile; | 506 | fileInfo.wzEmptyPath = pcd->sczEmptyFile; |
| 531 | 507 | ||
| 532 | // Use the provided token, otherwise default to the source file name. | 508 | // Use the provided token, otherwise default to the source file name. |
| 533 | if (pcd->prgDuplicates[dwDupeArrayFileIndex].pwzToken) | 509 | if (pcd->prgDuplicates[dwDupeArrayFileIndex].pwzToken) |
| @@ -643,7 +619,7 @@ extern "C" HRESULT DAPI CabCFinish( | |||
| 643 | if (pcd->fGoodCab && pcd->cDuplicates) | 619 | if (pcd->fGoodCab && pcd->cDuplicates) |
| 644 | { | 620 | { |
| 645 | hr = UpdateDuplicateFiles(pcd); | 621 | hr = UpdateDuplicateFiles(pcd); |
| 646 | CabcExitOnFailure(hr, "Failed to update duplicates in cabinet: %ls", pcd->wzCabinetPath); | 622 | CabcExitOnFailure(hr, "Failed to update duplicates in cabinet: %ls", pcd->sczCabinetPath); |
| 647 | } | 623 | } |
| 648 | 624 | ||
| 649 | LExit: | 625 | LExit: |
| @@ -692,6 +668,9 @@ static void FreeCabCData( | |||
| 692 | ReleaseMem(pcd->prgFiles); | 668 | ReleaseMem(pcd->prgFiles); |
| 693 | ReleaseMem(pcd->prgDuplicates); | 669 | ReleaseMem(pcd->prgDuplicates); |
| 694 | 670 | ||
| 671 | ReleaseStr(pcd->sczCabinetPath); | ||
| 672 | ReleaseStr(pcd->sczEmptyFile); | ||
| 673 | |||
| 695 | ReleaseMem(pcd); | 674 | ReleaseMem(pcd); |
| 696 | } | 675 | } |
| 697 | } | 676 | } |
| @@ -709,7 +688,7 @@ static HRESULT CheckForDuplicateFile( | |||
| 709 | __in LONGLONG llFileSize | 688 | __in LONGLONG llFileSize |
| 710 | ) | 689 | ) |
| 711 | { | 690 | { |
| 712 | DWORD i; | 691 | DWORD i = 0; |
| 713 | HRESULT hr = S_OK; | 692 | HRESULT hr = S_OK; |
| 714 | UINT er = ERROR_SUCCESS; | 693 | UINT er = ERROR_SUCCESS; |
| 715 | 694 | ||
| @@ -916,17 +895,17 @@ static HRESULT UpdateDuplicateFiles( | |||
| 916 | LPVOID pv = NULL; | 895 | LPVOID pv = NULL; |
| 917 | MS_CABINET_HEADER *pCabinetHeader = NULL; | 896 | MS_CABINET_HEADER *pCabinetHeader = NULL; |
| 918 | 897 | ||
| 919 | hCabinet = ::CreateFileW(pcd->wzCabinetPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | 898 | hCabinet = ::CreateFileW(pcd->sczCabinetPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
| 920 | if (INVALID_HANDLE_VALUE == hCabinet) | 899 | if (INVALID_HANDLE_VALUE == hCabinet) |
| 921 | { | 900 | { |
| 922 | CabcExitWithLastError(hr, "Failed to open cabinet: %ls", pcd->wzCabinetPath); | 901 | CabcExitWithLastError(hr, "Failed to open cabinet: %ls", pcd->sczCabinetPath); |
| 923 | } | 902 | } |
| 924 | 903 | ||
| 925 | // Shouldn't need more than 16 MB to get the whole cabinet header into memory so use that as | 904 | // Shouldn't need more than 16 MB to get the whole cabinet header into memory so use that as |
| 926 | // the upper bound for the memory map. | 905 | // the upper bound for the memory map. |
| 927 | if (!::GetFileSizeEx(hCabinet, &liCabinetSize)) | 906 | if (!::GetFileSizeEx(hCabinet, &liCabinetSize)) |
| 928 | { | 907 | { |
| 929 | CabcExitWithLastError(hr, "Failed to get size of cabinet: %ls", pcd->wzCabinetPath); | 908 | CabcExitWithLastError(hr, "Failed to get size of cabinet: %ls", pcd->sczCabinetPath); |
| 930 | } | 909 | } |
| 931 | 910 | ||
| 932 | if (0 == liCabinetSize.HighPart && liCabinetSize.LowPart < MAX_CABINET_HEADER_SIZE) | 911 | if (0 == liCabinetSize.HighPart && liCabinetSize.LowPart < MAX_CABINET_HEADER_SIZE) |
| @@ -942,11 +921,11 @@ static HRESULT UpdateDuplicateFiles( | |||
| 942 | hCabinetMapping = ::CreateFileMappingW(hCabinet, NULL, PAGE_READWRITE | SEC_COMMIT, 0, cbCabinet, NULL); | 921 | hCabinetMapping = ::CreateFileMappingW(hCabinet, NULL, PAGE_READWRITE | SEC_COMMIT, 0, cbCabinet, NULL); |
| 943 | if (NULL == hCabinetMapping || INVALID_HANDLE_VALUE == hCabinetMapping) | 922 | if (NULL == hCabinetMapping || INVALID_HANDLE_VALUE == hCabinetMapping) |
| 944 | { | 923 | { |
| 945 | CabcExitWithLastError(hr, "Failed to memory map cabinet file: %ls", pcd->wzCabinetPath); | 924 | CabcExitWithLastError(hr, "Failed to memory map cabinet file: %ls", pcd->sczCabinetPath); |
| 946 | } | 925 | } |
| 947 | 926 | ||
| 948 | pv = ::MapViewOfFile(hCabinetMapping, FILE_MAP_WRITE, 0, 0, 0); | 927 | pv = ::MapViewOfFile(hCabinetMapping, FILE_MAP_WRITE, 0, 0, 0); |
| 949 | CabcExitOnNullWithLastError(pv, hr, "Failed to map view of cabinet file: %ls", pcd->wzCabinetPath); | 928 | CabcExitOnNullWithLastError(pv, hr, "Failed to map view of cabinet file: %ls", pcd->sczCabinetPath); |
| 950 | 929 | ||
| 951 | pCabinetHeader = static_cast<MS_CABINET_HEADER*>(pv); | 930 | pCabinetHeader = static_cast<MS_CABINET_HEADER*>(pv); |
| 952 | 931 | ||
| @@ -1155,7 +1134,7 @@ static __callback INT_PTR DIAMONDAPI CabCOpen( | |||
| 1155 | 1134 | ||
| 1156 | if (INVALID_HANDLE_VALUE == reinterpret_cast<HANDLE>(pFile)) | 1135 | if (INVALID_HANDLE_VALUE == reinterpret_cast<HANDLE>(pFile)) |
| 1157 | { | 1136 | { |
| 1158 | CabcExitOnLastError(hr, "failed to open file: %s", pszFile); | 1137 | CabcExitOnLastError(hr, "failed to open file: %hs", pszFile); |
| 1159 | } | 1138 | } |
| 1160 | 1139 | ||
| 1161 | LExit: | 1140 | LExit: |
| @@ -1326,11 +1305,12 @@ static __callback BOOL DIAMONDAPI CabCGetTempFile( | |||
| 1326 | 1305 | ||
| 1327 | HRESULT hr = S_OK; | 1306 | HRESULT hr = S_OK; |
| 1328 | char szTempPath[MAX_PATH] = { }; | 1307 | char szTempPath[MAX_PATH] = { }; |
| 1329 | DWORD cchTempPath = MAX_PATH; | ||
| 1330 | DWORD dwProcessId = ::GetCurrentProcessId(); | 1308 | DWORD dwProcessId = ::GetCurrentProcessId(); |
| 1331 | HANDLE hTempFile = INVALID_HANDLE_VALUE; | 1309 | HANDLE hTempFile = INVALID_HANDLE_VALUE; |
| 1332 | 1310 | ||
| 1333 | if (MAX_PATH < ::GetTempPathA(cchTempPath, szTempPath)) | 1311 | // TODO: Allow user to pass in different temp path in case the default is too long, |
| 1312 | // and/or see if magic similar to CABC_MAGIC_UNICODE_STRING_MARKER can be used to pass ourselves a path longer than MAX_PATH. | ||
| 1313 | if (MAX_PATH < ::GetTempPathA(countof(szTempPath), szTempPath)) | ||
| 1334 | { | 1314 | { |
| 1335 | CabcExitWithLastError(hr, "Failed to get temp path during cabinet creation."); | 1315 | CabcExitWithLastError(hr, "Failed to get temp path during cabinet creation."); |
| 1336 | } | 1316 | } |
| @@ -1339,7 +1319,7 @@ static __callback BOOL DIAMONDAPI CabCGetTempFile( | |||
| 1339 | { | 1319 | { |
| 1340 | LONG dwTempIndex = ::InterlockedIncrement(reinterpret_cast<volatile LONG*>(&dwIndex)); | 1320 | LONG dwTempIndex = ::InterlockedIncrement(reinterpret_cast<volatile LONG*>(&dwIndex)); |
| 1341 | 1321 | ||
| 1342 | hr = ::StringCbPrintfA(szFile, cbFile, "%s\\%08x.%03x", szTempPath, dwTempIndex, dwProcessId); | 1322 | hr = ::StringCbPrintfA(szFile, cbFile, "%hs\\%08x.%03x", szTempPath, dwTempIndex, dwProcessId); |
| 1343 | CabcExitOnFailure(hr, "failed to format log file path."); | 1323 | CabcExitOnFailure(hr, "failed to format log file path."); |
| 1344 | 1324 | ||
| 1345 | hTempFile = ::CreateFileA(szFile, 0, FILE_SHARE_DELETE, NULL, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); | 1325 | hTempFile = ::CreateFileA(szFile, 0, FILE_SHARE_DELETE, NULL, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); |
| @@ -1351,7 +1331,11 @@ static __callback BOOL DIAMONDAPI CabCGetTempFile( | |||
| 1351 | } | 1331 | } |
| 1352 | else | 1332 | else |
| 1353 | { | 1333 | { |
| 1354 | hr = E_FAIL; // this file was taken so be pessimistic and assume we're not going to find one. | 1334 | hr = HRESULT_FROM_WIN32(::GetLastError()); // this file was taken so be pessimistic and assume we're not going to find one. |
| 1335 | if (SUCCEEDED(hr)) | ||
| 1336 | { | ||
| 1337 | hr = E_FAIL; | ||
| 1338 | } | ||
| 1355 | } | 1339 | } |
| 1356 | } | 1340 | } |
| 1357 | CabcExitOnFailure(hr, "failed to find temporary file."); | 1341 | CabcExitOnFailure(hr, "failed to find temporary file."); |
| @@ -1386,7 +1370,7 @@ static __callback BOOL DIAMONDAPI CabCGetNextCabinet( | |||
| 1386 | if (pccab->iCab == 1) | 1370 | if (pccab->iCab == 1) |
| 1387 | { | 1371 | { |
| 1388 | pcd->wzFirstCabinetName[0] = '\0'; | 1372 | pcd->wzFirstCabinetName[0] = '\0'; |
| 1389 | LPCWSTR pwzCabinetName = PathFile(pcd->wzCabinetPath); | 1373 | LPCWSTR pwzCabinetName = PathFile(pcd->sczCabinetPath); |
| 1390 | size_t len = wcsnlen(pwzCabinetName, sizeof(pwzCabinetName)); | 1374 | size_t len = wcsnlen(pwzCabinetName, sizeof(pwzCabinetName)); |
| 1391 | if (len > 4) | 1375 | if (len > 4) |
| 1392 | { | 1376 | { |
diff --git a/src/libs/dutil/WixToolset.DUtil/cabutil.cpp b/src/libs/dutil/WixToolset.DUtil/cabutil.cpp index f3629d57..57463e1a 100644 --- a/src/libs/dutil/WixToolset.DUtil/cabutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/cabutil.cpp | |||
| @@ -261,15 +261,15 @@ static HRESULT DAPI CabOperation( | |||
| 261 | ) | 261 | ) |
| 262 | { | 262 | { |
| 263 | HRESULT hr = S_OK; | 263 | HRESULT hr = S_OK; |
| 264 | BOOL fResult; | 264 | BOOL fResult = FALSE; |
| 265 | 265 | ||
| 266 | LPWSTR sczCabinet = NULL; | 266 | LPWSTR sczCabinet = NULL; |
| 267 | LPWSTR pwz = NULL; | 267 | LPWSTR pwz = NULL; |
| 268 | CHAR szCabDirectory[MAX_PATH * 4]; // Make sure these are big enough for UTF-8 strings | 268 | LPSTR pszCabDirectory = NULL; |
| 269 | CHAR szCabFile[MAX_PATH * 4]; | 269 | CHAR szCabFile[MAX_PATH * 4] = { }; // Make sure this is big enough for UTF-8 strings |
| 270 | 270 | ||
| 271 | CAB_CALLBACK_STRUCT ccs; | 271 | CAB_CALLBACK_STRUCT ccs = { }; |
| 272 | PFNFDINOTIFY pfnFdiNotify; | 272 | PFNFDINOTIFY pfnFdiNotify = NULL; |
| 273 | 273 | ||
| 274 | // | 274 | // |
| 275 | // ensure the cabinet.dll is loaded | 275 | // ensure the cabinet.dll is loaded |
| @@ -299,15 +299,13 @@ static HRESULT DAPI CabOperation( | |||
| 299 | // If a full path was not provided, use the relative current directory. | 299 | // If a full path was not provided, use the relative current directory. |
| 300 | if (wzCabinet == pwz) | 300 | if (wzCabinet == pwz) |
| 301 | { | 301 | { |
| 302 | hr = ::StringCchCopyA(szCabDirectory, countof(szCabDirectory), ".\\"); | 302 | hr = StrAnsiAllocStringAnsi(&pszCabDirectory, ".\\", 0); |
| 303 | CabExitOnFailure(hr, "Failed to copy relative current directory as cabinet directory."); | 303 | CabExitOnFailure(hr, "Failed to copy relative current directory as cabinet directory."); |
| 304 | } | 304 | } |
| 305 | else | 305 | else |
| 306 | { | 306 | { |
| 307 | if (!::WideCharToMultiByte(CP_UTF8, 0, sczCabinet, -1, szCabDirectory, countof(szCabDirectory), NULL, NULL)) | 307 | hr = StrAnsiAllocString(&pszCabDirectory, sczCabinet, 0, CP_UTF8); |
| 308 | { | 308 | CabExitOnFailure(hr, "failed to convert cabinet directory to ASCII: %ls", sczCabinet); |
| 309 | CabExitWithLastError(hr, "failed to convert cabinet directory to ASCII: %ls", sczCabinet); | ||
| 310 | } | ||
| 311 | } | 309 | } |
| 312 | 310 | ||
| 313 | // | 311 | // |
| @@ -331,7 +329,7 @@ static HRESULT DAPI CabOperation( | |||
| 331 | v_pfnNetFx11Notify = pfnNotify; | 329 | v_pfnNetFx11Notify = pfnNotify; |
| 332 | pfnFdiNotify = FDINotify; | 330 | pfnFdiNotify = FDINotify; |
| 333 | } | 331 | } |
| 334 | fResult = vpfnFDICopy(vhfdi, szCabFile, szCabDirectory, 0, pfnFdiNotify, NULL, static_cast<void*>(&ccs)); | 332 | fResult = vpfnFDICopy(vhfdi, szCabFile, pszCabDirectory, 0, pfnFdiNotify, NULL, static_cast<void*>(&ccs)); |
| 335 | if (!fResult && !ccs.fStopExtracting) // if something went wrong and it wasn't us just stopping the extraction, then return a failure | 333 | if (!fResult && !ccs.fStopExtracting) // if something went wrong and it wasn't us just stopping the extraction, then return a failure |
| 336 | { | 334 | { |
| 337 | CabExitWithLastError(hr, "failed to extract cabinet file: %ls", sczCabinet); | 335 | CabExitWithLastError(hr, "failed to extract cabinet file: %ls", sczCabinet); |
| @@ -339,6 +337,7 @@ static HRESULT DAPI CabOperation( | |||
| 339 | 337 | ||
| 340 | LExit: | 338 | LExit: |
| 341 | ReleaseStr(sczCabinet); | 339 | ReleaseStr(sczCabinet); |
| 340 | ReleaseStr(pszCabDirectory); | ||
| 342 | v_pfnNetFx11Notify = NULL; | 341 | v_pfnNetFx11Notify = NULL; |
| 343 | 342 | ||
| 344 | return hr; | 343 | return hr; |
| @@ -493,14 +492,15 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE | |||
| 493 | INT_PTR ipResult = 0; // result to return on success | 492 | INT_PTR ipResult = 0; // result to return on success |
| 494 | 493 | ||
| 495 | CAB_CALLBACK_STRUCT* pccs = static_cast<CAB_CALLBACK_STRUCT*>(pFDINotify->pv); | 494 | CAB_CALLBACK_STRUCT* pccs = static_cast<CAB_CALLBACK_STRUCT*>(pFDINotify->pv); |
| 496 | LPCSTR sz; | 495 | LPCSTR sz = NULL; |
| 497 | WCHAR wz[MAX_PATH]; | 496 | LPWSTR pwz = NULL; |
| 498 | FILETIME ft; | 497 | LPWSTR pwzPath = NULL; |
| 498 | FILETIME ft = { }; | ||
| 499 | 499 | ||
| 500 | switch (iNotification) | 500 | switch (iNotification) |
| 501 | { | 501 | { |
| 502 | case fdintCOPY_FILE: // begin extracting a resource from cabinet | 502 | case fdintCOPY_FILE: // begin extracting a resource from cabinet |
| 503 | CabExitOnNull(pFDINotify->psz1, hr, E_INVALIDARG, "No cabinet file ID given to convert"); | 503 | Assert(pccs && pFDINotify->psz1); |
| 504 | CabExitOnNull(pccs, hr, E_INVALIDARG, "Failed to call cabextract callback, because no callback struct was provided"); | 504 | CabExitOnNull(pccs, hr, E_INVALIDARG, "Failed to call cabextract callback, because no callback struct was provided"); |
| 505 | 505 | ||
| 506 | if (pccs->fStopExtracting) | 506 | if (pccs->fStopExtracting) |
| @@ -510,40 +510,37 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE | |||
| 510 | 510 | ||
| 511 | // convert params to useful variables | 511 | // convert params to useful variables |
| 512 | sz = static_cast<LPCSTR>(pFDINotify->psz1); | 512 | sz = static_cast<LPCSTR>(pFDINotify->psz1); |
| 513 | if (!::MultiByteToWideChar(CP_ACP, 0, sz, -1, wz, countof(wz))) | 513 | CabExitOnNull(sz, hr, E_INVALIDARG, "No cabinet file ID given to convert"); |
| 514 | { | 514 | |
| 515 | CabExitWithLastError(hr, "failed to convert cabinet file id to unicode: %s", sz); | 515 | hr = StrAllocStringAnsi(&pwz, sz, 0, CP_ACP); |
| 516 | } | 516 | CabExitOnFailure(hr, "failed to convert cabinet file id to unicode: %hs", sz); |
| 517 | 517 | ||
| 518 | if (pccs->pfnProgress) | 518 | if (pccs->pfnProgress) |
| 519 | { | 519 | { |
| 520 | hr = pccs->pfnProgress(TRUE, wz, pccs->pvContext); | 520 | hr = pccs->pfnProgress(TRUE, pwz, pccs->pvContext); |
| 521 | if (S_OK != hr) | 521 | if (S_OK != hr) |
| 522 | { | 522 | { |
| 523 | ExitFunction(); | 523 | ExitFunction(); |
| 524 | } | 524 | } |
| 525 | } | 525 | } |
| 526 | 526 | ||
| 527 | if (L'*' == *pccs->pwzExtract || 0 == lstrcmpW(pccs->pwzExtract, wz)) | 527 | if (L'*' == *pccs->pwzExtract || 0 == lstrcmpW(pccs->pwzExtract, pwz)) |
| 528 | { | 528 | { |
| 529 | // get the created date for the resource in the cabinet | 529 | // get the created date for the resource in the cabinet |
| 530 | FILETIME ftLocal; | 530 | FILETIME ftLocal; |
| 531 | if (!::DosDateTimeToFileTime(pFDINotify->date, pFDINotify->time, &ftLocal)) | 531 | if (!::DosDateTimeToFileTime(pFDINotify->date, pFDINotify->time, &ftLocal)) |
| 532 | { | 532 | { |
| 533 | CabExitWithLastError(hr, "failed to get time for resource: %ls", wz); | 533 | CabExitWithLastError(hr, "failed to get time for resource: %ls", pwz); |
| 534 | } | 534 | } |
| 535 | ::LocalFileTimeToFileTime(&ftLocal, &ft); | 535 | ::LocalFileTimeToFileTime(&ftLocal, &ft); |
| 536 | 536 | ||
| 537 | WCHAR wzPath[MAX_PATH]; | 537 | hr = PathConcat(pccs->pwzExtractDir, pwz, &pwzPath); |
| 538 | hr = ::StringCchCopyW(wzPath, countof(wzPath), pccs->pwzExtractDir); | 538 | CabExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", pccs->pwzExtractDir, pwz); |
| 539 | CabExitOnFailure(hr, "failed to copy in extract directory: %ls for file: %ls", pccs->pwzExtractDir, wz); | ||
| 540 | hr = ::StringCchCatW(wzPath, countof(wzPath), wz); | ||
| 541 | CabExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", wzPath, wz); | ||
| 542 | 539 | ||
| 543 | hFile = OpenFileWithRetry(wzPath, GENERIC_WRITE, CREATE_ALWAYS); | 540 | hFile = OpenFileWithRetry(pwzPath, GENERIC_WRITE, CREATE_ALWAYS); |
| 544 | if (INVALID_HANDLE_VALUE == hFile) | 541 | if (INVALID_HANDLE_VALUE == hFile) |
| 545 | { | 542 | { |
| 546 | CabExitWithLastError(hr, "failed to create file: %ls", wzPath); | 543 | CabExitWithLastError(hr, "failed to create file: %ls", pwzPath); |
| 547 | } | 544 | } |
| 548 | 545 | ||
| 549 | ::SetFileTime(hFile, &ft, &ft, &ft); // try to set the file time (who cares if it fails) | 546 | ::SetFileTime(hFile, &ft, &ft, &ft); // try to set the file time (who cares if it fails) |
| @@ -567,17 +564,15 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE | |||
| 567 | 564 | ||
| 568 | break; | 565 | break; |
| 569 | case fdintCLOSE_FILE_INFO: // resource extraction complete | 566 | case fdintCLOSE_FILE_INFO: // resource extraction complete |
| 570 | Assert(pFDINotify->hf && pFDINotify->psz1); | 567 | Assert(pFDINotify->hf && pccs && pFDINotify->psz1); |
| 571 | CabExitOnNull(pccs, hr, E_INVALIDARG, "Failed to call cabextract callback, because no callback struct was provided"); | 568 | CabExitOnNull(pccs, hr, E_INVALIDARG, "Failed to call cabextract callback, because no callback struct was provided"); |
| 572 | 569 | ||
| 573 | // convert params to useful variables | 570 | // convert params to useful variables |
| 574 | sz = static_cast<LPCSTR>(pFDINotify->psz1); | 571 | sz = static_cast<LPCSTR>(pFDINotify->psz1); |
| 575 | CabExitOnNull(sz, hr, E_INVALIDARG, "Failed to convert cabinet file id, because no cabinet file id was provided"); | 572 | CabExitOnNull(sz, hr, E_INVALIDARG, "Failed to convert cabinet file id, because no cabinet file id was provided"); |
| 576 | 573 | ||
| 577 | if (!::MultiByteToWideChar(CP_ACP, 0, sz, -1, wz, countof(wz))) | 574 | hr = StrAllocStringAnsi(&pwz, sz, 0, CP_ACP); |
| 578 | { | 575 | CabExitOnFailure(hr, "failed to convert cabinet file id to unicode: %hs", sz); |
| 579 | CabExitWithLastError(hr, "failed to convert cabinet file id to unicode: %s", sz); | ||
| 580 | } | ||
| 581 | 576 | ||
| 582 | if (NULL != pFDINotify->hf) // just close the file | 577 | if (NULL != pFDINotify->hf) // just close the file |
| 583 | { | 578 | { |
| @@ -586,7 +581,7 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE | |||
| 586 | 581 | ||
| 587 | if (pccs->pfnProgress) | 582 | if (pccs->pfnProgress) |
| 588 | { | 583 | { |
| 589 | hr = pccs->pfnProgress(FALSE, wz, pccs->pvContext); | 584 | hr = pccs->pfnProgress(FALSE, pwz, pccs->pvContext); |
| 590 | } | 585 | } |
| 591 | 586 | ||
| 592 | if (S_OK == hr && L'*' == *pccs->pwzExtract) // if everything is okay and we're extracting all files, keep going | 587 | if (S_OK == hr && L'*' == *pccs->pwzExtract) // if everything is okay and we're extracting all files, keep going |
| @@ -613,5 +608,8 @@ static __callback INT_PTR DIAMONDAPI CabExtractCallback(__in FDINOTIFICATIONTYPE | |||
| 613 | LExit: | 608 | LExit: |
| 614 | ReleaseFileHandle(hFile); | 609 | ReleaseFileHandle(hFile); |
| 615 | 610 | ||
| 611 | ReleaseStr(pwz); | ||
| 612 | ReleaseStr(pwzPath); | ||
| 613 | |||
| 616 | return (S_OK == hr) ? ipResult : -1; | 614 | return (S_OK == hr) ? ipResult : -1; |
| 617 | } | 615 | } |
diff --git a/src/libs/dutil/WixToolset.DUtil/dirutil.cpp b/src/libs/dutil/WixToolset.DUtil/dirutil.cpp index 94eab9e7..2c02225d 100644 --- a/src/libs/dutil/WixToolset.DUtil/dirutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/dirutil.cpp | |||
| @@ -59,34 +59,10 @@ LExit: | |||
| 59 | *******************************************************************/ | 59 | *******************************************************************/ |
| 60 | extern "C" HRESULT DAPI DirCreateTempPath( | 60 | extern "C" HRESULT DAPI DirCreateTempPath( |
| 61 | __in_z LPCWSTR wzPrefix, | 61 | __in_z LPCWSTR wzPrefix, |
| 62 | __out_ecount_z(cchPath) LPWSTR wzPath, | 62 | __out_opt LPWSTR* psczTempFile |
| 63 | __in DWORD cchPath | ||
| 64 | ) | 63 | ) |
| 65 | { | 64 | { |
| 66 | Assert(wzPrefix); | 65 | return PathCreateTempFile(NULL, NULL, 0, wzPrefix, 0, psczTempFile, NULL); |
| 67 | Assert(wzPath); | ||
| 68 | |||
| 69 | HRESULT hr = S_OK; | ||
| 70 | |||
| 71 | WCHAR wzDir[MAX_PATH]; | ||
| 72 | WCHAR wzFile[MAX_PATH]; | ||
| 73 | DWORD cch = 0; | ||
| 74 | |||
| 75 | cch = ::GetTempPathW(countof(wzDir), wzDir); | ||
| 76 | if (!cch || cch >= countof(wzDir)) | ||
| 77 | { | ||
| 78 | DirExitWithLastError(hr, "Failed to GetTempPath."); | ||
| 79 | } | ||
| 80 | |||
| 81 | if (!::GetTempFileNameW(wzDir, wzPrefix, 0, wzFile)) | ||
| 82 | { | ||
| 83 | DirExitWithLastError(hr, "Failed to GetTempFileName."); | ||
| 84 | } | ||
| 85 | |||
| 86 | hr = ::StringCchCopyW(wzPath, cchPath, wzFile); | ||
| 87 | |||
| 88 | LExit: | ||
| 89 | return hr; | ||
| 90 | } | 66 | } |
| 91 | 67 | ||
| 92 | 68 | ||
| @@ -192,18 +168,19 @@ extern "C" HRESULT DAPI DirEnsureDeleteEx( | |||
| 192 | Assert(wzPath && *wzPath); | 168 | Assert(wzPath && *wzPath); |
| 193 | 169 | ||
| 194 | HRESULT hr = S_OK; | 170 | HRESULT hr = S_OK; |
| 195 | DWORD er; | 171 | DWORD er = ERROR_SUCCESS; |
| 196 | 172 | ||
| 197 | DWORD dwAttrib; | 173 | DWORD dwAttrib = 0; |
| 198 | HANDLE hFind = INVALID_HANDLE_VALUE; | 174 | HANDLE hFind = INVALID_HANDLE_VALUE; |
| 199 | LPWSTR sczDelete = NULL; | 175 | LPWSTR sczDelete = NULL; |
| 200 | WIN32_FIND_DATAW wfd; | 176 | WIN32_FIND_DATAW wfd = { }; |
| 201 | 177 | ||
| 202 | BOOL fDeleteFiles = (DIR_DELETE_FILES == (dwFlags & DIR_DELETE_FILES)); | 178 | BOOL fDeleteFiles = (DIR_DELETE_FILES == (dwFlags & DIR_DELETE_FILES)); |
| 203 | BOOL fRecurse = (DIR_DELETE_RECURSE == (dwFlags & DIR_DELETE_RECURSE)); | 179 | BOOL fRecurse = (DIR_DELETE_RECURSE == (dwFlags & DIR_DELETE_RECURSE)); |
| 204 | BOOL fScheduleDelete = (DIR_DELETE_SCHEDULE == (dwFlags & DIR_DELETE_SCHEDULE)); | 180 | BOOL fScheduleDelete = (DIR_DELETE_SCHEDULE == (dwFlags & DIR_DELETE_SCHEDULE)); |
| 205 | WCHAR wzTempDirectory[MAX_PATH] = { }; | 181 | WCHAR wzSafeFileName[MAX_PATH + 1] = { }; |
| 206 | WCHAR wzTempPath[MAX_PATH] = { }; | 182 | LPWSTR sczTempDirectory = NULL; |
| 183 | LPWSTR sczTempPath = NULL; | ||
| 207 | 184 | ||
| 208 | if (-1 == (dwAttrib = ::GetFileAttributesW(wzPath))) | 185 | if (-1 == (dwAttrib = ::GetFileAttributesW(wzPath))) |
| 209 | { | 186 | { |
| @@ -231,10 +208,8 @@ extern "C" HRESULT DAPI DirEnsureDeleteEx( | |||
| 231 | { | 208 | { |
| 232 | if (fScheduleDelete) | 209 | if (fScheduleDelete) |
| 233 | { | 210 | { |
| 234 | if (!::GetTempPathW(countof(wzTempDirectory), wzTempDirectory)) | 211 | hr = PathGetTempPath(&sczTempDirectory, NULL); |
| 235 | { | 212 | DirExitOnFailure(hr, "Failed to get temp directory."); |
| 236 | DirExitWithLastError(hr, "Failed to get temp directory."); | ||
| 237 | } | ||
| 238 | } | 213 | } |
| 239 | 214 | ||
| 240 | // Delete everything in this directory. | 215 | // Delete everything in this directory. |
| @@ -256,10 +231,11 @@ extern "C" HRESULT DAPI DirEnsureDeleteEx( | |||
| 256 | } | 231 | } |
| 257 | 232 | ||
| 258 | // For extra safety and to silence OACR. | 233 | // For extra safety and to silence OACR. |
| 259 | wfd.cFileName[MAX_PATH - 1] = L'\0'; | 234 | hr = ::StringCchCopyNExW(wzSafeFileName, countof(wzSafeFileName), wfd.cFileName, countof(wfd.cFileName), NULL, NULL, STRSAFE_FILL_BEHIND_NULL | STRSAFE_NULL_ON_FAILURE); |
| 235 | DirExitOnFailure(hr, "Failed to ensure file name was null terminated."); | ||
| 260 | 236 | ||
| 261 | hr = PathConcat(wzPath, wfd.cFileName, &sczDelete); | 237 | hr = PathConcat(wzPath, wzSafeFileName, &sczDelete); |
| 262 | DirExitOnFailure(hr, "Failed to concat filename '%ls' to directory: %ls", wfd.cFileName, wzPath); | 238 | DirExitOnFailure(hr, "Failed to concat filename '%ls' to directory: %ls", wzSafeFileName, wzPath); |
| 263 | 239 | ||
| 264 | if (fRecurse && wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | 240 | if (fRecurse && wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
| 265 | { | 241 | { |
| @@ -288,16 +264,14 @@ extern "C" HRESULT DAPI DirEnsureDeleteEx( | |||
| 288 | { | 264 | { |
| 289 | if (fScheduleDelete) | 265 | if (fScheduleDelete) |
| 290 | { | 266 | { |
| 291 | if (!::GetTempFileNameW(wzTempDirectory, L"DEL", 0, wzTempPath)) | 267 | hr = PathGetTempFileName(sczTempDirectory, L"DEL", 0, &sczTempPath); |
| 292 | { | 268 | DirExitOnFailure(hr, "Failed to get temp file to move to."); |
| 293 | DirExitWithLastError(hr, "Failed to get temp file to move to."); | ||
| 294 | } | ||
| 295 | 269 | ||
| 296 | // Try to move the file to the temp directory then schedule for delete, | 270 | // Try to move the file to the temp directory then schedule for delete, |
| 297 | // otherwise just schedule for delete. | 271 | // otherwise just schedule for delete. |
| 298 | if (::MoveFileExW(sczDelete, wzTempPath, MOVEFILE_REPLACE_EXISTING)) | 272 | if (::MoveFileExW(sczDelete, sczTempPath, MOVEFILE_REPLACE_EXISTING)) |
| 299 | { | 273 | { |
| 300 | ::MoveFileExW(wzTempPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); | 274 | ::MoveFileExW(sczTempPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); |
| 301 | } | 275 | } |
| 302 | else | 276 | else |
| 303 | { | 277 | { |
| @@ -348,6 +322,8 @@ extern "C" HRESULT DAPI DirEnsureDeleteEx( | |||
| 348 | LExit: | 322 | LExit: |
| 349 | ReleaseFileFindHandle(hFind); | 323 | ReleaseFileFindHandle(hFind); |
| 350 | ReleaseStr(sczDelete); | 324 | ReleaseStr(sczDelete); |
| 325 | ReleaseStr(sczTempDirectory); | ||
| 326 | ReleaseStr(sczTempPath); | ||
| 351 | 327 | ||
| 352 | return hr; | 328 | return hr; |
| 353 | } | 329 | } |
diff --git a/src/libs/dutil/WixToolset.DUtil/fileutil.cpp b/src/libs/dutil/WixToolset.DUtil/fileutil.cpp index 9f68ee52..ac407916 100644 --- a/src/libs/dutil/WixToolset.DUtil/fileutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/fileutil.cpp | |||
| @@ -1284,21 +1284,18 @@ extern "C" HRESULT DAPI FileCreateTempW( | |||
| 1284 | Assert(wzPrefix && *wzPrefix); | 1284 | Assert(wzPrefix && *wzPrefix); |
| 1285 | HRESULT hr = E_FAIL; | 1285 | HRESULT hr = E_FAIL; |
| 1286 | 1286 | ||
| 1287 | WCHAR wzTempPath[MAX_PATH]; | 1287 | LPWSTR pwzTempPath = NULL; |
| 1288 | DWORD cchTempPath = countof(wzTempPath); | ||
| 1289 | LPWSTR pwzTempFile = NULL; | 1288 | LPWSTR pwzTempFile = NULL; |
| 1290 | 1289 | ||
| 1291 | HANDLE hTempFile = INVALID_HANDLE_VALUE; | 1290 | HANDLE hTempFile = INVALID_HANDLE_VALUE; |
| 1292 | int i = 0; | 1291 | int i = 0; |
| 1293 | 1292 | ||
| 1294 | if (!::GetTempPathW(cchTempPath, wzTempPath)) | 1293 | hr = PathGetTempPath(&pwzTempPath, NULL); |
| 1295 | { | 1294 | FileExitOnFailure(hr, "failed to get temp path"); |
| 1296 | FileExitOnLastError(hr, "failed to get temp path"); | ||
| 1297 | } | ||
| 1298 | 1295 | ||
| 1299 | for (i = 0; i < 1000 && INVALID_HANDLE_VALUE == hTempFile; ++i) | 1296 | for (i = 0; i < 1000 && INVALID_HANDLE_VALUE == hTempFile; ++i) |
| 1300 | { | 1297 | { |
| 1301 | hr = StrAllocFormatted(&pwzTempFile, L"%s%s%05d.%s", wzTempPath, wzPrefix, i, wzExtension); | 1298 | hr = StrAllocFormatted(&pwzTempFile, L"%s%s%05d.%s", pwzTempPath, wzPrefix, i, wzExtension); |
| 1302 | FileExitOnFailure(hr, "failed to allocate memory for temp filename"); | 1299 | FileExitOnFailure(hr, "failed to allocate memory for temp filename"); |
| 1303 | 1300 | ||
| 1304 | hTempFile = ::CreateFileW(pwzTempFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); | 1301 | hTempFile = ::CreateFileW(pwzTempFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); |
| @@ -1330,6 +1327,7 @@ extern "C" HRESULT DAPI FileCreateTempW( | |||
| 1330 | LExit: | 1327 | LExit: |
| 1331 | ReleaseFile(hTempFile); | 1328 | ReleaseFile(hTempFile); |
| 1332 | ReleaseStr(pwzTempFile); | 1329 | ReleaseStr(pwzTempFile); |
| 1330 | ReleaseStr(pwzTempPath); | ||
| 1333 | 1331 | ||
| 1334 | return hr; | 1332 | return hr; |
| 1335 | } | 1333 | } |
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/dirutil.h b/src/libs/dutil/WixToolset.DUtil/inc/dirutil.h index 42268a16..b8fc0431 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/dirutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/dirutil.h | |||
| @@ -20,8 +20,7 @@ BOOL DAPI DirExists( | |||
| 20 | 20 | ||
| 21 | HRESULT DAPI DirCreateTempPath( | 21 | HRESULT DAPI DirCreateTempPath( |
| 22 | __in_z LPCWSTR wzPrefix, | 22 | __in_z LPCWSTR wzPrefix, |
| 23 | __out_ecount_z(cchPath) LPWSTR wzPath, | 23 | __out_opt LPWSTR* psczTempFile |
| 24 | __in DWORD cchPath | ||
| 25 | ); | 24 | ); |
| 26 | 25 | ||
| 27 | HRESULT DAPI DirEnsureExists( | 26 | HRESULT DAPI DirEnsureExists( |
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h index 971ef887..de46b95d 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/pathutil.h | |||
| @@ -159,19 +159,31 @@ DAPI_(HRESULT) PathRelativeToModule( | |||
| 159 | /******************************************************************* | 159 | /******************************************************************* |
| 160 | PathCreateTempFile | 160 | PathCreateTempFile |
| 161 | 161 | ||
| 162 | Note: if wzDirectory is null, ::GetTempPath() will be used instead. | 162 | Note: if wzDirectory is null, ::GetTempPath2() will be used instead. |
| 163 | if wzFileNameTemplate is null, GetTempFileName() will be used instead. | 163 | if wzFileNameTemplate is null, GetTempFileName() will be used instead. |
| 164 | *******************************************************************/ | 164 | *******************************************************************/ |
| 165 | DAPI_(HRESULT) PathCreateTempFile( | 165 | DAPI_(HRESULT) PathCreateTempFile( |
| 166 | __in_opt LPCWSTR wzDirectory, | 166 | __in_opt LPCWSTR wzDirectory, |
| 167 | __in_opt __format_string LPCWSTR wzFileNameTemplate, | 167 | __in_opt __format_string LPCWSTR wzFileNameTemplate, |
| 168 | __in DWORD dwUniqueCount, | 168 | __in DWORD dwUniqueCount, |
| 169 | __in_z LPCWSTR wzPrefix, | ||
| 169 | __in DWORD dwFileAttributes, | 170 | __in DWORD dwFileAttributes, |
| 170 | __out_opt LPWSTR* psczTempFile, | 171 | __out_opt LPWSTR* psczTempFile, |
| 171 | __out_opt HANDLE* phTempFile | 172 | __out_opt HANDLE* phTempFile |
| 172 | ); | 173 | ); |
| 173 | 174 | ||
| 174 | /******************************************************************* | 175 | /******************************************************************* |
| 176 | PathGetTempFileName - wrapper around ::GetTempFileName. | ||
| 177 | If the wzPathName is too long, it will use its own algorithm. | ||
| 178 | *******************************************************************/ | ||
| 179 | DAPI_(HRESULT) PathGetTempFileName( | ||
| 180 | __in LPCWSTR wzPathName, | ||
| 181 | __in LPCWSTR wzPrefixString, | ||
| 182 | __in UINT uUnique, | ||
| 183 | __out LPWSTR* psczTempFileName | ||
| 184 | ); | ||
| 185 | |||
| 186 | /******************************************************************* | ||
| 175 | PathCreateTimeBasedTempFile - creates an empty temp file based on current | 187 | PathCreateTimeBasedTempFile - creates an empty temp file based on current |
| 176 | system time | 188 | system time |
| 177 | ********************************************************************/ | 189 | ********************************************************************/ |
| @@ -187,7 +199,7 @@ DAPI_(HRESULT) PathCreateTimeBasedTempFile( | |||
| 187 | /******************************************************************* | 199 | /******************************************************************* |
| 188 | PathCreateTempDirectory | 200 | PathCreateTempDirectory |
| 189 | 201 | ||
| 190 | Note: if wzDirectory is null, ::GetTempPath() will be used instead. | 202 | Note: if wzDirectory is null, ::GetTempPath2() will be used instead. |
| 191 | *******************************************************************/ | 203 | *******************************************************************/ |
| 192 | DAPI_(HRESULT) PathCreateTempDirectory( | 204 | DAPI_(HRESULT) PathCreateTempDirectory( |
| 193 | __in_opt LPCWSTR wzDirectory, | 205 | __in_opt LPCWSTR wzDirectory, |
| @@ -201,7 +213,24 @@ DAPI_(HRESULT) PathCreateTempDirectory( | |||
| 201 | that is backslash terminated. | 213 | that is backslash terminated. |
| 202 | *******************************************************************/ | 214 | *******************************************************************/ |
| 203 | DAPI_(HRESULT) PathGetTempPath( | 215 | DAPI_(HRESULT) PathGetTempPath( |
| 204 | __out_z LPWSTR* psczTempPath | 216 | __out_z LPWSTR* psczTempPath, |
| 217 | __out_opt SIZE_T* pcch | ||
| 218 | ); | ||
| 219 | |||
| 220 | /******************************************************************* | ||
| 221 | PathGetSystemDirectory - returns the path to the system folder | ||
| 222 | that is backslash terminated. | ||
| 223 | *******************************************************************/ | ||
| 224 | DAPI_(HRESULT) PathGetSystemDirectory( | ||
| 225 | __out_z LPWSTR* psczSystemPath | ||
| 226 | ); | ||
| 227 | |||
| 228 | /******************************************************************* | ||
| 229 | PathGetSystemWow64Directory - returns the path to the system WoW 64 folder | ||
| 230 | that is backslash terminated. | ||
| 231 | *******************************************************************/ | ||
| 232 | DAPI_(HRESULT) PathGetSystemWow64Directory( | ||
| 233 | __out_z LPWSTR* psczSystemPath | ||
| 205 | ); | 234 | ); |
| 206 | 235 | ||
| 207 | /******************************************************************* | 236 | /******************************************************************* |
| @@ -223,12 +252,11 @@ DAPI_(HRESULT) PathGetSystemTempPaths( | |||
| 223 | ); | 252 | ); |
| 224 | 253 | ||
| 225 | /******************************************************************* | 254 | /******************************************************************* |
| 226 | PathGetKnownFolder - returns the path to a well-known shell folder | 255 | PathGetVolumePathName - wrapper for ::GetVolumePathNameW. |
| 227 | |||
| 228 | *******************************************************************/ | 256 | *******************************************************************/ |
| 229 | DAPI_(HRESULT) PathGetKnownFolder( | 257 | DAPI_(HRESULT) PathGetVolumePathName( |
| 230 | __in int csidl, | 258 | __in_z LPCWSTR wzFileName, |
| 231 | __out LPWSTR* psczKnownFolder | 259 | __out_z LPWSTR* psczVolumePathName |
| 232 | ); | 260 | ); |
| 233 | 261 | ||
| 234 | /******************************************************************* | 262 | /******************************************************************* |
| @@ -340,6 +368,20 @@ DAPI_(HRESULT) PathGetHierarchyArray( | |||
| 340 | __inout LPUINT pcPathArray | 368 | __inout LPUINT pcPathArray |
| 341 | ); | 369 | ); |
| 342 | 370 | ||
| 371 | /******************************************************************** | ||
| 372 | Path2FunctionAllowFallback - allow functions only available in newer versions of Windows. | ||
| 373 | Typically used for unit testing. | ||
| 374 | |||
| 375 | *********************************************************************/ | ||
| 376 | void DAPI Path2FunctionAllowFallback(); | ||
| 377 | |||
| 378 | /******************************************************************** | ||
| 379 | Path2FunctionForceFallback - ignore functions only available in newer versions of Windows. | ||
| 380 | Typically used for unit testing. | ||
| 381 | |||
| 382 | *********************************************************************/ | ||
| 383 | void DAPI Path2FunctionForceFallback(); | ||
| 384 | |||
| 343 | /******************************************************************* | 385 | /******************************************************************* |
| 344 | PathCanonicalizePath - wrapper around PathCanonicalizeW. | 386 | PathCanonicalizePath - wrapper around PathCanonicalizeW. |
| 345 | *******************************************************************/ | 387 | *******************************************************************/ |
| @@ -349,6 +391,15 @@ DAPI_(HRESULT) PathCanonicalizePath( | |||
| 349 | ); | 391 | ); |
| 350 | 392 | ||
| 351 | /******************************************************************* | 393 | /******************************************************************* |
| 394 | PathAllocCanonicalizePath - wrapper around PathAllocCanonicalize. | ||
| 395 | *******************************************************************/ | ||
| 396 | DAPI_(HRESULT) PathAllocCanonicalizePath( | ||
| 397 | __in_z LPCWSTR wzPath, | ||
| 398 | __in DWORD dwFlags, | ||
| 399 | __deref_out_z LPWSTR* psczCanonicalized | ||
| 400 | ); | ||
| 401 | |||
| 402 | /******************************************************************* | ||
| 352 | PathCanonicalizeForComparison - canonicalizes the path based on the given flags. | 403 | PathCanonicalizeForComparison - canonicalizes the path based on the given flags. |
| 353 | . and .. directories are collapsed. | 404 | . and .. directories are collapsed. |
| 354 | All / are replaced with \. | 405 | All / are replaced with \. |
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/shelutil.h b/src/libs/dutil/WixToolset.DUtil/inc/shelutil.h index 0b9f539d..2ee7ce87 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/shelutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/shelutil.h | |||
| @@ -33,10 +33,25 @@ HRESULT DAPI ShelExecUnelevated( | |||
| 33 | __in_z_opt LPCWSTR wzWorkingDirectory, | 33 | __in_z_opt LPCWSTR wzWorkingDirectory, |
| 34 | __in int nShowCmd | 34 | __in int nShowCmd |
| 35 | ); | 35 | ); |
| 36 | |||
| 37 | /******************************************************************** | ||
| 38 | ShelGetFolder() - translates the CSIDL into KNOWNFOLDERID and calls ShelGetKnownFolder. | ||
| 39 | If that returns E_NOTIMPL then falls back to ::SHGetFolderPathW. | ||
| 40 | The CSIDL_FLAG values are not supported, CSIDL_FLAG_CREATE is always used. | ||
| 41 | The path is backslash terminated. | ||
| 42 | |||
| 43 | *******************************************************************/ | ||
| 36 | HRESULT DAPI ShelGetFolder( | 44 | HRESULT DAPI ShelGetFolder( |
| 37 | __out_z LPWSTR* psczFolderPath, | 45 | __out_z LPWSTR* psczFolderPath, |
| 38 | __in int csidlFolder | 46 | __in int csidlFolder |
| 39 | ); | 47 | ); |
| 48 | |||
| 49 | /******************************************************************** | ||
| 50 | ShelGetKnownFolder() - gets a folder by KNOWNFOLDERID with ::SHGetKnownFolderPath. | ||
| 51 | The path is backslash terminated. | ||
| 52 | |||
| 53 | Note: return E_NOTIMPL if called on pre-Vista operating systems. | ||
| 54 | *******************************************************************/ | ||
| 40 | HRESULT DAPI ShelGetKnownFolder( | 55 | HRESULT DAPI ShelGetKnownFolder( |
| 41 | __out_z LPWSTR* psczFolderPath, | 56 | __out_z LPWSTR* psczFolderPath, |
| 42 | __in REFKNOWNFOLDERID rfidFolder | 57 | __in REFKNOWNFOLDERID rfidFolder |
diff --git a/src/libs/dutil/WixToolset.DUtil/logutil.cpp b/src/libs/dutil/WixToolset.DUtil/logutil.cpp index 88a90d8c..3a130b4e 100644 --- a/src/libs/dutil/WixToolset.DUtil/logutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/logutil.cpp | |||
| @@ -684,9 +684,10 @@ LExit: | |||
| 684 | extern "C" HRESULT DAPI LogHeader() | 684 | extern "C" HRESULT DAPI LogHeader() |
| 685 | { | 685 | { |
| 686 | HRESULT hr = S_OK; | 686 | HRESULT hr = S_OK; |
| 687 | WCHAR wzComputerName[MAX_PATH]; | 687 | WCHAR wzComputerName[MAX_COMPUTERNAME_LENGTH + 1] = { }; |
| 688 | DWORD cchComputerName = countof(wzComputerName); | 688 | DWORD cchComputerName = countof(wzComputerName); |
| 689 | WCHAR wzPath[MAX_PATH]; | 689 | LPWSTR sczPath = NULL; |
| 690 | LPCWSTR wzPath = NULL; | ||
| 690 | DWORD dwMajorVersion = 0; | 691 | DWORD dwMajorVersion = 0; |
| 691 | DWORD dwMinorVersion = 0; | 692 | DWORD dwMinorVersion = 0; |
| 692 | LPCSTR szLevel = LOGUTIL_UNKNOWN; | 693 | LPCSTR szLevel = LOGUTIL_UNKNOWN; |
| @@ -695,12 +696,19 @@ extern "C" HRESULT DAPI LogHeader() | |||
| 695 | // | 696 | // |
| 696 | // get the interesting data | 697 | // get the interesting data |
| 697 | // | 698 | // |
| 698 | if (!::GetModuleFileNameW(NULL, wzPath, countof(wzPath))) | 699 | |
| 700 | hr = PathForCurrentProcess(&sczPath, NULL); | ||
| 701 | if (FAILED(hr)) | ||
| 702 | { | ||
| 703 | wzPath = L""; | ||
| 704 | } | ||
| 705 | else | ||
| 699 | { | 706 | { |
| 700 | memset(wzPath, 0, sizeof(wzPath)); | 707 | wzPath = sczPath; |
| 708 | |||
| 709 | hr = FileVersion(wzPath, &dwMajorVersion, &dwMinorVersion); | ||
| 701 | } | 710 | } |
| 702 | 711 | ||
| 703 | hr = FileVersion(wzPath, &dwMajorVersion, &dwMinorVersion); | ||
| 704 | if (FAILED(hr)) | 712 | if (FAILED(hr)) |
| 705 | { | 713 | { |
| 706 | dwMajorVersion = 0; | 714 | dwMajorVersion = 0; |
| @@ -743,6 +751,7 @@ extern "C" HRESULT DAPI LogHeader() | |||
| 743 | hr = S_OK; | 751 | hr = S_OK; |
| 744 | 752 | ||
| 745 | ReleaseStr(sczCurrentDateTime); | 753 | ReleaseStr(sczCurrentDateTime); |
| 754 | ReleaseStr(sczPath); | ||
| 746 | 755 | ||
| 747 | return hr; | 756 | return hr; |
| 748 | } | 757 | } |
diff --git a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp index 3c4b2f88..862a743d 100644 --- a/src/libs/dutil/WixToolset.DUtil/path2utl.cpp +++ b/src/libs/dutil/WixToolset.DUtil/path2utl.cpp | |||
| @@ -19,6 +19,65 @@ | |||
| 19 | #define PathExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_PATHUTIL, g, x, s, __VA_ARGS__) | 19 | #define PathExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_PATHUTIL, g, x, s, __VA_ARGS__) |
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | typedef HRESULT(WINAPI* PFN_PATH_ALLOC_CANONICALIZE)( | ||
| 23 | __in LPCWSTR wzSource, | ||
| 24 | __in DWORD dwFlags, | ||
| 25 | __out_z LPWSTR* psczPathOut | ||
| 26 | ); | ||
| 27 | |||
| 28 | static BOOL vfInitialized = FALSE; | ||
| 29 | static HMODULE vhPathApiSet_1_1_0 = NULL; | ||
| 30 | static PFN_PATH_ALLOC_CANONICALIZE vpfnPathAllocCanonicalize = NULL; | ||
| 31 | static BOOL vfForceFallback = FALSE; | ||
| 32 | |||
| 33 | // from PathCch.h | ||
| 34 | #ifndef PATHCCH_ALLOW_LONG_PATHS | ||
| 35 | #define PATHCCH_ALLOW_LONG_PATHS 0x01 | ||
| 36 | #endif | ||
| 37 | |||
| 38 | static HRESULT Initialize() | ||
| 39 | { | ||
| 40 | HRESULT hr = S_OK; | ||
| 41 | DWORD er = ERROR_SUCCESS; | ||
| 42 | |||
| 43 | if (vfInitialized) | ||
| 44 | { | ||
| 45 | ExitFunction(); | ||
| 46 | } | ||
| 47 | |||
| 48 | hr = LoadSystemApiSet(L"api-ms-win-core-path-l1-1-0.dll", &vhPathApiSet_1_1_0); | ||
| 49 | if (E_MODNOTFOUND == hr) | ||
| 50 | { | ||
| 51 | hr = E_NOTIMPL; | ||
| 52 | } | ||
| 53 | PathExitOnFailure(hr, "Failed to load api-ms-win-core-path-l1-1-0.dll"); | ||
| 54 | |||
| 55 | vpfnPathAllocCanonicalize = reinterpret_cast<PFN_PATH_ALLOC_CANONICALIZE>(::GetProcAddress(vhPathApiSet_1_1_0, "PathAllocCanonicalize")); | ||
| 56 | if (!vpfnPathAllocCanonicalize) | ||
| 57 | { | ||
| 58 | er = ::GetLastError(); | ||
| 59 | PathExitWithRootFailure(hr, ERROR_PROC_NOT_FOUND == er ? E_NOTIMPL : HRESULT_FROM_WIN32(er), "Failed to get address of PathAllocCanonicalize."); | ||
| 60 | } | ||
| 61 | |||
| 62 | vfInitialized = TRUE; | ||
| 63 | |||
| 64 | LExit: | ||
| 65 | return hr; | ||
| 66 | } | ||
| 67 | |||
| 68 | |||
| 69 | DAPI_(void) Path2FunctionAllowFallback() | ||
| 70 | { | ||
| 71 | vfForceFallback = FALSE; | ||
| 72 | } | ||
| 73 | |||
| 74 | |||
| 75 | DAPI_(void) Path2FunctionForceFallback() | ||
| 76 | { | ||
| 77 | vfForceFallback = TRUE; | ||
| 78 | } | ||
| 79 | |||
| 80 | |||
| 22 | DAPI_(HRESULT) PathCanonicalizePath( | 81 | DAPI_(HRESULT) PathCanonicalizePath( |
| 23 | __in_z LPCWSTR wzPath, | 82 | __in_z LPCWSTR wzPath, |
| 24 | __deref_out_z LPWSTR* psczCanonicalized | 83 | __deref_out_z LPWSTR* psczCanonicalized |
| @@ -43,6 +102,37 @@ LExit: | |||
| 43 | return hr; | 102 | return hr; |
| 44 | } | 103 | } |
| 45 | 104 | ||
| 105 | DAPI_(HRESULT) PathAllocCanonicalizePath( | ||
| 106 | __in_z LPCWSTR wzPath, | ||
| 107 | __in DWORD dwFlags, | ||
| 108 | __deref_out_z LPWSTR* psczCanonicalized | ||
| 109 | ) | ||
| 110 | { | ||
| 111 | HRESULT hr = S_OK; | ||
| 112 | LPWSTR sczCanonicalizedPath = NULL; | ||
| 113 | |||
| 114 | hr = Initialize(); | ||
| 115 | if (E_NOTIMPL == hr || SUCCEEDED(hr) && !vpfnPathAllocCanonicalize) | ||
| 116 | { | ||
| 117 | ExitFunction1(hr = E_NOTIMPL); | ||
| 118 | } | ||
| 119 | PathExitOnFailure(hr, "Failed to initialize path2utl."); | ||
| 120 | |||
| 121 | hr = vpfnPathAllocCanonicalize(wzPath, dwFlags, &sczCanonicalizedPath); | ||
| 122 | PathExitOnFailure(hr, "Failed to canonicalize: %ls", wzPath); | ||
| 123 | |||
| 124 | hr = StrAllocString(psczCanonicalized, sczCanonicalizedPath, 0); | ||
| 125 | PathExitOnFailure(hr, "Failed to copy the canonicalized path."); | ||
| 126 | |||
| 127 | LExit: | ||
| 128 | if (sczCanonicalizedPath) | ||
| 129 | { | ||
| 130 | ::LocalFree(sczCanonicalizedPath); | ||
| 131 | } | ||
| 132 | |||
| 133 | return hr; | ||
| 134 | } | ||
| 135 | |||
| 46 | DAPI_(HRESULT) PathCanonicalizeForComparison( | 136 | DAPI_(HRESULT) PathCanonicalizeForComparison( |
| 47 | __in_z LPCWSTR wzPath, | 137 | __in_z LPCWSTR wzPath, |
| 48 | __in DWORD dwCanonicalizeFlags, | 138 | __in DWORD dwCanonicalizeFlags, |
| @@ -75,7 +165,19 @@ DAPI_(HRESULT) PathCanonicalizeForComparison( | |||
| 75 | 165 | ||
| 76 | if (*wzNormalizedPath) | 166 | if (*wzNormalizedPath) |
| 77 | { | 167 | { |
| 78 | hr = PathCanonicalizePath(wzNormalizedPath, psczCanonicalized); | 168 | if (!vfForceFallback) |
| 169 | { | ||
| 170 | hr = PathAllocCanonicalizePath(wzNormalizedPath, PATHCCH_ALLOW_LONG_PATHS, psczCanonicalized); | ||
| 171 | } | ||
| 172 | else | ||
| 173 | { | ||
| 174 | hr = E_NOTIMPL; | ||
| 175 | } | ||
| 176 | |||
| 177 | if (E_NOTIMPL == hr) | ||
| 178 | { | ||
| 179 | hr = PathCanonicalizePath(wzNormalizedPath, psczCanonicalized); | ||
| 180 | } | ||
| 79 | PathExitOnFailure(hr, "Failed to canonicalize: %ls", wzNormalizedPath); | 181 | PathExitOnFailure(hr, "Failed to canonicalize: %ls", wzNormalizedPath); |
| 80 | } | 182 | } |
| 81 | else | 183 | else |
| @@ -273,33 +375,52 @@ DAPI_(HRESULT) PathSystemWindowsSubdirectory( | |||
| 273 | ) | 375 | ) |
| 274 | { | 376 | { |
| 275 | HRESULT hr = S_OK; | 377 | HRESULT hr = S_OK; |
| 276 | WCHAR wzTempPath[MAX_PATH + 1] = { }; | 378 | LPWSTR sczWindowsPath = NULL; |
| 379 | DWORD cchBuffer = MAX_PATH + 1; | ||
| 277 | DWORD cch = 0; | 380 | DWORD cch = 0; |
| 278 | 381 | ||
| 279 | cch = ::GetSystemWindowsDirectoryW(wzTempPath, countof(wzTempPath)); | 382 | hr = StrAlloc(&sczWindowsPath, cchBuffer); |
| 280 | if (!cch) | 383 | PathExitOnFailure(hr, "Failed to alloc Windows directory path."); |
| 281 | { | 384 | |
| 282 | PathExitWithLastError(hr, "Failed to get Windows directory path."); | 385 | cch = ::GetSystemWindowsDirectoryW(sczWindowsPath, cchBuffer); |
| 283 | } | 386 | PathExitOnNullWithLastError(cch, hr, "Failed to get Windows directory path with default size."); |
| 284 | else if (cch >= countof(wzTempPath)) | 387 | |
| 388 | cch += 1; // add 1 for null terminator. | ||
| 389 | |||
| 390 | if (cch > cchBuffer) | ||
| 285 | { | 391 | { |
| 286 | PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Windows directory path too long."); | 392 | hr = StrAlloc(&sczWindowsPath, cch); |
| 393 | PathExitOnFailure(hr, "Failed to realloc Windows directory path."); | ||
| 394 | |||
| 395 | cchBuffer = cch; | ||
| 396 | |||
| 397 | cch = ::GetSystemWindowsDirectoryW(sczWindowsPath, cchBuffer); | ||
| 398 | PathExitOnNullWithLastError(cch, hr, "Failed to get Windows directory path with returned size."); | ||
| 399 | |||
| 400 | cch += 1; // add 1 for null terminator. | ||
| 401 | |||
| 402 | if (cch > cchBuffer) | ||
| 403 | { | ||
| 404 | PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Failed to get Windows directory path with returned size."); | ||
| 405 | } | ||
| 287 | } | 406 | } |
| 288 | 407 | ||
| 289 | if (wzSubdirectory) | 408 | if (wzSubdirectory) |
| 290 | { | 409 | { |
| 291 | hr = PathConcatRelativeToBase(wzTempPath, wzSubdirectory, psczFullPath); | 410 | hr = PathConcatRelativeToBase(sczWindowsPath, wzSubdirectory, psczFullPath); |
| 292 | PathExitOnFailure(hr, "Failed to concat subdirectory on Windows directory path."); | 411 | PathExitOnFailure(hr, "Failed to concat subdirectory on Windows directory path."); |
| 293 | } | 412 | } |
| 294 | else | 413 | else |
| 295 | { | 414 | { |
| 296 | hr = StrAllocString(psczFullPath, wzTempPath, 0); | 415 | *psczFullPath = sczWindowsPath; |
| 297 | PathExitOnFailure(hr, "Failed to copy Windows directory path."); | 416 | sczWindowsPath = NULL; |
| 298 | } | 417 | } |
| 299 | 418 | ||
| 300 | hr = PathBackslashTerminate(psczFullPath); | 419 | hr = PathBackslashTerminate(psczFullPath); |
| 301 | PathExitOnFailure(hr, "Failed to terminate Windows directory path with backslash."); | 420 | PathExitOnFailure(hr, "Failed to terminate Windows directory path with backslash."); |
| 302 | 421 | ||
| 303 | LExit: | 422 | LExit: |
| 423 | ReleaseStr(sczWindowsPath); | ||
| 424 | |||
| 304 | return hr; | 425 | return hr; |
| 305 | } | 426 | } |
diff --git a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp index 0e2a5dec..dd5385fc 100644 --- a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp | |||
| @@ -20,6 +20,11 @@ | |||
| 20 | 20 | ||
| 21 | #define PATH_GOOD_ENOUGH 64 | 21 | #define PATH_GOOD_ENOUGH 64 |
| 22 | 22 | ||
| 23 | typedef DWORD(APIENTRY* PFN_GETTEMPPATH2W)( | ||
| 24 | __in DWORD BufferLength, | ||
| 25 | __out LPWSTR Buffer | ||
| 26 | ); | ||
| 27 | |||
| 23 | static BOOL IsPathSeparatorChar( | 28 | static BOOL IsPathSeparatorChar( |
| 24 | __in WCHAR wc | 29 | __in WCHAR wc |
| 25 | ); | 30 | ); |
| @@ -527,28 +532,55 @@ DAPI_(HRESULT) PathForCurrentProcess( | |||
| 527 | ) | 532 | ) |
| 528 | { | 533 | { |
| 529 | HRESULT hr = S_OK; | 534 | HRESULT hr = S_OK; |
| 530 | DWORD cch = MAX_PATH; | 535 | WCHAR smallBuffer[1] = { }; |
| 536 | SIZE_T cchMax = 0; | ||
| 537 | DWORD cchBuffer = 0; | ||
| 538 | DWORD cch = 0; | ||
| 539 | DWORD dwMaxAttempts = 20; | ||
| 531 | 540 | ||
| 532 | do | 541 | // GetModuleFileNameW didn't originally set the last error when the buffer was too small. |
| 542 | ::SetLastError(ERROR_SUCCESS); | ||
| 543 | |||
| 544 | cch = ::GetModuleFileNameW(hModule, smallBuffer, countof(smallBuffer)); | ||
| 545 | PathExitOnNullWithLastError(cch, hr, "Failed to get size of path for executing process."); | ||
| 546 | |||
| 547 | if (*psczFullPath && ERROR_INSUFFICIENT_BUFFER == ::GetLastError()) | ||
| 533 | { | 548 | { |
| 534 | hr = StrAlloc(psczFullPath, cch); | 549 | hr = StrMaxLength(*psczFullPath, &cchMax); |
| 535 | PathExitOnFailure(hr, "Failed to allocate string for module path."); | 550 | PathExitOnFailure(hr, "Failed to get max length of input buffer."); |
| 551 | |||
| 552 | cchBuffer = (DWORD)min(DWORD_MAX, cchMax); | ||
| 553 | } | ||
| 554 | else | ||
| 555 | { | ||
| 556 | cchBuffer = MAX_PATH + 1; | ||
| 557 | |||
| 558 | hr = StrAlloc(psczFullPath, cchBuffer); | ||
| 559 | PathExitOnFailure(hr, "Failed to allocate space for module path."); | ||
| 560 | } | ||
| 561 | |||
| 562 | ::SetLastError(ERROR_SUCCESS); | ||
| 536 | 563 | ||
| 537 | DWORD cchRequired = ::GetModuleFileNameW(hModule, *psczFullPath, cch); | 564 | for (DWORD i = 0; i < dwMaxAttempts; ++i) |
| 538 | if (0 == cchRequired) | 565 | { |
| 566 | cch = ::GetModuleFileNameW(hModule, *psczFullPath, cchBuffer); | ||
| 567 | PathExitOnNullWithLastError(cch, hr, "Failed to get path for executing process."); | ||
| 568 | |||
| 569 | if (ERROR_INSUFFICIENT_BUFFER != ::GetLastError()) | ||
| 539 | { | 570 | { |
| 540 | PathExitWithLastError(hr, "Failed to get path for executing process."); | 571 | break; |
| 541 | } | 572 | } |
| 542 | else if (cchRequired == cch) | 573 | |
| 574 | if ((dwMaxAttempts - 1) == i) | ||
| 543 | { | 575 | { |
| 544 | cch = cchRequired + 1; | 576 | PathExitWithRootFailure(hr, E_FAIL, "Unexpected failure getting path for executing process."); |
| 545 | hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); | ||
| 546 | } | 577 | } |
| 547 | else | 578 | |
| 548 | { | 579 | cchBuffer *= 2; |
| 549 | hr = S_OK; | 580 | |
| 550 | } | 581 | hr = StrAlloc(psczFullPath, cchBuffer); |
| 551 | } while (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr); | 582 | PathExitOnFailure(hr, "Failed to re-allocate more space for module path."); |
| 583 | } | ||
| 552 | 584 | ||
| 553 | LExit: | 585 | LExit: |
| 554 | return hr; | 586 | return hr; |
| @@ -582,17 +614,18 @@ DAPI_(HRESULT) PathCreateTempFile( | |||
| 582 | __in_opt LPCWSTR wzDirectory, | 614 | __in_opt LPCWSTR wzDirectory, |
| 583 | __in_opt __format_string LPCWSTR wzFileNameTemplate, | 615 | __in_opt __format_string LPCWSTR wzFileNameTemplate, |
| 584 | __in DWORD dwUniqueCount, | 616 | __in DWORD dwUniqueCount, |
| 617 | __in_z LPCWSTR wzPrefix, | ||
| 585 | __in DWORD dwFileAttributes, | 618 | __in DWORD dwFileAttributes, |
| 586 | __out_opt LPWSTR* psczTempFile, | 619 | __out_opt LPWSTR* psczTempFile, |
| 587 | __out_opt HANDLE* phTempFile | 620 | __out_opt HANDLE* phTempFile |
| 588 | ) | 621 | ) |
| 589 | { | 622 | { |
| 590 | AssertSz(0 < dwUniqueCount, "Must specify a non-zero unique count."); | 623 | Assert(wzPrefix); |
| 624 | AssertSz(!wzFileNameTemplate || !*wzFileNameTemplate || 0 < dwUniqueCount, "Must specify a non-zero unique count."); | ||
| 591 | 625 | ||
| 592 | HRESULT hr = S_OK; | 626 | HRESULT hr = S_OK; |
| 593 | 627 | ||
| 594 | LPWSTR sczTempPath = NULL; | 628 | LPWSTR sczTempPath = NULL; |
| 595 | DWORD cchTempPath = MAX_PATH; | ||
| 596 | 629 | ||
| 597 | HANDLE hTempFile = INVALID_HANDLE_VALUE; | 630 | HANDLE hTempFile = INVALID_HANDLE_VALUE; |
| 598 | LPWSTR scz = NULL; | 631 | LPWSTR scz = NULL; |
| @@ -605,13 +638,8 @@ DAPI_(HRESULT) PathCreateTempFile( | |||
| 605 | } | 638 | } |
| 606 | else | 639 | else |
| 607 | { | 640 | { |
| 608 | hr = StrAlloc(&sczTempPath, cchTempPath); | 641 | hr = PathGetTempPath(&sczTempPath, NULL); |
| 609 | PathExitOnFailure(hr, "Failed to allocate memory for the temp path."); | 642 | PathExitOnFailure(hr, "Failed to get temp path."); |
| 610 | |||
| 611 | if (!::GetTempPathW(cchTempPath, sczTempPath)) | ||
| 612 | { | ||
| 613 | PathExitWithLastError(hr, "Failed to get temp path."); | ||
| 614 | } | ||
| 615 | } | 643 | } |
| 616 | 644 | ||
| 617 | if (wzFileNameTemplate && *wzFileNameTemplate) | 645 | if (wzFileNameTemplate && *wzFileNameTemplate) |
| @@ -621,7 +649,7 @@ DAPI_(HRESULT) PathCreateTempFile( | |||
| 621 | hr = StrAllocFormatted(&scz, wzFileNameTemplate, i); | 649 | hr = StrAllocFormatted(&scz, wzFileNameTemplate, i); |
| 622 | PathExitOnFailure(hr, "Failed to allocate memory for file template."); | 650 | PathExitOnFailure(hr, "Failed to allocate memory for file template."); |
| 623 | 651 | ||
| 624 | hr = StrAllocFormatted(&sczTempFile, L"%s%s", sczTempPath, scz); | 652 | hr = StrAllocFormatted(&sczTempFile, L"%ls%ls", sczTempPath, scz); |
| 625 | PathExitOnFailure(hr, "Failed to allocate temp file name."); | 653 | PathExitOnFailure(hr, "Failed to allocate temp file name."); |
| 626 | 654 | ||
| 627 | hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_NEW, dwFileAttributes, NULL); | 655 | hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_NEW, dwFileAttributes, NULL); |
| @@ -642,13 +670,8 @@ DAPI_(HRESULT) PathCreateTempFile( | |||
| 642 | // the system to provide us a temp file using its built-in mechanism. | 670 | // the system to provide us a temp file using its built-in mechanism. |
| 643 | if (INVALID_HANDLE_VALUE == hTempFile) | 671 | if (INVALID_HANDLE_VALUE == hTempFile) |
| 644 | { | 672 | { |
| 645 | hr = StrAlloc(&sczTempFile, MAX_PATH); | 673 | hr = PathGetTempFileName(sczTempPath, wzPrefix, 0, &sczTempFile); |
| 646 | PathExitOnFailure(hr, "Failed to allocate memory for the temp path"); | 674 | PathExitOnFailure(hr, "Failed to create new temp file name."); |
| 647 | |||
| 648 | if (!::GetTempFileNameW(sczTempPath, L"TMP", 0, sczTempFile)) | ||
| 649 | { | ||
| 650 | PathExitWithLastError(hr, "Failed to create new temp file name."); | ||
| 651 | } | ||
| 652 | 675 | ||
| 653 | hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, dwFileAttributes, NULL); | 676 | hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, dwFileAttributes, NULL); |
| 654 | if (INVALID_HANDLE_VALUE == hTempFile) | 677 | if (INVALID_HANDLE_VALUE == hTempFile) |
| @@ -684,6 +707,82 @@ LExit: | |||
| 684 | } | 707 | } |
| 685 | 708 | ||
| 686 | 709 | ||
| 710 | DAPI_(HRESULT) PathGetTempFileName( | ||
| 711 | __in LPCWSTR wzPathName, | ||
| 712 | __in LPCWSTR wzPrefixString, | ||
| 713 | __in UINT uUnique, | ||
| 714 | __out LPWSTR* psczTempFileName | ||
| 715 | ) | ||
| 716 | { | ||
| 717 | HRESULT hr = S_OK; | ||
| 718 | size_t cchFullPath = 0; | ||
| 719 | WORD wValue = (WORD)(0xffff & uUnique); | ||
| 720 | LPWSTR scz = NULL; | ||
| 721 | LPWSTR sczTempFile = NULL; | ||
| 722 | HANDLE hTempFile = INVALID_HANDLE_VALUE; | ||
| 723 | |||
| 724 | hr = ::StringCchLengthW(wzPathName, STRSAFE_MAX_CCH, &cchFullPath); | ||
| 725 | PathExitOnFailure(hr, "Failed to get length of path to prefix."); | ||
| 726 | |||
| 727 | if (MAX_PATH - 14 >= cchFullPath) | ||
| 728 | { | ||
| 729 | hr = StrAlloc(psczTempFileName, MAX_PATH); | ||
| 730 | PathExitOnFailure(hr, "Failed to allocate buffer for GetTempFileNameW."); | ||
| 731 | |||
| 732 | if (!::GetTempFileNameW(wzPathName, wzPrefixString, uUnique, *psczTempFileName)) | ||
| 733 | { | ||
| 734 | PathExitWithLastError(hr, "Failed to create new temp file name."); | ||
| 735 | } | ||
| 736 | |||
| 737 | ExitFunction(); | ||
| 738 | } | ||
| 739 | |||
| 740 | // TODO: when uUnique is 0, consider not always starting at 0 to avoid collisions if this is called repeatedly. | ||
| 741 | // Purposely let it wrap around. | ||
| 742 | for (WORD w = 0; w < WORD_MAX && INVALID_HANDLE_VALUE == hTempFile; ++wValue) | ||
| 743 | { | ||
| 744 | hr = StrAllocFormatted(&scz, L"%ls%x.TMP", wzPrefixString, w); | ||
| 745 | PathExitOnFailure(hr, "Failed to allocate memory for file template."); | ||
| 746 | |||
| 747 | hr = PathConcat(wzPathName, scz, &sczTempFile); | ||
| 748 | PathExitOnFailure(hr, "Failed to allocate temp file name."); | ||
| 749 | |||
| 750 | hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_NEW, 0, NULL); | ||
| 751 | if (INVALID_HANDLE_VALUE == hTempFile) | ||
| 752 | { | ||
| 753 | // if the file already exists, try next one. | ||
| 754 | hr = HRESULT_FROM_WIN32(::GetLastError()); | ||
| 755 | if (HRESULT_FROM_WIN32(ERROR_FILE_EXISTS) == hr) | ||
| 756 | { | ||
| 757 | hr = S_OK; | ||
| 758 | } | ||
| 759 | PathExitOnFailure(hr, "Failed to create file: %ls", sczTempFile); | ||
| 760 | } | ||
| 761 | |||
| 762 | ++w; | ||
| 763 | } | ||
| 764 | |||
| 765 | if (INVALID_HANDLE_VALUE == hTempFile) | ||
| 766 | { | ||
| 767 | PathExitWithRootFailure(hr, HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "Failed to create temp file."); | ||
| 768 | } | ||
| 769 | |||
| 770 | hr = StrAllocString(psczTempFileName, sczTempFile, 0); | ||
| 771 | PathExitOnFailure(hr, "Failed to copy temp file string."); | ||
| 772 | |||
| 773 | LExit: | ||
| 774 | if (INVALID_HANDLE_VALUE != hTempFile) | ||
| 775 | { | ||
| 776 | ::CloseHandle(hTempFile); | ||
| 777 | } | ||
| 778 | |||
| 779 | ReleaseStr(scz); | ||
| 780 | ReleaseStr(sczTempFile); | ||
| 781 | |||
| 782 | return hr; | ||
| 783 | } | ||
| 784 | |||
| 785 | |||
| 687 | DAPI_(HRESULT) PathCreateTimeBasedTempFile( | 786 | DAPI_(HRESULT) PathCreateTimeBasedTempFile( |
| 688 | __in_z_opt LPCWSTR wzDirectory, | 787 | __in_z_opt LPCWSTR wzDirectory, |
| 689 | __in_z LPCWSTR wzPrefix, | 788 | __in_z LPCWSTR wzPrefix, |
| @@ -695,7 +794,7 @@ DAPI_(HRESULT) PathCreateTimeBasedTempFile( | |||
| 695 | { | 794 | { |
| 696 | HRESULT hr = S_OK; | 795 | HRESULT hr = S_OK; |
| 697 | BOOL fRetry = FALSE; | 796 | BOOL fRetry = FALSE; |
| 698 | WCHAR wzTempPath[MAX_PATH] = { }; | 797 | LPWSTR sczTempParentPath = NULL; |
| 699 | LPWSTR sczPrefix = NULL; | 798 | LPWSTR sczPrefix = NULL; |
| 700 | LPWSTR sczPrefixFolder = NULL; | 799 | LPWSTR sczPrefixFolder = NULL; |
| 701 | SYSTEMTIME time = { }; | 800 | SYSTEMTIME time = { }; |
| @@ -711,12 +810,10 @@ DAPI_(HRESULT) PathCreateTimeBasedTempFile( | |||
| 711 | } | 810 | } |
| 712 | else | 811 | else |
| 713 | { | 812 | { |
| 714 | if (!::GetTempPathW(countof(wzTempPath), wzTempPath)) | 813 | hr = PathGetTempPath(&sczTempParentPath, NULL); |
| 715 | { | 814 | PathExitOnFailure(hr, "Failed to get temp folder."); |
| 716 | PathExitWithLastError(hr, "Failed to get temp folder."); | ||
| 717 | } | ||
| 718 | 815 | ||
| 719 | hr = PathConcat(wzTempPath, wzPrefix, &sczPrefix); | 816 | hr = PathConcat(sczTempParentPath, wzPrefix, &sczPrefix); |
| 720 | PathExitOnFailure(hr, "Failed to concatenate the temp folder and log prefix."); | 817 | PathExitOnFailure(hr, "Failed to concatenate the temp folder and log prefix."); |
| 721 | } | 818 | } |
| 722 | 819 | ||
| @@ -778,6 +875,7 @@ DAPI_(HRESULT) PathCreateTimeBasedTempFile( | |||
| 778 | 875 | ||
| 779 | LExit: | 876 | LExit: |
| 780 | ReleaseFile(hTempFile); | 877 | ReleaseFile(hTempFile); |
| 878 | ReleaseStr(sczTempParentPath); | ||
| 781 | ReleaseStr(sczTempPath); | 879 | ReleaseStr(sczTempPath); |
| 782 | ReleaseStr(sczPrefixFolder); | 880 | ReleaseStr(sczPrefixFolder); |
| 783 | ReleaseStr(sczPrefix); | 881 | ReleaseStr(sczPrefix); |
| @@ -799,7 +897,6 @@ DAPI_(HRESULT) PathCreateTempDirectory( | |||
| 799 | HRESULT hr = S_OK; | 897 | HRESULT hr = S_OK; |
| 800 | 898 | ||
| 801 | LPWSTR sczTempPath = NULL; | 899 | LPWSTR sczTempPath = NULL; |
| 802 | DWORD cchTempPath = MAX_PATH; | ||
| 803 | 900 | ||
| 804 | LPWSTR scz = NULL; | 901 | LPWSTR scz = NULL; |
| 805 | 902 | ||
| @@ -813,13 +910,8 @@ DAPI_(HRESULT) PathCreateTempDirectory( | |||
| 813 | } | 910 | } |
| 814 | else | 911 | else |
| 815 | { | 912 | { |
| 816 | hr = StrAlloc(&sczTempPath, cchTempPath); | 913 | hr = PathGetTempPath(&sczTempPath, NULL); |
| 817 | PathExitOnFailure(hr, "Failed to allocate memory for the temp path."); | 914 | PathExitOnFailure(hr, "Failed to get temp path."); |
| 818 | |||
| 819 | if (!::GetTempPathW(cchTempPath, sczTempPath)) | ||
| 820 | { | ||
| 821 | PathExitWithLastError(hr, "Failed to get temp path."); | ||
| 822 | } | ||
| 823 | } | 915 | } |
| 824 | 916 | ||
| 825 | for (DWORD i = 1; i <= dwUniqueCount; ++i) | 917 | for (DWORD i = 1; i <= dwUniqueCount; ++i) |
| @@ -869,46 +961,230 @@ LExit: | |||
| 869 | 961 | ||
| 870 | 962 | ||
| 871 | DAPI_(HRESULT) PathGetTempPath( | 963 | DAPI_(HRESULT) PathGetTempPath( |
| 872 | __out_z LPWSTR* psczTempPath | 964 | __out_z LPWSTR* psczTempPath, |
| 965 | __out_opt SIZE_T* pcch | ||
| 966 | ) | ||
| 967 | { | ||
| 968 | |||
| 969 | HRESULT hr = S_OK; | ||
| 970 | SIZE_T cchMax = 0; | ||
| 971 | DWORD cchBuffer = 0; | ||
| 972 | DWORD cch = 0; | ||
| 973 | DWORD dwAttempts = 0; | ||
| 974 | HMODULE hModule = NULL; | ||
| 975 | PFN_GETTEMPPATH2W pfnGetTempPath = NULL; | ||
| 976 | const DWORD dwMaxAttempts = 10; | ||
| 977 | |||
| 978 | if (*psczTempPath) | ||
| 979 | { | ||
| 980 | hr = StrMaxLength(*psczTempPath, &cchMax); | ||
| 981 | PathExitOnFailure(hr, "Failed to get max length of input buffer."); | ||
| 982 | |||
| 983 | cchBuffer = (DWORD)min(DWORD_MAX, cchMax); | ||
| 984 | } | ||
| 985 | else | ||
| 986 | { | ||
| 987 | cchBuffer = MAX_PATH + 1; | ||
| 988 | |||
| 989 | hr = StrAlloc(psczTempPath, cchBuffer); | ||
| 990 | PathExitOnFailure(hr, "Failed to allocate space for temp path."); | ||
| 991 | } | ||
| 992 | |||
| 993 | hr = LoadSystemLibrary(L"kernel32.dll", &hModule); | ||
| 994 | PathExitOnFailure(hr, "Failed to load kernel32.dll"); | ||
| 995 | |||
| 996 | pfnGetTempPath = reinterpret_cast<PFN_GETTEMPPATH2W>(::GetProcAddress(hModule, "GetTempPath2W")); | ||
| 997 | if (!pfnGetTempPath) | ||
| 998 | { | ||
| 999 | pfnGetTempPath = ::GetTempPathW; | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | for (; dwAttempts < dwMaxAttempts; ++dwAttempts) | ||
| 1003 | { | ||
| 1004 | cch = pfnGetTempPath(cchBuffer, *psczTempPath); | ||
| 1005 | PathExitOnNullWithLastError(cch, hr, "Failed to get temp path."); | ||
| 1006 | |||
| 1007 | cch += 1; // add one for null terminator. | ||
| 1008 | |||
| 1009 | if (cch <= cchBuffer) | ||
| 1010 | { | ||
| 1011 | break; | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | hr = StrAlloc(psczTempPath, cch); | ||
| 1015 | PathExitOnFailure(hr, "Failed to reallocate space for temp path."); | ||
| 1016 | |||
| 1017 | cchBuffer = cch; | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | if (dwMaxAttempts == dwAttempts) | ||
| 1021 | { | ||
| 1022 | PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "GetTempPathW results never converged."); | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | if (pcch) | ||
| 1026 | { | ||
| 1027 | *pcch = cch - 1; // remove one for null terminator. | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | LExit: | ||
| 1031 | return hr; | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | |||
| 1035 | DAPI_(HRESULT) PathGetSystemDirectory( | ||
| 1036 | __out_z LPWSTR* psczSystemPath | ||
| 1037 | ) | ||
| 1038 | { | ||
| 1039 | HRESULT hr = S_OK; | ||
| 1040 | SIZE_T cchMax = 0; | ||
| 1041 | DWORD cchBuffer = 0; | ||
| 1042 | DWORD cch = 0; | ||
| 1043 | |||
| 1044 | if (*psczSystemPath) | ||
| 1045 | { | ||
| 1046 | hr = StrMaxLength(*psczSystemPath, &cchMax); | ||
| 1047 | PathExitOnFailure(hr, "Failed to get max length of input buffer."); | ||
| 1048 | |||
| 1049 | cchBuffer = (DWORD)min(DWORD_MAX, cchMax); | ||
| 1050 | } | ||
| 1051 | else | ||
| 1052 | { | ||
| 1053 | cchBuffer = MAX_PATH + 1; | ||
| 1054 | |||
| 1055 | hr = StrAlloc(psczSystemPath, cchBuffer); | ||
| 1056 | PathExitOnFailure(hr, "Failed to allocate space for system directory."); | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | cch = ::GetSystemDirectoryW(*psczSystemPath, cchBuffer); | ||
| 1060 | PathExitOnNullWithLastError(cch, hr, "Failed to get system directory path with default size."); | ||
| 1061 | |||
| 1062 | if (cch > cchBuffer) | ||
| 1063 | { | ||
| 1064 | hr = StrAlloc(psczSystemPath, cch); | ||
| 1065 | PathExitOnFailure(hr, "Failed to realloc system directory path."); | ||
| 1066 | |||
| 1067 | cchBuffer = cch; | ||
| 1068 | |||
| 1069 | cch = ::GetSystemDirectoryW(*psczSystemPath, cchBuffer); | ||
| 1070 | PathExitOnNullWithLastError(cch, hr, "Failed to get system directory path with returned size."); | ||
| 1071 | |||
| 1072 | if (cch > cchBuffer) | ||
| 1073 | { | ||
| 1074 | PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Failed to get system directory path with returned size."); | ||
| 1075 | } | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | hr = PathBackslashTerminate(psczSystemPath); | ||
| 1079 | PathExitOnFailure(hr, "Failed to terminate system directory path with backslash."); | ||
| 1080 | |||
| 1081 | LExit: | ||
| 1082 | return hr; | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | |||
| 1086 | DAPI_(HRESULT) PathGetSystemWow64Directory( | ||
| 1087 | __out_z LPWSTR* psczSystemPath | ||
| 873 | ) | 1088 | ) |
| 874 | { | 1089 | { |
| 875 | HRESULT hr = S_OK; | 1090 | HRESULT hr = S_OK; |
| 876 | WCHAR wzTempPath[MAX_PATH + 1] = { }; | 1091 | SIZE_T cchMax = 0; |
| 1092 | DWORD cchBuffer = 0; | ||
| 877 | DWORD cch = 0; | 1093 | DWORD cch = 0; |
| 878 | 1094 | ||
| 879 | cch = ::GetTempPathW(countof(wzTempPath), wzTempPath); | 1095 | if (*psczSystemPath) |
| 880 | if (!cch) | ||
| 881 | { | 1096 | { |
| 882 | PathExitWithLastError(hr, "Failed to GetTempPath."); | 1097 | hr = StrMaxLength(*psczSystemPath, &cchMax); |
| 1098 | PathExitOnFailure(hr, "Failed to get max length of input buffer."); | ||
| 1099 | |||
| 1100 | cchBuffer = (DWORD)min(DWORD_MAX, cchMax); | ||
| 883 | } | 1101 | } |
| 884 | else if (cch >= countof(wzTempPath)) | 1102 | else |
| 885 | { | 1103 | { |
| 886 | PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "TEMP directory path too long."); | 1104 | cchBuffer = MAX_PATH + 1; |
| 1105 | |||
| 1106 | hr = StrAlloc(psczSystemPath, cchBuffer); | ||
| 1107 | PathExitOnFailure(hr, "Failed to allocate space for system wow64 directory."); | ||
| 887 | } | 1108 | } |
| 888 | 1109 | ||
| 889 | hr = StrAllocString(psczTempPath, wzTempPath, cch); | 1110 | cch = ::GetSystemWow64DirectoryW(*psczSystemPath, cchBuffer); |
| 890 | PathExitOnFailure(hr, "Failed to copy TEMP directory path."); | 1111 | PathExitOnNullWithLastError(cch, hr, "Failed to get system wow64 directory path with default size."); |
| 1112 | |||
| 1113 | cch += 1; // add one for the null terminator. | ||
| 1114 | |||
| 1115 | if (cch > cchBuffer) | ||
| 1116 | { | ||
| 1117 | hr = StrAlloc(psczSystemPath, cch); | ||
| 1118 | PathExitOnFailure(hr, "Failed to realloc system wow64 directory path."); | ||
| 1119 | |||
| 1120 | cchBuffer = cch; | ||
| 1121 | |||
| 1122 | cch = ::GetSystemWow64DirectoryW(*psczSystemPath, cchBuffer); | ||
| 1123 | PathExitOnNullWithLastError(cch, hr, "Failed to get system wow64 directory path with returned size."); | ||
| 1124 | |||
| 1125 | cch += 1; // add one for the null terminator. | ||
| 1126 | |||
| 1127 | if (cch > cchBuffer) | ||
| 1128 | { | ||
| 1129 | PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Failed to get system wow64 directory path with returned size."); | ||
| 1130 | } | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | hr = PathBackslashTerminate(psczSystemPath); | ||
| 1134 | PathExitOnFailure(hr, "Failed to terminate system wow64 directory path with backslash."); | ||
| 891 | 1135 | ||
| 892 | LExit: | 1136 | LExit: |
| 893 | return hr; | 1137 | return hr; |
| 894 | } | 1138 | } |
| 895 | 1139 | ||
| 896 | 1140 | ||
| 897 | DAPI_(HRESULT) PathGetKnownFolder( | 1141 | DAPI_(HRESULT) PathGetVolumePathName( |
| 898 | __in int csidl, | 1142 | __in_z LPCWSTR wzFileName, |
| 899 | __out LPWSTR* psczKnownFolder | 1143 | __out_z LPWSTR* psczVolumePathName |
| 900 | ) | 1144 | ) |
| 901 | { | 1145 | { |
| 902 | HRESULT hr = S_OK; | 1146 | HRESULT hr = S_OK; |
| 1147 | DWORD cchBuffer = 0; | ||
| 1148 | SIZE_T cchMax = 0; | ||
| 1149 | const DWORD dwMaxAttempts = 20; | ||
| 903 | 1150 | ||
| 904 | hr = StrAlloc(psczKnownFolder, MAX_PATH); | 1151 | if (*psczVolumePathName) |
| 905 | PathExitOnFailure(hr, "Failed to allocate memory for known folder."); | 1152 | { |
| 1153 | hr = StrMaxLength(*psczVolumePathName, &cchMax); | ||
| 1154 | PathExitOnFailure(hr, "Failed to get max length of input buffer."); | ||
| 906 | 1155 | ||
| 907 | hr = ::SHGetFolderPathW(NULL, csidl, NULL, SHGFP_TYPE_CURRENT, *psczKnownFolder); | 1156 | cchBuffer = (DWORD)min(DWORD_MAX, cchMax); |
| 908 | PathExitOnFailure(hr, "Failed to get known folder path."); | 1157 | } |
| 1158 | else | ||
| 1159 | { | ||
| 1160 | cchBuffer = MAX_PATH + 1; | ||
| 1161 | |||
| 1162 | hr = StrAlloc(psczVolumePathName, cchBuffer); | ||
| 1163 | PathExitOnFailure(hr, "Failed to allocate space for volume path name."); | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | for (DWORD i = 0; i < dwMaxAttempts; ++i) | ||
| 1167 | { | ||
| 1168 | if (::GetVolumePathNameW(wzFileName, *psczVolumePathName, cchBuffer)) | ||
| 1169 | { | ||
| 1170 | break; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | hr = HRESULT_FROM_WIN32(::GetLastError()); | ||
| 1174 | if (HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) != hr && E_INSUFFICIENT_BUFFER != hr || | ||
| 1175 | (dwMaxAttempts - 1) == i) | ||
| 1176 | { | ||
| 1177 | PathExitWithRootFailure(hr, hr, "Failed to get volume path name of: %ls", wzFileName); | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | cchBuffer *= 2; | ||
| 1181 | |||
| 1182 | hr = StrAlloc(psczVolumePathName, cchBuffer); | ||
| 1183 | PathExitOnFailure(hr, "Failed to re-allocate more space for volume path name."); | ||
| 1184 | } | ||
| 909 | 1185 | ||
| 910 | hr = PathBackslashTerminate(psczKnownFolder); | 1186 | hr = PathBackslashTerminate(psczVolumePathName); |
| 911 | PathExitOnFailure(hr, "Failed to ensure known folder path is backslash terminated."); | 1187 | PathExitOnFailure(hr, "Failed to terminate volume path name with backslash."); |
| 912 | 1188 | ||
| 913 | LExit: | 1189 | LExit: |
| 914 | return hr; | 1190 | return hr; |
diff --git a/src/libs/dutil/WixToolset.DUtil/rexutil.cpp b/src/libs/dutil/WixToolset.DUtil/rexutil.cpp index 155ca714..ce28beb3 100644 --- a/src/libs/dutil/WixToolset.DUtil/rexutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/rexutil.cpp | |||
| @@ -28,7 +28,7 @@ static ERF verf; | |||
| 28 | static FAKE_FILE vrgffFileTable[FILETABLESIZE]; | 28 | static FAKE_FILE vrgffFileTable[FILETABLESIZE]; |
| 29 | static DWORD vcbRes; | 29 | static DWORD vcbRes; |
| 30 | static LPCBYTE vpbRes; | 30 | static LPCBYTE vpbRes; |
| 31 | static CHAR vszResource[MAX_PATH]; | 31 | static LPSTR vpszResource = NULL; |
| 32 | static REX_CALLBACK_WRITE vpfnWrite = NULL; | 32 | static REX_CALLBACK_WRITE vpfnWrite = NULL; |
| 33 | 33 | ||
| 34 | static HRESULT vhrLastError = S_OK; | 34 | static HRESULT vhrLastError = S_OK; |
| @@ -85,6 +85,8 @@ LExit: | |||
| 85 | { | 85 | { |
| 86 | ::FDIDestroy(vhfdi); | 86 | ::FDIDestroy(vhfdi); |
| 87 | vhfdi = NULL; | 87 | vhfdi = NULL; |
| 88 | |||
| 89 | ReleaseNullStr(vpszResource); | ||
| 88 | } | 90 | } |
| 89 | 91 | ||
| 90 | return hr; | 92 | return hr; |
| @@ -101,6 +103,8 @@ extern "C" void RexUninitialize() | |||
| 101 | { | 103 | { |
| 102 | ::FDIDestroy(vhfdi); | 104 | ::FDIDestroy(vhfdi); |
| 103 | vhfdi = NULL; | 105 | vhfdi = NULL; |
| 106 | |||
| 107 | ReleaseNullStr(vpszResource); | ||
| 104 | } | 108 | } |
| 105 | } | 109 | } |
| 106 | 110 | ||
| @@ -124,12 +128,12 @@ extern "C" HRESULT RexExtract( | |||
| 124 | { | 128 | { |
| 125 | Assert(vhfdi); | 129 | Assert(vhfdi); |
| 126 | HRESULT hr = S_OK; | 130 | HRESULT hr = S_OK; |
| 127 | BOOL fResult; | 131 | BOOL fResult = FALSE; |
| 128 | 132 | ||
| 129 | HRSRC hResInfo = NULL; | 133 | HRSRC hResInfo = NULL; |
| 130 | HANDLE hRes = NULL; | 134 | HANDLE hRes = NULL; |
| 131 | 135 | ||
| 132 | REX_CALLBACK_STRUCT rcs; | 136 | REX_CALLBACK_STRUCT rcs = { }; |
| 133 | 137 | ||
| 134 | // remember the write callback | 138 | // remember the write callback |
| 135 | vpfnWrite = pfnWrite; | 139 | vpfnWrite = pfnWrite; |
| @@ -158,7 +162,7 @@ extern "C" HRESULT RexExtract( | |||
| 158 | // RexExitOnLastError(hr, "failed to convert cabinet resource name to ASCII: %ls", wzResource); | 162 | // RexExitOnLastError(hr, "failed to convert cabinet resource name to ASCII: %ls", wzResource); |
| 159 | //} | 163 | //} |
| 160 | 164 | ||
| 161 | hr = ::StringCchCopyA(vszResource, countof(vszResource), szResource); | 165 | hr = StrAnsiAllocStringAnsi(&vpszResource, szResource, 0); |
| 162 | RexExitOnFailure(hr, "Failed to copy resource name to global."); | 166 | RexExitOnFailure(hr, "Failed to copy resource name to global."); |
| 163 | 167 | ||
| 164 | // | 168 | // |
| @@ -171,7 +175,7 @@ extern "C" HRESULT RexExtract( | |||
| 171 | rcs.pfnProgress = pfnProgress; | 175 | rcs.pfnProgress = pfnProgress; |
| 172 | rcs.pvContext = pvContext; | 176 | rcs.pvContext = pvContext; |
| 173 | 177 | ||
| 174 | fResult = ::FDICopy(vhfdi, vszResource, "", 0, RexCallback, NULL, static_cast<void*>(&rcs)); | 178 | fResult = ::FDICopy(vhfdi, vpszResource, "", 0, RexCallback, NULL, static_cast<void*>(&rcs)); |
| 175 | if (!fResult && !rcs.fStopExtracting) // if something went wrong and it wasn't us just stopping the extraction, then return a failure | 179 | if (!fResult && !rcs.fStopExtracting) // if something went wrong and it wasn't us just stopping the extraction, then return a failure |
| 176 | { | 180 | { |
| 177 | hr = vhrLastError; // TODO: put verf info in trace message here | 181 | hr = vhrLastError; // TODO: put verf info in trace message here |
| @@ -227,7 +231,7 @@ static __callback INT_PTR FAR DIAMONDAPI RexOpen(__in_z char FAR *pszFile, int o | |||
| 227 | RexExitOnFailure(hr, "File table exceeded"); | 231 | RexExitOnFailure(hr, "File table exceeded"); |
| 228 | } | 232 | } |
| 229 | 233 | ||
| 230 | if (0 == lstrcmpA(vszResource, pszFile)) | 234 | if (0 == lstrcmpA(vpszResource, pszFile)) |
| 231 | { | 235 | { |
| 232 | vrgffFileTable[i].fUsed = TRUE; | 236 | vrgffFileTable[i].fUsed = TRUE; |
| 233 | vrgffFileTable[i].fftType = MEMORY_FILE; | 237 | vrgffFileTable[i].fftType = MEMORY_FILE; |
| @@ -436,15 +440,16 @@ static __callback INT_PTR DIAMONDAPI RexCallback(FDINOTIFICATIONTYPE iNotificati | |||
| 436 | HANDLE hFile = INVALID_HANDLE_VALUE; | 440 | HANDLE hFile = INVALID_HANDLE_VALUE; |
| 437 | 441 | ||
| 438 | REX_CALLBACK_STRUCT* prcs = static_cast<REX_CALLBACK_STRUCT*>(pFDINotify->pv); | 442 | REX_CALLBACK_STRUCT* prcs = static_cast<REX_CALLBACK_STRUCT*>(pFDINotify->pv); |
| 439 | LPCSTR sz; | 443 | LPCSTR sz = NULL; |
| 440 | WCHAR wz[MAX_PATH]; | 444 | LPWSTR pwz = NULL; |
| 441 | FILETIME ft; | 445 | LPWSTR pwzPath = NULL; |
| 446 | FILETIME ft = { }; | ||
| 442 | int i = 0; | 447 | int i = 0; |
| 443 | 448 | ||
| 444 | switch (iNotification) | 449 | switch (iNotification) |
| 445 | { | 450 | { |
| 446 | case fdintCOPY_FILE: // beGIN extracting a resource from cabinet | 451 | case fdintCOPY_FILE: // beGIN extracting a resource from cabinet |
| 447 | Assert(pFDINotify->psz1); | 452 | Assert(pFDINotify->psz1 && prcs); |
| 448 | 453 | ||
| 449 | if (prcs->fStopExtracting) | 454 | if (prcs->fStopExtracting) |
| 450 | { | 455 | { |
| @@ -453,55 +458,50 @@ static __callback INT_PTR DIAMONDAPI RexCallback(FDINOTIFICATIONTYPE iNotificati | |||
| 453 | 458 | ||
| 454 | // convert params to useful variables | 459 | // convert params to useful variables |
| 455 | sz = static_cast<LPCSTR>(pFDINotify->psz1); | 460 | sz = static_cast<LPCSTR>(pFDINotify->psz1); |
| 456 | if (!::MultiByteToWideChar(CP_ACP, 0, sz, -1, wz, countof(wz))) | 461 | RexExitOnNull(sz, hr, E_INVALIDARG, "No cabinet file ID given to convert"); |
| 457 | { | 462 | |
| 458 | RexExitWithLastError(hr, "failed to convert cabinet file id to unicode: %s", sz); | 463 | hr = StrAllocStringAnsi(&pwz, sz, 0, CP_ACP); |
| 459 | } | 464 | RexExitOnFailure(hr, "failed to convert cabinet file id to unicode: %hs", sz); |
| 460 | 465 | ||
| 461 | if (prcs->pfnProgress) | 466 | if (prcs->pfnProgress) |
| 462 | { | 467 | { |
| 463 | hr = prcs->pfnProgress(TRUE, wz, prcs->pvContext); | 468 | hr = prcs->pfnProgress(TRUE, pwz, prcs->pvContext); |
| 464 | if (S_OK != hr) | 469 | if (S_OK != hr) |
| 465 | { | 470 | { |
| 466 | ExitFunction(); | 471 | ExitFunction(); |
| 467 | } | 472 | } |
| 468 | } | 473 | } |
| 469 | 474 | ||
| 470 | if (L'*' == *prcs->pwzExtract || 0 == lstrcmpW(prcs->pwzExtract, wz)) | 475 | if (L'*' == *prcs->pwzExtract || 0 == lstrcmpW(prcs->pwzExtract, pwz)) |
| 471 | { | 476 | { |
| 472 | // get the created date for the resource in the cabinet | 477 | // get the created date for the resource in the cabinet |
| 473 | if (!::DosDateTimeToFileTime(pFDINotify->date, pFDINotify->time, &ft)) | 478 | if (!::DosDateTimeToFileTime(pFDINotify->date, pFDINotify->time, &ft)) |
| 474 | { | 479 | { |
| 475 | RexExitWithLastError(hr, "failed to get time for resource: %ls", wz); | 480 | RexExitWithLastError(hr, "failed to get time for resource: %ls", pwz); |
| 476 | } | 481 | } |
| 477 | 482 | ||
| 478 | WCHAR wzPath[MAX_PATH]; | ||
| 479 | |||
| 480 | hr = ::StringCchCopyW(wzPath, countof(wzPath), prcs->pwzExtractDir); | ||
| 481 | RexExitOnFailure(hr, "failed to copy extract directory: %ls for file: %ls", prcs->pwzExtractDir, wz); | ||
| 482 | |||
| 483 | if (L'*' == *prcs->pwzExtract) | 483 | if (L'*' == *prcs->pwzExtract) |
| 484 | { | 484 | { |
| 485 | hr = ::StringCchCatW(wzPath, countof(wzPath), wz); | 485 | hr = PathConcat(prcs->pwzExtractDir, pwz, &pwzPath); |
| 486 | RexExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", wzPath, wz); | 486 | RexExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", prcs->pwzExtractDir, pwz); |
| 487 | } | 487 | } |
| 488 | else | 488 | else |
| 489 | { | 489 | { |
| 490 | Assert(*prcs->pwzExtractName); | 490 | Assert(*prcs->pwzExtractName); |
| 491 | 491 | ||
| 492 | hr = ::StringCchCatW(wzPath, countof(wzPath), prcs->pwzExtractName); | 492 | hr = PathConcat(prcs->pwzExtractDir, prcs->pwzExtractName, &pwzPath); |
| 493 | RexExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", wzPath, prcs->pwzExtractName); | 493 | RexExitOnFailure(hr, "failed to concat onto path: %ls file: %ls", prcs->pwzExtractDir, prcs->pwzExtractName); |
| 494 | } | 494 | } |
| 495 | 495 | ||
| 496 | // Quickly chop off the file name part of the path to ensure the path exists | 496 | // Quickly chop off the file name part of the path to ensure the path exists |
| 497 | // then put the file name back on the path (by putting the first character | 497 | // then put the file name back on the path (by putting the first character |
| 498 | // back over the null terminator). | 498 | // back over the null terminator). |
| 499 | LPWSTR wzFile = PathFile(wzPath); | 499 | LPWSTR wzFile = PathFile(pwzPath); |
| 500 | WCHAR wzFileFirstChar = *wzFile; | 500 | WCHAR wzFileFirstChar = *wzFile; |
| 501 | *wzFile = L'\0'; | 501 | *wzFile = L'\0'; |
| 502 | 502 | ||
| 503 | hr = DirEnsureExists(wzPath, NULL); | 503 | hr = DirEnsureExists(pwzPath, NULL); |
| 504 | RexExitOnFailure(hr, "failed to ensure directory: %ls", wzPath); | 504 | RexExitOnFailure(hr, "failed to ensure directory: %ls", pwzPath); |
| 505 | 505 | ||
| 506 | hr = S_OK; | 506 | hr = S_OK; |
| 507 | 507 | ||
| @@ -524,10 +524,10 @@ static __callback INT_PTR DIAMONDAPI RexCallback(FDINOTIFICATIONTYPE iNotificati | |||
| 524 | } | 524 | } |
| 525 | 525 | ||
| 526 | // open the file | 526 | // open the file |
| 527 | hFile = ::CreateFileW(wzPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | 527 | hFile = ::CreateFileW(pwzPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
| 528 | if (INVALID_HANDLE_VALUE == hFile) | 528 | if (INVALID_HANDLE_VALUE == hFile) |
| 529 | { | 529 | { |
| 530 | RexExitWithLastError(hr, "failed to open file: %ls", wzPath); | 530 | RexExitWithLastError(hr, "failed to open file: %ls", pwzPath); |
| 531 | } | 531 | } |
| 532 | 532 | ||
| 533 | vrgffFileTable[i].fUsed = TRUE; | 533 | vrgffFileTable[i].fUsed = TRUE; |
| @@ -554,20 +554,20 @@ static __callback INT_PTR DIAMONDAPI RexCallback(FDINOTIFICATIONTYPE iNotificati | |||
| 554 | 554 | ||
| 555 | break; | 555 | break; |
| 556 | case fdintCLOSE_FILE_INFO: // resource extraction complete | 556 | case fdintCLOSE_FILE_INFO: // resource extraction complete |
| 557 | Assert(pFDINotify->hf && pFDINotify->psz1); | 557 | Assert(pFDINotify->hf && prcs && pFDINotify->psz1); |
| 558 | 558 | ||
| 559 | // convert params to useful variables | 559 | // convert params to useful variables |
| 560 | sz = static_cast<LPCSTR>(pFDINotify->psz1); | 560 | sz = static_cast<LPCSTR>(pFDINotify->psz1); |
| 561 | if (!::MultiByteToWideChar(CP_ACP, 0, sz, -1, wz, countof(wz))) | 561 | RexExitOnNull(sz, hr, E_INVALIDARG, "No cabinet file ID given to convert"); |
| 562 | { | 562 | |
| 563 | RexExitWithLastError(hr, "failed to convert cabinet file id to unicode: %s", sz); | 563 | hr = StrAllocStringAnsi(&pwz, sz, 0, CP_ACP); |
| 564 | } | 564 | RexExitOnFailure(hr, "failed to convert cabinet file id to unicode: %hs", sz); |
| 565 | 565 | ||
| 566 | RexClose(pFDINotify->hf); | 566 | RexClose(pFDINotify->hf); |
| 567 | 567 | ||
| 568 | if (prcs->pfnProgress) | 568 | if (prcs->pfnProgress) |
| 569 | { | 569 | { |
| 570 | hr = prcs->pfnProgress(FALSE, wz, prcs->pvContext); | 570 | hr = prcs->pfnProgress(FALSE, pwz, prcs->pvContext); |
| 571 | } | 571 | } |
| 572 | 572 | ||
| 573 | if (S_OK == hr && L'*' == *prcs->pwzExtract) // if everything is okay and we're extracting all files, keep going | 573 | if (S_OK == hr && L'*' == *prcs->pwzExtract) // if everything is okay and we're extracting all files, keep going |
| @@ -597,5 +597,8 @@ LExit: | |||
| 597 | vhrLastError = hr; | 597 | vhrLastError = hr; |
| 598 | } | 598 | } |
| 599 | 599 | ||
| 600 | ReleaseStr(pwz); | ||
| 601 | ReleaseStr(pwzPath); | ||
| 602 | |||
| 600 | return (S_OK == hr) ? ipResult : -1; | 603 | return (S_OK == hr) ? ipResult : -1; |
| 601 | } | 604 | } |
diff --git a/src/libs/dutil/WixToolset.DUtil/sceutil.cpp b/src/libs/dutil/WixToolset.DUtil/sceutil.cpp index 4eede74f..590c937a 100644 --- a/src/libs/dutil/WixToolset.DUtil/sceutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/sceutil.cpp | |||
| @@ -317,7 +317,7 @@ extern "C" HRESULT DAPI SceOpenDatabase( | |||
| 317 | { | 317 | { |
| 318 | HRESULT hr = S_OK; | 318 | HRESULT hr = S_OK; |
| 319 | DWORD dwVersionFound = 0; | 319 | DWORD dwVersionFound = 0; |
| 320 | WCHAR wzTempDbFile[MAX_PATH]; | 320 | LPWSTR sczTempDbFile = NULL; |
| 321 | LPCWSTR wzPathToOpen = NULL; | 321 | LPCWSTR wzPathToOpen = NULL; |
| 322 | LPWSTR sczSchemaType = NULL; | 322 | LPWSTR sczSchemaType = NULL; |
| 323 | SCE_DATABASE *pNewSceDatabase = NULL; | 323 | SCE_DATABASE *pNewSceDatabase = NULL; |
| @@ -343,16 +343,16 @@ extern "C" HRESULT DAPI SceOpenDatabase( | |||
| 343 | // TODO: had trouble getting SQL CE to read a file read-only, so we're copying it to a temp path for now. | 343 | // TODO: had trouble getting SQL CE to read a file read-only, so we're copying it to a temp path for now. |
| 344 | if (fReadOnly) | 344 | if (fReadOnly) |
| 345 | { | 345 | { |
| 346 | hr = DirCreateTempPath(PathFile(sczFile), (LPWSTR)wzTempDbFile, _countof(wzTempDbFile)); | 346 | hr = DirCreateTempPath(PathFile(sczFile), &sczTempDbFile); |
| 347 | ExitOnFailure(hr, "Failed to get temp path"); | 347 | ExitOnFailure(hr, "Failed to get temp path"); |
| 348 | 348 | ||
| 349 | hr = FileEnsureCopy(sczFile, (LPCWSTR)wzTempDbFile, TRUE); | 349 | hr = FileEnsureCopy(sczFile, sczTempDbFile, TRUE); |
| 350 | ExitOnFailure(hr, "Failed to copy file to temp path"); | 350 | ExitOnFailure(hr, "Failed to copy file to temp path"); |
| 351 | 351 | ||
| 352 | hr = StrAllocString(&pNewSceDatabaseInternal->sczTempDbFile, (LPCWSTR)wzTempDbFile, 0); | 352 | hr = StrAllocString(&pNewSceDatabaseInternal->sczTempDbFile, sczTempDbFile, 0); |
| 353 | ExitOnFailure(hr, "Failed to copy temp db file path"); | 353 | ExitOnFailure(hr, "Failed to copy temp db file path"); |
| 354 | 354 | ||
| 355 | wzPathToOpen = (LPCWSTR)wzTempDbFile; | 355 | wzPathToOpen = sczTempDbFile; |
| 356 | } | 356 | } |
| 357 | else | 357 | else |
| 358 | { | 358 | { |
| @@ -424,6 +424,7 @@ extern "C" HRESULT DAPI SceOpenDatabase( | |||
| 424 | LExit: | 424 | LExit: |
| 425 | ReleaseBSTR(rgdbpDataSourceProp[0].vValue.bstrVal); | 425 | ReleaseBSTR(rgdbpDataSourceProp[0].vValue.bstrVal); |
| 426 | ReleaseStr(sczSchemaType); | 426 | ReleaseStr(sczSchemaType); |
| 427 | ReleaseStr(sczTempDbFile); | ||
| 427 | ReleaseDatabase(pNewSceDatabase); | 428 | ReleaseDatabase(pNewSceDatabase); |
| 428 | 429 | ||
| 429 | return hr; | 430 | return hr; |
diff --git a/src/libs/dutil/WixToolset.DUtil/shelutil.cpp b/src/libs/dutil/WixToolset.DUtil/shelutil.cpp index 2eb9a52a..72a0e5ce 100644 --- a/src/libs/dutil/WixToolset.DUtil/shelutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/shelutil.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #define ShelExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__) | 9 | #define ShelExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__) |
| 10 | #define ShelExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__) | 10 | #define ShelExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__) |
| 11 | #define ShelExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__) | 11 | #define ShelExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__) |
| 12 | #define ShelExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_SHELUTIL, x, e, s, __VA_ARGS__) | ||
| 12 | #define ShelExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__) | 13 | #define ShelExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_SHELUTIL, x, s, __VA_ARGS__) |
| 13 | #define ShelExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_SHELUTIL, p, x, e, s, __VA_ARGS__) | 14 | #define ShelExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_SHELUTIL, p, x, e, s, __VA_ARGS__) |
| 14 | #define ShelExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_SHELUTIL, p, x, s, __VA_ARGS__) | 15 | #define ShelExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_SHELUTIL, p, x, s, __VA_ARGS__) |
| @@ -19,6 +20,10 @@ | |||
| 19 | 20 | ||
| 20 | static PFN_SHELLEXECUTEEXW vpfnShellExecuteExW = ::ShellExecuteExW; | 21 | static PFN_SHELLEXECUTEEXW vpfnShellExecuteExW = ::ShellExecuteExW; |
| 21 | 22 | ||
| 23 | static HRESULT DAPI GetFolderFromCsidl( | ||
| 24 | __out_z LPWSTR* psczFolderPath, | ||
| 25 | __in int csidlFolder | ||
| 26 | ); | ||
| 22 | static HRESULT GetDesktopShellView( | 27 | static HRESULT GetDesktopShellView( |
| 23 | __in REFIID riid, | 28 | __in REFIID riid, |
| 24 | __out void **ppv | 29 | __out void **ppv |
| @@ -57,7 +62,14 @@ extern "C" HRESULT DAPI ShelExec( | |||
| 57 | ) | 62 | ) |
| 58 | { | 63 | { |
| 59 | HRESULT hr = S_OK; | 64 | HRESULT hr = S_OK; |
| 60 | SHELLEXECUTEINFOW shExecInfo = {}; | 65 | SHELLEXECUTEINFOW shExecInfo = { }; |
| 66 | size_t cchWorkingDirectory = 0; | ||
| 67 | |||
| 68 | // CreateProcessW has undocumented MAX_PATH restriction for lpCurrentDirectory even when long path support is enabled. | ||
| 69 | if (wzWorkingDirectory && FAILED(::StringCchLengthW(wzWorkingDirectory, MAX_PATH - 1, &cchWorkingDirectory))) | ||
| 70 | { | ||
| 71 | wzWorkingDirectory = NULL; | ||
| 72 | } | ||
| 61 | 73 | ||
| 62 | shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); | 74 | shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); |
| 63 | shExecInfo.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS; | 75 | shExecInfo.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS; |
| @@ -159,11 +171,7 @@ LExit: | |||
| 159 | } | 171 | } |
| 160 | 172 | ||
| 161 | 173 | ||
| 162 | /******************************************************************** | 174 | static HRESULT DAPI GetFolderFromCsidl( |
| 163 | ShelGetFolder() - gets a folder by CSIDL. | ||
| 164 | |||
| 165 | *******************************************************************/ | ||
| 166 | extern "C" HRESULT DAPI ShelGetFolder( | ||
| 167 | __out_z LPWSTR* psczFolderPath, | 175 | __out_z LPWSTR* psczFolderPath, |
| 168 | __in int csidlFolder | 176 | __in int csidlFolder |
| 169 | ) | 177 | ) |
| @@ -185,19 +193,6 @@ LExit: | |||
| 185 | } | 193 | } |
| 186 | 194 | ||
| 187 | 195 | ||
| 188 | /******************************************************************** | ||
| 189 | ShelGetKnownFolder() - gets a folder by KNOWNFOLDERID. | ||
| 190 | |||
| 191 | Note: return E_NOTIMPL if called on pre-Vista operating systems. | ||
| 192 | *******************************************************************/ | ||
| 193 | #ifndef REFKNOWNFOLDERID | ||
| 194 | #define REFKNOWNFOLDERID REFGUID | ||
| 195 | #endif | ||
| 196 | |||
| 197 | #ifndef KF_FLAG_CREATE | ||
| 198 | #define KF_FLAG_CREATE 0x00008000 // Make sure that the folder already exists or create it and apply security specified in folder definition | ||
| 199 | #endif | ||
| 200 | |||
| 201 | EXTERN_C typedef HRESULT (STDAPICALLTYPE *PFN_SHGetKnownFolderPath)( | 196 | EXTERN_C typedef HRESULT (STDAPICALLTYPE *PFN_SHGetKnownFolderPath)( |
| 202 | REFKNOWNFOLDERID rfid, | 197 | REFKNOWNFOLDERID rfid, |
| 203 | DWORD dwFlags, | 198 | DWORD dwFlags, |
| @@ -249,6 +244,181 @@ LExit: | |||
| 249 | return hr; | 244 | return hr; |
| 250 | } | 245 | } |
| 251 | 246 | ||
| 247 | extern "C" HRESULT DAPI ShelGetFolder( | ||
| 248 | __out_z LPWSTR* psczFolderPath, | ||
| 249 | __in int csidlFolder | ||
| 250 | ) | ||
| 251 | { | ||
| 252 | HRESULT hr = S_OK; | ||
| 253 | LPWSTR sczPath = NULL; | ||
| 254 | KNOWNFOLDERID rfid = { }; | ||
| 255 | |||
| 256 | csidlFolder &= ~CSIDL_FLAG_MASK; | ||
| 257 | |||
| 258 | switch (csidlFolder) | ||
| 259 | { | ||
| 260 | case CSIDL_ADMINTOOLS: | ||
| 261 | rfid = FOLDERID_AdminTools; | ||
| 262 | break; | ||
| 263 | case CSIDL_APPDATA: | ||
| 264 | rfid = FOLDERID_RoamingAppData; | ||
| 265 | break; | ||
| 266 | case CSIDL_CDBURN_AREA: | ||
| 267 | rfid = FOLDERID_CDBurning; | ||
| 268 | break; | ||
| 269 | case CSIDL_COMMON_ADMINTOOLS: | ||
| 270 | rfid = FOLDERID_CommonAdminTools; | ||
| 271 | break; | ||
| 272 | case CSIDL_COMMON_APPDATA: | ||
| 273 | rfid = FOLDERID_ProgramData; | ||
| 274 | break; | ||
| 275 | case CSIDL_COMMON_DESKTOPDIRECTORY: | ||
| 276 | rfid = FOLDERID_PublicDesktop; | ||
| 277 | break; | ||
| 278 | case CSIDL_COMMON_DOCUMENTS: | ||
| 279 | rfid = FOLDERID_PublicDocuments; | ||
| 280 | break; | ||
| 281 | case CSIDL_COMMON_MUSIC: | ||
| 282 | rfid = FOLDERID_PublicMusic; | ||
| 283 | break; | ||
| 284 | case CSIDL_COMMON_OEM_LINKS: | ||
| 285 | rfid = FOLDERID_CommonOEMLinks; | ||
| 286 | break; | ||
| 287 | case CSIDL_COMMON_PICTURES: | ||
| 288 | rfid = FOLDERID_PublicPictures; | ||
| 289 | break; | ||
| 290 | case CSIDL_COMMON_PROGRAMS: | ||
| 291 | rfid = FOLDERID_CommonPrograms; | ||
| 292 | break; | ||
| 293 | case CSIDL_COMMON_STARTMENU: | ||
| 294 | rfid = FOLDERID_CommonStartMenu; | ||
| 295 | break; | ||
| 296 | case CSIDL_COMMON_STARTUP: __fallthrough; | ||
| 297 | case CSIDL_COMMON_ALTSTARTUP: | ||
| 298 | rfid = FOLDERID_CommonStartup; | ||
| 299 | break; | ||
| 300 | case CSIDL_COMMON_TEMPLATES: | ||
| 301 | rfid = FOLDERID_CommonTemplates; | ||
| 302 | break; | ||
| 303 | case CSIDL_COMMON_VIDEO: | ||
| 304 | rfid = FOLDERID_PublicVideos; | ||
| 305 | break; | ||
| 306 | case CSIDL_COOKIES: | ||
| 307 | rfid = FOLDERID_Cookies; | ||
| 308 | break; | ||
| 309 | case CSIDL_DESKTOP: | ||
| 310 | case CSIDL_DESKTOPDIRECTORY: | ||
| 311 | rfid = FOLDERID_Desktop; | ||
| 312 | break; | ||
| 313 | case CSIDL_FAVORITES: __fallthrough; | ||
| 314 | case CSIDL_COMMON_FAVORITES: | ||
| 315 | rfid = FOLDERID_Favorites; | ||
| 316 | break; | ||
| 317 | case CSIDL_FONTS: | ||
| 318 | rfid = FOLDERID_Fonts; | ||
| 319 | break; | ||
| 320 | case CSIDL_HISTORY: | ||
| 321 | rfid = FOLDERID_History; | ||
| 322 | break; | ||
| 323 | case CSIDL_INTERNET_CACHE: | ||
| 324 | rfid = FOLDERID_InternetCache; | ||
| 325 | break; | ||
| 326 | case CSIDL_LOCAL_APPDATA: | ||
| 327 | rfid = FOLDERID_LocalAppData; | ||
| 328 | break; | ||
| 329 | case CSIDL_MYMUSIC: | ||
| 330 | rfid = FOLDERID_Music; | ||
| 331 | break; | ||
| 332 | case CSIDL_MYPICTURES: | ||
| 333 | rfid = FOLDERID_Pictures; | ||
| 334 | break; | ||
| 335 | case CSIDL_MYVIDEO: | ||
| 336 | rfid = FOLDERID_Videos; | ||
| 337 | break; | ||
| 338 | case CSIDL_NETHOOD: | ||
| 339 | rfid = FOLDERID_NetHood; | ||
| 340 | break; | ||
| 341 | case CSIDL_PERSONAL: | ||
| 342 | rfid = FOLDERID_Documents; | ||
| 343 | break; | ||
| 344 | case CSIDL_PRINTHOOD: | ||
| 345 | rfid = FOLDERID_PrintHood; | ||
| 346 | break; | ||
| 347 | case CSIDL_PROFILE: | ||
| 348 | rfid = FOLDERID_Profile; | ||
| 349 | break; | ||
| 350 | case CSIDL_PROGRAM_FILES: | ||
| 351 | rfid = FOLDERID_ProgramFiles; | ||
| 352 | break; | ||
| 353 | case CSIDL_PROGRAM_FILESX86: | ||
| 354 | rfid = FOLDERID_ProgramFilesX86; | ||
| 355 | break; | ||
| 356 | case CSIDL_PROGRAM_FILES_COMMON: | ||
| 357 | rfid = FOLDERID_ProgramFilesCommon; | ||
| 358 | break; | ||
| 359 | case CSIDL_PROGRAM_FILES_COMMONX86: | ||
| 360 | rfid = FOLDERID_ProgramFilesCommonX86; | ||
| 361 | break; | ||
| 362 | case CSIDL_PROGRAMS: | ||
| 363 | rfid = FOLDERID_Programs; | ||
| 364 | break; | ||
| 365 | case CSIDL_RECENT: | ||
| 366 | rfid = FOLDERID_Recent; | ||
| 367 | break; | ||
| 368 | case CSIDL_RESOURCES: | ||
| 369 | rfid = FOLDERID_ResourceDir; | ||
| 370 | break; | ||
| 371 | case CSIDL_RESOURCES_LOCALIZED: | ||
| 372 | rfid = FOLDERID_LocalizedResourcesDir; | ||
| 373 | break; | ||
| 374 | case CSIDL_SENDTO: | ||
| 375 | rfid = FOLDERID_SendTo; | ||
| 376 | break; | ||
| 377 | case CSIDL_STARTMENU: | ||
| 378 | rfid = FOLDERID_StartMenu; | ||
| 379 | break; | ||
| 380 | case CSIDL_STARTUP: | ||
| 381 | case CSIDL_ALTSTARTUP: | ||
| 382 | rfid = FOLDERID_Startup; | ||
| 383 | break; | ||
| 384 | case CSIDL_SYSTEM: | ||
| 385 | rfid = FOLDERID_System; | ||
| 386 | break; | ||
| 387 | case CSIDL_SYSTEMX86: | ||
| 388 | rfid = FOLDERID_SystemX86; | ||
| 389 | break; | ||
| 390 | case CSIDL_TEMPLATES: | ||
| 391 | rfid = FOLDERID_Templates; | ||
| 392 | break; | ||
| 393 | case CSIDL_WINDOWS: | ||
| 394 | rfid = FOLDERID_Windows; | ||
| 395 | break; | ||
| 396 | default: | ||
| 397 | ShelExitWithRootFailure(hr, E_INVALIDARG, "Unknown csidl: %d", csidlFolder); | ||
| 398 | } | ||
| 399 | |||
| 400 | hr = ShelGetKnownFolder(&sczPath, rfid); | ||
| 401 | if (E_NOTIMPL == hr) | ||
| 402 | { | ||
| 403 | hr = S_FALSE; | ||
| 404 | } | ||
| 405 | ShelExitOnFailure(hr, "Failed to get known folder."); | ||
| 406 | |||
| 407 | if (S_FALSE == hr) | ||
| 408 | { | ||
| 409 | hr = GetFolderFromCsidl(&sczPath, csidlFolder); | ||
| 410 | ShelExitOnFailure(hr, "Failed to get csidl folder."); | ||
| 411 | } | ||
| 412 | |||
| 413 | *psczFolderPath = sczPath; | ||
| 414 | sczPath = NULL; | ||
| 415 | |||
| 416 | LExit: | ||
| 417 | ReleaseStr(sczPath); | ||
| 418 | |||
| 419 | return hr; | ||
| 420 | } | ||
| 421 | |||
| 252 | 422 | ||
| 253 | // Internal functions. | 423 | // Internal functions. |
| 254 | 424 | ||
| @@ -287,7 +457,7 @@ static HRESULT GetDesktopShellView( | |||
| 287 | else if (S_FALSE == hr) | 457 | else if (S_FALSE == hr) |
| 288 | { | 458 | { |
| 289 | //Windows XP | 459 | //Windows XP |
| 290 | hr = SHGetDesktopFolder(&psf); | 460 | hr = ::SHGetDesktopFolder(&psf); |
| 291 | ShelExitOnFailure(hr, "Failed to get desktop folder."); | 461 | ShelExitOnFailure(hr, "Failed to get desktop folder."); |
| 292 | 462 | ||
| 293 | hr = psf->CreateViewObject(NULL, IID_IShellView, ppv); | 463 | hr = psf->CreateViewObject(NULL, IID_IShellView, ppv); |
diff --git a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp index e9ef1047..109c558c 100644 --- a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp +++ b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp | |||
| @@ -7,6 +7,11 @@ using namespace System::IO; | |||
| 7 | using namespace Xunit; | 7 | using namespace Xunit; |
| 8 | using namespace WixBuildTools::TestSupport; | 8 | using namespace WixBuildTools::TestSupport; |
| 9 | 9 | ||
| 10 | // from PathCch.h | ||
| 11 | #ifndef PATHCCH_ALLOW_LONG_PATHS | ||
| 12 | #define PATHCCH_ALLOW_LONG_PATHS 0x01 | ||
| 13 | #endif | ||
| 14 | |||
| 10 | namespace DutilTests | 15 | namespace DutilTests |
| 11 | { | 16 | { |
| 12 | public ref class PathUtil | 17 | public ref class PathUtil |
| @@ -102,18 +107,54 @@ namespace DutilTests | |||
| 102 | } | 107 | } |
| 103 | 108 | ||
| 104 | [Fact] | 109 | [Fact] |
| 110 | void PathCanonicalizeForComparisonFallbackTest() | ||
| 111 | { | ||
| 112 | Path2FunctionForceFallback(); | ||
| 113 | |||
| 114 | try | ||
| 115 | { | ||
| 116 | PathCanonicalizeForComparisonTestCore(FALSE); | ||
| 117 | } | ||
| 118 | finally | ||
| 119 | { | ||
| 120 | Path2FunctionAllowFallback(); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | [Fact] | ||
| 105 | void PathCanonicalizeForComparisonTest() | 125 | void PathCanonicalizeForComparisonTest() |
| 106 | { | 126 | { |
| 127 | PathCanonicalizeForComparisonTestCore(TRUE); | ||
| 128 | } | ||
| 129 | |||
| 130 | void PathCanonicalizeForComparisonTestCore(BOOL fLongPathSupported) | ||
| 131 | { | ||
| 107 | HRESULT hr = S_OK; | 132 | HRESULT hr = S_OK; |
| 108 | LPWSTR sczCanonicalized = NULL; | 133 | LPWSTR sczCanonicalized = NULL; |
| 109 | 134 | ||
| 110 | try | 135 | try |
| 111 | { | 136 | { |
| 112 | hr = PathCanonicalizeForComparison(L"C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", 0, &sczCanonicalized); | 137 | hr = PathCanonicalizeForComparison(L"C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", 0, &sczCanonicalized); |
| 113 | Assert::Equal<HRESULT>(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr); | 138 | if (!fLongPathSupported) |
| 139 | { | ||
| 140 | Assert::Equal<HRESULT>(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr); | ||
| 141 | } | ||
| 142 | else | ||
| 143 | { | ||
| 144 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | ||
| 145 | NativeAssert::StringEqual(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized); | ||
| 146 | } | ||
| 114 | 147 | ||
| 115 | hr = PathCanonicalizeForComparison(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", 0, &sczCanonicalized); | 148 | hr = PathCanonicalizeForComparison(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", 0, &sczCanonicalized); |
| 116 | Assert::Equal<HRESULT>(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr); | 149 | if (!fLongPathSupported) |
| 150 | { | ||
| 151 | Assert::Equal<HRESULT>(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr); | ||
| 152 | } | ||
| 153 | else | ||
| 154 | { | ||
| 155 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | ||
| 156 | NativeAssert::StringEqual(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized); | ||
| 157 | } | ||
| 117 | 158 | ||
| 118 | hr = PathCanonicalizeForComparison(L"\\\\server", PATH_CANONICALIZE_KEEP_UNC_ROOT, &sczCanonicalized); | 159 | hr = PathCanonicalizeForComparison(L"\\\\server", PATH_CANONICALIZE_KEEP_UNC_ROOT, &sczCanonicalized); |
| 119 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | 160 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); |
| @@ -238,6 +279,52 @@ namespace DutilTests | |||
| 238 | } | 279 | } |
| 239 | 280 | ||
| 240 | [Fact] | 281 | [Fact] |
| 282 | void PathAllocCanonicalizePathTest() | ||
| 283 | { | ||
| 284 | HRESULT hr = S_OK; | ||
| 285 | LPWSTR sczCanonicalized = NULL; | ||
| 286 | |||
| 287 | try | ||
| 288 | { | ||
| 289 | hr = PathAllocCanonicalizePath(L"C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized); | ||
| 290 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | ||
| 291 | NativeAssert::StringEqual(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized); | ||
| 292 | |||
| 293 | hr = PathAllocCanonicalizePath(L"abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized); | ||
| 294 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | ||
| 295 | NativeAssert::StringEqual(L"abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized); | ||
| 296 | |||
| 297 | hr = PathAllocCanonicalizePath(L"\\\\server\\share\\..\\..\\otherdir\\unc.exe", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized); | ||
| 298 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | ||
| 299 | NativeAssert::StringEqual(L"\\\\otherdir\\unc.exe", sczCanonicalized); // This is surprising. | ||
| 300 | |||
| 301 | hr = PathAllocCanonicalizePath(L"C:\\dir\\subdir\\..\\..\\otherdir\\backslashes.exe", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized); | ||
| 302 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | ||
| 303 | NativeAssert::StringEqual(L"C:\\otherdir\\backslashes.exe", sczCanonicalized); | ||
| 304 | |||
| 305 | hr = PathAllocCanonicalizePath(L"C:/dir/subdir/../../otherdir/forwardslashes.exe", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized); | ||
| 306 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | ||
| 307 | NativeAssert::StringEqual(L"C:/dir/subdir/../../otherdir/forwardslashes.exe", sczCanonicalized); | ||
| 308 | |||
| 309 | hr = PathAllocCanonicalizePath(L"\\\\?\\C:\\test\\..\\validlongpath.exe", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized); | ||
| 310 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | ||
| 311 | NativeAssert::StringEqual(L"C:\\validlongpath.exe", sczCanonicalized); | ||
| 312 | |||
| 313 | hr = PathAllocCanonicalizePath(L"\\\\?\\test\\..\\invalidlongpath.exe", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized); | ||
| 314 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | ||
| 315 | NativeAssert::StringEqual(L"\\\\?\\invalidlongpath.exe", sczCanonicalized); | ||
| 316 | |||
| 317 | hr = PathAllocCanonicalizePath(L"C:\\.\\invalid:pathchars?.exe", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized); | ||
| 318 | NativeAssert::Succeeded(hr, "Failed to canonicalize path"); | ||
| 319 | NativeAssert::StringEqual(L"C:\\invalid:pathchars?.exe", sczCanonicalized); | ||
| 320 | } | ||
| 321 | finally | ||
| 322 | { | ||
| 323 | ReleaseStr(sczCanonicalized); | ||
| 324 | } | ||
| 325 | } | ||
| 326 | |||
| 327 | [Fact] | ||
| 241 | void PathConcatTest() | 328 | void PathConcatTest() |
| 242 | { | 329 | { |
| 243 | HRESULT hr = S_OK; | 330 | HRESULT hr = S_OK; |
| @@ -545,6 +632,25 @@ namespace DutilTests | |||
| 545 | } | 632 | } |
| 546 | 633 | ||
| 547 | [Fact] | 634 | [Fact] |
| 635 | void PathForCurrentProcessTest() | ||
| 636 | { | ||
| 637 | HRESULT hr = S_OK; | ||
| 638 | LPWSTR sczPath = NULL; | ||
| 639 | |||
| 640 | try | ||
| 641 | { | ||
| 642 | hr = PathForCurrentProcess(&sczPath, NULL); | ||
| 643 | NativeAssert::Succeeded(hr, "Failed to get current process path."); | ||
| 644 | |||
| 645 | WixAssert::StringEqual(System::Diagnostics::Process::GetCurrentProcess()->MainModule->FileName, gcnew String(sczPath), false); | ||
| 646 | } | ||
| 647 | finally | ||
| 648 | { | ||
| 649 | ReleaseStr(sczPath); | ||
| 650 | } | ||
| 651 | } | ||
| 652 | |||
| 653 | [Fact] | ||
| 548 | void PathGetDirectoryTest() | 654 | void PathGetDirectoryTest() |
| 549 | { | 655 | { |
| 550 | HRESULT hr = S_OK; | 656 | HRESULT hr = S_OK; |
| @@ -828,6 +934,78 @@ namespace DutilTests | |||
| 828 | } | 934 | } |
| 829 | 935 | ||
| 830 | [Fact] | 936 | [Fact] |
| 937 | void PathGetTempPathTest() | ||
| 938 | { | ||
| 939 | HRESULT hr = S_OK; | ||
| 940 | LPCWSTR wzEnvName = L"TMP"; | ||
| 941 | LPCWSTR wzEnvName2 = L"TEMP"; | ||
| 942 | LPCWSTR wzLongTempPath = L"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\\cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\\"; | ||
| 943 | LPWSTR sczTempPath = NULL; | ||
| 944 | WCHAR wzOriginalTemp[MAX_PATH + 1] = { }; | ||
| 945 | WCHAR wzOriginalTemp2[MAX_PATH + 1] = { }; | ||
| 946 | DWORD cch = 0; | ||
| 947 | DWORD cch2 = 0; | ||
| 948 | SIZE_T cchTemp = 0; | ||
| 949 | size_t cchTemp2 = 0; | ||
| 950 | |||
| 951 | try | ||
| 952 | { | ||
| 953 | cch = ::GetEnvironmentVariableW(wzEnvName, wzOriginalTemp, countof(wzOriginalTemp)); | ||
| 954 | Assert::NotEqual<DWORD>(0, cch); | ||
| 955 | |||
| 956 | if (!::SetEnvironmentVariableW(wzEnvName, wzLongTempPath)) | ||
| 957 | { | ||
| 958 | Assert::Equal<DWORD>(0xFFFFFFFF, ::GetLastError()); | ||
| 959 | } | ||
| 960 | |||
| 961 | cch2 = ::GetEnvironmentVariableW(wzEnvName2, wzOriginalTemp2, countof(wzOriginalTemp2)); | ||
| 962 | Assert::NotEqual<DWORD>(0, cch2); | ||
| 963 | |||
| 964 | hr = PathGetTempPath(&sczTempPath, &cchTemp); | ||
| 965 | NativeAssert::Succeeded(hr, "Failed to get temp path."); | ||
| 966 | |||
| 967 | PathFixedBackslashTerminate(wzOriginalTemp2, countof(wzOriginalTemp2)); | ||
| 968 | |||
| 969 | hr = ::StringCchLengthW(wzOriginalTemp2, countof(wzOriginalTemp2), &cchTemp2); | ||
| 970 | NativeAssert::Succeeded(hr, "Failed to get temp path length."); | ||
| 971 | |||
| 972 | NativeAssert::StringEqual(wzOriginalTemp2, sczTempPath); | ||
| 973 | Assert::Equal<SIZE_T>(cchTemp2, cchTemp); | ||
| 974 | } | ||
| 975 | finally | ||
| 976 | { | ||
| 977 | if (cch) | ||
| 978 | { | ||
| 979 | ::SetEnvironmentVariableW(wzEnvName, wzOriginalTemp); | ||
| 980 | } | ||
| 981 | |||
| 982 | ReleaseStr(sczTempPath); | ||
| 983 | } | ||
| 984 | } | ||
| 985 | |||
| 986 | [Fact] | ||
| 987 | void PathGetVolumePathNameTest() | ||
| 988 | { | ||
| 989 | HRESULT hr = S_OK; | ||
| 990 | LPWSTR sczVolumePathName = NULL; | ||
| 991 | |||
| 992 | try | ||
| 993 | { | ||
| 994 | hr = StrAlloc(&sczVolumePathName, 1); | ||
| 995 | NativeAssert::Succeeded(hr, "Failed to alloc volume path name."); | ||
| 996 | |||
| 997 | hr = PathGetVolumePathName(L"C:\\Windows", &sczVolumePathName); | ||
| 998 | NativeAssert::Succeeded(hr, "PathGetVolumePathName failed."); | ||
| 999 | |||
| 1000 | NativeAssert::StringEqual(L"C:\\", sczVolumePathName); | ||
| 1001 | } | ||
| 1002 | finally | ||
| 1003 | { | ||
| 1004 | ReleaseStr(sczVolumePathName); | ||
| 1005 | } | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | [Fact] | ||
| 831 | void PathNormalizeSlashesFixedTest() | 1009 | void PathNormalizeSlashesFixedTest() |
| 832 | { | 1010 | { |
| 833 | HRESULT hr = S_OK; | 1011 | HRESULT hr = S_OK; |
diff --git a/src/test/burn/Directory.wixproj.targets b/src/test/burn/Directory.wixproj.targets index 17a46e2a..4037e865 100644 --- a/src/test/burn/Directory.wixproj.targets +++ b/src/test/burn/Directory.wixproj.targets | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | <WebServerBaseUrl Condition=" '$(WebServerBaseUrl)' == '' ">http://localhost:9999/e2e/</WebServerBaseUrl> | 7 | <WebServerBaseUrl Condition=" '$(WebServerBaseUrl)' == '' ">http://localhost:9999/e2e/</WebServerBaseUrl> |
| 8 | <DefineConstants>TestGroupName=$(TestGroupName);PackageName=$(PackageName);BundleName=$(BundleName);WebServerBaseUrl=$(WebServerBaseUrl);$(DefineConstants)</DefineConstants> | 8 | <DefineConstants>TestGroupName=$(TestGroupName);PackageName=$(PackageName);BundleName=$(BundleName);WebServerBaseUrl=$(WebServerBaseUrl);$(DefineConstants)</DefineConstants> |
| 9 | <DefineConstants Condition=" '$(BA)' != '' ">BA=$(BA);$(DefineConstants)</DefineConstants> | 9 | <DefineConstants Condition=" '$(BA)' != '' ">BA=$(BA);$(DefineConstants)</DefineConstants> |
| 10 | <DefineConstants Condition=" '$(BundleLogDirectory)' != '' ">BundleLogDirectory=$(BundleLogDirectory);$(DefineConstants)</DefineConstants> | ||
| 10 | <DefineConstants Condition=" '$(CabPrefix)' != '' ">CabPrefix=$(CabPrefix);$(DefineConstants)</DefineConstants> | 11 | <DefineConstants Condition=" '$(CabPrefix)' != '' ">CabPrefix=$(CabPrefix);$(DefineConstants)</DefineConstants> |
| 11 | <DefineConstants Condition=" '$(IncludeSoftwareTag)' == 'true' ">SoftwareTag=1;$(DefineConstants)</DefineConstants> | 12 | <DefineConstants Condition=" '$(IncludeSoftwareTag)' == 'true' ">SoftwareTag=1;$(DefineConstants)</DefineConstants> |
| 12 | <DefineConstants Condition=" '$(ProductCode)' != '' ">ProductCode=$(ProductCode);$(DefineConstants)</DefineConstants> | 13 | <DefineConstants Condition=" '$(ProductCode)' != '' ">ProductCode=$(ProductCode);$(DefineConstants)</DefineConstants> |
diff --git a/src/test/burn/TestData/LongPathTests/NonCompressedBundle/NonCompressedBundle.wixproj b/src/test/burn/TestData/LongPathTests/NonCompressedBundle/NonCompressedBundle.wixproj new file mode 100644 index 00000000..3686200c --- /dev/null +++ b/src/test/burn/TestData/LongPathTests/NonCompressedBundle/NonCompressedBundle.wixproj | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <OutputType>Bundle</OutputType> | ||
| 5 | <UpgradeCode>{EFCF768F-1B06-4B68-9DE0-9244F8212D31}</UpgradeCode> | ||
| 6 | <BundleLogDirectory>[LocalAppDataFolder]Temp</BundleLogDirectory> | ||
| 7 | </PropertyGroup> | ||
| 8 | <ItemGroup> | ||
| 9 | <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" /> | ||
| 10 | </ItemGroup> | ||
| 11 | <ItemGroup> | ||
| 12 | <ProjectReference Include="..\PackageA\PackageA.wixproj" /> | ||
| 13 | <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" /> | ||
| 14 | </ItemGroup> | ||
| 15 | <ItemGroup> | ||
| 16 | <PackageReference Include="WixToolset.Bal.wixext" /> | ||
| 17 | <PackageReference Include="WixToolset.NetFx.wixext" /> | ||
| 18 | </ItemGroup> | ||
| 19 | </Project> \ No newline at end of file | ||
diff --git a/src/test/burn/TestData/LongPathTests/NonCompressedBundle/NonCompressedBundle.wxs b/src/test/burn/TestData/LongPathTests/NonCompressedBundle/NonCompressedBundle.wxs new file mode 100644 index 00000000..e3872eb1 --- /dev/null +++ b/src/test/burn/TestData/LongPathTests/NonCompressedBundle/NonCompressedBundle.wxs | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | |||
| 3 | |||
| 4 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 5 | <Fragment> | ||
| 6 | <PackageGroup Id="BundlePackages"> | ||
| 7 | <MsiPackage Compressed="no" Id="PackageA" SourceFile="$(var.PackageA.TargetPath)" /> | ||
| 8 | </PackageGroup> | ||
| 9 | </Fragment> | ||
| 10 | </Wix> | ||
diff --git a/src/test/burn/TestData/LongPathTests/PackageA/PackageA.wixproj b/src/test/burn/TestData/LongPathTests/PackageA/PackageA.wixproj new file mode 100644 index 00000000..798452e7 --- /dev/null +++ b/src/test/burn/TestData/LongPathTests/PackageA/PackageA.wixproj | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <CabPrefix>a</CabPrefix> | ||
| 5 | <UpgradeCode>{4DC05A2A-382D-4E7D-B6DA-163908396373}</UpgradeCode> | ||
| 6 | </PropertyGroup> | ||
| 7 | <ItemGroup> | ||
| 8 | <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" /> | ||
| 9 | </ItemGroup> | ||
| 10 | </Project> \ No newline at end of file | ||
diff --git a/src/test/burn/TestData/Templates/Bundle.wxs b/src/test/burn/TestData/Templates/Bundle.wxs index b211d9c3..612e67f5 100644 --- a/src/test/burn/TestData/Templates/Bundle.wxs +++ b/src/test/burn/TestData/Templates/Bundle.wxs | |||
| @@ -3,10 +3,13 @@ | |||
| 3 | <?ifndef Version?> | 3 | <?ifndef Version?> |
| 4 | <?define Version = 1.0.0.0?> | 4 | <?define Version = 1.0.0.0?> |
| 5 | <?endif?> | 5 | <?endif?> |
| 6 | <?ifndef BundleLogDirectory?> | ||
| 7 | <?define BundleLogDirectory = .?> | ||
| 8 | <?endif?> | ||
| 6 | 9 | ||
| 7 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal"> | 10 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal"> |
| 8 | <Bundle Name="~$(var.TestGroupName) - $(var.BundleName)" Version="$(var.Version)" UpgradeCode="$(var.UpgradeCode)" Compressed="yes"> | 11 | <Bundle Name="~$(var.TestGroupName) - $(var.BundleName)" Version="$(var.Version)" UpgradeCode="$(var.UpgradeCode)" Compressed="yes"> |
| 9 | <Log Prefix="~$(var.TestGroupName)_$(var.BundleName)" /> | 12 | <Log Prefix="$(var.BundleLogDirectory)\~$(var.TestGroupName)_$(var.BundleName)" /> |
| 10 | 13 | ||
| 11 | <Variable Name="TestGroupName" Value="$(var.TestGroupName)" /> | 14 | <Variable Name="TestGroupName" Value="$(var.TestGroupName)" /> |
| 12 | 15 | ||
diff --git a/src/test/burn/TestExe/Task.cs b/src/test/burn/TestExe/Task.cs index 59f774fb..0d283c6c 100644 --- a/src/test/burn/TestExe/Task.cs +++ b/src/test/burn/TestExe/Task.cs | |||
| @@ -2,8 +2,10 @@ | |||
| 2 | 2 | ||
| 3 | using System; | 3 | using System; |
| 4 | using System.Collections.Generic; | 4 | using System.Collections.Generic; |
| 5 | using System.ComponentModel; | ||
| 5 | using System.Diagnostics; | 6 | using System.Diagnostics; |
| 6 | using System.IO; | 7 | using System.IO; |
| 8 | using System.Runtime.InteropServices; | ||
| 7 | using Microsoft.Win32; | 9 | using Microsoft.Win32; |
| 8 | 10 | ||
| 9 | namespace TestExe | 11 | namespace TestExe |
| @@ -151,6 +153,67 @@ namespace TestExe | |||
| 151 | } | 153 | } |
| 152 | } | 154 | } |
| 153 | 155 | ||
| 156 | public class DeleteManifestsTask : Task | ||
| 157 | { | ||
| 158 | public DeleteManifestsTask(string Data) : base(Data) { } | ||
| 159 | |||
| 160 | public override void RunTask() | ||
| 161 | { | ||
| 162 | string filePath = System.Environment.ExpandEnvironmentVariables(this.data); | ||
| 163 | IntPtr type = new IntPtr(24); //RT_MANIFEST | ||
| 164 | IntPtr name = new IntPtr(1); //CREATEPROCESS_MANIFEST_RESOURCE_ID | ||
| 165 | DeleteResource(filePath, type, name, 1033); | ||
| 166 | } | ||
| 167 | |||
| 168 | private static void DeleteResource(string filePath, IntPtr type, IntPtr name, ushort language, bool throwOnError = false) | ||
| 169 | { | ||
| 170 | bool discard = true; | ||
| 171 | IntPtr handle = BeginUpdateResourceW(filePath, false); | ||
| 172 | try | ||
| 173 | { | ||
| 174 | if (handle == IntPtr.Zero) | ||
| 175 | { | ||
| 176 | throw new Win32Exception(); | ||
| 177 | } | ||
| 178 | |||
| 179 | if (!UpdateResourceW(handle, type, name, language, IntPtr.Zero, 0)) | ||
| 180 | { | ||
| 181 | throw new Win32Exception(); | ||
| 182 | } | ||
| 183 | |||
| 184 | discard = false; | ||
| 185 | } | ||
| 186 | catch | ||
| 187 | { | ||
| 188 | if (throwOnError) | ||
| 189 | { | ||
| 190 | throw; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | finally | ||
| 194 | { | ||
| 195 | if (handle != IntPtr.Zero) | ||
| 196 | { | ||
| 197 | if (!EndUpdateResourceW(handle, discard) && throwOnError) | ||
| 198 | { | ||
| 199 | throw new Win32Exception(); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 206 | private extern static IntPtr BeginUpdateResourceW(string fileName, [MarshalAs(UnmanagedType.Bool)] bool deleteExistingResources); | ||
| 207 | |||
| 208 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 209 | [return: MarshalAs(UnmanagedType.Bool)] | ||
| 210 | private extern static bool UpdateResourceW(IntPtr hUpdate, IntPtr type, IntPtr name, ushort language, IntPtr pData, uint cb); | ||
| 211 | |||
| 212 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 213 | [return: MarshalAs(UnmanagedType.Bool)] | ||
| 214 | private extern static bool EndUpdateResourceW(IntPtr hUpdate, [MarshalAs(UnmanagedType.Bool)] bool discard); | ||
| 215 | } | ||
| 216 | |||
| 154 | public class TaskParser | 217 | public class TaskParser |
| 155 | { | 218 | { |
| 156 | 219 | ||
| @@ -197,6 +260,10 @@ namespace TestExe | |||
| 197 | t = new FileExistsTask(args[i + 1]); | 260 | t = new FileExistsTask(args[i + 1]); |
| 198 | tasks.Add(t); | 261 | tasks.Add(t); |
| 199 | break; | 262 | break; |
| 263 | case "/dm": | ||
| 264 | t = new DeleteManifestsTask(args[i + 1]); | ||
| 265 | tasks.Add(t); | ||
| 266 | break; | ||
| 200 | #if NET35 | 267 | #if NET35 |
| 201 | case "/pinfo": | 268 | case "/pinfo": |
| 202 | t = new ProcessInfoTask(args[i + 1]); | 269 | t = new ProcessInfoTask(args[i + 1]); |
diff --git a/src/test/burn/WixTestTools/BundleInstaller.cs b/src/test/burn/WixTestTools/BundleInstaller.cs index 5551d3c0..0f2cfa8f 100644 --- a/src/test/burn/WixTestTools/BundleInstaller.cs +++ b/src/test/burn/WixTestTools/BundleInstaller.cs | |||
| @@ -28,6 +28,8 @@ namespace WixTestTools | |||
| 28 | 28 | ||
| 29 | public int? AlternateExitCode { get; set; } | 29 | public int? AlternateExitCode { get; set; } |
| 30 | 30 | ||
| 31 | public string LogDirectory { get; set; } | ||
| 32 | |||
| 31 | public int? LastExitCode { get; set; } | 33 | public int? LastExitCode { get; set; } |
| 32 | 34 | ||
| 33 | /// <summary> | 35 | /// <summary> |
| @@ -194,7 +196,7 @@ namespace WixTestTools | |||
| 194 | sb.Append(" -quiet"); | 196 | sb.Append(" -quiet"); |
| 195 | 197 | ||
| 196 | // Generate the log file name. | 198 | // Generate the log file name. |
| 197 | string logFile = Path.Combine(Path.GetTempPath(), String.Format("{0}_{1}_{2:yyyyMMddhhmmss}_{4}_{3}.log", this.TestGroupName, this.TestName, DateTime.UtcNow, Path.GetFileNameWithoutExtension(this.Bundle), mode)); | 199 | string logFile = Path.Combine(this.LogDirectory ?? Path.GetTempPath(), String.Format("{0}_{1}_{2:yyyyMMddhhmmss}_{4}_{3}.log", this.TestGroupName, this.TestName, DateTime.UtcNow, Path.GetFileNameWithoutExtension(this.Bundle), mode)); |
| 198 | sb.AppendFormat(" -log \"{0}\"", logFile); | 200 | sb.AppendFormat(" -log \"{0}\"", logFile); |
| 199 | 201 | ||
| 200 | // Set operation. | 202 | // Set operation. |
diff --git a/src/test/burn/WixTestTools/MSIExec.cs b/src/test/burn/WixTestTools/MSIExec.cs index a10a48d6..5f57da7b 100644 --- a/src/test/burn/WixTestTools/MSIExec.cs +++ b/src/test/burn/WixTestTools/MSIExec.cs | |||
| @@ -110,7 +110,7 @@ namespace WixTestTools | |||
| 110 | this.NoRestart = true; | 110 | this.NoRestart = true; |
| 111 | this.ForceRestart = false; | 111 | this.ForceRestart = false; |
| 112 | this.PromptRestart = false; | 112 | this.PromptRestart = false; |
| 113 | this.LogFile = string.Empty; | 113 | this.LogFile = String.Empty; |
| 114 | this.LoggingOptions = MSIExecLoggingOptions.VOICEWARMUP; | 114 | this.LoggingOptions = MSIExecLoggingOptions.VOICEWARMUP; |
| 115 | this.OtherArguments = String.Empty; | 115 | this.OtherArguments = String.Empty; |
| 116 | } | 116 | } |
| @@ -230,14 +230,14 @@ namespace WixTestTools | |||
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | // logfile and logging options | 232 | // logfile and logging options |
| 233 | if (0 != loggingOptionsString.Length || !string.IsNullOrEmpty(this.LogFile)) | 233 | if (0 != loggingOptionsString.Length || !String.IsNullOrEmpty(this.LogFile)) |
| 234 | { | 234 | { |
| 235 | arguments.Append(" /l"); | 235 | arguments.Append(" /l"); |
| 236 | if (0 != loggingOptionsString.Length) | 236 | if (0 != loggingOptionsString.Length) |
| 237 | { | 237 | { |
| 238 | arguments.AppendFormat("{0} ", loggingOptionsString); | 238 | arguments.AppendFormat("{0} ", loggingOptionsString); |
| 239 | } | 239 | } |
| 240 | if (!string.IsNullOrEmpty(this.LogFile)) | 240 | if (!String.IsNullOrEmpty(this.LogFile)) |
| 241 | { | 241 | { |
| 242 | arguments.AppendFormat(" \"{0}\" ", this.LogFile); | 242 | arguments.AppendFormat(" \"{0}\" ", this.LogFile); |
| 243 | } | 243 | } |
| @@ -268,7 +268,7 @@ namespace WixTestTools | |||
| 268 | }; | 268 | }; |
| 269 | 269 | ||
| 270 | // product | 270 | // product |
| 271 | if (!string.IsNullOrEmpty(this.Product)) | 271 | if (!String.IsNullOrEmpty(this.Product)) |
| 272 | { | 272 | { |
| 273 | arguments.AppendFormat(" \"{0}\" ", this.Product); | 273 | arguments.AppendFormat(" \"{0}\" ", this.Product); |
| 274 | } | 274 | } |
| @@ -311,6 +311,12 @@ namespace WixTestTools | |||
| 311 | ERROR_CALL_NOT_IMPLEMENTED = 120, | 311 | ERROR_CALL_NOT_IMPLEMENTED = 120, |
| 312 | 312 | ||
| 313 | /// <summary> | 313 | /// <summary> |
| 314 | /// ERROR_FILENAME_EXCED_RANGE 206 | ||
| 315 | /// The filename or extension is too long. | ||
| 316 | /// </summary> | ||
| 317 | ERROR_FILENAME_EXCED_RANGE = 206, | ||
| 318 | |||
| 319 | /// <summary> | ||
| 314 | /// ERROR_APPHELP_BLOCK 1259 | 320 | /// ERROR_APPHELP_BLOCK 1259 |
| 315 | /// If Windows Installer determines a product may be incompatible with the current operating system, | 321 | /// If Windows Installer determines a product may be incompatible with the current operating system, |
| 316 | /// it displays a dialog box informing the user and asking whether to try to install anyway. | 322 | /// it displays a dialog box informing the user and asking whether to try to install anyway. |
diff --git a/src/test/burn/WixTestTools/TestTool.cs b/src/test/burn/WixTestTools/TestTool.cs index eb77c75b..79e7004c 100644 --- a/src/test/burn/WixTestTools/TestTool.cs +++ b/src/test/burn/WixTestTools/TestTool.cs | |||
| @@ -229,7 +229,7 @@ namespace WixTestTools | |||
| 229 | returnValue.AppendLine("Tool run result:"); | 229 | returnValue.AppendLine("Tool run result:"); |
| 230 | returnValue.AppendLine("----------------"); | 230 | returnValue.AppendLine("----------------"); |
| 231 | returnValue.AppendLine("Command:"); | 231 | returnValue.AppendLine("Command:"); |
| 232 | returnValue.AppendLine($"\"{result.StartInfo.FileName}\" {result.StartInfo.Arguments}"); | 232 | returnValue.AppendLine($"\"{result.FileName}\" {result.Arguments}"); |
| 233 | returnValue.AppendLine(); | 233 | returnValue.AppendLine(); |
| 234 | returnValue.AppendLine("Standard Output:"); | 234 | returnValue.AppendLine("Standard Output:"); |
| 235 | foreach (var line in result.StandardOutput ?? new string[0]) | 235 | foreach (var line in result.StandardOutput ?? new string[0]) |
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs new file mode 100644 index 00000000..ba793d7a --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs | |||
| @@ -0,0 +1,298 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolsetTest.BurnE2E | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.ComponentModel; | ||
| 7 | using System.IO; | ||
| 8 | using System.Runtime.InteropServices; | ||
| 9 | using Microsoft.Win32; | ||
| 10 | using WixBuildTools.TestSupport; | ||
| 11 | using WixTestTools; | ||
| 12 | using WixToolset.Mba.Core; | ||
| 13 | using Xunit; | ||
| 14 | using Xunit.Abstractions; | ||
| 15 | |||
| 16 | public class LongPathTests : BurnE2ETests | ||
| 17 | { | ||
| 18 | public LongPathTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } | ||
| 19 | |||
| 20 | [RuntimeFact] | ||
| 21 | public void CanInstallAndUninstallSimpleBundle_x86_wixstdba() | ||
| 22 | { | ||
| 23 | this.CanInstallAndUninstallSimpleBundle("PackageA", "BundleA"); | ||
| 24 | } | ||
| 25 | |||
| 26 | [RuntimeFact] | ||
| 27 | public void CanInstallAndUninstallSimpleBundle_x86_testba() | ||
| 28 | { | ||
| 29 | this.CanInstallAndUninstallSimpleBundle("PackageA", "BundleB"); | ||
| 30 | } | ||
| 31 | |||
| 32 | [RuntimeFact] | ||
| 33 | public void CanInstallAndUninstallSimpleBundle_x86_dnctestba() | ||
| 34 | { | ||
| 35 | this.CanInstallAndUninstallSimpleBundle("PackageA", "BundleC"); | ||
| 36 | } | ||
| 37 | |||
| 38 | [RuntimeFact] | ||
| 39 | public void CanInstallAndUninstallSimpleBundle_x86_wixba() | ||
| 40 | { | ||
| 41 | this.CanInstallAndUninstallSimpleBundle("PackageA", "BundleD"); | ||
| 42 | } | ||
| 43 | |||
| 44 | [RuntimeFact] | ||
| 45 | public void CanInstallAndUninstallSimpleBundle_x64_wixstdba() | ||
| 46 | { | ||
| 47 | this.CanInstallAndUninstallSimpleBundle("PackageA_x64", "BundleA_x64"); | ||
| 48 | } | ||
| 49 | |||
| 50 | [RuntimeFact] | ||
| 51 | public void CanInstallAndUninstallSimplePerUserBundle_x64_wixstdba() | ||
| 52 | { | ||
| 53 | this.CanInstallAndUninstallSimpleBundle("PackageApu_x64", "BundleApu_x64", "PackagePerUser.wxs", unchecked((int)0xc0000005)); | ||
| 54 | } | ||
| 55 | |||
| 56 | [RuntimeFact] | ||
| 57 | public void CanInstallAndUninstallSimpleBundle_x64_testba() | ||
| 58 | { | ||
| 59 | this.CanInstallAndUninstallSimpleBundle("PackageA_x64", "BundleB_x64"); | ||
| 60 | } | ||
| 61 | |||
| 62 | [RuntimeFact] | ||
| 63 | public void CanInstallAndUninstallSimpleBundle_x64_dnctestba() | ||
| 64 | { | ||
| 65 | this.CanInstallAndUninstallSimpleBundle("PackageA_x64", "BundleC_x64"); | ||
| 66 | } | ||
| 67 | |||
| 68 | [RuntimeFact] | ||
| 69 | public void CanInstallAndUninstallSimpleBundle_x64_dncwixba() | ||
| 70 | { | ||
| 71 | this.CanInstallAndUninstallSimpleBundle("PackageA_x64", "BundleD_x64"); | ||
| 72 | } | ||
| 73 | |||
| 74 | private void CanInstallAndUninstallSimpleBundle(string packageName, string bundleName, string fileName = "Package.wxs", int? alternateExitCode = null) | ||
| 75 | { | ||
| 76 | var package = this.CreatePackageInstaller(Path.Combine("..", "BasicFunctionalityTests", packageName)); | ||
| 77 | |||
| 78 | var bundle = this.CreateBundleInstaller(Path.Combine("..", "BasicFunctionalityTests", bundleName)); | ||
| 79 | bundle.AlternateExitCode = alternateExitCode; | ||
| 80 | |||
| 81 | using var dfs = new DisposableFileSystem(); | ||
| 82 | var baseFolder = GetLongPath(dfs.GetFolder()); | ||
| 83 | |||
| 84 | var packageSourceCodeInstalled = package.GetInstalledFilePath(fileName); | ||
| 85 | |||
| 86 | // Source file should *not* be installed | ||
| 87 | Assert.False(File.Exists(packageSourceCodeInstalled), $"{packageName} payload should not be there on test start: {packageSourceCodeInstalled}"); | ||
| 88 | |||
| 89 | var bundleFileInfo = new FileInfo(bundle.Bundle); | ||
| 90 | var bundleCopiedPath = Path.Combine(baseFolder, bundleFileInfo.Name); | ||
| 91 | bundleFileInfo.CopyTo(bundleCopiedPath); | ||
| 92 | |||
| 93 | bundle.Install(bundleCopiedPath); | ||
| 94 | bundle.VerifyRegisteredAndInPackageCache(); | ||
| 95 | |||
| 96 | // Source file should be installed | ||
| 97 | Assert.True(File.Exists(packageSourceCodeInstalled), $"Should have found {packageName} payload installed at: {packageSourceCodeInstalled}"); | ||
| 98 | |||
| 99 | if (alternateExitCode == bundle.LastExitCode) | ||
| 100 | { | ||
| 101 | WixAssert.Skip($"Install exited with {bundle.LastExitCode}"); | ||
| 102 | } | ||
| 103 | |||
| 104 | bundle.Uninstall(bundleCopiedPath); | ||
| 105 | |||
| 106 | // Source file should *not* be installed | ||
| 107 | Assert.False(File.Exists(packageSourceCodeInstalled), $"{packageName} payload should have been removed by uninstall from: {packageSourceCodeInstalled}"); | ||
| 108 | |||
| 109 | bundle.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
| 110 | |||
| 111 | if (alternateExitCode == bundle.LastExitCode) | ||
| 112 | { | ||
| 113 | WixAssert.Skip($"Uninstall exited with {bundle.LastExitCode}"); | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | [RuntimeFact] | ||
| 118 | public void CanLayoutNonCompressedBundleToLongPath() | ||
| 119 | { | ||
| 120 | var nonCompressedBundle = this.CreateBundleInstaller("NonCompressedBundle"); | ||
| 121 | var testBAController = this.CreateTestBAController(); | ||
| 122 | |||
| 123 | testBAController.SetPackageRequestedState("NetFx48Web", RequestState.None); | ||
| 124 | |||
| 125 | using var dfs = new DisposableFileSystem(); | ||
| 126 | var layoutDirectory = GetLongPath(dfs.GetFolder()); | ||
| 127 | |||
| 128 | nonCompressedBundle.Layout(layoutDirectory); | ||
| 129 | nonCompressedBundle.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
| 130 | |||
| 131 | Assert.True(File.Exists(Path.Combine(layoutDirectory, "NonCompressedBundle.exe"))); | ||
| 132 | Assert.True(File.Exists(Path.Combine(layoutDirectory, "PackageA.msi"))); | ||
| 133 | Assert.True(File.Exists(Path.Combine(layoutDirectory, "1a.cab"))); | ||
| 134 | Assert.False(File.Exists(Path.Combine(layoutDirectory, @"redist\ndp48-web.exe"))); | ||
| 135 | } | ||
| 136 | |||
| 137 | [RuntimeFact] | ||
| 138 | public void CanInstallNonCompressedBundleWithLongTempPath() | ||
| 139 | { | ||
| 140 | this.InstallNonCompressedBundle(longTemp: true, useOriginalTempForLog: true); | ||
| 141 | } | ||
| 142 | |||
| 143 | [RuntimeFact] | ||
| 144 | public void CannotInstallNonCompressedBundleWithLongPackageCachePath() | ||
| 145 | { | ||
| 146 | var installLogPath = this.InstallNonCompressedBundle((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE, longPackageCache: true); | ||
| 147 | Assert.True(LogVerifier.MessageInLogFile(installLogPath, @"Error 0x80070643: Failed to install MSI package")); | ||
| 148 | } | ||
| 149 | |||
| 150 | [RuntimeFact] | ||
| 151 | public void CannotInstallNonCompressedBundleWithLongWorkingPath() | ||
| 152 | { | ||
| 153 | var installLogPath = this.InstallNonCompressedBundle((int)MSIExec.MSIExecReturnCode.ERROR_FILENAME_EXCED_RANGE | unchecked((int)0x80070000), longWorkingPath: true); | ||
| 154 | Assert.True(LogVerifier.MessageInLogFile(installLogPath, @"Error 0x800700ce: Failed to load BA DLL")); | ||
| 155 | } | ||
| 156 | |||
| 157 | public string InstallNonCompressedBundle(int expectedExitCode = 0, bool longTemp = false, bool useOriginalTempForLog = false, bool longWorkingPath = false, bool longPackageCache = false, int? alternateExitCode = null) | ||
| 158 | { | ||
| 159 | var deletePolicyKey = false; | ||
| 160 | string originalEngineWorkingDirectoryValue = null; | ||
| 161 | string originalPackageCacheValue = null; | ||
| 162 | var originalTemp = Environment.GetEnvironmentVariable("TMP"); | ||
| 163 | var packageA = this.CreatePackageInstaller("PackageA"); | ||
| 164 | var nonCompressedBundle = this.CreateBundleInstaller("NonCompressedBundle"); | ||
| 165 | var policyPath = nonCompressedBundle.GetFullBurnPolicyRegistryPath(); | ||
| 166 | string installLogPath = null; | ||
| 167 | |||
| 168 | try | ||
| 169 | { | ||
| 170 | using var dfs = new DisposableFileSystem(); | ||
| 171 | var originalBaseFolder = dfs.GetFolder(); | ||
| 172 | var baseFolder = GetLongPath(originalBaseFolder); | ||
| 173 | var sourceFolder = Path.Combine(baseFolder, "source"); | ||
| 174 | var workingFolder = Path.Combine(baseFolder, "working"); | ||
| 175 | var tempFolder = Path.Combine(originalBaseFolder, new string('d', 260 - originalBaseFolder.Length - 2)); | ||
| 176 | var packageCacheFolder = Path.Combine(baseFolder, "package cache"); | ||
| 177 | |||
| 178 | var copyResult = TestDataFolderFileSystem.RobocopyFolder(this.TestContext.TestDataFolder, sourceFolder); | ||
| 179 | Assert.True(copyResult.ExitCode >= 0 && copyResult.ExitCode < 8, $"Exit code: {copyResult.ExitCode}\r\nOutput: {String.Join("\r\n", copyResult.StandardOutput)}\r\nError: {String.Join("\r\n", copyResult.StandardError)}"); | ||
| 180 | |||
| 181 | var bundleFileInfo = new FileInfo(nonCompressedBundle.Bundle); | ||
| 182 | var bundleCopiedPath = Path.Combine(sourceFolder, bundleFileInfo.Name); | ||
| 183 | |||
| 184 | var policyKey = Registry.LocalMachine.OpenSubKey(policyPath, writable: true); | ||
| 185 | if (policyKey == null) | ||
| 186 | { | ||
| 187 | policyKey = Registry.LocalMachine.CreateSubKey(policyPath, writable: true); | ||
| 188 | deletePolicyKey = true; | ||
| 189 | } | ||
| 190 | |||
| 191 | using (policyKey) | ||
| 192 | { | ||
| 193 | originalEngineWorkingDirectoryValue = policyKey.GetValue("EngineWorkingDirectory") as string; | ||
| 194 | originalPackageCacheValue = policyKey.GetValue("PackageCache") as string; | ||
| 195 | |||
| 196 | if (longWorkingPath) | ||
| 197 | { | ||
| 198 | policyKey.SetValue("EngineWorkingDirectory", workingFolder); | ||
| 199 | } | ||
| 200 | |||
| 201 | if (longPackageCache) | ||
| 202 | { | ||
| 203 | policyKey.SetValue("PackageCache", packageCacheFolder); | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | if (longTemp) | ||
| 208 | { | ||
| 209 | Environment.SetEnvironmentVariable("TMP", tempFolder); | ||
| 210 | |||
| 211 | if (useOriginalTempForLog) | ||
| 212 | { | ||
| 213 | nonCompressedBundle.LogDirectory = originalTemp; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | try | ||
| 218 | { | ||
| 219 | nonCompressedBundle.AlternateExitCode = alternateExitCode; | ||
| 220 | installLogPath = nonCompressedBundle.Install(bundleCopiedPath, expectedExitCode); | ||
| 221 | |||
| 222 | if (alternateExitCode == nonCompressedBundle.LastExitCode) | ||
| 223 | { | ||
| 224 | WixAssert.Skip($"Install exited with {nonCompressedBundle.LastExitCode}"); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | finally | ||
| 228 | { | ||
| 229 | TestDataFolderFileSystem.RobocopyFolder(tempFolder, originalTemp); | ||
| 230 | } | ||
| 231 | |||
| 232 | installLogPath = Path.Combine(originalTemp, Path.GetFileName(installLogPath)); | ||
| 233 | |||
| 234 | if (expectedExitCode == 0) | ||
| 235 | { | ||
| 236 | var registration = nonCompressedBundle.VerifyRegisteredAndInPackageCache(); | ||
| 237 | packageA.VerifyInstalled(true); | ||
| 238 | |||
| 239 | nonCompressedBundle.Uninstall(registration.CachePath); | ||
| 240 | |||
| 241 | if (alternateExitCode == nonCompressedBundle.LastExitCode) | ||
| 242 | { | ||
| 243 | WixAssert.Skip($"Uninstall exited with {nonCompressedBundle.LastExitCode}"); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | nonCompressedBundle.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
| 248 | packageA.VerifyInstalled(false); | ||
| 249 | |||
| 250 | return installLogPath; | ||
| 251 | } | ||
| 252 | finally | ||
| 253 | { | ||
| 254 | Environment.SetEnvironmentVariable("TMP", originalTemp); | ||
| 255 | |||
| 256 | if (deletePolicyKey) | ||
| 257 | { | ||
| 258 | Registry.LocalMachine.DeleteSubKeyTree(policyPath); | ||
| 259 | } | ||
| 260 | else | ||
| 261 | { | ||
| 262 | using (var policyKey = Registry.LocalMachine.OpenSubKey(policyPath, writable: true)) | ||
| 263 | { | ||
| 264 | policyKey?.SetValue("EngineWorkingDirectory", originalEngineWorkingDirectoryValue); | ||
| 265 | policyKey?.SetValue("PackageCache", originalPackageCacheValue); | ||
| 266 | } | ||
| 267 | } | ||
| 268 | } | ||
| 269 | } | ||
| 270 | |||
| 271 | private static string GetLongPath(string baseFolder) | ||
| 272 | { | ||
| 273 | Directory.CreateDirectory(baseFolder); | ||
| 274 | |||
| 275 | // Try to create a directory that is longer than MAX_PATH but without the \\?\ prefix to detect OS support for long paths. | ||
| 276 | // Need to PInvoke CreateDirectoryW directly because .NET methods will append the \\?\ prefix. | ||
| 277 | foreach (var c in new char[] { 'a', 'b', 'c' }) | ||
| 278 | { | ||
| 279 | baseFolder = Path.Combine(baseFolder, new string(c, 100)); | ||
| 280 | if (!CreateDirectoryW(baseFolder, IntPtr.Zero)) | ||
| 281 | { | ||
| 282 | int lastError = Marshal.GetLastWin32Error(); | ||
| 283 | if (lastError == 206) | ||
| 284 | { | ||
| 285 | WixAssert.Skip($"MAX_PATH is being enforced ({baseFolder})"); | ||
| 286 | } | ||
| 287 | throw new Win32Exception(lastError); | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | return baseFolder; | ||
| 292 | } | ||
| 293 | |||
| 294 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 295 | [return: MarshalAs(UnmanagedType.Bool)] | ||
| 296 | private extern static bool CreateDirectoryW(string lpPathName, IntPtr lpSecurityAttributes); | ||
| 297 | } | ||
| 298 | } | ||
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/testhost.longpathaware.manifest b/src/test/burn/WixToolsetTest.BurnE2E/testhost.longpathaware.manifest new file mode 100644 index 00000000..a56ab91a --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/testhost.longpathaware.manifest | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||
| 2 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 3 | |||
| 4 | |||
| 5 | <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> | ||
| 6 | <application xmlns="urn:schemas-microsoft-com:asm.v3"> | ||
| 7 | <windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings"> | ||
| 8 | <ws2:longPathAware>true</ws2:longPathAware> | ||
| 9 | </windowsSettings> | ||
| 10 | </application> | ||
| 11 | </assembly> | ||
diff --git a/src/test/burn/test_burn.cmd b/src/test/burn/test_burn.cmd index 83401614..80467f39 100644 --- a/src/test/burn/test_burn.cmd +++ b/src/test/burn/test_burn.cmd | |||
| @@ -9,11 +9,16 @@ | |||
| 9 | @if /i "%1"=="test" set RuntimeTestsEnabled=true | 9 | @if /i "%1"=="test" set RuntimeTestsEnabled=true |
| 10 | @if not "%1"=="" shift & goto parse_args | 10 | @if not "%1"=="" shift & goto parse_args |
| 11 | 11 | ||
| 12 | @set _B=%~dp0..\..\..\build\IntegrationBurn\%_C% | ||
| 13 | |||
| 12 | @echo Burn integration tests %_C% | 14 | @echo Burn integration tests %_C% |
| 13 | 15 | ||
| 14 | msbuild -t:Build -Restore -p:Configuration=%_C% -warnaserror -bl:%_L%\test_burn_build.binlog || exit /b | 16 | msbuild -t:Build -Restore -p:Configuration=%_C% -warnaserror -bl:%_L%\test_burn_build.binlog || exit /b |
| 15 | msbuild -t:Build -Restore TestData\TestData.proj -p:Configuration=%_C% -m -bl:%_L%\test_burn_data_build.binlog || exit /b | 17 | msbuild -t:Build -Restore TestData\TestData.proj -p:Configuration=%_C% -m -bl:%_L%\test_burn_data_build.binlog || exit /b |
| 16 | 18 | ||
| 19 | "%_B%\net35\win-x86\testexe.exe" /dm "%_B%\netcoreapp3.1\testhost.exe" | ||
| 20 | mt.exe -manifest "WixToolsetTest.BurnE2E\testhost.longpathaware.manifest" -updateresource:"%_B%\netcoreapp3.1\testhost.exe" | ||
| 21 | |||
| 17 | @if not "%RuntimeTestsEnabled%"=="true" goto :LExit | 22 | @if not "%RuntimeTestsEnabled%"=="true" goto :LExit |
| 18 | 23 | ||
| 19 | dotnet test -c %_C% --no-build WixToolsetTest.BurnE2E -l "trx;LogFileName=%_L%\TestResults\WixToolsetTest.BurnE2E.trx" || exit /b | 24 | dotnet test -c %_C% --no-build WixToolsetTest.BurnE2E -l "trx;LogFileName=%_L%\TestResults\WixToolsetTest.BurnE2E.trx" || exit /b |
diff --git a/src/wix/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs index 672bb235..67a6cb4a 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs | |||
| @@ -231,6 +231,10 @@ namespace WixToolset.Core.Burn.Bundles | |||
| 231 | writer.WriteEndElement(); | 231 | writer.WriteEndElement(); |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | writer.WriteStartElement("longPathAware", ws2016Namespace); | ||
| 235 | writer.WriteString("true"); | ||
| 236 | writer.WriteEndElement(); | ||
| 237 | |||
| 234 | writer.WriteEndElement(); // </windowSettings> | 238 | writer.WriteEndElement(); // </windowSettings> |
| 235 | writer.WriteEndElement(); // </application> | 239 | writer.WriteEndElement(); // </application> |
| 236 | } | 240 | } |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs index bc7fe7a4..a281ad0f 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs | |||
| @@ -169,7 +169,10 @@ namespace WixToolsetTest.CoreIntegration | |||
| 169 | "<dependency><dependentAssembly><assemblyIdentity name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"x86\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\" type=\"win32\" /></dependentAssembly></dependency>" + | 169 | "<dependency><dependentAssembly><assemblyIdentity name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"x86\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\" type=\"win32\" /></dependentAssembly></dependency>" + |
| 170 | "<compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\"><application><supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\" /><supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\" /><supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\" /><supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\" /><supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\" /></application></compatibility>" + | 170 | "<compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\"><application><supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\" /><supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\" /><supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\" /><supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\" /><supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\" /></application></compatibility>" + |
| 171 | "<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\"><security><requestedPrivileges><requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\" /></requestedPrivileges></security></trustInfo>" + | 171 | "<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\"><security><requestedPrivileges><requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\" /></requestedPrivileges></security></trustInfo>" + |
| 172 | "<application xmlns=\"urn:schemas-microsoft-com:asm.v3\"><windowsSettings><dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">true/pm</dpiAware><dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness></windowsSettings></application>" + | 172 | "<application xmlns=\"urn:schemas-microsoft-com:asm.v3\"><windowsSettings>" + |
| 173 | "<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">true/pm</dpiAware><dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>" + | ||
| 174 | "<longPathAware xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">true</longPathAware>" + | ||
| 175 | "</windowsSettings></application>" + | ||
| 173 | "</assembly>", actualManifestData); | 176 | "</assembly>", actualManifestData); |
| 174 | } | 177 | } |
| 175 | } | 178 | } |
| @@ -215,7 +218,10 @@ namespace WixToolsetTest.CoreIntegration | |||
| 215 | "<dependency><dependentAssembly><assemblyIdentity name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"amd64\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\" type=\"win32\" /></dependentAssembly></dependency>" + | 218 | "<dependency><dependentAssembly><assemblyIdentity name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"amd64\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\" type=\"win32\" /></dependentAssembly></dependency>" + |
| 216 | "<compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\"><application><supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\" /><supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\" /><supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\" /><supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\" /><supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\" /></application></compatibility>" + | 219 | "<compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\"><application><supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\" /><supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\" /><supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\" /><supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\" /><supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\" /></application></compatibility>" + |
| 217 | "<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\"><security><requestedPrivileges><requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\" /></requestedPrivileges></security></trustInfo>" + | 220 | "<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\"><security><requestedPrivileges><requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\" /></requestedPrivileges></security></trustInfo>" + |
| 218 | "<application xmlns=\"urn:schemas-microsoft-com:asm.v3\"><windowsSettings><dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">true/pm</dpiAware><dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness></windowsSettings></application>" + | 221 | "<application xmlns=\"urn:schemas-microsoft-com:asm.v3\"><windowsSettings>" + |
| 222 | "<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">true/pm</dpiAware><dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>" + | ||
| 223 | "<longPathAware xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">true</longPathAware>" + | ||
| 224 | "</windowsSettings></application>" + | ||
| 219 | "</assembly>", actualManifestData); | 225 | "</assembly>", actualManifestData); |
| 220 | 226 | ||
| 221 | var extractResult = BundleExtractor.ExtractAllContainers(null, exePath, baFolderPath, attachedFolderPath, extractFolderPath); | 227 | var extractResult = BundleExtractor.ExtractAllContainers(null, exePath, baFolderPath, attachedFolderPath, extractFolderPath); |
