ATL 7.0 & NT Service.
-
Can anyone tell me what (obvious to everyone else) piece I'm missing? The following code doesn't work when run as a service. It runs fine when run through the IDE. All it does is set a timer. The SetTimer returns a valid number, but the TimerProc callback is never hit. Any ideas? Carl /////////////////////////////////////////////////////////////////////////// [ module(SERVICE, uuid = "{99CCA443-725A-44F2-A5F3-9855AFACF970}", name = "QService", helpstring = "QService 1.0 Type Library", resource_name="IDS_SERVICENAME") ] class CQServiceModule { public: CQServiceModule() {}; public: HRESULT PreMessageLoop(int nShowCmd) { HRESULT hr = __super::PreMessageLoop(nShowCmd); if ( SUCCEEDED(hr) ) return S_OK; return hr; } HRESULT Start(int nCmd) { m_lTimer = (UINT)::SetTimer((HWND) NULL, 1, 10000, TimerProc); return __super::Start(nCmd); } static void CALLBACK TimerProc(HWND hwnd,UINT uMsg, UINT idEvent, DWORD dwTime) { _AtlModule.LogEvent(_T("TimerEvent")); } UINT m_lTimer; };
-
Can anyone tell me what (obvious to everyone else) piece I'm missing? The following code doesn't work when run as a service. It runs fine when run through the IDE. All it does is set a timer. The SetTimer returns a valid number, but the TimerProc callback is never hit. Any ideas? Carl /////////////////////////////////////////////////////////////////////////// [ module(SERVICE, uuid = "{99CCA443-725A-44F2-A5F3-9855AFACF970}", name = "QService", helpstring = "QService 1.0 Type Library", resource_name="IDS_SERVICENAME") ] class CQServiceModule { public: CQServiceModule() {}; public: HRESULT PreMessageLoop(int nShowCmd) { HRESULT hr = __super::PreMessageLoop(nShowCmd); if ( SUCCEEDED(hr) ) return S_OK; return hr; } HRESULT Start(int nCmd) { m_lTimer = (UINT)::SetTimer((HWND) NULL, 1, 10000, TimerProc); return __super::Start(nCmd); } static void CALLBACK TimerProc(HWND hwnd,UINT uMsg, UINT idEvent, DWORD dwTime) { _AtlModule.LogEvent(_T("TimerEvent")); } UINT m_lTimer; };
AFAIK services do not have message loops - and message loop is required when you want to use SetTimer, even with a callback function. Use Sleep() or waitable timer instead of SetTimer. Tomasz Sowinski -- http://www.shooltz.com
-
AFAIK services do not have message loops - and message loop is required when you want to use SetTimer, even with a callback function. Use Sleep() or waitable timer instead of SetTimer. Tomasz Sowinski -- http://www.shooltz.com
Thanks for the response. The ATL service code includes 3 methods PreMessageLoop(); RunMessageLoop(); PostMessageLoop(); Which lead me to think (incorrectly?) that this should work. It worked with the ATL code with version 6.0, although a lot of the code that had been explicitely generated before is now contained in CAtlServiceModuleT.
-
Thanks for the response. The ATL service code includes 3 methods PreMessageLoop(); RunMessageLoop(); PostMessageLoop(); Which lead me to think (incorrectly?) that this should work. It worked with the ATL code with version 6.0, although a lot of the code that had been explicitely generated before is now contained in CAtlServiceModuleT.
First, a service is a normal Windows 32 program, and as such it has at least a system message queue (even if it doesn't use it). Each thread may also have a thread specific message queue, but the creation is deferred until it's really needed (e.g., a User or GDI function is called). The old SetTimer function makes use of window messages (it was normally used for background processing purposes back in the 16-bit days), even if you specify a callback. Because of this reason, one must get and dispatch messages when it's used. Basically, all you need to do is to implement a Get-or-Peek/DispatchMessage-loop somewhere in your ServiceMain (or a function called from it). This is what makes the wheel go round. MFC and other framework libraries have a message loop buried way down in their private code, so you don't see it often these days, but it's still integral to Windows. However, if the only WM-based function you're going to be using is SetTimer, there is a better solution: Waitable Timers. A waitable timer is a kernel object that can be waited on using the WaitForXObject(s) set of functions (cf. CreateWaitableTimer API), and it can be set to an absolute or relative due time. This way you can combine it with waiting on other events such as a Quit event, which is a good service design.
-
First, a service is a normal Windows 32 program, and as such it has at least a system message queue (even if it doesn't use it). Each thread may also have a thread specific message queue, but the creation is deferred until it's really needed (e.g., a User or GDI function is called). The old SetTimer function makes use of window messages (it was normally used for background processing purposes back in the 16-bit days), even if you specify a callback. Because of this reason, one must get and dispatch messages when it's used. Basically, all you need to do is to implement a Get-or-Peek/DispatchMessage-loop somewhere in your ServiceMain (or a function called from it). This is what makes the wheel go round. MFC and other framework libraries have a message loop buried way down in their private code, so you don't see it often these days, but it's still integral to Windows. However, if the only WM-based function you're going to be using is SetTimer, there is a better solution: Waitable Timers. A waitable timer is a kernel object that can be waited on using the WaitForXObject(s) set of functions (cf. CreateWaitableTimer API), and it can be set to an absolute or relative due time. This way you can combine it with waiting on other events such as a Quit event, which is a good service design.
Thank you for responding to my query. I always appreciate it when people take the time to help. The Run() method in AtlServiceModule calls this method void RunMessageLoop() throw() { MSG msg; while (GetMessage(&msg, 0, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } } and I have checked and made sure this is being hit. As to only using a timer, my service is instantiating a COM object that uses WinSock messages (that weren't processed either). I have since written my own WinSock module that uses overlapped IO, but I am rather stubborn and would like to know WHY this code doesn't work. Timers worked fine in a service generated under VC6. Again, I'd like to thank the people that have responded to my query. I posted the same question in a newsgroup and no one responded.