<Windows Hello WBDI/EngineAdapter 开发> 关于Adapter Workflow的一个问题

问题描述

我在 Win10 操作系统上使用指纹模块开发 WBDI 和 EngineAdapter 时遇到问题。

问题是为什么在我完成下面的第 1 步和第 2 步后,EngineAdapter 没有进入下面的回调函数?

因为微软的文档中提到在注册工作流执行时会调用以下函数。 (https://docs.microsoft.com/zh-tw/windows/win32/secbiomet/adapter-workflow)

以下是不被调用的回调函数。

(1) "EngineAdapterCreateEnrollment" (2) "EngineAdapterSetEnrollmentParameters"

有人知道怎么解决吗? 非常感谢。

Step1

Step2

Adapter Workflow

引擎适配器日志

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

WBDI 日志

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_GET_SENSOR_STATUS,Wed Mar 17 14:22:46 2021

EngineAdapter 代码 (EngineAdapter.cpp)

static WINBIO_ENGINE_INTERFACE g_EngineInterface = {
#if (NTDDI_VERSION >= NTDDI_WIN10_RS4)
    WINBIO_ENGINE_INTERFACE_VERSION_6,#elif(NTDDI_VERSION >= NTDDI_WIN10_RS3)
    WINBIO_ENGINE_INTERFACE_VERSION_5,#elif(NTDDI_VERSION >= NTDDI_WIN10_RS1)
    WINBIO_ENGINE_INTERFACE_VERSION_4,#elif(NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
    WINBIO_ENGINE_INTERFACE_VERSION_3,#elif(NTDDI_VERSION >= NTDDI_WIN8)
    WINBIO_ENGINE_INTERFACE_VERSION_2,#elif
    WINBIO_ENGINE_INTERFACE_VERSION_1,#endif

    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,#if(NTDDI_VERSION >= NTDDI_WIN8)
     EngineAdapterNotifyPowerChange,EngineAdapter_RESERVED,//EngineAdapterReserved_1;
#endif//(NTDDI_VERSION >= NTDDI_WIN8)


#if(NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
    //
    // V3.0 methods begin here...
    //
    EngineAdapterPipelineInit,EngineAdapterPipelineCleanup,EngineAdapterActivate,EngineAdapterDeactivate,EngineAdapterQueryExtendedInfo,EngineAdapterIdentifyAll,EngineAdapterSetEnrollmentSelector,EngineAdapterSetEnrollmentParameters,EngineAdapterQueryExtendedEnrollmentStatus,EngineAdapterRefreshCache,EngineAdapterSelectCalibrationFormat,EngineAdapterQueryCalibrationData,EngineAdapterSetAccountPolicy,#endif //(NTDDI_VERSION >= NTDDI_WINTHRESHOLD)


#if(NTDDI_VERSION >= NTDDI_WIN10_RS1)
    //
    // V4.0 methods begin here...
    //
    EngineAdapterCreateKey,EngineAdapterIdentifyFeatureSetSecure,#endif//(NTDDI_VERSION >= NTDDI_WIN10_RS1)

#if(NTDDI_VERSION >= NTDDI_WIN10_RS3)
    //
    // V5.0 methods begin here...
    //
    EngineAdapterAcceptPrivateSensorTypeInfo,#endif(NTDDI_VERSION >= NTDDI_WIN10_RS3)

#if(NTDDI_VERSION >= NTDDI_WIN10_RS4)
//
// V6.0 methods begin here...
//
    EngineAdapterCreateEnrollmentAuthenticated,EngineAdapterIdentifyFeatureSetAuthenticated
#endif//(NTDDI_VERSION >= NTDDI_WIN10_RS4)

};

WBDI 代码

switch (ControlCode) {

    //
    // Mandatory IOCTLs
    //
    case IOCTL_BIOMETRIC_GET_ATTRIBUTES:
        m_BiometricDevice->OnGetAttributes(FxRequest);
        break;

    case IOCTL_BIOMETRIC_RESET:
        m_BiometricDevice->OnReset(FxRequest);
        break;

    case IOCTL_BIOMETRIC_CALIBRATE:
        m_BiometricDevice->OnCalibrate(FxRequest);
        break;
        
    case IOCTL_BIOMETRIC_GET_SENSOR_STATUS:
        m_BiometricDevice->OnGetSensorStatus(FxRequest);
        break;

    case IOCTL_BIOMETRIC_CAPTURE_DATA:
        m_BiometricDevice->OnCaptureData(FxRequest);
        break;
}

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,"%!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,(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,"%!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,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,(PUCHAR *)&captureParams,(PUCHAR *)&captureData,&outputBufferSize);

    //
    // Check input parameters.
    //
     if (inputBufferSize < sizeof (WINBIO_CAPTURE_PARAMETERS)) 
     {
        // Invalid arguments
        TraceEvents(TRACE_LEVEL_ERROR,"%!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,"%!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,"%!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,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;
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)