I'm implementing a custom Vista Credential Provider that uses a smart card to pass credentials to LogonUI to authenticate and log on.
To poll for the smart card when the CredProv is created I start a thread which calls SCardEstablishContext() to prepare for card polling. The problem is the smart card service isn't started immediately on boot so the SCardEstablishContext() was failing. To fix that failing API call I just put the SCardEstablishContext into a while loop which waited for the result != SCARD_E_NO_SERVICE. This worked until the smart card service was turned off during testing. At that point my credential tile was not displayed, as designed, when no user was logged on. Unfortunately, none of the other users could log on. You would attempt to log on and the "Welcome" screen would just stall.
I assumed the issue was related to the while loop in my thread, so I began trying to find a way to only call SCardEstablishContext() if the smart card service was running. To do this, after some trial and error, I found that using NotifyServiceStatusChange(
) with a WaitForSingleObjectEx() would be the best method.
But as you can assume it's not working as I would hope. The code snippets are the function I call from my thread that should wait for the service to be SERVICE_RUNNING before returning as well as the CALLBACK function for NotifyServiceStatusChange(
What's happening is if the service is not running, the DoQuerySvc() seems to loop, calling itself every 7 seconds or so. This isn't so bad on boot because it only loops twice, but when the smart card service is turned off, it loops continuously causing a flashing screen that doesn't allow the user to log onto any of the other tiles, requiring a reboot.
I figured the NotifyServiceStatusChange(
) and WaitForSingleObjectEx() would wait only once until the SERVICE_RUNNING flag is provided, rather than looping?
PSERVICE_NOTIFY pNotifyBuffer = NULL;
StringCchCopy(szSvcName, 80, L"scardsvr");
// Get a handle to the SCM database.
schSCManager = OpenSCManager(
NULL, // local computer
NULL, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (NULL == schSCManager)
// Get a handle to the service.
schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
SERVICE_ALL_ACCESS); // need query config access
if (schService == NULL)
if (ssp.dwCurrentState != SERVICE_RUNNING)
memset(&ServiceNotify, 0, sizeof(ServiceNotify));
ServiceNotify->dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
ServiceNotify->pfnNotifyCallback = onServiceChange;
ServiceNotify->pContext = &EventHandle;
static VOID CALLBACK onServiceChange(IN PVOID pParameter)
ServiceNotify = (SERVICE_NOTIFY*) pParameter;
EventHandle = *(HANDLE*)ServiceNotify->pContext;