Когда функция не определяет соглашение о вызовах (например, ваше), большинство компиляторов 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()
и т. Д.