加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 在Windows服务中使用命名管道时出现故障

发布时间:2020-12-16 07:23:52 所属栏目:百科 来源:网络整理
导读:我正在为 Windows 10创建服务.我已经按照本教程. https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus 但是,当我将代码添加到此示例时,发生了一些事情,我无法停止服务列表中的服务.我只能从任务经理那里阻止它.但如果我评论我
我正在为 Windows 10创建服务.我已经按照本教程. https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus

但是,当我将代码添加到此示例时,发生了一些事情,我无法停止服务列表中的服务.我只能从任务经理那里阻止它.但如果我评论我的代码,服务正常停止.

我会很感激任何建议.代码如下.

#include <Windows.h>
#include <tchar.h>
#include <string>
#include <fstream>

SERVICE_STATUS        g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE                g_ServiceStopEvent = INVALID_HANDLE_VALUE;

std::wofstream output(L"C:Usersx0sourceServiceoutput.txt");

VOID WINAPI ServiceMain(DWORD argc,LPTSTR *argv);
VOID WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);

#define SERVICE_NAME _T("TestService")

DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
    auto dwFlags = FILE_ATTRIBUTE_NORMAL;
    STARTUPINFOW si;
    GetStartupInfoW(&si);
    PROCESS_INFORMATION pi;
    ZeroMemory(&si,sizeof(si));
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_HIDE;
    ZeroMemory(&pi,sizeof(pi));

    HANDLE service_pipe = CreateNamedPipe(TEXT("\.pipeServicePipe"),PIPE_ACCESS_DUPLEX,PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,128,16 * 1024,nullptr);

    if (service_pipe == INVALID_HANDLE_VALUE)
    {
        return 1;
    }

    TCHAR inbox_buffer[1024];
    DWORD read,write;

    while (1)
    {
        if (WaitForSingleObject(g_ServiceStopEvent,0) != WAIT_OBJECT_0)
        {
            //If I comment this 'if block',service stopping properly. But I don't see any errors in this part of code.
            if (ConnectNamedPipe(service_pipe,nullptr))
            {
                if (ReadFile(service_pipe,inbox_buffer,1024 * sizeof(TCHAR),&read,nullptr))
                {
                    std::wstring args = inbox_buffer;

                    std::wstring command = L""C:Program Files (x86)Unilityutility.exe" " + args;

                    if (!CreateProcessW(NULL,(LPWSTR)command.c_str(),NULL,TRUE,CREATE_NO_WINDOW,&si,&pi))
                    {
                        output << "CreateProcessW Error = " << GetLastError() << std::endl;
                    }
                    WaitForSingleObject(pi.hProcess,INFINITE);
                    CloseHandle(pi.hProcess);
                    CloseHandle(pi.hThread);

                    bool success = false;
                    do
                    {
                        success = WriteFile(service_pipe,L"executed",sizeof(L"executed"),&write,nullptr);
                    } while (!success);
                }
                DisconnectNamedPipe(service_pipe);
            }
        }
        else
        {
            output << "WaitForSingleObject(g_ServiceStopEvent,0)" << std::endl;
            break;
        }
    }

    output << "CloseHandle(service_pipe)_1" << std::endl;
    CloseHandle(service_pipe);
    output << "CloseHandle(service_pipe)_2" << std::endl;
    return ERROR_SUCCESS;
}

VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode)
{
    switch (CtrlCode)
    {
    case SERVICE_CONTROL_STOP:

        if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
            break;

        g_ServiceStatus.dwControlsAccepted = 0;
        g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
        g_ServiceStatus.dwWin32ExitCode = 0;
        g_ServiceStatus.dwCheckPoint = 4;

        if (SetServiceStatus(g_StatusHandle,&g_ServiceStatus) == FALSE)
        {
            output << "TestService: ServiceCtrlHandler: SetServiceStatus returned error" << std::endl;
        }
        SetEvent(g_ServiceStopEvent);

        output << "SetEvent(g_ServiceStopEvent)_1" << std::endl;
        break;

    default:
        break;
    }
    output << "SetEvent(g_ServiceStopEvent)_2" << std::endl;
}

