PIBIO_STORAGE_ADD_RECORD_FN回调函数 (winbio_adapter.h)

由引擎适配器调用以将模板添加到数据库。

语法

PIBIO_STORAGE_ADD_RECORD_FN PibioStorageAddRecordFn;

HRESULT PibioStorageAddRecordFn(
  [in, out] PWINBIO_PIPELINE Pipeline,
  [in]      PWINBIO_STORAGE_RECORD RecordContents
)
{...}

参数

[in, out] Pipeline

指向与执行操作的生物识别单元关联的 WINBIO_PIPELINE 结构的指针。

[in] RecordContents

指向包含要添加的模板 的WINBIO_STORAGE_RECORD 结构的指针。

返回值

如果函数成功,则返回S_OK。 如果函数失败,它必须返回以下 HRESULT 值之一来指示错误。

返回代码 说明
E_INVALIDARG
RecordContents 参数指定的结构成员无效。
E_POINTER
强制指针参数为 NULL
WINBIO_E_DATABASE_BAD_INDEX_VECTOR
WINBIO_STORAGE_RECORD 结构中指定的索引向量的大小与创建数据库时指定的索引大小不匹配。
WINBIO_E_DUPLICATE_ENROLLMENT
数据库已包含一个模板,其中包含 IdentitySubFactor 参数指定的值组合。
WINBIO_E_DATABASE_CORRUPTED
数据库存在未指定的问题。
WINBIO_E_DATABASE_FULL
数据库已满,无法添加其他记录。
WINBIO_E_DATABASE_LOCKED
数据库已锁定。
WINBIO_E_DATABASE_WRITE_ERROR
由于未指定的问题,记录添加失败。
WINBIO_E_INVALID_DEVICE_STATE
管道对象的 StorageContext 成员为 NULLFileHandle 成员无效。

注解

RecordContents 参数标识的内存是 Windows 生物识别框架的 属性。 从 StorageAdapterAddRecord 返回后,存储适配器不得保留此指针的副本或WINBIO_STORAGE_RECORD结构中包含的任何指针的副本。

重要说明  

请勿尝试验证为 RecordContents 参数的 SubFactor 值提供的值。 Windows 生物识别服务会在将所提供的值传递给实现之前对其进行验证。 如果值为 WINBIO_SUBTYPE_NO_INFORMATIONWINBIO_SUBTYPE_ANY,请在适当位置进行验证。

 

示例

以下伪代码演示了此函数的一种可能实现。 该示例不编译。 必须根据自己的目的调整它。

