mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-24 04:00:02 +01:00
fix bundle no installlocation
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user