Link to home
Start Free TrialLog in
Avatar of MattC
MattC

asked on

timed polling of a database in a W2K service

Using the ATL Wizard in VC++6 I've created a service.  I'm guessing that my code has to go in the run() method.

My first question is:

If all I want my service to do is after a set time interval get some data from the database.  How do I loop?
If I put a while loop in the run method then i will effectively lock the service from communicating with the SCM.

Any help or small examples would be great, I do have a book on it but as of yet I've not found anything regarding this, and I am pushed for time.

Second question:
Can ATL system services support MFC class usage?
ASKER CERTIFIED SOLUTION
Avatar of cookre
cookre
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of MattC
MattC

ASKER

i thought about starting a worker thread in Run() then making that a while(SERVICE_RUNNING) and then at the top of the while do a Sleep(300000) so each time round it waits 300 seconds before going round again.
Avatar of MattC

ASKER

oops that should be:

while(_Module.m_status = SERVICE_RUNNING){
   Sleep(300000);

   //do code here
}
Sounds reasonable, as long as you don't need to be doing anything else at the time (including message processing).
Avatar of DanRollins
>>Can ATL system services support MFC class usage?

When you create the service, the AppWizard presents that as an option.  There is a "Support MFC" checkbox.

-- Dan
oops, I see that the Support MFC checkbox gets dimmed when you select the Service radio button.  Looking at my code, for a service that uses MFC, I see that I needed to add some headers to StdAfx.h:

#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions

I also see that for some reason I have this in the InitInstance:

    afxContextIsDLL= FALSE;

Alas, I did not comment the reason for that code!
-- Dan
Why don't you just kick off a separate thread from the service in order to do the polling work - it could be as simple as

long WINAPI TimerThread ( LPVOID pv) {

DWORD dwWait = ( DWORD) pv,

for ( ;;) {

 Sleep ( dwWait);

 // do work here...
}
}
BTW, if you'd like something more sophisticated than the above, check out http://support.microsoft.com/support/kb/articles/q184/7/96.asp ("HOWTO: Use a Waitable Timer with an Asynchronous Procedure Call (Q184796)") and http://msdn.microsoft.com/library/en-us/dllproc/synchro_2bcj.asp ("Using Waitable Timer Objects")
Avatar of MattC

ASKER

Ah, drat as usual, excellent answer....but from completely different people.

Thanks guys.  Gimme a couple of days and I will dish out some points. :-)

MattC
Avatar of MattC

ASKER

one last thing :-)

below is the Run() method.
I have put '*****************' where i think my code should go, is this right???

void CServiceModule::Run()
{
    _Module.dwThreadID = GetCurrentThreadId();

    HRESULT hr = CoInitialize(NULL);
//  If you are running on NT 4.0 or higher you can use the following call
//  instead to make the EXE free threaded.
//  This means that calls come in on a random RPC thread
//  HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);

    _ASSERTE(SUCCEEDED(hr));

    // This provides a NULL DACL which will allow access to everyone.
    CSecurityDescriptor sd;
    sd.InitializeFromThreadToken();
    hr = CoInitializeSecurity(sd, -1, NULL, NULL,
        RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
    _ASSERTE(SUCCEEDED(hr));

    hr = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, REGCLS_MULTIPLEUSE);
    _ASSERTE(SUCCEEDED(hr));

    LogEvent(_T("Service started"));
    if (m_bService)
        SetServiceStatus(SERVICE_RUNNING);

    MSG msg;
    while (GetMessage(&msg, 0, 0, 0))
        DispatchMessage(&msg);

************************************** //<-- My Code here

    _Module.RevokeClassObjects();

    CoUninitialize();
}
Well, that depends on what your code is like :o)
Avatar of MattC

ASKER

:-)

see cookre's response at the top, I was gonna do something like that.
Matt
>>I was gonna do something like that

Uh, so your service has a UI?
Avatar of MattC

ASKER

no, but the hWnd argument can be NULL.
Yes, but the docs to 'SetTimer()' state:

"Remarks
An application can process WM_TIMER messages by including a WM_TIMER case statement in the window procedure or by specifying a TimerProc callback function when creating the timer. When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER."

If you don't have any UI, there will be no msg processing/dispatching...
Avatar of MattC

ASKER

MSG msg;
while (GetMessage(&msg, 0, 0, 0))
DispatchMessage(&msg);

i thought that's what this section did?
Ooops :o)
Avatar of MattC

ASKER

phew, i thought i was gonna have to rewrite a whole load of documentation there :0)
Documentation?
You mean there's more to this job than coding?
>>******************************* //<-- My Code here

I think you would want to start the timer above there, then handle it in the TimerProc, outside of the loop.

-- Dan

Dear MattC

I think you forgot this question. I will ask Community Support to close it unless you finalize it within 7 days. You can always request to keep this question open. But remember, experts can only help you if you provide feedback to their questions.
Unless there is objection or further activity,  I will suggest to split between

     "jkr, DanRollins, cookre"

comment(s) as an answer.

If you think your question was not answered at all, you can post a request in Community support (please include this link) to refund your points. The link to the Community Support area is: https://www.experts-exchange.com/commspt/

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!
======
Werner