2

I am implementing a Windows Biometric Driver using the umdf sample from github. When I call WinBioCaptureSample the next plugin's methods run in a loop.

SensorAdapterClearContext
EngineAdapterClearContext
SensorAdapterStartCapture
SensorAdapterFinishCapture

I used TraceView to debug my driver and it shows the next trace messages when is stuck in a loop.

00000001    driver  352840  439560  1   1   04\05\2018-16:46:13:12  CBiometricDevice::OnGetSensorStatus Called.
00000002    driver  352840  439560  1   2   04\05\2018-16:46:13:12  CBiometricDevice::OnGetAttributes Called.
00000003    driver  352840  439560  1   3   04\05\2018-16:46:13:12  CBiometricDevice::OnCaptureDataBuffer too small - must be at least 0x18.
00000004    driver  352840  439560  1   4   04\05\2018-16:46:13:12  CBiometricDevice::OnCaptureData Called.
00000005    driver  352840  439560  4   5   04\05\2018-16:46:13:28  CBiometricDevice::OnGetSensorStatus Called.
00000006    driver  352840  439560  1   6   04\05\2018-16:46:13:29  CBiometricDevice::OnCaptureDataBuffer too small - must be at least 0x18.
00000007    driver  352840  439560  1   7   04\05\2018-16:46:13:29  CBiometricDevice::OnCaptureData Called.
00000008    driver  352840  439560  1   8   04\05\2018-16:46:13:30  CBiometricDevice::OnGetSensorStatus Called.
00000009    driver  352840  439560  4   9   04\05\2018-16:46:13:30  CBiometricDevice::OnCaptureDataBuffer too small - must be at least 0x18.
00000010    driver  352840  439560  1   10  04\05\2018-16:46:13:31  CBiometricDevice::OnCaptureData Called.
...

The method CBiometricDevice::OnGetSensorStatus always returns WINBIO_SENSOR_READY

diagnostics->WinBioHresult = S_OK;    
diagnostics->SensorStatus = WINBIO_SENSOR_READY;    
MyRequest.SetInformation(diagnostics->PayloadSize);
MyRequest.SetCompletionHr(S_OK);

Next is the method CBiometricDevice::OnCaptureData

DWORD WINAPI
CaptureSleepThread(
    LPVOID lpParam
    ) 
{ 
    CBiometricDevice *device = (CBiometricDevice *) lpParam;
    PCAPTURE_SLEEP_PARAMS sleepParams = device->GetCaptureSleepParams();
   if (sleepParams->SleepValue > 60)
    {
        sleepParams->SleepValue = 60;
    }

    Sleep(sleepParams->SleepValue * 1000);

    UCHAR szBuffer[] = { 0x08, 0x01, 0x00, 0x02 };
    ULONG cbRead = 4;

    sleepParams->captureData->WinBioHresult = S_OK;
    sleepParams->captureData->SensorStatus = WINBIO_SENSOR_ACCEPT;
    sleepParams->captureData->RejectDetail = 0;
    sleepParams->captureData->CaptureData.Size = cbRead;

    RtlCopyMemory(sleepParams->captureData->CaptureData.Data, szBuffer, cbRead);

    device->CompletePendingRequest(sleepParams->Hr, sleepParams->Information);

    return 0;
}

CBiometricDevice::OnCaptureData(
    _Inout_ IWDFIoRequest *FxRequest
    )

