[Windows Hello WBDI/EngineAdapter development] A question about Adapter Workflow

Morgan 1 Reputation point
2021-03-17T07:37:04.19+00:00

Hi All,
I got a problem when I developed the WBDI and EngineAdapter on my fingerprint module.
The problem is why the EngineAdapter doesn't go into below callback functions after I finished Step 1 and Step 2 ?
- "EngineAdapterCreateEnrollment"
- "EngineAdapterSetEnrollmentParameters"

Note:
(1) Due to the document of Microsoft mentioned that upon functions will be called when enrollment workflow goes through.
(https://learn.microsoft.com/zh-tw/windows/win32/secbiomet/adapter-workflow)

(2) The log "EngineAdapter log" that is some funcions be called in EngineAdapter when I finished Step 1 and Step 2.

(3) The log "WBDI log" that is the WBDI receives some IOCTL from windows biometric framework when I finished Step 1 and Step 2.

Thanks

Step 1
78675-step-1.png

Step 2
78619-step-2.png

Adapter Workflow
78620-adapterworkflow.png

"EngineAdapter log"
DllMain, Wed Mar 17 14:22:37 2021
WbioQueryEngineInterface, Wed Mar 17 14:22:37 2021
EngineAdapterAttach, Wed Mar 17 14:22:37 2021
EngineAdapterSelectCalibrationFormat, Wed Mar 17 14:22:37 2021
EngineAdapterPipelineInit, Wed Mar 17 14:22:37 2021
DllMain, Wed Mar 17 14:22:42 2021
EngineAdapterActivate, Wed Mar 17 14:22:42 2021
EngineAdapterQueryExtendedInfo, Wed Mar 17 14:22:42 2021
EngineAdapterSetAccountPolicy, Wed Mar 17 14:22:42 2021
DllMain, Wed Mar 17 14:22:43 2021
EngineAdapterClearContext, Wed Mar 17 14:22:45 2021
EngineAdapterQueryPreferredFormat, Wed Mar 17 14:22:45 2021
EngineAdapterCreateKey, Wed Mar 17 14:22:46 2021
EngineAdapterCreateKey, Wed Mar 17 14:22:46 2021
EngineAdapterAcceptSampleData, Wed Mar 17 14:22:46 2021
EngineAdapterIdentifyFeatureSet, Wed Mar 17 14:22:46 2021
EngineAdapterClearContext, Wed Mar 17 14:22:46 2021
EngineAdapterClearContext, Wed Mar 17 14:22:46 2021

"WBDI log"
IOCTL_BIOMETRIC_GET_ATTRIBUTES, Wed Mar 17 14:22:37 2021
IOCTL_BIOMETRIC_GET_SENSOR_STATUS, Wed Mar 17 14:22:45 2021
IOCTL_BIOMETRIC_GET_ATTRIBUTES, Wed Mar 17 14:22:45 2021
IOCTL_BIOMETRIC_CAPTURE_DATA, Wed Mar 17 14:22:45 2021
IOCTL_BIOMETRIC_CAPTURE_DATA, Wed Mar 17 14:22:45 2021
IOCTL_BIOMETRIC_GET_SENSOR_STATUS, Wed Mar 17 14:22:46 2021

EngineAdapter code
static WINBIO_ENGINE_INTERFACE g_EngineInterface = {
WINBIO_ENGINE_INTERFACE_VERSION_6,
WINBIO_ADAPTER_TYPE_ENGINE,
sizeof(WINBIO_ENGINE_INTERFACE),
{0xb876fdc8, 0x34e7, 0x471a, {0x82, 0xc8, 0x9c, 0xba, 0x6a, 0x35, 0x38, 0xec}},

EngineAdapterAttach,  
EngineAdapterDetach,  
EngineAdapterClearContext,  
EngineAdapterQueryPreferredFormat,  
EngineAdapterQueryIndexVectorSize,  
EngineAdapterQueryHashAlgorithms,  
EngineAdapterSetHashAlgorithm,  
EngineAdapterAcceptSampleHint,  
EngineAdapterAcceptSampleData,  
EngineAdapterExportEngineData,  
EngineAdapterVerifyFeatureSet,  
EngineAdapterIdentifyFeatureSet,  
EngineAdapterCreateEnrollment,  
EngineAdapterUpdateEnrollment,  
EngineAdapterGetEnrollmentStatus,  
EngineAdapterGetEnrollmentHash,  
EngineAdapterCheckForDuplicate,  
EngineAdapterCommitEnrollment,  
EngineAdapterDiscardEnrollment,  
EngineAdapterControlUnit,  
EngineAdapterControlUnitPrivileged,  

 EngineAdapterNotifyPowerChange,  
 EngineAdapter_RESERVED,  


EngineAdapterPipelineInit,  
EngineAdapterPipelineCleanup,  
EngineAdapterActivate,  
EngineAdapterDeactivate,  
EngineAdapterQueryExtendedInfo,  
EngineAdapterIdentifyAll,  
EngineAdapterSetEnrollmentSelector,  
EngineAdapterSetEnrollmentParameters,  
EngineAdapterQueryExtendedEnrollmentStatus,  
EngineAdapterRefreshCache,  
EngineAdapterSelectCalibrationFormat,  
EngineAdapterQueryCalibrationData,  
EngineAdapterSetAccountPolicy,  


EngineAdapterCreateKey,  
EngineAdapterIdentifyFeatureSetSecure,  



EngineAdapterAcceptPrivateSensorTypeInfo,  

EngineAdapterCreateEnrollmentAuthenticated,  
EngineAdapterIdentifyFeatureSetAuthenticated  

};

WBDI code
void
CBiometricDevice::OnGetAttributes(
Inout IWDFIoRequest *FxRequest
)

{
CRequestHelper MyRequest(FxRequest); // RAII helper class
ULONG controlCode = 0;
PUCHAR inputBuffer= NULL;
SIZE_T inputBufferSize = 0;
PWINBIO_SENSOR_ATTRIBUTES sensorAttributes = NULL;
SIZE_T outputBufferSize;

//  
// Get the request parameters  
//  
GetIoRequestParams(FxRequest,  
                  &controlCode,  
                  &inputBuffer,  
                  &inputBufferSize,  
                  (PUCHAR *)&sensorAttributes,  
                  &outputBufferSize);  

//  
// Make sure we have an output buffer big enough  
//  
if (sensorAttributes == NULL || outputBufferSize < sizeof(DWORD))   
{  
    // We cannot return size information.  
    TraceEvents(TRACE_LEVEL_ERROR,   
               BIOMETRIC_TRACE_DEVICE,   
               "%!FUNC!Output buffer NULL or too small to return size information.");  
    MyRequest.SetCompletionHr(E_INVALIDARG);  
    return;  
}  

// We only have one supported format, so sizeof (WINBIO_SENSOR_ATTRIBUTES) is sufficient.  
if (outputBufferSize < sizeof(WINBIO_SENSOR_ATTRIBUTES))   
{  
    // Buffer too small.  
    TraceEvents(TRACE_LEVEL_ERROR,   
               BIOMETRIC_TRACE_DEVICE,   
               "%!FUNC!Buffer too small - return size necessary in PayloadSize - 0x%x.", sizeof(WINBIO_SENSOR_ATTRIBUTES));  
    sensorAttributes->PayloadSize = (DWORD) sizeof(WINBIO_SENSOR_ATTRIBUTES);  
    MyRequest.SetInformation(sizeof(DWORD));  
    MyRequest.SetCompletionHr(S_OK);  
    return;  
}  

//  
// Fill in the attribute payload structure  
//  
RtlZeroMemory(sensorAttributes, outputBufferSize);  
sensorAttributes->PayloadSize = (DWORD) sizeof(WINBIO_SENSOR_ATTRIBUTES);  
sensorAttributes->WinBioHresult = S_OK;  
sensorAttributes->WinBioVersion.MajorVersion = WINBIO_WBDI_MAJOR_VERSION;  
sensorAttributes->WinBioVersion.MinorVersion = WINBIO_WBDI_MINOR_VERSION;  
sensorAttributes->SensorType = WINBIO_TYPE_FINGERPRINT;  
sensorAttributes->SensorSubType = WINBIO_FP_SENSOR_SUBTYPE_TOUCH;// WINBIO_FP_SENSOR_SUBTYPE_SWIPE;//WINBIO_FP_SENSOR_SUBTYPE_TOUCH;  
sensorAttributes->Capabilities = WINBIO_CAPABILITY_SENSOR | WINBIO_CAPABILITY_MATCHING | WINBIO_CAPABILITY_DATABASE;// WINBIO_CAPABILITY_SENSOR | WINBIO_CAPABILITY_MATCHING | WINBIO_CAPABILITY_DATABASE | WINBIO_CAPABILITY_PROCESSING;// WINBIO_CAPABILITY_SENSOR;  
sensorAttributes->SupportedFormatEntries = 1;  
sensorAttributes->SupportedFormat[0].Owner = WINBIO_ANSI_381_FORMAT_OWNER;  
sensorAttributes->SupportedFormat[0].Type= WINBIO_ANSI_381_FORMAT_TYPE;  
RtlCopyMemory(sensorAttributes->ManufacturerName, SAMPLE_MANUFACTURER_NAME, (wcslen(SAMPLE_MANUFACTURER_NAME)+1)*sizeof(WCHAR));  
RtlCopyMemory(sensorAttributes->ModelName, SAMPLE_MODEL_NAME, (wcslen(SAMPLE_MODEL_NAME)+1)*sizeof(WCHAR));  
RtlCopyMemory(sensorAttributes->SerialNumber, SAMPLE_SERIAL_NUMBER, (wcslen(SAMPLE_SERIAL_NUMBER)+1)*sizeof(WCHAR));  
sensorAttributes->FirmwareVersion.MajorVersion = 1;  
sensorAttributes->FirmwareVersion.MinorVersion = 0;  

MyRequest.SetInformation(sensorAttributes->PayloadSize);  
MyRequest.SetCompletionHr(S_OK);  

}

void
CBiometricDevice::OnGetSensorStatus(
Inout IWDFIoRequest *FxRequest
)
{
CRequestHelper MyRequest(FxRequest); // RAII helper class
ULONG controlCode = 0;
PUCHAR inputBuffer= NULL;
SIZE_T inputBufferSize = 0;
PWINBIO_DIAGNOSTICS diagnostics = NULL;
SIZE_T outputBufferSize;

//  
// Get the request parameters  
//  
GetIoRequestParams(FxRequest,  
                  &controlCode,  
                  &inputBuffer,  
                  &inputBufferSize,  
                  (PUCHAR *)&diagnostics,  
                  &outputBufferSize);  

//  
// Make sure we have an output buffer big enough  
//  
if (diagnostics == NULL || outputBufferSize < sizeof(DWORD))   
{  
    // We cannot return size information.  
    TraceEvents(TRACE_LEVEL_ERROR,   
               BIOMETRIC_TRACE_DEVICE,   
               "%!FUNC!Output buffer NULL or too small to return size information.");  
    MyRequest.SetCompletionHr(E_INVALIDARG);  
    return;  
}  

if (outputBufferSize < sizeof(WINBIO_DIAGNOSTICS))  
{  
    // Buffer too small.  
    TraceEvents(TRACE_LEVEL_ERROR,  
        BIOMETRIC_TRACE_DEVICE,  
        "%!FUNC!Buffer too small - return size necessary in PayloadSize - 0x%x.", sizeof(WINBIO_DIAGNOSTICS));  
    diagnostics->PayloadSize = (DWORD)sizeof(WINBIO_DIAGNOSTICS);  
    MyRequest.SetInformation(sizeof(DWORD));  
    MyRequest.SetCompletionHr(S_OK);  

    return;  
}  

//  
// Fill in the OUT payload structure  
//  
RtlZeroMemory(diagnostics, outputBufferSize);  
diagnostics->PayloadSize = (DWORD) sizeof(WINBIO_DIAGNOSTICS);  
diagnostics->WinBioHresult = S_OK;  
//diagnostics->SensorStatus = WINBIO_SENSOR_READY;  

if (SensorStatusFlag)  
{  
    SensorStatusFlag = 0;  
    diagnostics->SensorStatus = WINBIO_SENSOR_ACCEPT;  
}  
else  
{  
    diagnostics->SensorStatus = WINBIO_SENSOR_READY;  
}  

MyRequest.SetInformation(diagnostics->PayloadSize);  
MyRequest.SetCompletionHr(S_OK);  

}

void
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;

//  
// We can only have one outstanding data capture request at a time.  
// Check to see if we have a request pending.  
//  
bool requestPending = false;  

EnterCriticalSection(&m_RequestLock);  

if (m_PendingRequest == NULL)   
{  
    //  
    // See if we have an active sleep thread.  
    // If so, tell it to exit.  
    // Wait for it to exit.  
    //  
    if (m_SleepThread != INVALID_HANDLE_VALUE)  
    {  
        LeaveCriticalSection(&m_RequestLock);  

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

        // NOTE: Sleeping for INFINITE time is dangerous. A real driver  
        // should be able to handle the case where the thread does  
        // not exit.  
        WaitForSingleObject(m_SleepThread, INFINITE);  
        CloseHandle(m_SleepThread);  
        m_SleepThread = INVALID_HANDLE_VALUE;  

        EnterCriticalSection(&m_RequestLock);  
    }  

    //   
    // We might have had to leave the CS to wait for the sleep thread.  
    // Double check that the pending request is still NULL.  
    //  
    if (m_PendingRequest == NULL)  
    {  
        // Save the request.  
        m_PendingRequest = FxRequest;  

        // Mark the request as cancellable.  
        m_PendingRequest->MarkCancelable(this);  
    }  
    else  
    {  
        requestPending = true;  
    }  
}   
else   
{  
    requestPending = true;  
}  

LeaveCriticalSection(&m_RequestLock);  

if (requestPending)  
{  
    // Complete the request to tell the app that there is already  
    // a pending data collection request.  
    FxRequest->Complete(WINBIO_E_DATA_COLLECTION_IN_PROGRESS);  
    return;  
}  

//  
// Get the request parameters  
//  
GetIoRequestParams(FxRequest,  
                   &controlCode,  
                   (PUCHAR *)&captureParams,  
                   &inputBufferSize,  
                   (PUCHAR *)&captureData,  
                   &outputBufferSize);  

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

//  
// Make sure we have an output buffer big enough  
//  
if (outputBufferSize < sizeof(DWORD))   
{  
    // We cannot return size information.  
    TraceEvents(TRACE_LEVEL_ERROR,   
               BIOMETRIC_TRACE_DEVICE,   
               "%!FUNC!Output buffer NULL or too small to return size information.");  
    CompletePendingRequest(E_INVALIDARG, 0);  
    return;  
}  

//  
// Check output buffer size.  
//  
if (outputBufferSize < sizeof (WINBIO_CAPTURE_DATA))   
{  
    // Buffer too small.  
    TraceEvents(TRACE_LEVEL_ERROR,   
               BIOMETRIC_TRACE_DEVICE,   
               "%!FUNC!Buffer too small - must be at least 0x%x.", sizeof (WINBIO_CAPTURE_DATA));  
    //  
    // NOTE:  The output buffer size necessary for this sample is sizeof(WINBIO_CAPTURE_DATA).  
    // Real devices will need additional space to handle a typical capture.  
    // The value that should be returned here is sizeof(WINBIO_CAPTURE_DATA) + CaptureBufferSize.  
    //  

    captureData->PayloadSize = (DWORD)sizeof(WINBIO_CAPTURE_DATA)+12;  
    CompletePendingRequest(S_OK, sizeof(DWORD));  
    return;  
}  

//  
// NOTE:  This call always fails in this sample since it is not  
// written for a real device.  
//  

//  
// Set default values in output buffer.  
//  
SensorStatusFlag = 1;  
RtlZeroMemory(captureData, outputBufferSize);  
captureData->PayloadSize = (DWORD)outputBufferSize;  

captureData->WinBioHresult = S_OK;  
captureData->SensorStatus = WINBIO_SENSOR_ACCEPT;  
captureData->RejectDetail = 0;  
captureData->CaptureData.Size = (DWORD)12;  
  
UCHAR szBuffer[] = { 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04 };  
RtlCopyMemory(captureData->CaptureData.Data, szBuffer,12);  

//  
// Check purpose, format and type.  
//  
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;  
}  

//  
// Create thread to sleep 1 seconds before completing the request.  
//  
m_SleepParams.SleepValue = 1;  
m_SleepParams.Hr = S_OK;  
m_SleepParams.Information = captureData->PayloadSize;  
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   

}

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

//  
// Make sure it is less than or equal to 1 minute.  
//  
if (sleepParams->SleepValue > 60)  
{  
    sleepParams->SleepValue = 60;  
}  

Sleep(sleepParams->SleepValue * 1000);  

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

return 0;  

}

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,411 questions
Windows Hardware Performance
Windows Hardware Performance
Windows: A family of Microsoft operating systems that run across personal computers, tablets, laptops, phones, internet of things devices, self-contained mixed reality headsets, large collaboration screens, and other devices.Hardware Performance: Delivering / providing hardware or hardware systems or adjusting / adapting hardware or hardware systems.
1,540 questions
0 comments No comments
{count} votes