/////////////////////////////////////////////////////////////////////////////////////////
//
// StorageAdapterAddRecord
//
// Purpose:
//      Adds a template to the database.
//
// Parameters:
//      Pipeline       - Pointer to a WINBIO_PIPELINE structure associated with 
//                       the biometric unit performing the operation.
//      RecordContents - Pointer to a WINBIO_STORAGE_RECORD structure that contains 
//                       the template to add.
//
static HRESULT
WINAPI
StorageAdapterAddRecord(
    __inout PWINBIO_PIPELINE Pipeline,
    __in PWINBIO_STORAGE_RECORD RecordContents
    )
{
    HRESULT hr = S_OK;
    struct _MY_ADAPTER_RECORD_HEADER *newRecord = NULL;
    SIZE_T newRecordSize = 0;
    BOOL lockAcquired = FALSE;
    ULONG index = 0;
    PUCHAR encryptedTemplateBlob = NULL;
    SIZE_T encryptedTemplateBlobSize = 0;
    struct _MY_ADAPTER_FILE_HEADER fileHeader = {0};
    SIZE_T templateBlobOffset = 0;
    SIZE_T payloadBlobOffset = 0;
    struct _MY_ADAPTER_DPAPI_DATA protectedData = {0};
    SIZE_T duplicateRecordCount = 0;

    // Verify that pointer arguments are not NULL.
    if (!ARGUMENT_PRESENT(Pipeline) ||
        !ARGUMENT_PRESENT(RecordContents))
    {
        hr = E_POINTER;
        goto cleanup;
    }

    // Retrieve the context from the pipeline.
    PWINBIO_STORAGE_CONTEXT storageContext = (PWINBIO_STORAGE_CONTEXT)Pipeline->StorageContext;

    // Verify the pipeline state.
    if (storageContext == NULL || storageContext->FileHandle == INVALID_HANDLE_VALUE)
    {
        hr =  WINBIO_E_INVALID_DEVICE_STATE;
        goto cleanup;
    }

    // Check various values associated with the record contents. The
    // following example code assumes that a database record contains
    // a valid:
    //    Identity
    //    Sub-factor characteristic
    //    Biometric template
    //    Payload associated with the template
    //    Index vector
    //
    if (!ARGUMENT_PRESENT(RecordContents->Identity))
    {
        hr = E_POINTER;
        goto cleanup;
    }

    if (RecordContents->Identity->Type != WINBIO_ID_TYPE_GUID &&
        RecordContents->Identity->Type != WINBIO_ID_TYPE_SID)
    {
        hr = E_INVALIDARG;
        goto cleanup;
    }

    if (RecordContents->SubFactor == WINBIO_SUBTYPE_NO_INFORMATION ||
        RecordContents->SubFactor == WINBIO_SUBTYPE_ANY)
    {
        hr = E_INVALIDARG;
        goto cleanup;
    }

    if (RecordContents->TemplateBlobSize == 0 ||
        !ARGUMENT_PRESENT(RecordContents->TemplateBlob))
    {
        hr = E_INVALIDARG;
        goto cleanup;
    }

    if (RecordContents->PayloadBlobSize > 0 && 
        !ARGUMENT_PRESENT(RecordContents->PayloadBlob))
    {
        hr = E_POINTER;
        goto cleanup;
    }

    if (RecordContents->IndexElementCount != storageContext->IndexElementCount)
    {
        hr = WINBIO_E_DATABASE_BAD_INDEX_VECTOR;
        goto cleanup;
    }

    if (RecordContents->IndexElementCount > 0 &&
        !ARGUMENT_PRESENT(RecordContents->IndexVector))
    {
        hr = E_POINTER;
        goto cleanup;
    }

    // Call a private function (_CheckForDuplicateEnrollments) to query the
    // database for existing records with the same identity and sub-factor 
    // values as the new record. If a duplicate is found, return.
    hr = _CheckForDuplicateEnrollments(
            Pipeline,
            RecordContents->Identity,
            RecordContents->SubFactor,
            &duplicateRecordCount
            );
    if (FAILED(hr))
    {
        goto cleanup;
    }
    if (duplicateRecordCount > 0)
    {
        hr = WINBIO_E_DUPLICATE_ENROLLMENT;
        goto cleanup;
    }

    // Call a custom function (_EncryptTemplateData) to encrypt the template 
    // data. Do this now so that you can determine how much space will be 
    // required to store the encrypted template.
    hr = _EncryptTemplateData(
            &storageContext->CryptoContext,
            RecordContents->TemplateBlob,
            RecordContents->TemplateBlobSize,
            &encryptedTemplateBlob,
            &encryptedTemplateBlobSize
            );
    if (FAILED(hr))
    {
        hr = WINBIO_E_DATABASE_WRITE_ERROR;
        goto cleanup;
    }

    // Call a custom function (_AllocateNewRecord) to allocate memory for the 
    // new record. You must allocate enough memory to hold the index vector, the
    // encrypted template, the identity structure, sub-factor information, and the 
    // payload blob. You must also allocate enough memory to hold and any other 
    // data that will be used by the storage adapter but that will
    // not be made visible to the engine adapter.
    hr = _AllocateNewRecord(
            RecordContents->IndexElementCount, 
            encryptedTemplateBlobSize,
            RecordContents->PayloadBlobSize,
            &newRecord,                         // [out] Address of the new record buffer
            &newRecordSize                      // [out] Size of the new record buffer
            );
    if (FAILED(hr))
    {
        goto cleanup;
    }

    // Copy the identity information into the new record.
    CopyMemory(
        &newRecord->Identity,
        RecordContents->Identity,
        sizeof(WINBIO_IDENTITY)
        );

    // Copy the sub-factor information to the new record.
    newRecord->SubFactor = RecordContents->SubFactor;

    // Copy the index vector, if present, into the new record.
    if (RecordContents->IndexElementCount > 0)
    {
        PULONG indexVector = _GetIndexVector(newRecord);
        for (index=0; index < RecordContents->IndexElementCount; ++index)
        {
            indexVector[index] = RecordContents->IndexVector[index];
        }
    }

    // Copy the encrypted template.
    templateBlobOffset = 
        sizeof(struct _MY_ADAPTER_RECORD_HEADER) + 
        RecordContents->IndexElementCount * sizeof(ULONG);

    newRecord->TemplateBlobSize = RecordContents->TemplateBlobSize;
    newRecord->EncryptedTemplateBlobSize = encryptedTemplateBlobSize;

    CopyMemory(
        (PUCHAR)newRecord + templateBlobOffset,
        encryptedTemplateBlob,
        encryptedTemplateBlobSize
        );
       
    // Copy the payload blob if present.
    if (RecordContents->PayloadBlobSize > 0)
    {
        payloadBlobOffset =
            templateBlobOffset + 
            encryptedTemplateBlobSize;

        newRecord->PayloadBlobSize = RecordContents->PayloadBlobSize;

        CopyMemory(
            (PUCHAR)newRecord + payloadBlobOffset, 
            RecordContents->PayloadBlob, 
            RecordContents->PayloadBlobSize
            );
    }

    // Call a custom function (_LockDatabase) to lock the database for writing
    // (EXCLUSIVE ownership).
    hr = _LockDatabase(Pipeline->StorageHandle, TRUE);
    if (FAILED(hr))
    {
        goto cleanup;
    }
    lockAcquired = TRUE;

    // Call a custom function (_ReadFileHeader) to read the header block.
    hr = _ReadFileHeader( Pipeline->StorageHandle, &fileHeader );
    if (FAILED(hr))
    {
        goto cleanup;
    }

    // Write the new data record to the first free byte at the end of the
    // active data area in the database file.
    hr = _WriteRecord( 
            Pipeline->StorageHandle, 
            fileHeader.FirstFreeByte, 
            newRecord 
            );
    if (FAILED(hr))
    {
        goto cleanup;
    }

    // Update the bookkeeping information in the header and write the header
    // back to the file.
    fileHeader.FirstFreeByte.QuadPart += newRecord->RecordSize;
    ++fileHeader.TotalRecordCount;

    hr = _WriteFileHeader(
            Pipeline->StorageHandle,
            &fileHeader
            );
    if (FAILED(hr))
    {
        hr = WINBIO_E_DATABASE_CORRUPTED;
        goto cleanup;
    }

    // Recompute the file hash and write it to the protected data area in the database
    // file. The hash value is an integrity check on data stored in the file. Note that
    // the DPAPI-protected data block is NOT included in the hash.
    hr = _ReadProtectedData(
            Pipeline->StorageHandle,
            &protectedData
            );
    if (FAILED(hr))
    {
        goto cleanup;
    }

    hr = _ComputeFileHash(
            Pipeline->StorageHandle,
            _MY_ADAPTER_DPAPI_BLOCK_OFFSET,
            (SIZE_T)(fileHeader.FirstFreeByte.QuadPart - 
                     _MY_ADAPTER_DPAPI_BLOCK_SIZE),
            protectedData.FileHash,
            _MY_ADAPTER_FILE_HASH_LENGTH,
            (PSIZE_T)&protectedData.FileHashLength
            );
    if (FAILED(hr))
    {
        hr = WINBIO_E_DATABASE_CORRUPTED;
        goto cleanup;
    }

    hr = _WriteProtectedData(
                Pipeline->StorageHandle,
                &protectedData
                );
    if (FAILED(hr))
    {
        hr = WINBIO_E_DATABASE_CORRUPTED;
        goto cleanup;
    }

cleanup:

    // Call the SecureZero function to overwrite the template encryption key 
    // on the stack.
    SecureZeroMemory( &protectedData, sizeof(struct _MY_ADAPTER_DPAPI_DATA));

    if (lockAcquired == TRUE)
    {
        _UnlockDatabase( Pipeline->StorageHandle);
        lockAcquired = FALSE;
    }

    if (encryptedTemplateBlob != NULL)
    {
        SecureZeroMemory(encryptedTemplateBlob, encryptedTemplateBlobSize);
        _AdapterRelease(encryptedTemplateBlob);
        encryptedTemplateBlob = NULL;
    }

    if (newRecord != NULL)
    {
        SecureZeroMemory( newRecord, newRecordSize);
        _AdapterRelease(newRecord);
        newRecord = NULL;
    }

    return hr;
}

要求

要求
最低受支持的客户端 Windows 7 [仅限桌面应用]
最低受支持的服务器 Windows Server 2008 R2 [仅限桌面应用]
目标平台 Windows
标头 winbio_adapter.h (包括 Winbio_adapter.h)

另请参阅

插件函数

StorageAdapterDeleteRecord