Оконные Услуги - PullRequest
       16

Оконные Услуги

0 голосов
/ 26 апреля 2018

Я написал простую службу Windows, которая записывает информацию о памяти в текстовый файл:

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <string>

using namespace std;

#define SLEEP_TIME 5000
#define LOGFILE "C:\\MyServices\\memstatus.txt"

SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;

void  ServiceMain(int argc, char** argv);
void  ControlHandler(DWORD request);
int InitService();

int WriteToLog(string file_name, string input)
{
    FILE *f;
    fopen_s(&f, file_name.c_str(), "a+");
    fprintf(f, "%s\n", input.c_str());
    fclose(f);
    return 0;
}

string N = "MemoryStatus";
LPWSTR Name = new wchar_t(N.size() + 1);

int main()
{
    SERVICE_TABLE_ENTRY ServiceTable[2];
    ServiceTable[0].lpServiceName = Name;
    ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;

    ServiceTable[1].lpServiceName = NULL;
    ServiceTable[1].lpServiceProc = NULL;
    // Start the control dispatcher thread for our service
    StartServiceCtrlDispatcher(ServiceTable);
    return 0;
}


void ServiceMain(int argc, char** argv)
{
    int error;

    ServiceStatus.dwServiceType = SERVICE_WIN32;
    ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
    ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    ServiceStatus.dwWin32ExitCode = 0;
    ServiceStatus.dwServiceSpecificExitCode = 0;
    ServiceStatus.dwCheckPoint = 0;
    ServiceStatus.dwWaitHint = 0;

    hStatus = RegisterServiceCtrlHandler(
        Name,
        (LPHANDLER_FUNCTION)ControlHandler);
    if (hStatus == (SERVICE_STATUS_HANDLE)0)
    {
        // Registering Control Handler failed
        return;
    }
    // Initialize Service 
    error = InitService();
    if (error)
    {
        // Initialization failed
        ServiceStatus.dwCurrentState = SERVICE_STOPPED;
        ServiceStatus.dwWin32ExitCode = -1;
        SetServiceStatus(hStatus, &ServiceStatus);
        return;
    }
    // We report the running status to SCM. 
    ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    SetServiceStatus(hStatus, &ServiceStatus);

    MEMORYSTATUS memory;
    // The worker loop of a service
    while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
    {
        char buffer[16];
        GlobalMemoryStatus(&memory);
        sprintf_s(buffer, "%d", memory.dwAvailPhys);
        int result = WriteToLog("TestFile.txt", buffer);
        if (result)
        {
            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
            ServiceStatus.dwWin32ExitCode = -1;
            SetServiceStatus(hStatus, &ServiceStatus);
            return;
        }

        Sleep(SLEEP_TIME);
    }
    return;
}

// Service initialization
int InitService()
{
    int result;
    result = WriteToLog("TestFile.txt", "Monitoring started.");
    return(result);
}

// Control handler function
void ControlHandler(DWORD request)
{
    switch (request)
    {
    case SERVICE_CONTROL_STOP:
        WriteToLog("TestFile.txt", "Monitoring stopped.");

        ServiceStatus.dwWin32ExitCode = 0;
        ServiceStatus.dwCurrentState = SERVICE_STOPPED;
        SetServiceStatus(hStatus, &ServiceStatus);
        return;

    case SERVICE_CONTROL_SHUTDOWN:
        WriteToLog("TestFile.txt", "Monitoring stopped.");

        ServiceStatus.dwWin32ExitCode = 0;
        ServiceStatus.dwCurrentState = SERVICE_STOPPED;
        SetServiceStatus(hStatus, &ServiceStatus);
        return;

    default:
        break;
    }

    // Report current status
    SetServiceStatus(hStatus, &ServiceStatus);

    return;
}

Я успешно установил его, но диспетчер задач показывает его состояние как остановленное. Когда я щелкаю правой кнопкой мыши и нажимаю кнопку «Пуск», я получаю сообщение об ошибке, что система не может найти указанный файл.

Почти во всех примерах, которые я использовал в StackOverflow или где-либо еще, произошла та же ошибка.

Ответы [ 2 ]

0 голосов
/ 27 апреля 2018

Вы можете попробовать несколько вещей для устранения неисправностей-

1.Какой путь к образу службы находится в следующем разделе реестра: HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ YourServiceName \ ImagePath 2. Проверьте, указав полный путь к исполняемому файлу службы.

0 голосов
/ 26 апреля 2018

Когда функция не определяет соглашение о вызовах (например, ваше), большинство компиляторов C ++ по умолчанию используют соглашение о вызовах __cdecl, если не настроено другое значение по умолчанию. Однако Win32 API использует соглашение о вызовах __stdcall. Вам нужно добавить это соглашение о вызовах в объявления ваших функций, которые вы предоставляете сервисному API. Вам также необходимо убедиться, что те же функции также используют правильные типы параметров (а ваши нет).

