You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测可执行文件是以Windows服务还是普通程序方式启动?

检测Windows程序是否以服务方式启动(MinGW环境)

在MinGW开发Windows服务时,你可以通过以下两种可靠方法判断程序是否以服务方式启动,再决定是否初始化SERVICE_TABLE_ENTRY。

方法1:利用IsProcessInJob API判断

服务进程通常会被服务控制管理器(SCM)纳入Job对象管理,通过IsProcessInJob可检测当前进程是否属于此类Job:

#include <windows.h>

BOOL IsRunningAsService() {
    HANDLE hCurrentProcess = GetCurrentProcess();
    BOOL isInJob = FALSE;
    // 传入NULL表示检查是否属于任意Job对象
    if (!IsProcessInJob(hCurrentProcess, NULL, &isInJob)) {
        // 调用失败时默认返回FALSE(兼容低版本系统)
        return FALSE;
    }
    return isInJob;
}

该方法简洁高效,大部分场景下足够准确,仅需链接kernel32.lib(MinGW编译时默认包含)。

方法2:检查父进程是否为services.exe

服务进程的直接父进程是系统的services.exe,通过遍历进程快照可验证这一点:

#include <windows.h>
#include <tlhelp32.h>
#include <string.h>

BOOL IsRunningAsService() {
    DWORD currentPid = GetCurrentProcessId();
    DWORD parentPid = 0;

    // 获取进程快照
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) return FALSE;

    PROCESSENTRY32 pe = { .dwSize = sizeof(PROCESSENTRY32) };
    if (Process32First(hSnapshot, &pe)) {
        do {
            if (pe.th32ProcessID == currentPid) {
                parentPid = pe.th32ParentProcessID;
                break;
            }
        } while (Process32Next(hSnapshot, &pe));
    }
    CloseHandle(hSnapshot);

    if (parentPid == 0) return FALSE;

    // 查询父进程名称
    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) return FALSE;

    BOOL isService = FALSE;
    if (Process32First(hSnapshot, &pe)) {
        do {
            if (pe.th32ProcessID == parentPid) {
                if (_stricmp(pe.szExeFile, "services.exe") == 0) {
                    isService = TRUE;
                }
                break;
            }
        } while (Process32Next(hSnapshot, &pe));
    }
    CloseHandle(hSnapshot);

    return isService;
}

编译时需链接psapi.lib和kernel32.lib,MinGW编译命令:

gcc -o MyService.exe MyService.c -lpsapi -lkernel32

主程序逻辑示例

将检测逻辑整合到主函数中,按需初始化服务或执行普通进程逻辑:

#include <windows.h>
#include <stdio.h>

// 引入上面的IsRunningAsService函数

VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv) {
    SERVICE_STATUS_HANDLE hServiceStatus = RegisterServiceCtrlHandler(L"MyService", ServiceCtrlHandler);
    SERVICE_STATUS serviceStatus = {
        .dwServiceType = SERVICE_WIN32_OWN_PROCESS,
        .dwCurrentState = SERVICE_RUNNING,
        .dwControlsAccepted = SERVICE_ACCEPT_STOP
    };
    SetServiceStatus(hServiceStatus, &serviceStatus);

    // 服务核心逻辑
    // ...

    // 服务停止时更新状态
    serviceStatus.dwCurrentState = SERVICE_STOPPED;
    SetServiceStatus(hServiceStatus, &serviceStatus);
}

VOID WINAPI ServiceCtrlHandler(DWORD ctrlCode) {
    // 处理服务控制命令(停止、暂停等)
    switch (ctrlCode) {
        case SERVICE_CONTROL_STOP:
            // 执行停止逻辑
            break;
        default:
            break;
    }
}

int main(int argc, char* argv[]) {
    if (IsRunningAsService()) {
        SERVICE_TABLE_ENTRY serviceTable[] = {
            {L"MyService", (LPSERVICE_MAIN_FUNCTION)ServiceMain},
            {NULL, NULL}
        };
        if (!StartServiceCtrlDispatcher(serviceTable)) {
            return GetLastError();
        }
    } else {
        // 普通进程模式逻辑,比如控制台交互、调试输出
        printf("Running as normal process\n");
        // ... 你的业务代码
    }
    return 0;
}

测试说明

  1. 服务模式:用sc create MyService binPath= "C:\path\to\MyService.exe"创建服务,sc start MyService启动
  2. 普通模式:直接双击可执行文件或在控制台运行

内容的提问来源于stack exchange,提问作者Gusteivos gp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 21:35:14