Avatar of howardsd
howardsd

asked on 

Issue attempting to use NotifyServiceStatusChange() during Vista boot

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?

Any ideas?

int DoQuerySvc()
{
     SC_HANDLE schSCManager;
     SC_HANDLE schService;
     SERVICE_STATUS_PROCESS ssp;
     DWORD dwBytesNeeded; 
     TCHAR szSvcName[80];
     PSERVICE_NOTIFY pNotifyBuffer = NULL;
     HANDLE EventHandle;
     SERVICE_NOTIFY* ServiceNotify;
 
     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) 
     {
          return 0;
     }
 
     // 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)
     { 
          CloseServiceHandle(schSCManager);
          return 0;
     }
 
     if( !QueryServiceStatusEx(
                    schService,
                    SC_STATUS_PROCESS_INFO, 
                    (LPBYTE) &ssp,
                    sizeof(SERVICE_STATUS_PROCESS), 
                    &dwBytesNeeded))
                    {
                         goto cleanup; 
                    }
 
     if (ssp.dwCurrentState != SERVICE_RUNNING)
     {
          memset(&ServiceNotify, 0, sizeof(ServiceNotify));
 
          ServiceNotify->dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
          ServiceNotify->pfnNotifyCallback = onServiceChange;
          ServiceNotify->pContext = &EventHandle;
 
          NotifyServiceStatusChange( 
                         schService,
	                 SERVICE_NOTIFY_RUNNING,
			 ServiceNotify);
 
          WaitForSingleObjectEx(EventHandle, INFINITE);
     }
 
     return ssp.dwCurrentState; 
 
cleanup:
CloseServiceHandle(schService); 
CloseServiceHandle(schSCManager);
return 0;
 
static VOID CALLBACK onServiceChange(IN PVOID pParameter)
{
     SERVICE_NOTIFY* ServiceNotify;
     HANDLE EventHandle;
 
     ServiceNotify = (SERVICE_NOTIFY*) pParameter;
     EventHandle = *(HANDLE*)ServiceNotify->pContext;
     SetEvent(EventHandle);
}

Open in new window

System ProgrammingWindows VistaC++

Avatar of undefined
Last Comment
jkr

8/22/2022 - Mon