Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Run exe as Service.


Автор: knut 27.2.2010, 20:17
добрый день.
хочу запустить ехе как сервис.
если приложение консольное то ехе без проблем запускается как сервис но вот если виндовс приложением проблема.
получаю ошибку 1053 (The service did not respond to the start or control request in a timely fashion.) в чем проблема?
вот сам код
Код

int InstallSvr()
{
    SC_HANDLE NishService,scm;
    scm=OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
    if(!scm)
    {
        ShowErr();
        return 1;
    }
    NishService=CreateService(scm,L"Service",
        L"Hack5",
        SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS,SERVICE_DEMAND_START,
        SERVICE_ERROR_NORMAL,
        L"D:\\simple.exe",
        0,0,0,0,0);
    if(!NishService)
    {
        CloseServiceHandle(scm);
        ShowErr();
        return 1;
    }
    CloseServiceHandle(NishService);
    CloseServiceHandle(scm);
    return 0;
}



Код

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
   int res = InstallSvr(); // все нормально 
   SC_HANDLE NishService,scm;
   scm=OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
    if(!scm)
    {
        //ShowErr();
        return 1;
    }
    NishService=OpenService(scm,L"Service",SERVICE_ALL_ACCESS);
    if(!NishService)
    {
        CloseServiceHandle(scm);
        //ShowErr();
        return 1;
    }

    
    StartService(NishService,0,NULL);
    DWORD dwError = GetLastError();   // вот здесь error  1053 ???????????
    CloseServiceHandle(NishService);
    CloseServiceHandle(scm);

}


Автор: xvr 27.2.2010, 20:58
Видимо проблема в D:\\simple.exe, а так же возможно в том, что его при каждом запуске этой программы пытаются установить заново (это пройдет только в первый раз, потом будет давать ошибки)

Автор: knut 27.2.2010, 21:06
xvr, 
код каторый я привел и есть simple.exe.
я вот чего не могу понять.
если я создаю косольное преложение  то у меня сервис стартуется нормально в вот с виндовс  приложением у меня возникает эта проблема.

Автор: Artemon 27.2.2010, 21:49
Если твое приложение использует некоторые элементы GUI, например иконку в таскбаре, то такое приложение невозможно запустить как сервис.

Автор: xvr 28.2.2010, 18:22
Цитата(knut @ 27.2.2010,  21:06)
xvr, 
код каторый я привел и есть simple.exe.

В таком случае в нем отсуствует то, что должно запускаться как сервис. См. функции RegisterServiceCtrlHandler, StartServiceCtrlDispatcher, SetServiceStatus
Именно они определяют успех или неуспех запуска сервиса

Автор: knut 1.3.2010, 22:13
xvr, 
Сервис запустить удалось. Но
у меня вопрос.
возможно ли поставить хук при запуске сервиса?
у меня не как не получается. отдельно хук работает.

Автор: xvr 2.3.2010, 17:11
Цитата(knut @ 1.3.2010,  22:13)
xvr, 
Сервис запустить удалось. Но
у меня вопрос.
возможно ли поставить хук при запуске сервиса?

Какой хук? И где его надо поставить?
Цитата

у меня не как не получается. отдельно хук работает.
 smile 

Автор: knut 2.3.2010, 21:52
есть сервис и есть глобальный хук на клаву.
надо.при старте сервиса установить хук.
как я делаю.
Код

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    

    if(!SetHook(true))MessageBox(NULL, L"Error",L"Error",MB_OK);

    SERVICE_TABLE_ENTRY servicetable[]=
    {
        {strServiceName,(LPSERVICE_MAIN_FUNCTION)ServiceMain},
        {NULL,NULL}
    };
}
......
BOOL SetHook(BOOL fSet)
{

    if (fSet)
    {
        if (!hmodHook)
        {
            if (!(hmodHook = LoadLibrary(L"../debug/KeyBoargHook.dll"))) 
            {
                 
                 return FALSE;
            }
            
        }
    }
   ........
}


сервис устанавливается нормально.
вроди и хук устанавливается. но на нажатьие клавы не реагирует.
p.s
отдельно запускаю хук(без сервиса) работает отлично.

Автор: DrHex 3.3.2010, 11:31
Библиотека не грузится? Или в сервисе MessageBox не вылетает? Если второе то у сервисов GUI нету...

Автор: xvr 3.3.2010, 13:15
Попробуйте поставить хук в ServiceMain (а не в WinMain).
Кроме того, все равно не видно, как именно ставится ХУК. Пока видно только, что грузится какая то dll. Учтите, что у сервиса будет свой десктоп и WinStation. Хук может быть будет работать именно на них, а не у пользователя

 

