Fix. Msi. Terminate brokers. (#7693)

* Fix. Msi. Terminate brokers.

Signed-off-by: fufesou <shuanglongchen@yeah.net>

* Fix. Msi, remove tray shortcut in startmenu

Signed-off-by: fufesou <shuanglongchen@yeah.net>

* Msi. format

Signed-off-by: fufesou <shuanglongchen@yeah.net>

* Feat. Msi, set property

Signed-off-by: fufesou <shuanglongchen@yeah.net>

* Fix. Mis, only do InstallValidate if is Install

Signed-off-by: fufesou <shuanglongchen@yeah.net>

---------

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2024-04-12 17:42:26 +08:00 committed by GitHub
parent 98df2b111e
commit 8231d07706
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 581 additions and 98 deletions

View File

@ -0,0 +1,15 @@
#pragma once
#include <Windows.h>
#include <string>
bool AddFirewallRule(bool add, LPWSTR exeName, LPWSTR exeFile);
bool IsServiceRunningW(LPCWSTR serviceName);
bool MyCreateServiceW(LPCWSTR serviceName, LPCWSTR displayName, LPCWSTR binaryPath);
bool MyDeleteServiceW(LPCWSTR serviceName);
bool MyStartServiceW(LPCWSTR serviceName);
bool MyStopServiceW(LPCWSTR serviceName);
std::wstring ReadConfig(const std::wstring& filename, const std::wstring& key);

View File

@ -8,6 +8,8 @@
#include <netfw.h>
#include <shlwapi.h>
#include "./Common.h"
#pragma comment(lib, "Shlwapi.lib")
UINT __stdcall CustomActionHello(
@ -271,7 +273,6 @@ void RemoveFirewallRuleCmdline(LPWSTR exeName)
}
}
bool AddFirewallRule(bool add, LPWSTR exeName, LPWSTR exeFile);
UINT __stdcall AddFirewallRules(
__in MSIHANDLE hInstall)
{
@ -323,3 +324,220 @@ LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall SetPropertyIsServiceRunning(__in MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
DWORD er = ERROR_SUCCESS;
wchar_t szAppName[500] = { 0 };
DWORD cchAppName = sizeof(szAppName) / sizeof(szAppName[0]);
wchar_t szPropertyName[500] = { 0 };
DWORD cchPropertyName = sizeof(szPropertyName) / sizeof(szPropertyName[0]);
bool isRunning = false;
hr = WcaInitialize(hInstall, "SetPropertyIsServiceRunning");
ExitOnFailure(hr, "Failed to initialize");
MsiGetPropertyW(hInstall, L"AppName", szAppName, &cchAppName);
WcaLog(LOGMSG_STANDARD, "Try query service of : \"%ls\"", szAppName);
MsiGetPropertyW(hInstall, L"PropertyName", szPropertyName, &cchPropertyName);
WcaLog(LOGMSG_STANDARD, "Try set is service running, property name : \"%ls\"", szPropertyName);
isRunning = IsServiceRunningW(szAppName);
MsiSetPropertyW(hInstall, szPropertyName, isRunning ? L"'N'" : L"'Y'");
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall CreateStartService(__in MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
DWORD er = ERROR_SUCCESS;
LPWSTR svcParams = NULL;
LPWSTR pwz = NULL;
LPWSTR pwzData = NULL;
LPWSTR svcName = NULL;
LPWSTR svcBinary = NULL;
wchar_t szSvcDisplayName[500] = { 0 };
DWORD cchSvcDisplayName = sizeof(szSvcDisplayName) / sizeof(szSvcDisplayName[0]);
hr = WcaInitialize(hInstall, "CreateStartService");
ExitOnFailure(hr, "Failed to initialize");
hr = WcaGetProperty(L"CustomActionData", &pwzData);
ExitOnFailure(hr, "failed to get CustomActionData");
pwz = pwzData;
hr = WcaReadStringFromCaData(&pwz, &svcParams);
ExitOnFailure(hr, "failed to read database key from custom action data: %ls", pwz);
WcaLog(LOGMSG_STANDARD, "Try create start service : %ls", svcParams);
svcName = svcParams;
svcBinary = wcschr(svcParams, L';');
if (svcBinary == NULL) {
WcaLog(LOGMSG_STANDARD, "Failed to find binary : %ls", svcParams);
goto LExit;
}
svcBinary[0] = L'\0';
svcBinary += 1;
hr = StringCchPrintfW(szSvcDisplayName, cchSvcDisplayName, L"%ls Service", svcName);
ExitOnFailure(hr, "Failed to compose a resource identifier string");
if (MyCreateServiceW(svcName, szSvcDisplayName, svcBinary)) {
WcaLog(LOGMSG_STANDARD, "Service \"%ls\" is created.", svcName);
if (MyStartServiceW(svcName)) {
WcaLog(LOGMSG_STANDARD, "Service \"%ls\" is started.", svcName);
}
else {
WcaLog(LOGMSG_STANDARD, "Failed to start service: \"%ls\"", svcName);
}
}
else {
WcaLog(LOGMSG_STANDARD, "Failed to create service: \"%ls\"", svcName);
}
LExit:
if (pwzData) {
ReleaseStr(pwzData);
}
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall TryStopDeleteService(__in MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
DWORD er = ERROR_SUCCESS;
int nResult = 0;
LPWSTR svcName = NULL;
LPWSTR pwz = NULL;
LPWSTR pwzData = NULL;
wchar_t szExeFile[500] = { 0 };
DWORD cchExeFile = sizeof(szExeFile) / sizeof(szExeFile[0]);
hr = WcaInitialize(hInstall, "TryStopDeleteService");
ExitOnFailure(hr, "Failed to initialize");
hr = WcaGetProperty(L"CustomActionData", &pwzData);
ExitOnFailure(hr, "failed to get CustomActionData");
pwz = pwzData;
hr = WcaReadStringFromCaData(&pwz, &svcName);
ExitOnFailure(hr, "failed to read database key from custom action data: %ls", pwz);
WcaLog(LOGMSG_STANDARD, "Try stop and delete service : %ls", svcName);
if (MyStopServiceW(svcName)) {
for (int i = 0; i < 10; i++) {
if (IsServiceRunningW(svcName)) {
Sleep(100);
}
else {
break;
}
}
WcaLog(LOGMSG_STANDARD, "Service \"%ls\" is stopped", svcName);
}
else {
WcaLog(LOGMSG_STANDARD, "Failed to stop service: \"%ls\"", svcName);
}
if (MyDeleteServiceW(svcName)) {
WcaLog(LOGMSG_STANDARD, "Service \"%ls\" is deleted", svcName);
}
else {
WcaLog(LOGMSG_STANDARD, "Failed to delete service: \"%ls\"", svcName);
}
// It's really strange that we need sleep here.
// But the upgrading may be stucked at "copying new files" because the file is in using.
// Steps to reproduce: Install -> stop service in tray --> start service -> upgrade
// Sleep(300);
// Or we can terminate the process
hr = StringCchPrintfW(szExeFile, cchExeFile, L"%ls.exe", svcName);
ExitOnFailure(hr, "Failed to compose a resource identifier string");
TerminateProcessesByNameW(szExeFile, L"--not-in-use");
LExit:
if (pwzData) {
ReleaseStr(pwzData);
}
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall TryDeleteStartupShortcut(__in MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
DWORD er = ERROR_SUCCESS;
wchar_t szShortcut[500] = { 0 };
DWORD cchShortcut = sizeof(szShortcut) / sizeof(szShortcut[0]);
wchar_t szStartupDir[500] = { 0 };
DWORD cchStartupDir = sizeof(szStartupDir) / sizeof(szStartupDir[0]);
WCHAR pwszTemp[1024] = L"";
hr = WcaInitialize(hInstall, "DeleteStartupShortcut");
ExitOnFailure(hr, "Failed to initialize");
MsiGetPropertyW(hInstall, L"StartupFolder", szStartupDir, &cchStartupDir);
MsiGetPropertyW(hInstall, L"ShortcutName", szShortcut, &cchShortcut);
WcaLog(LOGMSG_STANDARD, "Try delete startup shortcut of : \"%ls\"", szShortcut);
hr = StringCchPrintfW(pwszTemp, 1024, L"%ls%ls.lnk", szStartupDir, szShortcut);
ExitOnFailure(hr, "Failed to compose a resource identifier string");
if (DeleteFile(pwszTemp)) {
WcaLog(LOGMSG_STANDARD, "Failed to delete startup shortcut of : \"%ls\"", pwszTemp);
}
else {
WcaLog(LOGMSG_STANDARD, "Startup shortcut is deleted : \"%ls\"", pwszTemp);
}
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall SetPropertyFromConfig(__in MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
DWORD er = ERROR_SUCCESS;
wchar_t szConfigFile[1024] = { 0 };
DWORD cchConfigFile = sizeof(szConfigFile) / sizeof(szConfigFile[0]);
wchar_t szConfigKey[500] = { 0 };
DWORD cchConfigKey = sizeof(szConfigKey) / sizeof(szConfigKey[0]);
wchar_t szPropertyName[500] = { 0 };
DWORD cchPropertyName = sizeof(szPropertyName) / sizeof(szPropertyName[0]);
std::wstring configValue;
hr = WcaInitialize(hInstall, "SetPropertyFromConfig");
ExitOnFailure(hr, "Failed to initialize");
MsiGetPropertyW(hInstall, L"ConfigFile", szConfigFile, &cchConfigFile);
WcaLog(LOGMSG_STANDARD, "Try read config file of : \"%ls\"", szConfigFile);
MsiGetPropertyW(hInstall, L"ConfigKey", szConfigKey, &cchConfigKey);
WcaLog(LOGMSG_STANDARD, "Try read configuration, config key : \"%ls\"", szConfigKey);
MsiGetPropertyW(hInstall, L"PropertyName", szPropertyName, &cchPropertyName);
WcaLog(LOGMSG_STANDARD, "Try read configuration, property name : \"%ls\"", szPropertyName);
configValue = ReadConfig(szConfigFile, szConfigKey);
MsiSetPropertyW(hInstall, szPropertyName, configValue.c_str());
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}

View File

@ -5,3 +5,8 @@ EXPORTS
RemoveInstallFolder
TerminateProcesses
AddFirewallRules
SetPropertyIsServiceRunning
TryStopDeleteService
CreateStartService
TryDeleteStartupShortcut
SetPropertyFromConfig

View File

@ -54,6 +54,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Common.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="pch.h" />
</ItemGroup>
@ -64,6 +65,8 @@
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="ReadConfig.cpp" />
<ClCompile Include="ServiceUtils.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="CustomActions.def" />

View File

@ -0,0 +1,36 @@
#include "pch.h"
#include <iostream>
#include <fstream>
#include <string>
#include <cwctype>
void trim(std::wstring& str) {
str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](wchar_t ch) {
return !std::iswspace(ch);
}));
str.erase(std::find_if(str.rbegin(), str.rend(), [](wchar_t ch) {
return !std::iswspace(ch);
}).base(), str.end());
}
std::wstring ReadConfig(const std::wstring& filename, const std::wstring& key)
{
std::wstring configValue;
std::wstring line;
std::wifstream file(filename);
while (std::getline(file, line)) {
trim(line);
if (line.find(key) == 0) {
std::size_t position = line.find(L"=", key.size());
if (position != std::string::npos) {
configValue = line.substr(position + 1);
trim(configValue);
break;
}
}
}
file.close();
return configValue;
}

View File

@ -0,0 +1,173 @@
// https://learn.microsoft.com/en-us/windows/win32/services/installing-a-service
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <strsafe.h>
bool MyCreateServiceW(LPCWSTR serviceName, LPCWSTR displayName, LPCWSTR binaryPath)
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
// Get a handle to the SCM database.
schSCManager = OpenSCManager(
NULL, // local computer
NULL, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (NULL == schSCManager)
{
WcaLog(LOGMSG_STANDARD, "OpenSCManager failed (%d)\n", GetLastError());
return false;
}
// Create the service
schService = CreateService(
schSCManager, // SCM database
serviceName, // name of service
displayName, // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type
binaryPath, // path to service's binary
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // no dependencies
NULL, // LocalSystem account
NULL); // no password
if (schService == NULL)
{
WcaLog(LOGMSG_STANDARD, "CreateService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return false;
}
else
{
WcaLog(LOGMSG_STANDARD, "Service installed successfully\n");
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return true;
}
bool MyDeleteServiceW(LPCWSTR serviceName)
{
SC_HANDLE hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
if (hSCManager == NULL) {
WcaLog(LOGMSG_STANDARD, "Failed to open Service Control Manager");
return false;
}
SC_HANDLE hService = OpenServiceW(hSCManager, serviceName, SERVICE_STOP | DELETE);
if (hService == NULL) {
WcaLog(LOGMSG_STANDARD, "Failed to open service: %ls", serviceName);
CloseServiceHandle(hSCManager);
return false;
}
SERVICE_STATUS serviceStatus;
if (ControlService(hService, SERVICE_CONTROL_STOP, &serviceStatus)) {
WcaLog(LOGMSG_STANDARD, "Stopping service: %ls", serviceName);
}
bool success = DeleteService(hService);
if (!success) {
WcaLog(LOGMSG_STANDARD, "Failed to delete service: %ls", serviceName);
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return success;
}
bool MyStartServiceW(LPCWSTR serviceName)
{
SC_HANDLE hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
if (hSCManager == NULL) {
WcaLog(LOGMSG_STANDARD, "Failed to open Service Control Manager");
return false;
}
SC_HANDLE hService = OpenServiceW(hSCManager, serviceName, SERVICE_START);
if (hService == NULL) {
WcaLog(LOGMSG_STANDARD, "Failed to open service: %ls", serviceName);
CloseServiceHandle(hSCManager);
return false;
}
bool success = StartService(hService, 0, NULL);
if (!success) {
WcaLog(LOGMSG_STANDARD, "Failed to start service: %ls", serviceName);
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return success;
}
bool MyStopServiceW(LPCWSTR serviceName)
{
SC_HANDLE hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
if (hSCManager == NULL) {
WcaLog(LOGMSG_STANDARD, "Failed to open Service Control Manager");
return false;
}
SC_HANDLE hService = OpenServiceW(hSCManager, serviceName, SERVICE_STOP);
if (hService == NULL) {
WcaLog(LOGMSG_STANDARD, "Failed to open service: %ls", serviceName);
CloseServiceHandle(hSCManager);
return false;
}
SERVICE_STATUS serviceStatus;
if (!ControlService(hService, SERVICE_CONTROL_STOP, &serviceStatus)) {
WcaLog(LOGMSG_STANDARD, "Failed to stop service: %ls", serviceName);
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return false;
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return true;
}
bool IsServiceRunningW(LPCWSTR serviceName)
{
SC_HANDLE hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
if (hSCManager == NULL) {
WcaLog(LOGMSG_STANDARD, "Failed to open Service Control Manager");
return false;
}
SC_HANDLE hService = OpenServiceW(hSCManager, serviceName, SERVICE_QUERY_STATUS);
if (hService == NULL) {
WcaLog(LOGMSG_STANDARD, "Failed to open service: %ls", serviceName);
CloseServiceHandle(hSCManager);
return false;
}
SERVICE_STATUS_PROCESS serviceStatus;
DWORD bytesNeeded;
if (!QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, reinterpret_cast<LPBYTE>(&serviceStatus), sizeof(serviceStatus), &bytesNeeded)) {
WcaLog(LOGMSG_STANDARD, "Failed to query service: %ls", serviceName);
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return false;
}
bool isRunning = (serviceStatus.dwCurrentState == SERVICE_RUNNING);
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return isRunning;
}

View File

@ -9,35 +9,67 @@
<File Id="$(var.Product).exe" Name="$(var.Product).exe" KeyPath="yes" Checksum="yes">
<!--<fire:FirewallException Id="RustDeskEx" Name="$(var.Product) Service" Scope="any" IgnoreFailure="yes" />-->
</File>
<ServiceInstall Id="ServiceInstaller" Type="ownProcess" Vital="yes" Name="$(var.Product)" DisplayName="!(loc.Service_DisplayName)" Description="!(loc.Service_Description)" Start="auto" Account="LocalSystem" ErrorControl="ignore" Interactive="no" Arguments="--service" />
<ServiceControl Id="StartService" Start="install" Stop="both" Remove="uninstall" Name="$(var.Product)" Wait="yes" />
</Component>
</DirectoryRef>
<SetProperty Id="RestartService" Value="&quot;net&quot; start $(var.Product)" Before="RestartService" Sequence="execute" />
<CustomAction Id="RestartService" DllEntry="WixQuietExec" Execute="deferred" Return="asyncWait" BinaryRef="Wix4UtilCA_$(sys.BUILDARCHSHORT)" />
<CustomAction Id="RemoveInstallFolder.SetParam" Return="check" Property="RemoveInstallFolder" Value="[INSTALLFOLDER]" />
<CustomAction Id="AddFirewallRules.SetParam" Return="check" Property="AddFirewallRules" Value="1[INSTALLFOLDER]$(var.Product).exe" />
<CustomAction Id="RemoveFirewallRules.SetParam" Return="check" Property="RemoveFirewallRules" Value="0[INSTALLFOLDER]$(var.Product).exe" />
<CustomAction Id="CreateStartService.SetParam" Return="check" Property="CreateStartService" Value="$(var.Product);&quot;[INSTALLFOLDER]$(var.Product).exe&quot; --service" />
<CustomAction Id="TryStopDeleteService.SetParam" Return="check" Property="TryStopDeleteService" Value="$(var.Product)" />
<CustomAction Id="LaunchApp" ExeCommand="" Return="asyncNoWait" FileRef="RustDesk.exe" />
<CustomAction Id="LaunchAppTray" ExeCommand=" --tray" Return="asyncNoWait" FileRef="RustDesk.exe" />
<Property Id="TerminateProcesses" Value="RustDeskTest.exe" />
<CustomAction Id="TerminateProcesses.SetParam" Return="check" Property="TerminateProcesses" Value="$(var.Product).exe" />
<CustomAction Id="TerminateBrokers.SetParam" Return="check" Property="TerminateProcesses" Value="RuntimeBroker_rustdesk.exe" />
<CustomAction Id="SetPropertyIsServiceRunning.SetParam.AppName" Return="check" Property="AppName" Value="$(var.Product)" />
<CustomAction Id="SetPropertyIsServiceRunning.SetParam.PropertyName" Return="check" Property="PropertyName" Value="STOP_SERVICE" />
<CustomAction Id="SetPropertyServiceStop.SetParam.ConfigFile" Return="check" Property="ConfigFile" Value="[AppDataFolder]rustdesk\config\rustdesk2.toml" />
<CustomAction Id="SetPropertyServiceStop.SetParam.ConfigKey" Return="check" Property="ConfigKey" Value="stop-service" />
<CustomAction Id="SetPropertyServiceStop.SetParam.PropertyName" Return="check" Property="PropertyName" Value="STOP_SERVICE" />
<CustomAction Id="TryDeleteStartupShortcut.SetParam" Return="check" Property="ShortcutName" Value="$(var.Product) Tray" />
<InstallExecuteSequence>
<!--The ServiceControl element above handles starting/stopping the server on install/uninstall,
however it also needs to be restarted after a modify or repair install. This action does
that provided the server feature is already installed and not being uninstalled.-->
<Custom Action="SetPropertyIsServiceRunning" After="InstallInitialize" Condition="Installed" />
<Custom Action="SetPropertyIsServiceRunning.SetParam.AppName" Before="SetPropertyIsServiceRunning" Condition="Installed" />
<Custom Action="SetPropertyIsServiceRunning.SetParam.PropertyName" Before="SetPropertyIsServiceRunning" Condition="Installed" />
<Custom Action="SetPropertyServiceStop" After="InstallInitialize" Condition="NOT Installed" />
<Custom Action="SetPropertyServiceStop.SetParam.ConfigFile" Before="SetPropertyServiceStop" Condition="NOT Installed" />
<Custom Action="SetPropertyServiceStop.SetParam.ConfigKey" Before="SetPropertyServiceStop" Condition="NOT Installed" />
<Custom Action="SetPropertyServiceStop.SetParam.PropertyName" Before="SetPropertyServiceStop" Condition="NOT Installed" />
<Custom Action="CreateStartService" Before="InstallFinalize" Condition="NOT STOP_SERVICE=&quot;&apos;Y&apos;&quot;" />
<Custom Action="CreateStartService.SetParam" Before="CreateStartService" Condition="NOT STOP_SERVICE=&quot;&apos;Y&apos;&quot;" />
<Custom Action="RestartService" Before="InstallFinalize" />
<Custom Action="CustomActionHello" Before="InstallFinalize" />
<!--Shortcut is in InstallValidate section. So we just let it be created, then try delete if stopping service.-->
<Custom Action="TryDeleteStartupShortcut" After="InstallFinalize" Condition="STOP_SERVICE=&quot;&apos;Y&apos;&quot;" />
<Custom Action="TryDeleteStartupShortcut.SetParam" Before="SetPropertyIsServiceRunning" Condition="STOP_SERVICE=&quot;&apos;Y&apos;&quot;" />
<!-- Launch ClientLauncher if installing or already installed and not uninstalling -->
<Custom Action="LaunchApp" After="InstallFinalize" />
<Custom Action="LaunchAppTray" After="InstallFinalize" Condition="NOT STOP_SERVICE=&quot;&apos;Y&apos;&quot;"/>
<!--Workaround of "fire:FirewallException". If Outbound="Yes" or Outbound="true", the following error occurs.-->
<!--ExecFirewallExceptions: Error 0x80070057: failed to add app to the authorized apps list-->
<Custom Action="AddFirewallRules.SetParam" Before="InstallFinalize" Condition="NOT Installed"/>
<Custom Action="AddFirewallRules" After="AddFirewallRules.SetParam"/>
<Custom Action="AddFirewallRules" Before="InstallFinalize"/>
<Custom Action="AddFirewallRules.SetParam" Before="AddFirewallRules" Condition="NOT Installed"/>
<Custom Action="RemoveInstallFolder.SetParam" After="RemoveFiles" Condition="Installed AND UPGRADINGPRODUCTCODE" />
<Custom Action="RemoveInstallFolder" After="RemoveInstallFolder.SetParam"/>
<Custom Action="RemoveFirewallRules.SetParam" Before="RemoveFiles"/>
<Custom Action="RemoveFirewallRules" After="RemoveFirewallRules.SetParam"/>
<Custom Action="RemoveInstallFolder" Before="RemoveFiles" Condition="Installed AND NOT UPGRADINGPRODUCTCODE AND REMOVE"/>
<Custom Action="RemoveInstallFolder.SetParam" Before="RemoveInstallFolder" Condition="Installed AND NOT UPGRADINGPRODUCTCODE AND REMOVE"/>
<Custom Action="TryStopDeleteService" Before="RemoveInstallFolder.SetParam" />
<Custom Action="TryStopDeleteService.SetParam" Before="TryStopDeleteService" />
<Custom Action="RemoveFirewallRules" Before="RemoveFiles"/>
<Custom Action="RemoveFirewallRules.SetParam" Before="RemoveFirewallRules"/>
<Custom Action="TerminateProcesses" Before="RemoveFiles"/>
<Custom Action="TerminateProcesses.SetParam" Before="TerminateProcesses"/>
<Custom Action="TerminateBrokers" Before="RemoveFiles"/>
<Custom Action="TerminateBrokers.SetParam" Before="TerminateBrokers"/>
</InstallExecuteSequence>
<!-- Shortcuts -->
@ -58,11 +90,6 @@
<RegistryValue Root="HKCU" Key="Software\$(var.Product)" Name="App.StartMenu.Shortcut" Type="string" Value="1" KeyPath="yes" />
</Component>
<Component Id="App.StartMenu.ShortcutTray" Guid="9362C316-40BB-41C1-859C-08182AA47E8D" Condition="STARTMENUSHORTCUTS = 1">
<Shortcut Id="App.StartMenu.ShortcutTray" Name="!(loc.SC_Client_Tray)" Description="!(loc.SC_Client_Tray_Desc)" Target="[!RustDesk.exe]" Arguments="--tray" Icon="AppIcon" WorkingDirectory="INSTALLFOLDER" />
<RegistryValue Root="HKCU" Key="Software\$(var.Product)" Name="App.StartMenu.ShortcutTray" Type="string" Value="1" KeyPath="yes" />
</Component>
<Component Id="App.StartMenu.ShortcutUninstall" Guid="E100D7F8-D607-4513-28DA-2C95E5EA698E" Condition="STARTMENUSHORTCUTS = 1">
<Shortcut Id="App.StartMenu.ShortcutUninstall" Name="!(loc.SC_Uninstall)" Description="!(loc.SC_Uninstall_Desc)" Target="[System6432Folder]msiexec.exe" Arguments="/x [ProductCode]" Icon="AppIcon" />
<RegistryValue Root="HKCU" Key="Software\$(var.Product)" Name="App.StartMenu.ShortcutUninstall" Type="string" Value="1" KeyPath="yes" />
@ -74,6 +101,12 @@
<RegistryValue Root="HKCU" Key="Software\$(var.Product)" Name="App.Desktop.Shortcut" Type="string" Value="1" KeyPath="yes" />
</Component>
</StandardDirectory>
<StandardDirectory Id="StartupFolder">
<Component Id="App.StartupFolder.ShortcutTray" Guid="B1D1E2BB-E53E-E159-DB7C-744D5C726A8C" Condition="STARTUPSHORTCUTS = 1">
<Shortcut Id="App.StartupFolder.ShortcutTray" Name="!(loc.SC_Client_Tray)" Description="!(loc.SC_Client_Tray_Desc)" Target="[!RustDesk.exe]" Arguments="--tray" Icon="AppIcon" WorkingDirectory="INSTALLFOLDER" />
<RegistryValue Root="HKCU" Key="Software\$(var.Product)" Name="App.StartupFolder.ShortcutTray" Type="string" Value="1" KeyPath="yes" />
</Component>
</StandardDirectory>
<!--<DirectoryRef Id="INSTALLFOLDER">
<Component Id="App.UninstallShortcut" Guid="FB0F2AC7-2AE5-4C54-B860-5E472620B6B1">
@ -86,8 +119,8 @@
<ComponentRef Id="App.Desktop.Shortcut" />
<!--<ComponentRef Id="App.UninstallShortcut" />-->
<ComponentRef Id="App.StartMenu.Shortcut" />
<ComponentRef Id="App.StartMenu.ShortcutTray" />
<ComponentRef Id="App.StartMenu.ShortcutUninstall" />
<ComponentRef Id="App.StartupFolder.ShortcutTray" />
<!--$AutoComonentStart$-->
<!--$AutoComponentEnd$-->

View File

@ -6,6 +6,9 @@
<Property Id="AddRemovePropertiesFile" Value="1" />
<!--STOP_SERVICE is set to 'Y'. Because the cofig value may be empty or 'Y'-->
<Property Id="STOP_SERVICE" Value="&apos;Y&apos;" />
<!--
Support entries shown when clicking "Click here for support information"
in Control Panel's Add/Remove Programs https://learn.microsoft.com/en-us/windows/win32/msi/property-reference
@ -18,7 +21,7 @@
<Property Id="ARPURLUPDATEINFO" Value="https://github.com/rustdesk/rustdesk" />-->
<Property Id="ARPPRODUCTICON" Value="AppIcon" />
<!--$ArpStart$-->
<!--$ArpEnd$-->

View File

@ -1,14 +1,19 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Fragment>
<?include ../Includes.wxi?>
<Fragment>
<?include ../Includes.wxi?>
<Binary Id="Custom_Actions_Dll" SourceFile="$(var.CustomActions.TargetDir)$(var.CustomActions.TargetName).dll" />
<Binary Id="Custom_Actions_Dll" SourceFile="$(var.CustomActions.TargetDir)$(var.CustomActions.TargetName).dll" />
<CustomAction Id="CustomActionHello" DllEntry="CustomActionHello" Impersonate="yes" Execute="immediate" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="RemoveInstallFolder" DllEntry="RemoveInstallFolder" Impersonate="no" Execute="deferred" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="TerminateProcesses" DllEntry="TerminateProcesses" Impersonate="yes" Execute="immediate" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="AddFirewallRules" DllEntry="AddFirewallRules" Impersonate="no" Execute="deferred" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="RemoveFirewallRules" DllEntry="AddFirewallRules" Impersonate="no" Execute="deferred" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
</Fragment>
<CustomAction Id="CustomActionHello" DllEntry="CustomActionHello" Impersonate="yes" Execute="immediate" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="RemoveInstallFolder" DllEntry="RemoveInstallFolder" Impersonate="no" Execute="deferred" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="TerminateProcesses" DllEntry="TerminateProcesses" Impersonate="yes" Execute="immediate" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="TerminateBrokers" DllEntry="TerminateProcesses" Impersonate="yes" Execute="immediate" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="AddFirewallRules" DllEntry="AddFirewallRules" Impersonate="no" Execute="deferred" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="RemoveFirewallRules" DllEntry="AddFirewallRules" Impersonate="no" Execute="deferred" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="SetPropertyIsServiceRunning" DllEntry="SetPropertyIsServiceRunning" Impersonate="yes" Execute="immediate" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="CreateStartService" DllEntry="CreateStartService" Impersonate="no" Execute="deferred" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="TryStopDeleteService" DllEntry="TryStopDeleteService" Impersonate="no" Execute="deferred" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="TryDeleteStartupShortcut" DllEntry="TryDeleteStartupShortcut" Impersonate="yes" Execute="immediate" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
<CustomAction Id="SetPropertyServiceStop" DllEntry="SetPropertyFromConfig" Impersonate="yes" Execute="immediate" Return="ignore" BinaryRef="Custom_Actions_Dll"/>
</Fragment>
</Wix>

View File

@ -1,51 +1,52 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Fragment>
<Fragment>
<?include ..\Includes.wxi?>
<?include ..\Includes.wxi?>
<!--
<!--
Properties and related actions for specifying whether to install start menu/desktop shortcuts.
-->
<!-- These are the actual properties that get used in conditions to determine whether to
<!-- These are the actual properties that get used in conditions to determine whether to
install start menu shortcuts, they are initialized with a default value to install shortcuts.
They should not be set directly from the command line or registry, instead the CREATE* properties
below should be set, then they will update these properties with their values only if set. -->
<Property Id="STARTMENUSHORTCUTS" Value="1" Secure="yes"></Property>
<Property Id="DESKTOPSHORTCUTS" Value="1" Secure="yes"></Property>
<Property Id="STARTMENUSHORTCUTS" Value="1" Secure="yes"></Property>
<Property Id="DESKTOPSHORTCUTS" Value="1" Secure="yes"></Property>
<Property Id="STARTUPSHORTCUTS" Value="1" Secure="yes"></Property>
<!-- These properties get set from either the command line, bundle or registry value,
<!-- These properties get set from either the command line, bundle or registry value,
if set they update the properties above with their value. -->
<Property Id="CREATESTARTMENUSHORTCUTS" Secure="yes">
<RegistrySearch Id="CreateStartMenuShortcutsSearch" Root="HKCR" Key="$(var.RegKeyRoot)" Name="STARTMENUSHORTCUTS" Type="raw" />
</Property>
<Property Id="CREATEDESKTOPSHORTCUTS" Secure="yes">
<RegistrySearch Id="CreateDesktopShortcutsSearch" Root="HKCR" Key="$(var.RegKeyRoot)" Name="DESKTOPSHORTCUTS" Type="raw" />
</Property>
<Property Id="CREATESTARTMENUSHORTCUTS" Secure="yes">
<RegistrySearch Id="CreateStartMenuShortcutsSearch" Root="HKCR" Key="$(var.RegKeyRoot)" Name="STARTMENUSHORTCUTS" Type="raw" />
</Property>
<Property Id="CREATEDESKTOPSHORTCUTS" Secure="yes">
<RegistrySearch Id="CreateDesktopShortcutsSearch" Root="HKCR" Key="$(var.RegKeyRoot)" Name="DESKTOPSHORTCUTS" Type="raw" />
</Property>
<!-- Component that persists the property values to the registry so they are available during an upgrade/modify -->
<DirectoryRef Id="INSTALLFOLDER">
<Component Id="Product.Registry.PersistedShortcutProperties" Guid="1BBAD054-6EC2-4362-BF1B-E8BDE988B597">
<RegistryKey Root="HKCR" Key="$(var.RegKeyRoot)">
<RegistryValue Type="string" Name="STARTMENUSHORTCUTS" Value="[STARTMENUSHORTCUTS]" KeyPath="yes" />
<RegistryValue Type="string" Name="DESKTOPSHORTCUTS" Value="[DESKTOPSHORTCUTS]" />
</RegistryKey>
</Component>
</DirectoryRef>
<!-- Component that persists the property values to the registry so they are available during an upgrade/modify -->
<DirectoryRef Id="INSTALLFOLDER">
<Component Id="Product.Registry.PersistedShortcutProperties" Guid="1BBAD054-6EC2-4362-BF1B-E8BDE988B597">
<RegistryKey Root="HKCR" Key="$(var.RegKeyRoot)">
<RegistryValue Type="string" Name="STARTMENUSHORTCUTS" Value="[STARTMENUSHORTCUTS]" KeyPath="yes" />
<RegistryValue Type="string" Name="DESKTOPSHORTCUTS" Value="[DESKTOPSHORTCUTS]" />
</RegistryKey>
</Component>
</DirectoryRef>
<!-- If a property value has been passed via the command line (which includes when set from the bundle), the registry search will
<!-- If a property value has been passed via the command line (which includes when set from the bundle), the registry search will
overwrite the command line value, these actions temporarily store the command line value before the registry search
is performed so they can be restored after the registry search is complete -->
<SetProperty Id="SavedStartMenuShortcutsCmdLineValue" Value="[CREATESTARTMENUSHORTCUTS]" Before="AppSearch" Sequence="first" Condition="CREATESTARTMENUSHORTCUTS" />
<SetProperty Id="SavedDesktopShortcutsCmdLineValue" Value="[CREATEDESKTOPSHORTCUTS]" Before="AppSearch" Sequence="first" Condition="CREATEDESKTOPSHORTCUTS" />
<SetProperty Id="SavedStartMenuShortcutsCmdLineValue" Value="[CREATESTARTMENUSHORTCUTS]" Before="AppSearch" Sequence="first" Condition="CREATESTARTMENUSHORTCUTS" />
<SetProperty Id="SavedDesktopShortcutsCmdLineValue" Value="[CREATEDESKTOPSHORTCUTS]" Before="AppSearch" Sequence="first" Condition="CREATEDESKTOPSHORTCUTS" />
<!-- If a command line value was stored, restore it after the registry search has been performed -->
<SetProperty Action="RestoreSavedStartMenuShortcutsValue" Id="CREATESTARTMENUSHORTCUTS" Value="[SavedStartMenuShortcutsCmdLineValue]" After="AppSearch" Sequence="first" Condition="SavedStartMenuShortcutsCmdLineValue" />
<SetProperty Action="RestoreSavedDesktopShortcutsValue" Id="CREATEDESKTOPSHORTCUTS" Value="[SavedDesktopShortcutsCmdLineValue]" After="AppSearch" Sequence="first" Condition="SavedDesktopShortcutsCmdLineValue" />
<!-- If a command line value was stored, restore it after the registry search has been performed -->
<SetProperty Action="RestoreSavedStartMenuShortcutsValue" Id="CREATESTARTMENUSHORTCUTS" Value="[SavedStartMenuShortcutsCmdLineValue]" After="AppSearch" Sequence="first" Condition="SavedStartMenuShortcutsCmdLineValue" />
<SetProperty Action="RestoreSavedDesktopShortcutsValue" Id="CREATEDESKTOPSHORTCUTS" Value="[SavedDesktopShortcutsCmdLineValue]" After="AppSearch" Sequence="first" Condition="SavedDesktopShortcutsCmdLineValue" />
<!-- If a command line value or registry value was set, update the main properties with the value -->
<SetProperty Id="STARTMENUSHORTCUTS" Value="[CREATESTARTMENUSHORTCUTS]" After="RestoreSavedStartMenuShortcutsValue" Sequence="first" Condition="CREATESTARTMENUSHORTCUTS" />
<SetProperty Id="DESKTOPSHORTCUTS" Value="[CREATEDESKTOPSHORTCUTS]" After="RestoreSavedDesktopShortcutsValue" Sequence="first" Condition="CREATEDESKTOPSHORTCUTS" />
<!-- If a command line value or registry value was set, update the main properties with the value -->
<SetProperty Id="STARTMENUSHORTCUTS" Value="[CREATESTARTMENUSHORTCUTS]" After="RestoreSavedStartMenuShortcutsValue" Sequence="first" Condition="CREATESTARTMENUSHORTCUTS" />
<SetProperty Id="DESKTOPSHORTCUTS" Value="[CREATEDESKTOPSHORTCUTS]" After="RestoreSavedDesktopShortcutsValue" Sequence="first" Condition="CREATEDESKTOPSHORTCUTS" />
</Fragment>
</Fragment>
</Wix>

View File

@ -1,10 +1,10 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Fragment>
<Fragment>
<Property Id="UpgradesFile" Value="1" />
<Property Id="UpgradesFile" Value="1" />
<!--$UpgradeStart$-->
<!--$UpgradeEnd$-->
<!--$UpgradeStart$-->
<!--$UpgradeEnd$-->
</Fragment>
</Fragment>
</Wix>

View File

@ -9,7 +9,7 @@
<SummaryInformation Keywords="Installer" Description="$(var.Description)" Codepage="!(loc.SummaryCodepage)" />
<!--<PropertyRef Id="UpgradesFile" />-->
<PropertyRef Id="AddRemovePropertiesFile" />
<Media Id="1" Cabinet="cab1.cab" EmbedCab="yes" CompressionLevel="high" />
@ -26,25 +26,15 @@
</InstallUISequence>
<InstallExecuteSequence>
<!-- Launch ClientLauncher if installing or already installed and not uninstalling -->
<Custom Action="LaunchApp" After="InstallFinalize" />
<Custom Action="LaunchAppTray" After="InstallFinalize" />
<InstallExecute After="RemoveExistingProducts" />
<!--Only do InstallValidate if is not Uninstall-->
<!--Do InstallValidate if is Install, Change, Repair, Upgrade-->
<InstallValidate Condition="NOT (Installed AND REMOVE AND NOT UPGRADINGPRODUCTCODE )" />
<Custom Action="TerminateProcesses" Before="RemoveFiles"/>
<Custom Action="TerminateProcesses.SetParam" Before="TerminateProcesses"/>
<!--<InstallValidate Condition="NOT (Installed AND REMOVE AND NOT UPGRADINGPRODUCTCODE )" />-->
<!--Only do InstallValidate if is Install-->
<InstallValidate Condition="NOT Installed" />
</InstallExecuteSequence>
<CustomAction Id="LaunchApp" ExeCommand="" Return="asyncNoWait" FileRef="RustDesk.exe" />
<CustomAction Id="LaunchAppTray" ExeCommand=" --tray" Return="asyncNoWait" FileRef="RustDesk.exe" />
<Property Id="TerminateProcesses" Value="RustDeskTest.exe" />
<CustomAction Id="TerminateProcesses.SetParam" Return="check" Property="TerminateProcesses" Value="$(var.Product).exe" />
<MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" Schedule="afterInstallInitialize" AllowSameVersionUpgrades="yes" />
<Feature Id="App" Level="1" AllowAdvertise="no" Display="expand" Title="!(loc.F_App)" Description="!(loc.F_App_Desc)" AllowAbsent="no">

View File

@ -1,15 +1,15 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Fragment>
<UI>
<Dialog Id="AnotherAppDialog" Width="370" Height="270" Title="!(loc.ExitDialog_Title)">
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="!(loc.WixUICancel)">
<Publish Event="EndDialog" Value="ErrorAbort" />
</Control>
<Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="!(loc.ExitDialogBitmap)" />
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
<Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="40" Transparent="yes" NoPrefix="yes" Text="!(loc.AnotherAppDialogDescription)" />
<Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="!(loc.AnotherAppDialogTitle)" />
</Dialog>
</UI>
</Fragment>
<Fragment>
<UI>
<Dialog Id="AnotherAppDialog" Width="370" Height="270" Title="!(loc.ExitDialog_Title)">
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="!(loc.WixUICancel)">
<Publish Event="EndDialog" Value="ErrorAbort" />
</Control>
<Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="!(loc.ExitDialogBitmap)" />
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
<Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="40" Transparent="yes" NoPrefix="yes" Text="!(loc.AnotherAppDialogDescription)" />
<Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="!(loc.AnotherAppDialogTitle)" />
</Dialog>
</UI>
</Fragment>
</Wix>

View File

@ -39,5 +39,6 @@ Run `msiexec /i package.msi /l*v install.log` to record the log.
## Refs
1. [windows-installer-portal](https://learn.microsoft.com/en-us/windows/win32/Msi/windows-installer-portal)
1. [wxs](https://wixtoolset.org/docs/schema/wxs/)
1. [wxs github](https://github.com/wixtoolset/wix)