{
    ULONG controlCode = 0;
    PWINBIO_CAPTURE_PARAMETERS captureParams = NULL;
    SIZE_T inputBufferSize = 0;
    PWINBIO_CAPTURE_DATA captureData = NULL;
    SIZE_T outputBufferSize = 0;
    bool requestPending = false;

    EnterCriticalSection(&m_RequestLock);

    if (m_PendingRequest == NULL) 
    {

        if (m_SleepThread != INVALID_HANDLE_VALUE)
        {
            LeaveCriticalSection(&m_RequestLock);

            // TODO: Add code to signal thread to exit.

            WaitForSingleObject(m_SleepThread, INFINITE);
            CloseHandle(m_SleepThread);
            m_SleepThread = INVALID_HANDLE_VALUE;

            EnterCriticalSection(&m_RequestLock);
        }

        if (m_PendingRequest == NULL)
        {
            m_PendingRequest = FxRequest;
            m_PendingRequest->MarkCancelable(this);
        }
        else
        {
            requestPending = true;
        }

    } 
    else 
    {
        requestPending = true;
    }

    LeaveCriticalSection(&m_RequestLock);

    if (requestPending)
    {
        FxRequest->Complete(WINBIO_E_DATA_COLLECTION_IN_PROGRESS);
        return;
    }

    GetIoRequestParams(FxRequest,
                       &controlCode,
                       (PUCHAR *)&captureParams,
                       &inputBufferSize,
                       (PUCHAR *)&captureData,
                       &outputBufferSize);

     if (inputBufferSize < sizeof (WINBIO_CAPTURE_PARAMETERS)) 
     {
        TraceEvents(TRACE_LEVEL_ERROR, 
                   BIOMETRIC_TRACE_DEVICE, 
                   "%!FUNC!Invalid argument(s).");
        CompletePendingRequest(E_INVALIDARG, 0);
        return;
    }

    if (outputBufferSize < sizeof(DWORD)) 
    {
        TraceEvents(TRACE_LEVEL_ERROR, 
                   BIOMETRIC_TRACE_DEVICE, 
                   "%!FUNC!Output buffer NULL or too small to return size information.");
        CompletePendingRequest(E_INVALIDARG, 0);
        return;
    }

    if (outputBufferSize < sizeof (WINBIO_CAPTURE_DATA)) 
    {
        TraceEvents(TRACE_LEVEL_ERROR, 
                   BIOMETRIC_TRACE_DEVICE, 
                   "%!FUNC!Buffer too small - must be at least 0x%x.", sizeof (WINBIO_CAPTURE_DATA));

        DWORD cbSize = 262144;//obtained from MAXIMUM_TRANSFER_SIZE policy of WinUsb
        captureData->PayloadSize = (DWORD) sizeof(WINBIO_CAPTURE_DATA) + cbSize;
        CompletePendingRequest(S_OK, sizeof(DWORD));
        return;
    }

    RtlZeroMemory(captureData, outputBufferSize);

    captureData->PayloadSize = (DWORD) outputBufferSize;// (DWORD) sizeof(WINBIO_CAPTURE_DATA);
    captureData->WinBioHresult = WINBIO_E_NO_CAPTURE_DATA;
    captureData->SensorStatus = WINBIO_SENSOR_FAILURE;
    captureData->RejectDetail= 0;
    captureData->CaptureData.Size = 0;

    if (captureParams->Purpose == WINBIO_NO_PURPOSE_AVAILABLE)
    {
        captureData->WinBioHresult = WINBIO_E_UNSUPPORTED_PURPOSE;
    }
    else if ((captureParams->Format.Type != WINBIO_ANSI_381_FORMAT_TYPE) ||
             (captureParams->Format.Owner != WINBIO_ANSI_381_FORMAT_OWNER))
    {
        captureData->WinBioHresult = WINBIO_E_UNSUPPORTED_DATA_FORMAT;
    }
    else if (captureParams->Flags != WINBIO_DATA_FLAG_RAW)
    {
        captureData->WinBioHresult = WINBIO_E_UNSUPPORTED_DATA_TYPE;
    }

    struct _WINUSB_PIPE_INFORMATION InputPipeInfo, OutputPipeInfo;
    m_pIUsbInputPipe->GetInformation(&InputPipeInfo);
    m_pIUsbOutputPipe->GetInformation(&OutputPipeInfo);

    m_SleepParams.PipeInId = InputPipeInfo.PipeId;
    m_SleepParams.PipeOutId = OutputPipeInfo.PipeId;
    m_SleepParams.hDeviceHandle = m_pIUsbInterface->GetWinUsbHandle();
    m_SleepParams.cbSize = (DWORD) outputBufferSize;

    m_SleepParams.SleepValue = 5;
    m_SleepParams.Hr = S_OK;
    m_SleepParams.Information = captureData->PayloadSize;
    m_SleepParams.captureData = captureData;
    m_SleepThread = CreateThread(NULL,                   // default security attributes
                                 0,                      // use default stack size  
                                 CaptureSleepThread,     // thread function name
                                 this,                   // argument to thread function 
                                 0,                      // use default creation flags 
                                 NULL);                  // returns the thread identifier 

    TraceEvents(TRACE_LEVEL_ERROR,
        BIOMETRIC_TRACE_DEVICE,
        "%!FUNC! Called.");
}