Автор: knut 3.3.2010, 18:58
Цитата

Кроме того, все равно не видно, как именно ставится ХУК.

ок  код у меня большой  вот и подумал лен будет вам разбираться в нем.
вот сервис.

Код

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{





    HACCEL hAccelTable;

    SERVICE_TABLE_ENTRY servicetable[]=
    {
        {strServiceName,(LPSERVICE_MAIN_FUNCTION)ServiceMain},
        {NULL,NULL}
    };
    BOOL success;
    success=StartServiceCtrlDispatcher(servicetable);
}

void ServiceMain(DWORD argc, LPTSTR *argv)
{
    

    if(!SetHook(true))MessageBox(NULL, L"Error",L"Error",MB_OK);
    
    
    BOOL success;
    nServiceStatusHandle=RegisterServiceCtrlHandler(strServiceName,
        (LPHANDLER_FUNCTION)ServiceCtrlHandler);
    if(!nServiceStatusHandle)
    {
        return;
    }
    success=UpdateServiceStatus(SERVICE_START_PENDING,NO_ERROR,0,1,3000);
    if(!success)
    {
        return;
    }
    killServiceEvent=CreateEvent(0,TRUE,FALSE,0);
    if(killServiceEvent==NULL)
    {
        return;
    }
    success=UpdateServiceStatus(SERVICE_START_PENDING,NO_ERROR,0,2,1000);
    if(!success)
    {
        return;
    }
    success=StartServiceThread();
    if(!success)
    {
        return;
    }
    nServiceCurrentStatus=SERVICE_RUNNING;
    success=UpdateServiceStatus(SERVICE_RUNNING,NO_ERROR,0,0,0);
    if(!success)
    {
        return;
    }
    WaitForSingleObject(killServiceEvent,INFINITE);
    CloseHandle(killServiceEvent);
}



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);

    if(!success)
    {
        KillService();
        return success;
    }
    else
        return success;
}

BOOL StartServiceThread()
{    
    DWORD id;
    hServiceThread=CreateThread(0,0,
        (LPTHREAD_START_ROUTINE)ServiceExecutionThread,
        0,0,&id);
    if(hServiceThread==0)
    {
        return false;
    }
    else
    {
        nServiceRunning=true;
        return true;
    }
}

DWORD ServiceExecutionThread(LPDWORD param)
{
    while(nServiceRunning)
    {
        Beep(450,150);
        Sleep(4000);
    }
    return 0;
}

void KillService()
{
    nServiceRunning=false;
    SetEvent(killServiceEvent);
    UpdateServiceStatus(SERVICE_STOPPED,NO_ERROR,0,0,0);
}

void ServiceCtrlHandler(DWORD nControlCode)
{
    BOOL success;
    switch(nControlCode)
    {    
    case SERVICE_CONTROL_SHUTDOWN:
    case SERVICE_CONTROL_STOP:
        nServiceCurrentStatus=SERVICE_STOP_PENDING;
        success=UpdateServiceStatus(SERVICE_STOP_PENDING,NO_ERROR,0,1,3000);
        KillService();        
        return;
    default:
        break;
    }
    UpdateServiceStatus(nServiceCurrentStatus,NO_ERROR,0,0,0);
}

BOOL SetHook(BOOL fSet)
{
    
    static HHOOK hhkKbdHook = NULL;
    static HANDLE hmodHook;

    if (fSet)
    {
        if (!hmodHook)
        {
            if (!(hmodHook = LoadLibrary(L"../debug/KeyBoargHook.dll"))) 
            {
                 
                 return FALSE;
            }
            
        }
        if (!hhkKbdHook)
        {

HOOKPROC hkprcSysMsg; 
static HINSTANCE hinstDLL; 
static HHOOK hhookSysMsg; 

 if (!(hhkKbdHook =  SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)
  GetProcAddress((HINSTANCE)hmodHook,"KeyboardProc"),(HINSTANCE)hmodHook,0)))
            {
                DWORD dw = GetLastError(); 
                return FALSE;
            }
        }

 }
    else
    {
        if (hhkKbdHook)
        {
            UnhookWindowsHookEx(hhkKbdHook);
            hhkKbdHook = NULL;
        }

    }

    return TRUE;
}

а вот сам хук
Код

