Проверьте, запущено ли Windows-приложение как служба

#winapi

#winapi

Вопрос:

Есть ли способ определить, запускается ли Windows-процесс как служба? Существует ли какой-либо фиксированный родительский процесс всех служб, который я могу идентифицировать, чтобы гарантировать, что процесс является сервисным процессом.

Комментарии:

1. возможно, используйте EnumServicesStatusExW для получения идентификатора процесса всех служб и сравнения с известным. но какой в этом смысл?

2. Некоторые службы выполняются внутри svchost.exe процесса, но большинство служб выполняются как автономные процессы. Итак, если scm.exe при перечислении процессов не отображается как родительский процесс Process32(First|Next)() , все, что вы можете сделать, это перечислить установленные службы в поисках .exe интересующего вас файла или идентификатора процесса.

3. Я хочу знать, запускается ли приложение из командной строки или как служба. EnumServicesStatusExW не помогает, потому что вызов будет выполнен до того, как EXE-файл будет зарегистрирован SCM.

4. Я хочу знать, запускается ли приложение из командной строки или как служба — вам нужно установить специальный параметр тега в command ( lpBinaryPathName ) при регистрации собственного приложения в качестве службы и при запуске — просто проверьте командную строку

Ответ №1:

если приложение предназначено для запуска как как служба, так и как отдельное приложение, лучший способ узнать, как запущено приложение — использовать командную строку. когда вы регистрируете службу с помощью CreateServiceW — передайте lpBinaryPathName некоторые аргументы. а затем при запуске — проверьте строку, возвращаемую GetCommandLineW() — присутствуют ли эти аргументы. если да — вы запускаетесь как служба, если нет — как отдельное приложение.

например, добавьте n символ к пути к двоичному файлу службы :

 WCHAR BinaryPathName[MAX_PATH   3];
ULONG cch = GetModuleFileNameW(0, BinaryPathName   1, _countof(BinaryPathName) - 3);
if (GetLastError() == NOERROR)
{
    BinaryPathName[0] = '"';
    BinaryPathName[cch   1] = '"';
    BinaryPathName[cch   2] = 'n';
    BinaryPathName[cch   3] = 0;
    //CreateServiceW(.., BinaryPathName, ..);
}
 

n (выбрано, потому что этот символ не может быть в командной строке, если выполнить приложение вручную)

а затем в точке входа приложения выполните очень простую и быструю проверку

 if (wcschr(GetCommandLineW(), 'n'))
{
    const static SERVICE_TABLE_ENTRY ste[] = { { L"my_service_name", ServiceMain }, {} };
    StartServiceCtrlDispatcher(ste);
}
else 
{
  // run as standalone application
}
 

я думаю, что это решение является лучшим. однако возможны и другие. например, мы можем выполнить следующую проверку:

 ULONG SessionId;
if (ProcessIdToSessionId(GetCurrentProcessId(), amp;SessionId) amp;amp; 
    WTSGetActiveConsoleSessionId() == SessionId)
{
    // we not run as service;
}