Using a Waitable Timer from within a Windows Service
I am attempting to use a WaitableTimer in a Windows Service written in C++ to bring a Windows XP machine out of sleep/stand-by mode but I cannot seem to get it to work. I copy/pasted the code I am using in the service into a standalone app and that works fine. Is there a step I am missing to get this to work within a service?
The code I am using to set up the waitable timer is as follows (the call to UpdateWaitableTimer() happens within a thread that loops indefinitely):
void UpdateWaitableTimer(job_definition *jobdef)
{
HANDLE existingHandle;
try
{
if (jobdef->JobType == JOB_TYPE_SCAN)
{
char szTimerName[MAX_PATH];
sprintf_s(szTimerName, MAX_PATH, "Timer_%I64d", jobdef->JobID);
existingHandle = OpenWaitableTimer(TIMER_ALL_ACCESS, TRUE, szTimerName);
if (existingHandle != NULL)
{
// A timer handle already exists for this job, so cancel it
CancelWaitableTimer(existingHandle);
}
else
{
// No timer handle exists, create one
existingHandle = CreateWaitableTimer(NULL, TRUE, szTimerName);
}
if (jobdef->JobStatus != JOB_STATUS_SCHEDULED)
{
// This job was cancelled, so close the handle
CloseHandle(existingHandle);
}
else
{
time_t now = time(NULL);
time_t dt = jobdef->JobScheduleTime;
while(dt < now)
{
dt += 86400;
}
// Get a FILETIME one minute before
FILETIME utcFileTime = GetTimestamp(dt - 60);
// Convert to LARGE_INTEGER
LARGE_INTEGER dueTime;
dueTime.HighPart = utcFileTime.dwHighDateTime;
dueTime.LowPart = utcFileTime.dwLowDateTime;
SYSTEMTIME st;
FILETIME *ft = &utcFileTime;
FileTimeToSystemTime(ft, &st);
LogRelease(false, "Setting Timer for scheduled job: %02d/%02d/%d %02d:%02d:%02d", st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond);
if(SetWaitableTimer(existingHandle, &dueTime, 0, NULL, NULL, TRUE))
{
if(GetLastError() == ERROR_NOT_SUPPORTED)
{
LogRelease(false, "Resume from sleep/stand-by feature not supported on this operating system.");
}
}
else
{
LogError(false, "Could not create timer. Error: %d", GetLastError());
}
}
}
}
catch(...)
{
LogError(fa开发者_如何学JAVAlse, "An exception occured while updating waitable timer for job %I64d", jobdef->JobID);
}
LogRelease(false, "Finished Updating Waitable Timer [Job:%I64d]", jobdef->JobID);
}
If it works outside a service then your code is probably fine. There are really only two things I can think of that might cause it to behave differently:
Resuming might require the service to be able to "interact with the desktop." Try setting that option in the service manager under the log on tab, and restart your service.
Services running as LOCAL_SYSTEM might not have rights to resume from sleep. Try running the service as yourself, or create a service account specifically for the service to run from.
If you're already running the service as a specific user, then perhaps that user account has insufficient permissions.
精彩评论