2013-12-19 4 views
0

Служба Windows предоставляет SIGSEGV в конце функции ServiceMain.Служба Windows SIGSEGV

Вот код:

Начало:

int main(int argc, char* argv[]) 
{ 

    SrvName[16]=0; 
    SERVICE_TABLE_ENTRY servicetable[]= 
    { 
     {strServiceName,(LPSERVICE_MAIN_FUNCTION)ServiceMain}, 
     {NULL,NULL} 
    }; 
    BOOL success; 
    success=StartServiceCtrlDispatcher(servicetable); 
assert(success!=0); 
    return(0); 
} 

Сервис старт:

void ServiceMain(DWORD argc, LPTSTR *argv) 
{ 

    BOOL success; 
    nServiceStatusHandle=RegisterServiceCtrlHandlerEx(strServiceName, 
     (LPHANDLER_FUNCTION_EX)ServiceCtrlHandler, NULL); 
assert(nServiceStatusHandle!=0); 
success=UpdateServiceStatus(SERVICE_START_PENDING,NO_ERROR,0,1,20000); 
assert(success!=0); 
killServiceEvent=CreateEvent(0,TRUE,FALSE,0); 
assert(killServiceEvent!=NULL); 

success=UpdateServiceStatus(SERVICE_START_PENDING,NO_ERROR,0,2,10000); 
assert(success!=0); 

nServiceCurrentStatus=SERVICE_RUNNING; 
success=UpdateServiceStatus(SERVICE_RUNNING,NO_ERROR,0,0,0); 
assert(success!=0); 

WaitForSingleObject(killServiceEvent,INFINITE); 
CloseHandle(killServiceEvent); 

UpdateServiceStatus(SERVICE_STOPPED,NO_ERROR,0,0,0); 
return; 
}///2x SIGSEGV here 

функция обновления состояния:

BOOL UpdateServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, 
     DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint, 
       DWORD dwWaitHint) 
{ 
BOOL success; 
SERVICE_STATUS nServiceStatus; 
nServiceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; 
nServiceStatus.dwCurrentState=dwCurrentState; 
if(dwCurrentState==SERVICE_START_PENDING) 
{ 
    nServiceStatus.dwControlsAccepted=0; 
} 
else 
{ 
    nServiceStatus.dwControlsAccepted=SERVICE_ACCEPT_STOP 
     |SERVICE_ACCEPT_SHUTDOWN; 
} 
if(dwServiceSpecificExitCode==0) 
{ 
    nServiceStatus.dwWin32ExitCode=dwWin32ExitCode; 
} 
else 
{ 
    nServiceStatus.dwWin32ExitCode=ERROR_SERVICE_SPECIFIC_ERROR; 
} 
nServiceStatus.dwServiceSpecificExitCode=dwServiceSpecificExitCode; 
nServiceStatus.dwCheckPoint=dwCheckPoint; 
nServiceStatus.dwWaitHint=dwWaitHint; 

success=SetServiceStatus(nServiceStatusHandle,&nServiceStatus); 

    return success; 
} 

SCM сообщения обработчика:

void ServiceCtrlHandler(DWORD nControlCode,DWORD dwEventType, 
LPVOID lpEventData,LPVOID lpContext) 
{ 
switch(nControlCode) 
{ 
case SERVICE_CONTROL_SHUTDOWN: 
case SERVICE_CONTROL_STOP: 
    nServiceCurrentStatus=SERVICE_STOP_PENDING; 
    UpdateServiceStatus(SERVICE_STOP_PENDING,NO_ERROR,0,1,10000); 
    SetEvent(killServiceEvent); 
    return; 
default: 
    break; 
} 
UpdateServiceStatus(nServiceCurrentStatus,NO_ERROR,0,0,0); 
return; 
} 

Итак, у меня есть 2 SIGSEGV в конце ServiceMain(): "Service.exe вызвала нарушение прав доступа на месте 00000000 Reading от места 00000000." Регистры:

eax=00000000 ebx=00617d60 ecx=75bd76ba edx=00600174 esi=00000001 edi=00000000 
eip=00000000 esp=010eff8c ebp=00617d70 iopl=0   nv up ei pl zr na po nc 
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000    efl=00010246 

AddrPC Params 
00000000 00617D60 010EFFD4 77A437EB 
7765ED5C 00617D60 70866618 00000000 kernel32.dll!BaseThreadInitThunk 
77A437EB 77B47587 00617D60 00000000 ntdll.dll!RtlInitializeExceptionChain 
77A437BE 77B47587 00617D60 00000000 ntdll.dll!RtlInitializeExceptionChain 

Я использую Code :: Blocks с MinGW, Win7 32-битной Pro.

У вас есть идеи об этом?

+4

Не отвергни 'ServiceMain'. Исправьте действительную подпись, установив правильное соглашение о вызове. AFAIK, то, что использует ваш SERVICE_TABLE_ENTRY, ожидает, что «ServiceMain» очистит стек, но «ServiceMain» ожидает, что вышеупомянутая функция очистит его. Похоже на проблему. – chris

+1

При создании службы Windows всегда хорошо иметь способ запускать ее как обычную несервисную программу. Таким образом, отладка будет намного проще, поскольку вы можете запустить ее в отладчике. –

+2

Я заставлю его не бросить совет. Если вам нужно отдать его, он не будет объявлен правильно. –

ответ

1

Все служебные обработчики не имеют соглашения о выделении WINAPI (__stdcall), и ваш HandlerEx также не имеет возвращаемого значения. Эти ошибки вызывают неправильное управление стеком вызовов.

Исправьте свои объявления и избавьтесь от типоразмеров. Компилятор выдал бы ошибки о неправильных объявлениях, но вы заставили его игнорировать их и принять ваш плохой код.

SERVICE_TABLE_ENTRY servicetable[]= 
{ 
    {strServiceName, &ServiceMain}, 
    {NULL,NULL} 
}; 

void WINAPI ServiceMain(DWORD argc, LPTSTR *argv) 
{ 
    ... 
    nServiceStatusHandle = RegisterServiceCtrlHandlerEx(..., &ServiceCtrlHandler, ...); 
    ... 
} 

DWORD WINAPI ServiceCtrlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext) 
{ 
    switch(dwControl) 
    { 
     case SERVICE_CONTROL_SHUTDOWN: 
     case SERVICE_CONTROL_STOP: 
      ... 
      return NO_ERROR; 

     case SERVICE_CONTROL_INTERROGATE: 
      ... 
      return NO_ERROR; 

     default: 
      return ERROR_CALL_NOT_IMPLEMENTED; 
    } 
} 
+0

Спасибо за помощь! – SilentHunt