Избавьтесь от приведений типов, которые скрывают от вас ошибки компилятора. Компилятор жалуется по причине, не игнорируйте ее.

Попробуйте это:

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <string>
#include <fstream>

using namespace std;

#define SLEEP_TIME 5000
#define LOGFILE "C:\\MyServices\\memstatus.txt"

SERVICE_STATUS ServiceStatus = {};
SERVICE_STATUS_HANDLE hStatus = NULL;

void WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
void WINAPI ControlHandler(DWORD request);
bool InitService();    

bool WriteToLog(const string &file_name, const string &input)
{
    ofstream f(file_name.c_str(), ios_base::app);
    if (f.is_open())
        f << input << "\n";
    return !f.fail();
}

LPCTSTR Name = TEXT("MemoryStatus");

int main()
{
    SERVICE_TABLE_ENTRY ServiceTable[2];
    ServiceTable[0].lpServiceName = Name;
    ServiceTable[0].lpServiceProc = &ServiceMain;

    ServiceTable[1].lpServiceName = NULL;
    ServiceTable[1].lpServiceProc = NULL;

    // Start the control dispatcher thread for our service
    StartServiceCtrlDispatcher(ServiceTable);

    return 0;
}

void WINAPI ServiceMain(DWORD argc, LPTSTR* argv)
{
    ServiceStatus.dwServiceType = SERVICE_WIN32;
    ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
    ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    ServiceStatus.dwWin32ExitCode = 0;
    ServiceStatus.dwServiceSpecificExitCode = 0;
    ServiceStatus.dwCheckPoint = 0;
    ServiceStatus.dwWaitHint = 0;

    hStatus = RegisterServiceCtrlHandler(Name, &ControlHandler);
    if (!hStatus)
    {
        // Registering Control Handler failed
        return;
    }

    // Initialize Service 
    if (!InitService())
    {
        // Initialization failed
        ServiceStatus.dwCurrentState = SERVICE_STOPPED;
        ServiceStatus.dwWin32ExitCode = -1;
        SetServiceStatus(hStatus, &ServiceStatus);
        return;
    }

    // We report the running status to SCM. 
    ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    SetServiceStatus(hStatus, &ServiceStatus);

    MEMORYSTATUS memory;
    // The worker loop of a service
    while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
    {
        char buffer[16];
        GlobalMemoryStatus(&memory);
        sprintf_s(buffer, "%d", memory.dwAvailPhys);
        if (!WriteToLog("TestFile.txt", buffer))
        {
            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
            ServiceStatus.dwWin32ExitCode = -1;
            SetServiceStatus(hStatus, &ServiceStatus);
            return;
        }

        Sleep(SLEEP_TIME);
    }
}

// Service initialization
bool InitService()
{
    return WriteToLog("TestFile.txt", "Monitoring started.");
}

// Control handler function
void WINAPI ControlHandler(DWORD request)
{
    switch (request)
    {
        case SERVICE_CONTROL_STOP:
            WriteToLog("TestFile.txt", "Monitoring stopped.");
            ServiceStatus.dwWin32ExitCode = 0;
            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
            break;

        case SERVICE_CONTROL_SHUTDOWN:
            WriteToLog("TestFile.txt", "Monitoring stopped.");
            ServiceStatus.dwWin32ExitCode = 0;
            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
            break;
        }

        // Report current status
        SetServiceStatus(hStatus, &ServiceStatus);    
    }
}

Я предлагаю вам прочитать документацию Microsoft о том, как правильно написать сервис:

Сервисные программы

Задачи программы обслуживания

Пример полного обслуживания

При этом вы говорите, что ваша служба не может запуститься, потому что Windows утверждает, что не может найти файл. Это означает, что вы, возможно, неправильно устанавливаете службу в SCM. Но вы не показали фактическую командную строку, которую вы передаете sc.exe. Убедитесь, что значение binPath, которое вы передаете, является правильным путем к вашему EXE-файлу службы.

Если вы уверены, что это так, то другая возможность может заключаться в том, что ваш EXE-файл зависит от внешней библиотеки DLL, которая не находится в пути поиска Windows. Это также может вызвать сбой запуска вашего EXE-файла с ошибкой «файл не найден».

Я предлагаю вам запустить SysInternals Process Monitor при попытке запустить службу. Это покажет вам, какой именно файл Windows ищет, когда происходит ошибка. Это даст вам лучшее представление о том, где вам нужно устранить неполадки при установке.


Кстати, в Windows есть встроенная поддержка ведения журнала. Вам не нужно вручную записывать сообщения журнала в текстовый файл. Рассмотрите возможность регистрации сообщений в стандартном средстве просмотра событий Windows с использованием таких функций, как ReportEvent(), EventWrite() и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...