gpt4 book ai didi

c++ - 我们如何判断 C++ 应用程序是否作为 Windows 服务启动?

转载 作者:可可西里 更新时间:2023-11-01 18:18:11 28 4
gpt4 key购买 nike

我们有一个控制台应用程序,我们从命令提示符启动以进行调试,但我们也将其作为 NT 服务启动以用于生产。

现在,代码具有以下逻辑:

if (__argc <= 1) {
assumeService();
} else {
assumeForgound();
}

有没有更好的方法来检查流程是如何启动的?我们是一个开源项目,所以每次我们有新的 Windows 开发人员时,我们都必须解释他们必须指定 -f arg 来阻止应用程序连接到服务 Controller 。

检查父进程呢?

更新:

我忘了说我们使用的是 C++(非托管)。

最佳答案

您可以检查进程父进程是services.exe 还是svchost.exe。或者您可以使用 WinApi 查询服务控制管理器您的服务是否已启动以及当前进程 ID 是否等于已启动服务之一。

在 C# 中,以下代码会执行此操作(因为它是基于 WinApi 的,因此在 C++ 中应该类似地工作,示例代码 here ):

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;

class Program
{
static void Main(string[] args)
{
if (IsRunningAsService("myServiceName"))
{
Console.WriteLine("I'm a service.");
}
else
{
Console.WriteLine("I'm not a service.");
}
}

static bool IsRunningAsService(string serviceName)
{
IntPtr serviceManagerHandle = WinApi.OpenSCManager(null, null, (uint)WinApi.SCM_ACCESS.SC_MANAGER_ALL_ACCESS);
if (serviceManagerHandle == IntPtr.Zero)
{
throw new Win32Exception();
}

IntPtr serviceHandle = WinApi.OpenService(serviceManagerHandle, serviceName, (uint)WinApi.SERVICE_ACCESS.SERVICE_ALL_ACCESS);
if (serviceHandle == IntPtr.Zero)
{
throw new Win32Exception();
}

WinApi.SERVICE_STATUS_PROCESS serviceStatus = new WinApi.SERVICE_STATUS_PROCESS();
byte[] buffer = new byte[1000];
int bytesNeeded;
GCHandle bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try
{
bool success = WinApi.QueryServiceStatusEx(serviceHandle, WinApi.SC_STATUS_PROCESS_INFO, buffer, 1000, out bytesNeeded);
if (!success)
{
throw new Win32Exception();
}
IntPtr buffIntPtr = bufferHandle.AddrOfPinnedObject();
Marshal.PtrToStructure(buffIntPtr, serviceStatus);
}
finally
{
bufferHandle.Free();
}

WinApi.CloseServiceHandle(serviceHandle);
WinApi.CloseServiceHandle(serviceManagerHandle);

return Process.GetCurrentProcess().Id == serviceStatus.processID;
}
}

Windows API 导入:

