Как проверить, что текущий процесс работает как служба Windows, используя функции WinAPI? - PullRequest
3 голосов
/ 04 апреля 2019

У меня есть программа, которая может быть запущена как простое консольное приложение или может быть зарегистрирована как служба Windows.Я хочу определить в main() функции текущий текущий контекст:

#include <windows.h>

BOOL IsWindowsService()
{
    ???
}

int main(int argc, char** argv)
{
    if (IsWindowsService())
    {
        // Running as Windows Service...
        RunService();
        return;
    }

    // Running as console application...    
    return 0;
}

Основной вариант использования - иметь один exe-файл, который можно установить и запустить как службу Windows с помощью '--installАргументы 'и' --start 'или выполнены без параметров в режиме консоли (например, из отладчика VS).

Можете ли вы помочь мне с возможной реализацией функции IsWindowsService()?

Ответы [ 5 ]

3 голосов
/ 04 апреля 2019
int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
    { 
    SERVICE_TABLE_ENTRY ServiceTable[] =
    {
        { SERVICE_NAME,(LPSERVICE_MAIN_FUNCTION)ServiceMain },
    { NULL,NULL }
    };
    if (StartServiceCtrlDispatcher(ServiceTable))
        //service
    else app; // last error ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
}


VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{...}

Документация https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-startservicectrldispatchera

0 голосов
/ 13 апреля 2019

Кажется, что я нашел элегантное решение для проблемы, которое не требует предоставления специального аргумента командной строки для обработки (решение, предоставляемое @RbMn):

BOOL IsWindowsService()
{
    DWORD sessionId = 0;
    ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
    return !sessionId;
}

Это решение работает, потому что все службы Windows работают в сеансе 0 вместе с приложениями .

0 голосов
/ 12 апреля 2019

Вы можете использовать функцию system () . Он выполнит любую команду, которая может быть запущена в командной строке. Используйте это так:

system("tasklist > tasks.txt");

При этом все запущенные задачи будут сохранены в tasks.txt . Затем вы можете проверить, работает ваша программа или нет, выполнив поиск в файле.

для получения дополнительной информации о список задач , запустите командную строку, выполните это:

tasklist /?
0 голосов
/ 07 апреля 2019

Обычно это делается для облегчения отладки кода. Вам нужно прочитать эту страницу MSDN , заметки о ведении журнала очень важны, потому что эти операторы printf () сейчас довольно привлекательны, но вы будете слепы, как летучая мышь, когда они работают как служба.

В последнем абзаце рассказывается, как узнать, действительно ли ваша программа работает как консольное приложение. Цитирование:

Иногда может потребоваться запустить службу как консольное приложение для целей отладки. В этом случае функция StartServiceCtrlDispatcher вернет ERROR_FAILED_SERVICE_CONTROLLER_CONNECT. Поэтому убедитесь, что ваш код структурирован так, чтобы при возврате этой ошибки не вызывался специфичный для службы код.

Так легко, просто, всегда вызывайте StartServiceCtrlDispatcher () и обращайте внимание на возвращаемое значение FALSE и код возврата GetLastError ().

0 голосов
/ 05 апреля 2019

Общий подход таков: во-первых, получите идентификатор текущего процесса с помощью GetCurrentProcessId .Затем получите список всех запущенных служб с помощью EnumServicesStatusEx , чтобы проверить, соответствует ли pid текущему pid.

BOOL IsWindowsService()
{
    LONG lRet = 0;
    BOOL bRet = FALSE;
    SC_HANDLE hSCM = NULL;
    char *pBuf = NULL;
    DWORD dwBufSize = 0;
    DWORD dwBufNeed = 0;
    DWORD dwNumberOfService = 0;
    ENUM_SERVICE_STATUS_PROCESS *pServiceInfo = NULL;

    hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT);
    if (NULL == hSCM)
    {
        printf("OpenSCManager error.\n");
        return false;
    }
    EnumServicesStatusEx(hSCM, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, dwBufSize, &dwBufNeed, &dwNumberOfService, NULL, NULL);
    dwBufSize = dwBufNeed + sizeof(ENUM_SERVICE_STATUS_PROCESS);
    pBuf = (char *)malloc(dwBufSize);
    memset(pBuf, 0, dwBufSize);
    bRet = EnumServicesStatusEx(hSCM, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, (LPBYTE)pBuf, dwBufSize, &dwBufNeed, &dwNumberOfService, NULL, NULL);
    if (bRet == FALSE)
    {
        printf("EnumServicesStatusEx error.\n");
        ::CloseServiceHandle(hSCM);
        free(pBuf);
        return false;
    }
    CloseServiceHandle(hSCM);
    pServiceInfo = (LPENUM_SERVICE_STATUS_PROCESS)pBuf;
    DWORD id = GetCurrentProcessId();
    for (unsigned int i = 0; i < dwNumberOfService; i++)
    {
        if (pServiceInfo[i].ServiceStatusProcess.dwProcessId == id)
            return true;
    }
    free(pBuf);
    return false;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...