The methods SensorAdapterStartCapture and SensorAdapterFinishCapture returns S_OK

static HRESULT
WINAPI
SensorAdapterStartCapture(
    _Inout_ PWINBIO_PIPELINE Pipeline,
    _In_ WINBIO_BIR_PURPOSE Purpose,
    _Out_ LPOVERLAPPED *Overlapped
    )
{
    HRESULT hr = S_OK;
    WINBIO_SENSOR_STATUS sensorStatus = WINBIO_SENSOR_FAILURE;
    WINBIO_CAPTURE_PARAMETERS captureParameters = { 0 };
    BOOL result = TRUE;
    DWORD bytesReturned = 0;

    // Verify that pointer arguments are not NULL.
    if (!ARGUMENT_PRESENT(Pipeline) ||
        !ARGUMENT_PRESENT(Purpose) ||
        !ARGUMENT_PRESENT(Overlapped))
    {
        return E_POINTER;

    }

    // Retrieve the context from the pipeline.
    PWINIBIO_SENSOR_CONTEXT sensorContext =
        (PWINIBIO_SENSOR_CONTEXT)Pipeline->SensorContext;

    // Verify the state of the pipeline.
    if (sensorContext == NULL ||
        Pipeline->SensorHandle == INVALID_HANDLE_VALUE)
    {
        return WINBIO_E_INVALID_DEVICE_STATE;
    }

    *Overlapped = NULL;

    //  Synchronously retrieve the status.
    hr = SensorAdapterQueryStatus(Pipeline, &sensorStatus);
    if (FAILED(hr))
    {
        return hr;
    }

    // Determine whether the sensor requires calibration.
    //if (sensorStatus == WINBIO_SENSOR_NOT_CALIBRATED)
    //{
        // Call a custom function that sends IOCTLs to
        // the sensor to calibrate it. This operation is
        // synchronous.
        //hr = _SensorAdapterCalibrate(Pipeline);

        // Retrieve the status again to determine whether the 
        // sensor is ready.
        //if (SUCCEEDED(hr))
        //{
        //    hr = SensorAdapterQueryStatus(Pipeline, &sensorStatus);
        //}

        //if (FAILED(hr))
        //{
        //    return hr;
        //}
    //}
    if (sensorStatus == WINBIO_SENSOR_BUSY)
    {
        return WINBIO_E_DEVICE_BUSY;
    }

    if (sensorStatus != WINBIO_SENSOR_READY)
    {
        return WINBIO_E_INVALID_DEVICE_STATE;
    }

    // Determine whether the data format has been previously determined.
    // If it has not, find a format supported by both the engine and 
    // the sensor.
    if ((sensorContext->Format.Owner == 0) &&
        (sensorContext->Format.Type == 0))
    {

        // Retrieve the format preferred by the engine.
        hr = Pipeline->EngineInterface->QueryPreferredFormat(
            Pipeline,
            &sensorContext->Format,
            &sensorContext->VendorFormat
        );
        if (SUCCEEDED(hr))
        {
            // Call a private function that queries the sensor driver
            // and attaches an attribute array to the sensor context.
            // This operation is synchronous.
            hr = _SensorAdapterGetAttributes(Pipeline);
        }

        if (SUCCEEDED(hr))
        {
            // Search the sensor attributes array for the format
            // preferred by the engine adapter.
            DWORD i = 0;
            for (i = 0; i < sensorContext->AttributesBuffer->SupportedFormatEntries; i++)
            {
                if ((sensorContext->AttributesBuffer->SupportedFormat[i].Owner == sensorContext->Format.Owner) &&
                    (sensorContext->AttributesBuffer->SupportedFormat[i].Type == sensorContext->Format.Type))
                {
                    break;
                }
            }

            if (i == sensorContext->AttributesBuffer->SupportedFormatEntries)
            {
                // No match was found. Use the default.
                sensorContext->Format.Owner = WINBIO_ANSI_381_FORMAT_OWNER;
                sensorContext->Format.Type = WINBIO_ANSI_381_FORMAT_TYPE;
            }
        }
        else
        {
            return hr;
        }
    }

    // Set up the parameter-input block needed for the IOCTL.
    captureParameters.PayloadSize = sizeof(WINBIO_CAPTURE_PARAMETERS);
    captureParameters.Purpose = Purpose;
    captureParameters.Format.Owner = sensorContext->Format.Owner;
    captureParameters.Format.Type = sensorContext->Format.Type;
    CopyMemory(&captureParameters.VendorFormat, &sensorContext->VendorFormat, sizeof(WINBIO_UUID));
    captureParameters.Flags = WINBIO_DATA_FLAG_RAW;

     // Determine whether a buffer has already been allocated for this sensor.
    if (sensorContext->CaptureBuffer == NULL)
    {
        DWORD allocationSize = 0;

        sensorContext->CaptureBufferSize = 0;

        // This sample assumes that the sensor driver returns
        // a fixed-size DWORD buffer containing the required
        // size of the capture buffer if it receives a buffer
        // that is smaller than sizeof(WINBIO_CAPTURE_DATA).
        //
        // Call the driver with a small buffer to get the 
        // allocation size required for this sensor.
        //
        // Because this operation is asynchronous, you must block 
        // and wait for it to complete.
        result = DeviceIoControl(
            Pipeline->SensorHandle,
            IOCTL_BIOMETRIC_CAPTURE_DATA,
            &captureParameters,
            sizeof(WINBIO_CAPTURE_PARAMETERS),
            &allocationSize,
            sizeof(DWORD),
            &bytesReturned,
           &sensorContext->Overlapped
        );
        if (!result && GetLastError() == ERROR_IO_PENDING)
        {
            SetLastError(ERROR_SUCCESS);

            result = GetOverlappedResult(
                Pipeline->SensorHandle,
                &sensorContext->Overlapped,
                &bytesReturned,
                TRUE
            );
        }

        if (!result || bytesReturned != sizeof(DWORD))
        {
            // An error occurred.
            hr = _AdapterGetHresultFromWin32(GetLastError());
            return hr;
        }

        // Make sure that you allocate at least the minimum buffer 
        // size needed to get the payload structure.
        if (allocationSize < sizeof(WINBIO_CAPTURE_DATA))
        {
            allocationSize = sizeof(WINBIO_CAPTURE_DATA);
        }

        // Allocate the buffer.
        sensorContext->CaptureBuffer = (PWINBIO_CAPTURE_DATA)_AdapterAlloc(allocationSize);
        if (!sensorContext->CaptureBuffer)
        {
            sensorContext->CaptureBufferSize = 0;
            return E_OUTOFMEMORY;
        }
        sensorContext->CaptureBufferSize = allocationSize;
    }
    else
    {
        // The buffer has already been allocated. Clear the buffer contents. 
        SensorAdapterClearContext(Pipeline);
    }

    // Send the capture request. Because this is an asynchronous operation,
    // the IOCTL call will return immediately regardless of 
    // whether the I/O has completed.
    result = DeviceIoControl(
        Pipeline->SensorHandle,
        IOCTL_BIOMETRIC_CAPTURE_DATA,
        &captureParameters,
        sizeof(WINBIO_CAPTURE_PARAMETERS),
        sensorContext->CaptureBuffer,
        (DWORD)sensorContext->CaptureBufferSize,
        &bytesReturned,
        &sensorContext->Overlapped
    );

    if (result ||
        (!result && GetLastError() == ERROR_IO_PENDING))
    {
        *Overlapped = &sensorContext->Overlapped;
        return S_OK;
    }
    else
    {
        hr = _AdapterGetHresultFromWin32(GetLastError());
        return hr;
    }

}

