我写了一个简单的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或其他任何地方跟随的几乎所有示例都遇到了同样的错误。
答案 0 :(得分:0)
当一个函数没有指定一个调用约定(和你的一样)时,大多数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依赖于不在Windows上的外部DLL&#39;搜索路径。这也可能导致您的EXE无法运行未找到&#39;文件&#34;错误。
我建议您在尝试启动服务时运行SysInternals Process Monitor。这将显示错误发生时Windows正在查找的文件。这将为您提供更好的线索,了解您需要对安装进行故障排除的位置。
另外,Windows内置了对日志记录的支持。您不需要手动将日志消息写入文本文件。考虑使用ReportEvent()
,EventWrite()
等功能将消息记录到标准Windows事件查看器。
答案 1 :(得分:-2)
您可以尝试一些方法进行故障排除 -
1.以下注册表位置中的服务映像路径是什么 - HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ YourServiceName \ ImagePath 2.通过提供服务可执行文件的完全限定路径进行检查。