VOID WINAPI ServiceMain(DWORD argc,LPTSTR *argv)
{
    DWORD Status = E_FAIL;

    g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME,ServiceCtrlHandler);

    if (g_StatusHandle == NULL)
    {
        return;
    }

    ZeroMemory(&g_ServiceStatus,sizeof(g_ServiceStatus));
    g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    g_ServiceStatus.dwControlsAccepted = 0;
    g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
    g_ServiceStatus.dwWin32ExitCode = 0;
    g_ServiceStatus.dwServiceSpecificExitCode = 0;
    g_ServiceStatus.dwCheckPoint = 0;

    if (SetServiceStatus(g_StatusHandle,&g_ServiceStatus) == FALSE)
    {
            output << "TestService: ServiceMain: SetServiceStatus returned error" << std::endl;
    }

    g_ServiceStopEvent = CreateEvent(NULL,FALSE,NULL);
    if (g_ServiceStopEvent == NULL)
    {
        g_ServiceStatus.dwControlsAccepted = 0;
        g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
        g_ServiceStatus.dwWin32ExitCode = GetLastError();
        g_ServiceStatus.dwCheckPoint = 1;

        if (SetServiceStatus(g_StatusHandle,&g_ServiceStatus) == FALSE)
        {
            output << "TestService: ServiceMain: SetServiceStatus returned error" << std::endl;
        }
        return;
    }

    g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    g_ServiceStatus.dwWin32ExitCode = 0;
    g_ServiceStatus.dwCheckPoint = 0;

    if (SetServiceStatus(g_StatusHandle,&g_ServiceStatus) == FALSE)
    {
        output << "TestService: ServiceMain: SetServiceStatus returned error" << std::endl;
    }

    HANDLE hThread = CreateThread(NULL,ServiceWorkerThread,NULL);

    WaitForSingleObject(hThread,INFINITE);

    output << "CloseHandle(g_ServiceStopEvent)_1" << std::endl;
    CloseHandle(g_ServiceStopEvent);
    output << "CloseHandle(g_ServiceStopEvent)_2" << std::endl;

    g_ServiceStatus.dwControlsAccepted = 0;
    g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
    g_ServiceStatus.dwWin32ExitCode = 0;
    g_ServiceStatus.dwCheckPoint = 3;

    if (SetServiceStatus(g_StatusHandle,&g_ServiceStatus) == FALSE)
    {
        output << "TestService: ServiceMain: SetServiceStatus returned error" << std::endl;
    }

    return;
}

int _tmain(int argc,TCHAR *argv[])
{
    SERVICE_TABLE_ENTRY ServiceTable[] =
    {
        {(LPWSTR)"TestService",(LPSERVICE_MAIN_FUNCTION)ServiceMain},{NULL,NULL}
    };

    if (StartServiceCtrlDispatcher(ServiceTable) == FALSE)
    {
        return GetLastError();
    }

    return 0;
}

解决方法

肮脏的方式,但它的工作.我创建了一个处理与管道相关的所有工作的函数.我在新线程中运行了这个函数.当服务收到停止信号时,我向管道发送停止消息并停止循环.

#include <Windows.h>
#include <tchar.h>
#include <string>
#include <thread>
#include <fstream>

SERVICE_STATUS        g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE                g_ServiceStopEvent = INVALID_HANDLE_VALUE;

VOID WINAPI ServiceMain(DWORD argc,LPTSTR *argv);
VOID WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);

#define SERVICE_NAME _T("TestService")