static HRESULT
WINAPI
SensorAdapterFinishCapture(
    _Inout_ PWINBIO_PIPELINE Pipeline,
    _Out_ PWINBIO_REJECT_DETAIL RejectDetail
    )
{
    HRESULT hr = S_OK;
    //WINBIO_SENSOR_STATUS sensorStatus = WINBIO_SENSOR_FAILURE;
    WINBIO_CAPTURE_PARAMETERS captureParameters = { 0 };
    BOOL result = TRUE;
    DWORD bytesReturned = 0;

    // Verify that pointer arguments are not NULL.
    if (!ARGUMENT_PRESENT(Pipeline) ||
        !ARGUMENT_PRESENT(RejectDetail))
    {
        return E_POINTER;        
    }

    // Retrieve the context from the pipeline.
    PWINIBIO_SENSOR_CONTEXT sensorContext =
        (PWINIBIO_SENSOR_CONTEXT)Pipeline->SensorContext;

    // Verify the state of the pipeline.
    if (sensorContext == NULL ||
        Pipeline->SensorHandle == INVALID_HANDLE_VALUE)
    {
        return WINBIO_E_INVALID_DEVICE_STATE;
    }

    // Initialize the RejectDetail argument.
    *RejectDetail = 0;

    // Wait for I/O completion. This sample assumes that the I/O operation was 
    // started using the code example shown in the SensorAdapterStartCapture
    // documentation.
    SetLastError(ERROR_SUCCESS);

    result = GetOverlappedResult(
        Pipeline->SensorHandle,
        &sensorContext->Overlapped,
        &bytesReturned,
        TRUE
    );
    if (!result)
    {
        // There was an I/O error.
        return _AdapterGetHresultFromWin32(GetLastError());
    }

    if (bytesReturned == sizeof(DWORD))
    {
        // The buffer is not large enough.  This can happen if a device needs a 
        // bigger buffer depending on the purpose. Allocate a larger buffer and 
        // force the caller to reissue their I/O request.
        DWORD allocationSize = sensorContext->CaptureBuffer->PayloadSize;

        // Allocate at least the minimum buffer size needed to retrieve the 
        // payload structure.
        if (allocationSize < sizeof(WINBIO_CAPTURE_DATA))
        {
            allocationSize = sizeof(WINBIO_CAPTURE_DATA);
        }

        // Free the old buffer and allocate a new one.
        _AdapterRelease(sensorContext->CaptureBuffer);
        sensorContext->CaptureBuffer = NULL;

        sensorContext->CaptureBuffer =
            (PWINBIO_CAPTURE_DATA)_AdapterAlloc(allocationSize);
        if (sensorContext->CaptureBuffer == NULL)
        {
            sensorContext->CaptureBufferSize = 0;
            return E_OUTOFMEMORY;
        }
        sensorContext->CaptureBufferSize = allocationSize;
        return WINBIO_E_BAD_CAPTURE;
    }

    // Normalize the status value before sending it back to the biometric service.
    if (sensorContext->CaptureBuffer != NULL &&
        sensorContext->CaptureBufferSize >= sizeof(WINBIO_CAPTURE_DATA))
    {
        switch (sensorContext->CaptureBuffer->SensorStatus)
        {
        case WINBIO_SENSOR_ACCEPT:
        {
            // The capture was acceptable.
            DWORD cbRead = sensorContext->CaptureBuffer->CaptureData.Size;
            UCHAR * data = sensorContext->CaptureBuffer->CaptureData.Data;
            //wprintf(L"%d ", cbRead);
            break;
        }
        case WINBIO_SENSOR_REJECT:
            // The capture was not acceptable. Overwrite the WinBioHresult value
            // in case it has not been properly set.
            sensorContext->CaptureBuffer->WinBioHresult = WINBIO_E_BAD_CAPTURE;
            break;

        case WINBIO_SENSOR_BUSY:
            // The device is busy. Reset the WinBioHresult value in case it 
            // has not been properly set.
            sensorContext->CaptureBuffer->WinBioHresult = WINBIO_E_DEVICE_BUSY;
            break;

        case WINBIO_SENSOR_READY:
        case WINBIO_SENSOR_NOT_CALIBRATED:
        case WINBIO_SENSOR_FAILURE:
        default:
            // There has been a device failure. Reset the WinBioHresult value
            // in case it has not been properly set.
            sensorContext->CaptureBuffer->WinBioHresult = WINBIO_E_INVALID_DEVICE_STATE;
            break;
        }

        *RejectDetail = sensorContext->CaptureBuffer->RejectDetail;
        hr = sensorContext->CaptureBuffer->WinBioHresult;
    }
    else
    {
        // The buffer is not large enough or the buffer pointer is NULL.
        hr = WINBIO_E_INVALID_DEVICE_STATE;
    }
    return hr;

}

