首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Window服务

Window服务
EN

Stack Overflow用户
提问于 2018-04-26 20:26:56
回答 2查看 387关注 0票数 0

我编写了一个简单的Windows服务,将内存信息写入文本文件:

代码语言:javascript
复制
#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或其他任何地方跟踪的几乎所有示例都得到了相同的错误。

EN

回答 2

Stack Overflow用户

发布于 2018-04-27 03:13:35

如果函数没有指定调用约定(与您的一样),除非配置了不同的默认值,否则大多数C++编译器都默认使用__cdecl调用约定。但是,Win32应用编程接口使用__stdcall调用约定。您需要将调用约定添加到您提供给服务API的函数的声明中。您还需要确保这些相同的函数也使用了正确的参数类型(您的参数类型不正确)。

摆脱那些对你隐藏编译器错误的类型转换。编译器抱怨是有原因的,不要忽视它。

试试这个:

代码语言:javascript
复制
#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的文档,了解如何正确编写服务:

Service Programs

Service Program Tasks

The Complete Service Example

也就是说,你说你的服务无法启动,因为Windows声称它找不到文件。这意味着您可能没有正确地将服务安装到SCM中。但是您没有显示要传递给sc.exe的实际命令行。确保您传递的EXE值是服务binPath的正确路径。

如果您确定是,则另一种可能是您的EXE依赖于不在Windows搜索路径上的外部DLL。这也可能导致您的EXE无法运行,并出现“找不到文件”错误。

我建议您在尝试启动服务时运行SysInternals Process Monitor。当错误发生时,这将确切地告诉你Windows正在寻找哪个文件。这将为您提供更好的线索,告诉您在何处需要对安装进行故障排除。

顺便说一句,Windows内置了对日志的支持。您不需要手动将日志消息写入文本文件。考虑使用ReportEvent()EventWrite()等函数将消息记录到标准的Windows事件查看器中。

票数 0
EN

Stack Overflow用户

发布于 2018-04-27 15:34:19

你可以尝试一些方法来排除故障-

1.以下注册表位置中的服务映像路径是什么- HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\YourServiceName\ImagePath 2.通过提供服务可执行文件的完全限定路径进行检查。

票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50042985

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档