class WinApi
{
[DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);

[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseServiceHandle(IntPtr hSCObject);

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);

[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ControlService(IntPtr hService, SERVICE_CONTROL dwControl, ref SERVICE_STATUS lpServiceStatus);

[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool QueryServiceStatusEx(IntPtr serviceHandle, int infoLevel, byte[] buffer, int bufferSize, out int bytesNeeded);

[Flags]
public enum SCM_ACCESS : uint
{
/// <summary>
/// Required to connect to the service control manager.
/// </summary>
SC_MANAGER_CONNECT = 0x00001,

/// <summary>
/// Required to call the CreateService function to create a service
/// object and add it to the database.
/// </summary>
SC_MANAGER_CREATE_SERVICE = 0x00002,

/// <summary>
/// Required to call the EnumServicesStatusEx function to list the
/// services that are in the database.
/// </summary>
SC_MANAGER_ENUMERATE_SERVICE = 0x00004,

/// <summary>
/// Required to call the LockServiceDatabase function to acquire a
/// lock on the database.
/// </summary>
SC_MANAGER_LOCK = 0x00008,

/// <summary>
/// Required to call the QueryServiceLockStatus function to retrieve
/// the lock status information for the database.
/// </summary>
SC_MANAGER_QUERY_LOCK_STATUS = 0x00010,

/// <summary>
/// Required to call the NotifyBootConfigStatus function.
/// </summary>
SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020,

/// <summary>
/// Includes STANDARD_RIGHTS_REQUIRED, in addition to all access
/// rights in this table.
/// </summary>
SC_MANAGER_ALL_ACCESS = ACCESS_MASK.STANDARD_RIGHTS_REQUIRED |
SC_MANAGER_CONNECT |
SC_MANAGER_CREATE_SERVICE |
SC_MANAGER_ENUMERATE_SERVICE |
SC_MANAGER_LOCK |
SC_MANAGER_QUERY_LOCK_STATUS |
SC_MANAGER_MODIFY_BOOT_CONFIG,

GENERIC_READ = ACCESS_MASK.STANDARD_RIGHTS_READ |
SC_MANAGER_ENUMERATE_SERVICE |
SC_MANAGER_QUERY_LOCK_STATUS,

GENERIC_WRITE = ACCESS_MASK.STANDARD_RIGHTS_WRITE |
SC_MANAGER_CREATE_SERVICE |
SC_MANAGER_MODIFY_BOOT_CONFIG,

GENERIC_EXECUTE = ACCESS_MASK.STANDARD_RIGHTS_EXECUTE |
SC_MANAGER_CONNECT | SC_MANAGER_LOCK,

GENERIC_ALL = SC_MANAGER_ALL_ACCESS,
}

[Flags]
enum ACCESS_MASK : uint
{
DELETE = 0x00010000,
READ_CONTROL = 0x00020000,
WRITE_DAC = 0x00040000,
WRITE_OWNER = 0x00080000,
SYNCHRONIZE = 0x00100000,

STANDARD_RIGHTS_REQUIRED = 0x000f0000,

STANDARD_RIGHTS_READ = 0x00020000,
STANDARD_RIGHTS_WRITE = 0x00020000,
STANDARD_RIGHTS_EXECUTE = 0x00020000,

STANDARD_RIGHTS_ALL = 0x001f0000,

SPECIFIC_RIGHTS_ALL = 0x0000ffff,

ACCESS_SYSTEM_SECURITY = 0x01000000,

MAXIMUM_ALLOWED = 0x02000000,

GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_ALL = 0x10000000,

DESKTOP_READOBJECTS = 0x00000001,
DESKTOP_CREATEWINDOW = 0x00000002,
DESKTOP_CREATEMENU = 0x00000004,
DESKTOP_HOOKCONTROL = 0x00000008,
DESKTOP_JOURNALRECORD = 0x00000010,
DESKTOP_JOURNALPLAYBACK = 0x00000020,
DESKTOP_ENUMERATE = 0x00000040,
DESKTOP_WRITEOBJECTS = 0x00000080,
DESKTOP_SWITCHDESKTOP = 0x00000100,

WINSTA_ENUMDESKTOPS = 0x00000001,
WINSTA_READATTRIBUTES = 0x00000002,
WINSTA_ACCESSCLIPBOARD = 0x00000004,
WINSTA_CREATEDESKTOP = 0x00000008,
WINSTA_WRITEATTRIBUTES = 0x00000010,
WINSTA_ACCESSGLOBALATOMS = 0x00000020,
WINSTA_EXITWINDOWS = 0x00000040,
WINSTA_ENUMERATE = 0x00000100,
WINSTA_READSCREEN = 0x00000200,

WINSTA_ALL_ACCESS = 0x0000037f
}

[Flags]
public enum SERVICE_ACCESS : uint
{
STANDARD_RIGHTS_REQUIRED = 0xF0000,
SERVICE_QUERY_CONFIG = 0x00001,
SERVICE_CHANGE_CONFIG = 0x00002,
SERVICE_QUERY_STATUS = 0x00004,
SERVICE_ENUMERATE_DEPENDENTS = 0x00008,
SERVICE_START = 0x00010,
SERVICE_STOP = 0x00020,
SERVICE_PAUSE_CONTINUE = 0x00040,
SERVICE_INTERROGATE = 0x00080,
SERVICE_USER_DEFINED_CONTROL = 0x00100,
SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
SERVICE_QUERY_CONFIG |
SERVICE_CHANGE_CONFIG |
SERVICE_QUERY_STATUS |
SERVICE_ENUMERATE_DEPENDENTS |
SERVICE_START |
SERVICE_STOP |
SERVICE_PAUSE_CONTINUE |
SERVICE_INTERROGATE |
SERVICE_USER_DEFINED_CONTROL)
}

[Flags]
public enum SERVICE_CONTROL : uint
{
STOP = 0x00000001,
PAUSE = 0x00000002,
CONTINUE = 0x00000003,
INTERROGATE = 0x00000004,
SHUTDOWN = 0x00000005,
PARAMCHANGE = 0x00000006,
NETBINDADD = 0x00000007,
NETBINDREMOVE = 0x00000008,
NETBINDENABLE = 0x00000009,
NETBINDDISABLE = 0x0000000A,
DEVICEEVENT = 0x0000000B,
HARDWAREPROFILECHANGE = 0x0000000C,
POWEREVENT = 0x0000000D,
SESSIONCHANGE = 0x0000000E
}

public enum SERVICE_STATE : uint
{
SERVICE_STOPPED = 0x00000001,
SERVICE_START_PENDING = 0x00000002,
SERVICE_STOP_PENDING = 0x00000003,
SERVICE_RUNNING = 0x00000004,
SERVICE_CONTINUE_PENDING = 0x00000005,
SERVICE_PAUSE_PENDING = 0x00000006,
SERVICE_PAUSED = 0x00000007
}

[Flags]
public enum SERVICE_ACCEPT : uint
{
STOP = 0x00000001,
PAUSE_CONTINUE = 0x00000002,
SHUTDOWN = 0x00000004,
PARAMCHANGE = 0x00000008,
NETBINDCHANGE = 0x00000010,
HARDWAREPROFILECHANGE = 0x00000020,
POWEREVENT = 0x00000040,
SESSIONCHANGE = 0x00000080,
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SERVICE_STATUS
{
public static readonly int SizeOf = Marshal.SizeOf(typeof(SERVICE_STATUS));
public SERVICE_TYPES dwServiceType;
public SERVICE_STATE dwCurrentState;
public uint dwControlsAccepted;
public uint dwWin32ExitCode;
public uint dwServiceSpecificExitCode;
public uint dwCheckPoint;
public uint dwWaitHint;
}

[Flags]
public enum SERVICE_TYPES : int
{
SERVICE_KERNEL_DRIVER = 0x00000001,
SERVICE_FILE_SYSTEM_DRIVER = 0x00000002,
SERVICE_WIN32_OWN_PROCESS = 0x00000010,
SERVICE_WIN32_SHARE_PROCESS = 0x00000020,
SERVICE_INTERACTIVE_PROCESS = 0x00000100
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class SERVICE_STATUS_PROCESS
{
public int serviceType;
public int currentState;
public int controlsAccepted;
public int win32ExitCode;
public int serviceSpecificExitCode;
public int checkPoint;
public int waitHint;
public int processID;
public int serviceFlags;
}

public const int SC_STATUS_PROCESS_INFO = 0;
}

相同函数的 C++ 版本:

#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <aclapi.h>
#include <stdio.h>

bool IsRunningAsService(const TCHAR* szSvcName)
{
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwBytesNeeded;

SC_HANDLE schSCManager = OpenSCManager(
NULL, // local computer
NULL, // servicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights

if (NULL == schSCManager)
{
printf("OpenSCManager failed (%d)\n", GetLastError());
return false;
}

// Get a handle to the service.
SC_HANDLE schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
SERVICE_ALL_ACCESS); // full access

if (schService == NULL)
{
printf("OpenService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return false;
}

// Check the status in case the service is not stopped.

if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // information level
(LPBYTE) &ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded ) ) // size needed if buffer is too small
{
printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return false;
}

return GetCurrentProcessId() == ssStatus.dwProcessId;
}

关于c++ - 我们如何判断 C++ 应用程序是否作为 Windows 服务启动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1974828/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com