fix bundle no installlocation

This commit is contained in:
Leilei Zhang
2025-09-26 14:29:58 +08:00
parent 4693131c0a
commit 0c2ca3edb3
3 changed files with 94 additions and 98 deletions

View File

@@ -1384,120 +1384,112 @@ UINT __stdcall SetBundleInstallLocationCA(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
std::wstring installationFolder;
// Declare variables at the beginning to avoid goto issues
std::wstring bundleName;
HKEY rootKey = HKEY_LOCAL_MACHINE;
LPWSTR installScopeBuffer = nullptr;
std::wstring uninstallPath;
HKEY uninstallKey = nullptr;
bool bundleFound = false;
// Declare all variables at the beginning to avoid goto issues
std::wstring customActionData;
std::wstring installationFolder;
std::wstring bundleUpgradeCode;
std::wstring installScope;
bool isPerUser = false;
size_t pos1 = std::wstring::npos;
size_t pos2 = std::wstring::npos;
std::vector<HKEY> keysToTry;
hr = WcaInitialize(hInstall, "SetBundleInstallLocationCA");
ExitOnFailure(hr, "Failed to initialize");
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Starting custom action");
// Parse CustomActionData: "installFolder;upgradeCode;installScope"
hr = getInstallFolder(hInstall, customActionData);
ExitOnFailure(hr, "Failed to get CustomActionData.");
hr = getInstallFolder(hInstall, installationFolder);
ExitOnFailure(hr, "Failed to get installFolder.");
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Installation folder: %ls", installationFolder.c_str());
// Get bundle name with platform
bundleName = L"PowerToys (Preview) ";
#ifdef _M_ARM64
bundleName += L"ARM64";
#else
bundleName += L"x64";
#endif
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Looking for Bundle: %ls", bundleName.c_str());
// Get InstallScope property to determine if per-user or per-machine
hr = WcaGetProperty(L"InstallScope", &installScopeBuffer);
if (SUCCEEDED(hr) && installScopeBuffer && wcscmp(installScopeBuffer, L"perUser") == 0)
pos1 = customActionData.find(L';');
if (pos1 == std::wstring::npos)
{
rootKey = HKEY_CURRENT_USER;
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Using HKEY_CURRENT_USER");
}
else
{
rootKey = HKEY_LOCAL_MACHINE;
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Using HKEY_LOCAL_MACHINE");
hr = E_INVALIDARG;
ExitOnFailure(hr, "Invalid CustomActionData format - missing first semicolon");
}
// Search for Bundle registry entry
uninstallPath = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
LONG result = RegOpenKeyExW(rootKey, uninstallPath.c_str(), 0, KEY_READ | KEY_ENUMERATE_SUB_KEYS, &uninstallKey);
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: RegOpenKeyExW result: %ld", result);
if (result == ERROR_SUCCESS)
pos2 = customActionData.find(L';', pos1 + 1);
if (pos2 == std::wstring::npos)
{
DWORD index = 0;
wchar_t subKeyName[256];
DWORD subKeyNameSize = sizeof(subKeyName) / sizeof(wchar_t);
while (RegEnumKeyExW(uninstallKey, index, subKeyName, &subKeyNameSize, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
hr = E_INVALIDARG;
ExitOnFailure(hr, "Invalid CustomActionData format - missing second semicolon");
}
installationFolder = customActionData.substr(0, pos1);
bundleUpgradeCode = customActionData.substr(pos1 + 1, pos2 - pos1 - 1);
installScope = customActionData.substr(pos2 + 1);
isPerUser = (installScope == L"perUser");
// Use the appropriate registry based on install scope
HKEY targetKey = isPerUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
const wchar_t* keyName = isPerUser ? L"HKCU" : L"HKLM";
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Searching for Bundle in %ls registry", keyName);
HKEY uninstallKey;
LONG openResult = RegOpenKeyExW(targetKey, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", 0, KEY_READ | KEY_ENUMERATE_SUB_KEYS, &uninstallKey);
if (openResult != ERROR_SUCCESS)
{
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Failed to open uninstall key, error: %ld", openResult);
goto LExit;
}
DWORD index = 0;
wchar_t subKeyName[256];
DWORD subKeyNameSize = sizeof(subKeyName) / sizeof(wchar_t);
while (RegEnumKeyExW(uninstallKey, index, subKeyName, &subKeyNameSize, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
{
HKEY productKey;
if (RegOpenKeyExW(uninstallKey, subKeyName, 0, KEY_READ | KEY_WRITE, &productKey) == ERROR_SUCCESS)
{
HKEY productKey;
if (RegOpenKeyExW(uninstallKey, subKeyName, 0, KEY_READ | KEY_WRITE, &productKey) == ERROR_SUCCESS)
{
wchar_t displayName[512];
DWORD displayNameSize = sizeof(displayName);
DWORD valueType;
if (RegQueryValueExW(productKey, L"DisplayName", nullptr, &valueType,
reinterpret_cast<LPBYTE>(displayName), &displayNameSize) == ERROR_SUCCESS)
{
WcaLog(LOGMSG_VERBOSE, "SetBundleInstallLocationCA: Found entry: %ls", displayName);
// Check if this matches our Bundle name (case-insensitive and flexible)
if (wcsstr(displayName, L"PowerToys") && wcsstr(displayName, L"Preview"))
{
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Found PowerToys Bundle: %ls", displayName);
// Found the Bundle entry, add InstallLocation
LONG setResult = RegSetValueExW(productKey, L"InstallLocation", 0, REG_SZ,
reinterpret_cast<const BYTE*>(installationFolder.c_str()),
static_cast<DWORD>((installationFolder.length() + 1) * sizeof(wchar_t)));
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: RegSetValueExW result: %ld", setResult);
if (setResult == ERROR_SUCCESS)
{
bundleFound = true;
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Successfully set InstallLocation to: %ls", installationFolder.c_str());
}
else
{
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Failed to set InstallLocation, error: %ld", setResult);
}
RegCloseKey(productKey);
break;
}
}
RegCloseKey(productKey);
}
wchar_t upgradeCode[256];
DWORD upgradeCodeSize = sizeof(upgradeCode);
DWORD valueType;
index++;
subKeyNameSize = sizeof(subKeyName) / sizeof(wchar_t);
if (RegQueryValueExW(productKey, L"BundleUpgradeCode", nullptr, &valueType,
reinterpret_cast<LPBYTE>(upgradeCode), &upgradeCodeSize) == ERROR_SUCCESS)
{
// Remove brackets from registry upgradeCode for comparison (bundleUpgradeCode doesn't have brackets)
std::wstring regUpgradeCode = upgradeCode;
if (!regUpgradeCode.empty() && regUpgradeCode.front() == L'{' && regUpgradeCode.back() == L'}')
{
regUpgradeCode = regUpgradeCode.substr(1, regUpgradeCode.length() - 2);
}
if (_wcsicmp(regUpgradeCode.c_str(), bundleUpgradeCode.c_str()) == 0)
{
// Found matching Bundle, set InstallLocation
LONG setResult = RegSetValueExW(productKey, L"InstallLocation", 0, REG_SZ,
reinterpret_cast<const BYTE*>(installationFolder.c_str()),
static_cast<DWORD>((installationFolder.length() + 1) * sizeof(wchar_t)));
if (setResult == ERROR_SUCCESS)
{
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: InstallLocation set successfully");
}
else
{
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Failed to set InstallLocation, error: %ld", setResult);
}
RegCloseKey(productKey);
RegCloseKey(uninstallKey);
goto LExit;
}
}
RegCloseKey(productKey);
}
RegCloseKey(uninstallKey);
index++;
subKeyNameSize = sizeof(subKeyName) / sizeof(wchar_t);
}
if (!bundleFound)
{
WcaLog(LOGMSG_STANDARD, "SetBundleInstallLocationCA: Bundle entry not found");
}
RegCloseKey(uninstallKey);
LExit:
if (installScopeBuffer)
{
ReleaseStr(installScopeBuffer);
}
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}

View File

@@ -28,6 +28,9 @@
<Log Disable="no" Prefix="powertoys-bootstrapper-msi-$(var.Version)" Extension=".log" />
<!-- Store Bundle UpgradeCode for CustomAction -->
<Variable Name="BundleUpgradeCode" Type="string" Value="$(var.UpgradeCode)" />
<!-- Only install/upgrade if the version is greater or equal than the currently installed version of PowerToys, to handle the case in which PowerToys was installed from old MSI (before WiX bootstrapper was used) -->
<!-- If the previous installation is a bundle installation, just let WiX run its logic. -->
<Variable Name="MinimumVersion" Type="version" Value="0.0.0.0" />
@@ -58,6 +61,7 @@
<MsiPackage DisplayName="PowerToys MSI" SourceFile="$(var.PowerToysPlatform)\Release\$(var.MSIPath)\$(var.MSIName)" Compressed="yes" bal:DisplayInternalUICondition="false">
<MsiProperty Name="BOOTSTRAPPERINSTALLFOLDER" Value="[InstallFolder]" />
<MsiProperty Name="MSIRESTARTMANAGERCONTROL" Value="Disable" />
<MsiProperty Name="BUNDLEINFO" Value="[BundleUpgradeCode]" />
</MsiPackage>
</Chain>
</Bundle>

View File

@@ -164,7 +164,7 @@
<CustomAction Id="SetInstallCmdPalPackageParam" Property="InstallCmdPalPackage" Value="[INSTALLFOLDER]" />
<!-- Set InstallLocation for Bundle entry as well -->
<CustomAction Id="SetBundleInstallLocationData" Property="SetBundleInstallLocation" Value="[INSTALLFOLDER]" />
<CustomAction Id="SetBundleInstallLocationData" Property="SetBundleInstallLocation" Value="[INSTALLFOLDER];[BUNDLEINFO];[InstallScope]" />
<CustomAction Id="LaunchPowerToys" Return="ignore" Impersonate="yes" Execute="deferred" DllEntry="LaunchPowerToysCA" BinaryRef="PTCustomActions" />