Hi ALL
I am Srinivasan S Saripalli. I have a VC++ doubt which I have notified below. Hope you can give me a solution.

I have developed a ATL,COM 32-bit Service and in the Service I am implementing Timer functionality using either SetWaitableTimer or CreateWaitableTimer. When I compile my Service App I get the error as shown below

The ATL Win32 Service wizard generates a class mentioned below

class CServiceModule : public CComModule
{


public:


------------------------------------


------------------------------------


// here I have declared my Timer callback function to be


VOID CALLBACK TimerAPCProc(LPVOID lpArg,DWORD dwTimerLowValue,DWORD dwTimerHighValue);
HANDLE gDoneEvent;


};


In the implementation file ( *.cpp ) my code is shown below


#define _SECOND 10000000
typedef struct _MYDATA {
TCHAR *szText;
DWORD dwValue;
} MYDATA;
VOID CALLBACK CServiceModule::TimerAPCProc(
LPVOID lpArg,               // Data value
DWORD dwTimerLowValue,      // Timer low value
DWORD dwTimerHighValue )    // Timer high value


{
MYDATA *pMyData = (MYDATA *)lpArg;


/*_tprintf( TEXT("Message: %s\nValue: %d\n\n"), pMyData->szText,
pMyData->dwValue );
MessageBeep(0);*/


}


I have added the Timer functionality in the Run() method of the class CServiceModule


if (m_bService)
{
HANDLE          hTimer;
BOOL            bSuccess;
__int64         qwDueTime;
LARGE_INTEGER   liDueTime;
MYDATA          MyData;


MyData.szText = TEXT("This is my data");
MyData.dwValue = 100;


hTimer = CreateWaitableTimer(
NULL,                   // Default security attributes
FALSE,                  // Create auto-reset timer
TEXT("MyTimer"));       // Name of waitable timer


if (hTimer != NULL)
{
// Create an integer that will be used to signal the timer
// 5 seconds from now.
qwDueTime = -5 * _SECOND;


// Copy the relative time into a LARGE_INTEGER.
liDueTime.LowPart  = (DWORD) ( qwDueTime & 0xFFFFFFFF );
liDueTime.HighPart = (LONG)  ( qwDueTime >> 32 );


bSuccess = SetWaitableTimer(
hTimer,           // Handle to the timer object
&liDueTime,       // When timer will become signaled
2000,             // Periodic timer interval of 2 seconds
TimerAPCProc,     // Completion routine
&MyData,          // Argument to the completion routine
FALSE );


if ( bSuccess )
{
for ( ; MyData.dwValue < 1000; MyData.dwValue += 100 )
{
SleepEx(
INFINITE,     // Wait forever
TRUE );       // Put thread in an alertable state
}


}
else
{
printf("SetWaitableTimer failed with error %d\n",
GetLastError());
}
CloseHandle(hTimer);


}
else
{
printf("CreateWaitableTimer failed with error %d\n",
GetLastError());
}

When I compile this application I get the error as shown below

C:\srini\adminservice\SinumerikTimerService\SinumerikTimerService.cpp(398) : error C2664: 'SetWaitableTimer' : cannot convert parameter 4 from 'void (void *,unsigned long,unsigned long)' to 'void (__stdcall *)(void *,unsigned long,unsigned long)'

None of the functions with this name in scope match the target type
Error executing cl.exe.

Searching at Google and a person tells me that I should replace CALLBACK with __stdcall but why should I do that because CALLBACK in <winbase.h> is #define CALLBACK __stdcall but still I changed CALLBACK to __stdcall and also typecasted TimerAPCProc to be (PTIMERAPCROUTINE)TimerAPCProc but still I get the same error with respect to SetWaitableTimer

I have also #defined _WIN32_WINNT macro to be 0x0500 but still the error comes.

Also I have installed WinXP SP2 Platform SDK, Visual Studio 2005.

Therefore, I have added the path "C:\PROGRAM FILES\MICROSOFT PLATFORM SDK FOR WINDOWS XP SP2\INCLUDE" in Tools--> Options --> Directories and this gives me one more error

msxml.idl
C:\PROGRAM FILES\MICROSOFT PLATFORM SDK FOR WINDOWS XP SP2\INCLUDE\msxml.idl(52) : fatal error C1083: Cannot open include file: 'xmldom.idl': No such file or directory
midl : command line error MIDL1003 : error returned by the C preprocessor (2)
Error executing midl.exe.

To resolve the above xmldom.idl error I came to know that I have to install latest platform SDK.

However If I include "C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO 8\VC\PLATFORMSDK\INCLUDE" then the above xmldom.idl gets resolved and I get the below actual error

C:\srini\adminservice\SinumerikTimerService\SinumerikTimerService.cpp(398) : error C2664: 'SetWaitableTimer' : cannot convert parameter 4 from 'void (void *,unsigned long,unsigned long)' to 'void (__stdcall *)(void *,unsigned long,unsigned long)'
None of the functions with this name in scope match the target type
Error executing cl.exe.

I would be thankful to everybody who can give me a effective solution to the above problem.

Regards,

Srinivasan

Dani AI

Generated

Brief diagnosis and a safe fix.

The C2664 here is caused by trying to pass a C++ non‑static member function where SetWaitableTimer expects a plain C‑style callback. A non‑static member has an implicit this parameter (different signature / calling convention), so the compiler cannot convert it to the PTIMERAPCROUTINE type. is correct that putting the callback outside the instance fixes the mismatch.

Practical options that keep instance state accessible:

  • Make the callback a static member (no implicit this) and give it the exact signature used by PTIMERAPCROUTINE (VOID CALLBACK func(LPVOID, DWORD, DWORD)), or
  • Implement a free (global) function with that signature, or
  • Use a small static wrapper function that receives the LPVOID context (pass a pointer to the object or a context struct when creating the timer) and then forwards to an instance method. That wrapper lets the instance method remain non‑static while the callback itself matches the expected function pointer type.

Important cautions and cleanups:

  • Do not suppress the problem with casts to PTIMERAPCROUTINE; that hides type errors and can cause undefined behavior at runtime.
  • Ensure the callback signature exactly matches CALLBACK (__stdcall) and that the function is not overloaded.
  • Define _WIN32_WINNT in the project preprocessor settings (before including Windows headers) so the API prototypes are visible.
  • Guarantee the lifetime of the data passed via lpArg: either allocate it on the heap or keep it in a class member and cancel the timer / close the handle before freeing it.

About the msxml.idl/Platform SDK issue: avoid changing global VC6 include order in Tools->Options. Install the matching Platform SDK (or add its include directory to the project/MIDL include paths) so xmldom.idl is available, and keep SDK include order compatible with the compiler to prevent MIDL errors.

Implement the timer proc outside the CServiceModule class.
I.e. you will have

VOID CALLBACK ::TimerAPCProc(...)

instead of

VOID CALLBACK CServiceModule::TimerAPCProc(...)
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.