mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-10 22:41:05 +03:00
fix(msi): pass the printer name in a format the custom action can read
[~] is MSI's escape for a NUL character, not the delimiter WcaReadStringFromCaData splits on -- that is a literal wide char 128, which a Formatted property value cannot carry -- and WcaGetProperty returns a null-terminated string anyway. So the second field was unreachable: InstallPrinter always fell back to the stock name and installed a printer and port called "RustDesk Printer" inside a customer's branded package, while UninstallPrinter, whose data is a single field and parsed fine, went looking for "Acme Printer" and left the real one behind for good. Both actions now read CustomActionData directly and split on a character that cannot occur in a Windows path or in a validated app name. A package built before this carries no separator and keeps the stock name, as it did. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7fBdTwziR5BHTkSz7Tzcm
This commit is contained in:
@@ -1021,10 +1021,9 @@ UINT __stdcall InstallPrinter(
|
||||
DWORD er = ERROR_SUCCESS;
|
||||
|
||||
int nResult = 0;
|
||||
LPWSTR installFolder = NULL;
|
||||
LPWSTR appName = NULL;
|
||||
LPWSTR pwz = NULL;
|
||||
LPWSTR pwzData = NULL;
|
||||
std::wstring appNameValue;
|
||||
std::wstring installFolderValue;
|
||||
|
||||
hr = WcaInitialize(hInstall, "InstallPrinter");
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
@@ -1032,25 +1031,30 @@ UINT __stdcall InstallPrinter(
|
||||
hr = WcaGetProperty(L"CustomActionData", &pwzData);
|
||||
ExitOnFailure(hr, "failed to get CustomActionData");
|
||||
|
||||
pwz = pwzData;
|
||||
hr = WcaReadStringFromCaData(&pwz, &installFolder);
|
||||
ExitOnFailure(hr, "failed to read database key from custom action data: %ls", pwz);
|
||||
|
||||
// Names the printer. Optional, so that a package built before this was passed in
|
||||
// still installs, keeping the stock printer name.
|
||||
if (FAILED(WcaReadStringFromCaData(&pwz, &appName)))
|
||||
// "<app name>|<install folder>". Split here rather than through
|
||||
// WcaReadStringFromCaData, whose delimiter is a literal wide char 128 that a
|
||||
// Formatted property value cannot carry.
|
||||
{
|
||||
ReleaseNullStr(appName);
|
||||
std::wstring data(pwzData);
|
||||
size_t separator = data.find(L'|');
|
||||
if (separator == std::wstring::npos)
|
||||
{
|
||||
// A package built before the name was passed in; keep the stock name.
|
||||
appNameValue.clear();
|
||||
installFolderValue = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
appNameValue = data.substr(0, separator);
|
||||
installFolderValue = data.substr(separator + 1);
|
||||
}
|
||||
}
|
||||
|
||||
WcaLog(LOGMSG_STANDARD, "Try to install RD printer in : %ls", installFolder);
|
||||
RemotePrinter::installUpdatePrinter(installFolder, appName ? appName : L"");
|
||||
WcaLog(LOGMSG_STANDARD, "Try to install RD printer in : %ls", installFolderValue.c_str());
|
||||
RemotePrinter::installUpdatePrinter(installFolderValue, appNameValue);
|
||||
WcaLog(LOGMSG_STANDARD, "Install RD printer done");
|
||||
|
||||
LExit:
|
||||
if (appName) {
|
||||
ReleaseStr(appName);
|
||||
}
|
||||
if (pwzData) {
|
||||
ReleaseStr(pwzData);
|
||||
}
|
||||
@@ -1065,32 +1069,24 @@ UINT __stdcall UninstallPrinter(
|
||||
HRESULT hr = S_OK;
|
||||
DWORD er = ERROR_SUCCESS;
|
||||
|
||||
LPWSTR appName = NULL;
|
||||
LPWSTR pwz = NULL;
|
||||
LPWSTR pwzData = NULL;
|
||||
std::wstring appNameValue;
|
||||
|
||||
hr = WcaInitialize(hInstall, "UninstallPrinter");
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
|
||||
// Must match the name install used, otherwise the printer is left behind. Absent
|
||||
// on packages built before this was passed in, where it was the stock name.
|
||||
if (SUCCEEDED(WcaGetProperty(L"CustomActionData", &pwzData)))
|
||||
if (SUCCEEDED(WcaGetProperty(L"CustomActionData", &pwzData)) && pwzData)
|
||||
{
|
||||
pwz = pwzData;
|
||||
if (FAILED(WcaReadStringFromCaData(&pwz, &appName)))
|
||||
{
|
||||
ReleaseNullStr(appName);
|
||||
}
|
||||
appNameValue = pwzData;
|
||||
}
|
||||
|
||||
WcaLog(LOGMSG_STANDARD, "Try to uninstall RD printer");
|
||||
RemotePrinter::uninstallPrinter(appName ? appName : L"");
|
||||
RemotePrinter::uninstallPrinter(appNameValue);
|
||||
WcaLog(LOGMSG_STANDARD, "Uninstall RD printer done");
|
||||
|
||||
LExit:
|
||||
if (appName) {
|
||||
ReleaseStr(appName);
|
||||
}
|
||||
if (pwzData) {
|
||||
ReleaseStr(pwzData);
|
||||
}
|
||||
|
||||
@@ -30,9 +30,13 @@
|
||||
<CustomAction Id="SetPropertyServiceStop.SetParam.PropertyName" Return="check" Property="PropertyName" Value="STOP_SERVICE" />
|
||||
<CustomAction Id="TryDeleteStartupShortcut.SetParam" Return="check" Property="ShortcutName" Value="$(var.Product) Tray" />
|
||||
<CustomAction Id="RemoveAmyuniIdd.SetParam" Return="check" Property="RemoveAmyuniIdd" Value="[INSTALLFOLDER_INNER]" />
|
||||
<!-- [~] separates the fields the custom action reads back. ProductName names the
|
||||
printer, so the dll carries no app name and one build serves every custom client. -->
|
||||
<CustomAction Id="InstallPrinter.SetParam" Return="check" Property="InstallPrinter" Value="[INSTALLFOLDER_INNER][~][ProductName]" />
|
||||
<!-- The app name comes first and is separated by '|', which cannot occur in a
|
||||
Windows path nor in a validated app name. wcautil's own delimiter is a
|
||||
literal wide char 128 that a Formatted value cannot carry, and [~] is
|
||||
MSI's NUL escape rather than that delimiter, so the action parses this
|
||||
itself. Passing the name keeps the dll free of it, so one build serves
|
||||
every custom client. -->
|
||||
<CustomAction Id="InstallPrinter.SetParam" Return="check" Property="InstallPrinter" Value="[ProductName]|[INSTALLFOLDER_INNER]" />
|
||||
<CustomAction Id="UninstallPrinter.SetParam" Return="check" Property="UninstallPrinter" Value="[ProductName]" />
|
||||
<InstallExecuteSequence>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user