From be243919934a2f52b8d44300458b79e458e1e7fd Mon Sep 17 00:00:00 2001 From: rustdesk Date: Wed, 5 Aug 2026 20:47:38 +0800 Subject: [PATCH] refactor(msi): pass the app name to the printer custom actions preprocess.py rewrote the CustomActions sources per customer so the printer carried the app name, which meant the dll was recompiled for every custom client and, worse, left the app name baked into a compiled binary. Pass it through CustomActionData instead. Only the printer and its port ever varied: the INF path and the driver name ship under their stock names and preprocess.py already forced the driver name back to RustDesk, so a single build of the dll now serves every custom client. Both actions treat the name as optional and fall back to the stock name, so a package built before this still installs and uninstalls its printer. This also unblocks patching a prebuilt msi template, which cannot work while a compiled dll contains the app name: replacing a string inside a PE would shift everything after it. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Q7fBdTwziR5BHTkSz7Tzcm --- res/msi/CustomActions/Common.h | 7 +++-- res/msi/CustomActions/CustomActions.cpp | 37 +++++++++++++++++++++++-- res/msi/CustomActions/RemotePrinter.cpp | 25 +++++++++++++---- res/msi/Package/Components/RustDesk.wxs | 6 +++- res/msi/preprocess.py | 14 ---------- 5 files changed, 64 insertions(+), 25 deletions(-) diff --git a/res/msi/CustomActions/Common.h b/res/msi/CustomActions/Common.h index 08302d98c..bc9ed1ad9 100644 --- a/res/msi/CustomActions/Common.h +++ b/res/msi/CustomActions/Common.h @@ -18,6 +18,9 @@ void UninstallDriver(LPCWSTR hardwareId, BOOL &rebootRequired); namespace RemotePrinter { - VOID installUpdatePrinter(const std::wstring& installFolder); - VOID uninstallPrinter(); + // `appName` names the printer and its port. It is passed in rather than compiled + // in so that a single dll serves every custom client; an empty value keeps the + // stock "RustDesk Printer" name. + VOID installUpdatePrinter(const std::wstring& installFolder, const std::wstring& appName); + VOID uninstallPrinter(const std::wstring& appName); } diff --git a/res/msi/CustomActions/CustomActions.cpp b/res/msi/CustomActions/CustomActions.cpp index f4780dd87..f53a910a9 100644 --- a/res/msi/CustomActions/CustomActions.cpp +++ b/res/msi/CustomActions/CustomActions.cpp @@ -1022,6 +1022,7 @@ UINT __stdcall InstallPrinter( int nResult = 0; LPWSTR installFolder = NULL; + LPWSTR appName = NULL; LPWSTR pwz = NULL; LPWSTR pwzData = NULL; @@ -1035,11 +1036,21 @@ UINT __stdcall InstallPrinter( 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))) + { + ReleaseNullStr(appName); + } + WcaLog(LOGMSG_STANDARD, "Try to install RD printer in : %ls", installFolder); - RemotePrinter::installUpdatePrinter(installFolder); + RemotePrinter::installUpdatePrinter(installFolder, appName ? appName : L""); WcaLog(LOGMSG_STANDARD, "Install RD printer done"); LExit: + if (appName) { + ReleaseStr(appName); + } if (pwzData) { ReleaseStr(pwzData); } @@ -1054,14 +1065,36 @@ UINT __stdcall UninstallPrinter( HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; + LPWSTR appName = NULL; + LPWSTR pwz = NULL; + LPWSTR pwzData = NULL; + 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))) + { + pwz = pwzData; + if (FAILED(WcaReadStringFromCaData(&pwz, &appName))) + { + ReleaseNullStr(appName); + } + } + WcaLog(LOGMSG_STANDARD, "Try to uninstall RD printer"); - RemotePrinter::uninstallPrinter(); + RemotePrinter::uninstallPrinter(appName ? appName : L""); WcaLog(LOGMSG_STANDARD, "Uninstall RD printer done"); LExit: + if (appName) { + ReleaseStr(appName); + } + if (pwzData) { + ReleaseStr(pwzData); + } + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); } diff --git a/res/msi/CustomActions/RemotePrinter.cpp b/res/msi/CustomActions/RemotePrinter.cpp index 767c8c82c..532a3524b 100644 --- a/res/msi/CustomActions/RemotePrinter.cpp +++ b/res/msi/CustomActions/RemotePrinter.cpp @@ -18,12 +18,19 @@ namespace RemotePrinter { #define HRESULT_ERR_ELEMENT_NOT_FOUND 0x80070490 + // The driver files and the driver name ship with the app under their stock names + // and stay fixed for every custom client. Only the printer and its port carry the + // app name, and that arrives at runtime so one dll serves every custom client. LPCWCH RD_DRIVER_INF_PATH = L"drivers\\RustDeskPrinterDriver\\RustDeskPrinterDriver.inf"; - LPCWCH RD_PRINTER_PORT = L"RustDesk Printer"; - LPCWCH RD_PRINTER_NAME = L"RustDesk Printer"; LPCWCH RD_PRINTER_DRIVER_NAME = L"RustDesk v4 Printer Driver"; + LPCWCH RD_DEFAULT_APP_NAME = L"RustDesk"; LPCWCH XCV_MONITOR_LOCAL_PORT = L",XcvMonitor Local Port"; + static std::wstring printerNameOf(const std::wstring &appName) + { + return (appName.empty() ? std::wstring(RD_DEFAULT_APP_NAME) : appName) + L" Printer"; + } + using FuncEnum = std::function; template using FuncOnData = std::function(const T &)>; @@ -458,8 +465,12 @@ namespace RemotePrinter // We should not check the driver version because the driver is deployed with the application. // It's better to uninstall the existing driver and install the driver from the application. // 3. Add the printer. - VOID installUpdatePrinter(const std::wstring &installFolder) + VOID installUpdatePrinter(const std::wstring &installFolder, const std::wstring &appName) { + const std::wstring printerName = printerNameOf(appName); + const LPCWCH RD_PRINTER_NAME = printerName.c_str(); + const LPCWCH RD_PRINTER_PORT = printerName.c_str(); + const std::wstring infFile = installFolder + L"\\" + RemotePrinter::RD_DRIVER_INF_PATH; if (!FileExists(infFile)) { @@ -505,13 +516,15 @@ namespace RemotePrinter } } - VOID uninstallPrinter() + VOID uninstallPrinter(const std::wstring &appName) { - deletePrinter(RD_PRINTER_NAME); + const std::wstring printerName = printerNameOf(appName); + + deletePrinter(printerName.c_str()); WcaLog(LOGMSG_STANDARD, "Deleted the printer\n"); uninstallDriver(RD_PRINTER_DRIVER_NAME); WcaLog(LOGMSG_STANDARD, "Uninstalled the printer driver\n"); - checkDeleteLocalPort(RD_PRINTER_PORT); + checkDeleteLocalPort(printerName.c_str()); WcaLog(LOGMSG_STANDARD, "Deleted the local port\n"); } } diff --git a/res/msi/Package/Components/RustDesk.wxs b/res/msi/Package/Components/RustDesk.wxs index 5ca5364a7..3e77e76d1 100644 --- a/res/msi/Package/Components/RustDesk.wxs +++ b/res/msi/Package/Components/RustDesk.wxs @@ -30,7 +30,10 @@ - + + + @@ -86,6 +89,7 @@ + diff --git a/res/msi/preprocess.py b/res/msi/preprocess.py index ff0b5f510..3f52aceb8 100644 --- a/res/msi/preprocess.py +++ b/res/msi/preprocess.py @@ -10,7 +10,6 @@ import subprocess import re import platform from pathlib import Path -from itertools import chain import shutil g_indent_unit = "\t" @@ -189,18 +188,6 @@ def replace_app_name_in_langs(app_name): with open(file_path, "w", encoding="utf-8") as f: f.writelines(lines) -def replace_app_name_in_custom_actions(app_name): - custion_actions_dir = Path(sys.argv[0]).parent.joinpath("CustomActions") - for file_path in chain(custion_actions_dir.glob("*.cpp"), custion_actions_dir.glob("*.h")): - with open(file_path, "r", encoding="utf-8") as f: - lines = f.readlines() - for i, line in enumerate(lines): - line = re.sub(r"\bRustDesk\b", app_name, line) - line = line.replace(f"{app_name} v4 Printer Driver", "RustDesk v4 Printer Driver") - lines[i] = line - with open(file_path, "w", encoding="utf-8") as f: - f.writelines(lines) - def gen_upgrade_info(): def func(lines, index_start): indent = g_indent_unit * 3 @@ -557,4 +544,3 @@ if __name__ == "__main__": sys.exit(-1) replace_app_name_in_langs(args.app_name) - replace_app_name_in_custom_actions(args.app_name)