1

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

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

因为微软的文件提到,当注册工作流程通过时,将调用以下函数。( https://docs.microsoft.com/zh-tw/windows/win32/secbiomet/adapter-workflow )

以下是未调用的回调函数。

(1) “EngineAdapterCreateEnrollment” (2) “EngineAdapterSetEnrollmentParameters”

有谁知道如何解决它?非常感谢。

步骤1

第2步

适配器工作流程

EngineAdapter 日志

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 日志

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 代码 (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, 
                   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;
}
4

0 回答 0