I used the next code from this github project

HRESULT CaptureSample()
{
  HRESULT hr = S_OK;
  WINBIO_SESSION_HANDLE sessionHandle = NULL;
  WINBIO_UNIT_ID unitId = 0;
  WINBIO_REJECT_DETAIL rejectDetail = 0;
  PWINBIO_BIR sample = NULL;
  SIZE_T sampleSize = 0;

  // Connect to the system pool. 
  hr = WinBioOpenSession(
    WINBIO_TYPE_FINGERPRINT,    // Service provider
    WINBIO_POOL_SYSTEM,         // Pool type
    WINBIO_FLAG_RAW,            // Access: Capture raw data //To call WinBioCaptureSample function successfully, you must open the session handle by specifying WINBIO_FLAG_RAW
                                //WINBIO_FLAG_RAW: The client application captures raw biometric data using WinBioCaptureSample.
    NULL,                       // Array of biometric unit IDs //NULL if the PoolType parameter is WINBIO_POOL_SYSTEM
    0,                          // Count of biometric unit IDs//zero if the PoolType parameter is WINBIO_POOL_SYSTEM.
    WINBIO_DB_DEFAULT,          // Default database
    &sessionHandle              // [out] Session handle
    );

  if(FAILED(hr))
  {
    std::cout << "WinBioOpenSession failed. hr = 0x" << std::hex << hr << std::dec << "\n";

    if(sample != NULL)
    {
      WinBioFree(sample);
      sample = NULL;
    }

    if(sessionHandle != NULL)
    {
      WinBioCloseSession(sessionHandle);
      sessionHandle = NULL;
    }

    return hr;
  }

  // Capture a biometric sample.
  std::cout << "Calling WinBioCaptureSample - Swipe sensor...\n";

  hr = WinBioCaptureSample(
    sessionHandle,
    WINBIO_NO_PURPOSE_AVAILABLE,
    WINBIO_DATA_FLAG_RAW,//WINBIO_DATA_FLAG_RAW
    &unitId,
    &sample,
    &sampleSize,
    &rejectDetail
    );

  if(FAILED(hr))
  {
    if(hr == WINBIO_E_BAD_CAPTURE)
      std:: cout << "Bad capture; reason: " << rejectDetail << "\n";
    else
      std::cout << "WinBioCaptureSample failed.hr = 0x" << std::hex << hr << std::dec << "\n";

    if(sample != NULL)
    {
      WinBioFree(sample);
      sample = NULL;
    }

    if(sessionHandle != NULL)
    {
      WinBioCloseSession(sessionHandle);
      sessionHandle = NULL;
    }

    return hr;
  }

  std::cout << "Swipe processed - Unit ID: " << unitId << "\n";
  std::cout << "Captured " << sampleSize << " bytes.\n";

  if(sample != NULL)
  {            
    WinBioFree(sample);
    sample = NULL;
  }

  if(sessionHandle != NULL)
  {
    WinBioCloseSession(sessionHandle);
    sessionHandle = NULL;
  }

  return hr;
}


