我在 Win10 操作系统上使用指纹模块开发 WBDI 和 EngineAdapter 时遇到了问题。
问题是为什么在我完成下面的第 1 步和第 2 步之后,EngineAdapter 没有进入下面的回调函数?
因为微软的文件提到,当注册工作流程通过时,将调用以下函数。( https://docs.microsoft.com/zh-tw/windows/win32/secbiomet/adapter-workflow )
以下是未调用的回调函数。
(1) “EngineAdapterCreateEnrollment” (2) “EngineAdapterSetEnrollmentParameters”
有谁知道如何解决它?非常感谢。
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;
}