void pipe_server_function() {
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
    auto dwFlags = FILE_ATTRIBUTE_NORMAL;
    STARTUPINFOW si;
    GetStartupInfoW(&si);
    PROCESS_INFORMATION pi;
    ZeroMemory(&si,nullptr);

    if (service_pipe == INVALID_HANDLE_VALUE)
    {
        return;
    }

    TCHAR inbox_buffer[1024];
    std::fill(inbox_buffer,inbox_buffer + 1024,'');
    DWORD read,write;

    while (true)
    {

        if (ConnectNamedPipe(service_pipe,nullptr))
        {
            if (ReadFile(service_pipe,nullptr))
            {
                std::wstring args = inbox_buffer;

                if (args.find("stop_signal") != std::wstring::npos)
                {
                    DisconnectNamedPipe(service_pipe);
                    break;
                }

                std::wstring command = L""C:Program Files (x86)Unilityutility.exe" " + args;

                if (!CreateProcessW(NULL,&pi))
                {
                    //CreateProcessW failed. You should log this!
                }
                WaitForSingleObject(pi.hProcess,INFINITE);
                CloseHandle(pi.hProcess);
                CloseHandle(pi.hThread);

                bool success = false;
                do
                {
                    success = WriteFile(service_pipe,nullptr);
                } while (!success);
            }
            DisconnectNamedPipe(service_pipe);
            std::fill(inbox_buffer,'');
        }
    }
    CloseHandle(service_pipe);
}

DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
    if (WaitForSingleObject(g_ServiceStopEvent,0) != WAIT_OBJECT_0) {
        Sleep(1000);
    }

    service::handle gsprint_pipe = CreateFile(TEXT("\.pipeServicePipe"),GENERIC_READ | GENERIC_WRITE,nullptr,OPEN_EXISTING,nullptr);
    bool succeess = false;
    DWORD read;
    do
    {
        succeess = WriteFile(gsprint_pipe,L"stop_signal",sizeof(L"stop_signal"),nullptr);
    } while (!succeess);
    return ERROR_SUCCESS;
}

VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode)
{
    switch (CtrlCode)
    {
    case SERVICE_CONTROL_STOP:

        if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
            break;

        g_ServiceStatus.dwControlsAccepted = 0;
        g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
        g_ServiceStatus.dwWin32ExitCode = 0;
        g_ServiceStatus.dwCheckPoint = 4;

        if (SetServiceStatus(g_StatusHandle,&g_ServiceStatus) == FALSE)
        {
            //SetServiceStatus failed. You should log this!
        }
        SetEvent(g_ServiceStopEvent);

        break;

    default:
        break;
    }
}

VOID WINAPI ServiceMain(DWORD argc,&g_ServiceStatus) == FALSE)
    {
        //SetServiceStatus failed. You should log this!
    }

    g_ServiceStopEvent = CreateEvent(NULL,&g_ServiceStatus) == FALSE)
        {
            //SetServiceStatus failed. You should log this!
        }
        return;
    }

    g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    g_ServiceStatus.dwWin32ExitCode = 0;
    g_ServiceStatus.dwCheckPoint = 0;

    if (SetServiceStatus(g_StatusHandle,&g_ServiceStatus) == FALSE)
    {
        //SetServiceStatus failed. You should log this!
    }

    std::thread pipe_server(pipe_server_function);

    HANDLE hThread = CreateThread(NULL,INFINITE);

    pipe_server.join();

    CloseHandle(g_ServiceStopEvent);

    g_ServiceStatus.dwControlsAccepted = 0;
    g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
    g_ServiceStatus.dwWin32ExitCode = 0;
    g_ServiceStatus.dwCheckPoint = 3;

    if (SetServiceStatus(g_StatusHandle,&g_ServiceStatus) == FALSE)
    {
        //SetServiceStatus failed. You should log this!
    }

    return;
}

int _tmain(int argc,NULL}
    };

    if (StartServiceCtrlDispatcher(ServiceTable) == FALSE)
    {
        return GetLastError();
    }

    return 0;
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读