int main()
{
  EnumerateSensors();
  CreateDirectoryA("data", NULL);
  CaptureSample();
}

Sometimes my code is stuck in a loop and other times is not :(

Any hint is welcomed Thanks.

Juan Rojas
  • 8,711
  • 1
  • 22
  • 30
  • I forgot to mention that I am using an expired certificate changing the system date one year earlier to sign the plugins and driver. I am not sure if this is the cause or there is an error in my code causing the loop. – Juan Rojas Apr 08 '19 at 14:31
  • I also noticed that the loop starts when I attach a debugger Windbg and/or Visual Studio (for debugging plugins) but If I don't use debuggers and Disable/enable my device and stop and start Windows Biometric Service the code runs fine – Juan Rojas Apr 08 '19 at 19:42

1 Answers1

1

It seems I might have found a temporary solution to my problem. First what I did is to change the sensor mode from basic to advanced.

[DriverPlugInAddReg]
HKR,WinBio\Configurations,DefaultConfiguration,,"0"
HKR,WinBio\Configurations\0,SensorMode,0x10001,2                                ; Basic - 1, Advanced - 2

And the loop won't start

But I also noticed If I comment the call to the Sleep method inside CaptureSleepThread the loop starts again.

My guess is that Windows Biometric Service is expecting the method CaptureSleepThread to take some time to be considered successful but if the method ends very fast it is considered to be failed despite of the successful responses S_OK and WINBIO_SENSOR_ACCEPT and Windows Biometric Service will retry again calling to SensorAdapterStartCapture causing a loop.

DWORD WINAPI
CaptureSleepThread(
    LPVOID lpParam
    ) 
{ 
    CBiometricDevice *device = (CBiometricDevice *) lpParam;
    PCAPTURE_SLEEP_PARAMS sleepParams = device->GetCaptureSleepParams();

    //
    // 1 minute or half a minute delay is the trick.
    //
   if (sleepParams->SleepValue > 60)
    {
        sleepParams->SleepValue = 60;
    }

    Sleep(sleepParams->SleepValue * 1000);

    UCHAR szBuffer[] = { 0x08, 0x01, 0x00, 0x02 };
    ULONG cbRead = 4;

    sleepParams->captureData->WinBioHresult = S_OK;
    sleepParams->captureData->SensorStatus = WINBIO_SENSOR_ACCEPT;
    sleepParams->captureData->RejectDetail = 0;
    sleepParams->captureData->CaptureData.Size = cbRead;

    RtlCopyMemory(sleepParams->captureData->CaptureData.Data, szBuffer, cbRead);

    device->CompletePendingRequest(sleepParams->Hr, sleepParams->Information);

    return 0;
}

Other things I observed can cause a loop is when the call fails and not proper response is set.

//No delay is going to cause a loop
//Sleep(sleepParams->SleepValue * 1000);

//zeroes buffer is considered failed
UCHAR szBuffer[] = { 0x00, 0x00, 0x00, 0x00 };
//zero size is a failed read
ULONG cbRead = 0;
//returning other than S_FALSE or S_OK will cause a loop
sleepParams->captureData->WinBioHresult = S_FALSE;
sleepParams->captureData->SensorStatus = WINBIO_SENSOR_ACCEPT;
sleepParams->captureData->RejectDetail = 0;
sleepParams->captureData->CaptureData.Size = cbRead;
//It is going to fail if CaptureData.Data is empty
//RtlCopyMemory(sleepParams->captureData->CaptureData.Data, szBuffer, cbRead);

Also attaching a debugger like WinDbg or Visual Studio will cause a loop so is better to debug using only Trace messages and TraceView tool and attach a debugger when necessary and a loop will be expected in this case, just ignore it.

Juan Rojas
  • 8,711
  • 1
  • 22
  • 30