Report error:access violation when I use StartServiceCtrlDispatcher(entrytable)

1

My program reports the error when the program executes to StartServiceCtrlDispatcher().

The error: Exception thrown at 0x74BFFF70 (sechost.dll) in ConsoleApplication33.exe: 0xC0000005: Access violation reading location 0xCCCCCCCC.

I tried many ways but failed. Where did i write wrong. Please let me know. Thank you in advance. The code is below:

#include "pch.h"
#include<Windows.h>
#include<iostream>
#include<atlstr.h>
#include<fstream>
#include<tchar.h>
bool brun = false;
SERVICE_STATUS servicestatus;
SERVICE_STATUS_HANDLE hstatus;
void WriteToLog(const std::string &str)
{
    std::ofstream p("D:/log.txt", std::ios::app);
    if (!p.is_open())
        return;
    p << str << std::endl;
    p.close();
}

void WINAPI CtrlHandler(DWORD request)
{
    switch (request)
    {
    case SERVICE_CONTROL_STOP:
        brun = false;
        servicestatus.dwCurrentState = SERVICE_STOPPED;
        break;
    case SERVICE_CONTROL_SHUTDOWN:
        brun = false;
        servicestatus.dwCurrentState = SERVICE_STOPPED;
    }
    SetServiceStatus(hstatus, &servicestatus);
}
void WINAPI ServiceMain(int argc, char **argv)
{
    servicestatus.dwServiceType = SERVICE_WIN32;
    servicestatus.dwCurrentState = SERVICE_START_PENDING;
    servicestatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
    servicestatus.dwWin32ExitCode = 0;
    servicestatus.dwServiceSpecificExitCode = 0;
    servicestatus.dwCheckPoint = 0;
    servicestatus.dwWaitHint = 0;
    hstatus = ::RegisterServiceCtrlHandler("MyService", CtrlHandler);
    if (hstatus == 0)
    {
        WriteToLog("RegisterServiceCtrlHandler failed");
        return;
    }
    WriteToLog("RegisterServiceCtrlHandler success");
    servicestatus.dwCurrentState = SERVICE_RUNNING;
    SetServiceStatus(hstatus, &servicestatus);
    brun = true;
    MEMORYSTATUSEX memstatus;
    char str[100];
    memset(str, '\0', 100);
    while (brun)
    {
        GlobalMemoryStatusEx(&memstatus);
        SIZE_T availmb = memstatus.ullAvailPhys / 1024 / 1024;
        sprintf_s(str, 100, "available memory is %zdMB", availmb);
        WriteToLog(str);
        Sleep(2000);
    }
    WriteToLog("service stopped");
}
int _tmain(int argc, _TCHAR **argv)
{
    SERVICE_TABLE_ENTRY entrytable[1];
    CString cstr("MyService");
    entrytable[0].lpServiceName = cstr.GetBuffer();
    cstr.ReleaseBuffer();
    entrytable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
    StartServiceCtrlDispatcher(entrytable);
    return 0;
}
c++
sdk
asked on Stack Overflow Aug 22, 2019 by Suarez Zhou • edited Apr 29, 2021 by klutt

1 Answer

7

The SERVICE_TABLE_ENTRY structure array requires the last member to be NULL, which we call "Sentinel" (all values are NULL), it indicates the end of the service table. Once a service is started, StartServiceCtrlDispatcher() is called to notify the service controller that the service is executing and to provide the address. StartServiceCtrlDispatcher() requires only an array of at least two SERVICE_TABLE_ENTRY structures.

This is why access violations occur. When your program executes to StartServiceCtrlDispatcher(entrytable), It will acess the second element ofSERVICE_TABLE_ENTRY, but your array definition has only one element, so it results in access violation.

int _tmain(int argc, _TCHAR **argv)
{
    //SERVICE_TABLE_ENTRY entrytable[] = 
    //{ 
    //  {(LPWSTR)"MyService", (LPSERVICE_MAIN_FUNCTION)ServiceMain},
    //  {NULL, NULL}
    //};
    SERVICE_TABLE_ENTRY entrytable[2];
    CString cstr("MyService");
    entrytable[0].lpServiceName = cstr.GetBuffer();
    cstr.ReleaseBuffer();
    entrytable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
    entrytable[1].lpServiceName = NULL;
    entrytable[1].lpServiceProc = NULL;
    StartServiceCtrlDispatcher(entrytable);
    return 0;
}
answered on Stack Overflow Aug 22, 2019 by Jeaninez - MSFT

User contributions licensed under CC BY-SA 3.0