mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-04-13 11:01:29 +03:00
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:
15
res/msi/CustomActions/Common.h
Normal file
15
res/msi/CustomActions/Common.h
Normal 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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -5,3 +5,8 @@ EXPORTS
|
||||
RemoveInstallFolder
|
||||
TerminateProcesses
|
||||
AddFirewallRules
|
||||
SetPropertyIsServiceRunning
|
||||
TryStopDeleteService
|
||||
CreateStartService
|
||||
TryDeleteStartupShortcut
|
||||
SetPropertyFromConfig
|
||||
|
||||
@@ -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" />
|
||||
|
||||
36
res/msi/CustomActions/ReadConfig.cpp
Normal file
36
res/msi/CustomActions/ReadConfig.cpp
Normal 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;
|
||||
}
|
||||
173
res/msi/CustomActions/ServiceUtils.cpp
Normal file
173
res/msi/CustomActions/ServiceUtils.cpp
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user