BOOL APIENTRY DllMain(HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)
{
    ghDLLInst = hModule;
    switch (ul_reason_for_call)
    {
            case DLL_PROCESS_ATTACH:
         {
             
                // ....
                
                

         }    
        case DLL_PROCESS_DETACH:
        {
        }
    default:
            break;
    }

    return TRUE;
}

LRESULT  CALLBACK KeyboardProc(
     int nCode,  // hook code
     WPARAM wParam,     // virtual-key code
     LPARAM lParam      // keystroke-message information
   )
{
    
    if (HC_ACTION==nCode)
    {        
          if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
          {
               // ....  
          }
            
    }
            return CallNextHookEx(NULL, nCode, wParam, lParam );


    
}


сервис нормально стартуется но хук не реагирует на нажатие клавы

Автор: xvr 4.3.2010, 21:42
Читаем описание LowLevelKeyboardProc:
Цитата

This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.
Смотрим ServiceMain где вызывается SetHook, вместо message loop видим WaitForSingleObject(killServiceEvent,INFINITE);

PS. Для WH_KEYBOARD_LL dll не нужна, этот хук может быть в exe

Автор: knut 5.3.2010, 16:45
xvr, 
да вы правы у тред который устанавливает хук должен иметь месидж луп. но чтоб в ServiceMain  е не  создавать этот цыкл я вызываю
setHook в winMain e . здесь ведь все нормально  с луп ом. но результат тот же.

Автор: xvr 6.3.2010, 19:06
Цитата(knut @ 5.3.2010,  16:45)
xvr, 
да вы правы у тред который устанавливает хук должен иметь месидж луп. но чтоб в ServiceMain  е не  создавать этот цыкл я вызываю
setHook в winMain e . здесь ведь все нормально  с луп ом. но результат тот же.

А с чего там будет 'все нормально с message loopом'? winmain вообще блокируется в StartServiceCtrlDispatcher

Автор: knut 6.3.2010, 22:46
xvr, 
создал я месидж луп как и вы посоветовали но результат тот же(никакой).
вот сервис маин.
Код

void ServiceMain(DWORD argc, LPTSTR *argv)
{
nServiceStatusHandle=RegisterServiceCtrlHandler(strServiceName,
        (LPHANDLER_FUNCTION)ServiceCtrlHandler);
    if(!nServiceStatusHandle)
    {
        return;
    }
    success=UpdateServiceStatus(SERVICE_START_PENDING,NO_ERROR,0,1,3000);
    if(!success)
    {
        return;
    }
    killServiceEvent=CreateEvent(0,TRUE,FALSE,0);
    if(killServiceEvent==NULL)
    {
        return;
    }
    success=UpdateServiceStatus(SERVICE_START_PENDING,NO_ERROR,0,2,1000);
    if(!success)
    {
        return;
    }
    success=StartServiceThread();
    if(!success)
    {
        return;
    }
    nServiceCurrentStatus=SERVICE_RUNNING;
    success=UpdateServiceStatus(SERVICE_RUNNING,NO_ERROR,0,0,0);
    if(!success)
    {
        return;
    }



    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_FIRSTSERVICEW, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    
    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_FIRSTSERVICEW));


    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    if(!SetHook(true))MessageBox(NULL, L"error",L"error",MB_OK);

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


что теперь не так?

Автор: xvr 7.3.2010, 12:20
Цитата

что теперь не так?
SetHook должен вызываться ДО message loop'а, а не после.
И завершение сервиса должно теперь происходить через посылку WM_QUIT в очередь thread'а, а не через event killServiceEvent (до его ожидания просто не дойдет управление)

Автор: knut 7.3.2010, 15:58
Цитата

И завершение сервиса должно теперь происходить через посылку WM_QUIT

ну до выгода мне пока надо хук запустить что пока у меня не получается.
Цитата

SetHook должен вызываться ДО message loop'а, а не после.

все равно KeyboardProc не вызывается smile  smile  smile  smile 

Автор: xvr 7.3.2010, 17:12
Тогда действительно возможны проблемы с десктопом. Поставьте сервису флажок 'Разрешить взаимодействовать с Рабочим Столом' при инсталяции.

Автор: knut 7.3.2010, 17:28
xvr, 
стоит. я сервис содаю именно с этим флагом.

Код

NishService = CreateService(scm, L"test", L"test", 
            SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS ,
            SERVICE_DEMAND_START,  SERVICE_ERROR_NORMAL,
            L"FirstServiceW.exe", NULL, NULL,NULL, 
            NULL,NULL); 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)