데이터베이스에서 하나 이상의 템플릿을 삭제하기 위해 Windows 생체 인식 프레임워크에서 호출됩니다.
문법
PIBIO_STORAGE_DELETE_RECORD_FN PibioStorageDeleteRecordFn;
HRESULT PibioStorageDeleteRecordFn(
[in, out] PWINBIO_PIPELINE Pipeline,
[in] PWINBIO_IDENTITY Identity,
[in] WINBIO_BIOMETRIC_SUBTYPE SubFactor
)
{...}
매개 변수
[in, out] Pipeline
작업을 수행하는 생체 인식 단위와 연결된 WINBIO_PIPELINE 구조체에 대한 포인터입니다.
[in] Identity
삭제할 템플릿의 GUID 또는 SID가 포함된 WINBIO_IDENTITY 구조체에 대한 포인터입니다.
[in] SubFactor
삭제할 템플릿과 연결된 하위 요소를 지정하는 WINBIO_BIOMETRIC_SUBTYPE 값입니다.
반환 값
함수가 성공하면 S_OK 반환합니다. 함수가 실패하면 오류를 나타내기 위해 다음 HRESULT 값 중 하나를 반환해야 합니다.
| 반환 코드 | Description |
|---|---|
|
SubFactor 매개 변수로 지정된 인수가 잘못되었거나 Identity 매개 변수로 지정된 구조체의 멤버가 잘못되었습니다. |
|
레코드 헤더에 메모리를 할당할 수 없습니다. |
|
필수 포인터 인수는 NULL입니다. |
|
데이터베이스에 지정되지 않은 문제가 있습니다. |
|
데이터베이스에서 일치하는 레코드를 찾을 수 없습니다. |
|
파이프라인 개체의 StorageContext 멤버가 NULL 이거나 FileHandle 멤버가 잘못되었습니다. |
비고
Identity 매개 변수가 가리키는 WINBIO_IDENTITY 구조의 형식 필드가 WINBIO_IDENTITY_TYPE_WILDCARD 설정되어 있고 SubFactor 매개 변수가 WINBIO_SUBTYPE_ANY 경우 스토리지 어댑터는 데이터베이스에서 모든 레코드를 삭제해야 합니다.
SubFactor 매개 변수에 제공된 값의 유효성을 검사하지 마세요. Windows 생체 인식 서비스는 제공된 값을 구현에 전달하기 전에 유효성을 검사합니다. 값이 WINBIO_SUBTYPE_NO_INFORMATION 또는 WINBIO_SUBTYPE_ANY 경우 적절한 경우 유효성을 검사합니다.
예시
다음 의사 코드는 이 함수의 가능한 구현을 보여 줍니다. 이 예제는 컴파일되지 않습니다. 목적에 맞게 조정해야 합니다.
/////////////////////////////////////////////////////////////////////////////////////////
//
// StorageAdapterDeleteRecord
//
// Purpose:
// Deletes one or more templates from the database.
//
// Parameters:
// Pipeline - Pointer to a WINBIO_PIPELINE structure associated with
// the biometric unit performing the operation.
// Identity - Pointer to a WINBIO_IDENTITY structure that contains the GUID or
// SID of the template to delete.
// SubFactor - A WINBIO_BIOMETRIC_SUBTYPE value that specifies the sub-factor
// associated with the template to delete.
//
static HRESULT
WINAPI
StorageAdapterDeleteRecord(
__inout PWINBIO_PIPELINE Pipeline,
__in PWINBIO_IDENTITY Identity,
__in WINBIO_BIOMETRIC_SUBTYPE SubFactor
)
{
HRESULT hr = S_OK;
BOOL lockAcquired = FALSE;
struct _MY_ADAPTER_FILE_HEADER fileHeader = {0};
SIZE_T remainingRecords = 0;
LARGE_INTEGER currentRecordOffset = {0};
struct _MY_ADAPTER_RECORD_HEADER *recordHeader = NULL;
SIZE_T recordHeaderSize = 0;
struct _MY_ADAPTER_DPAPI_DATA protectedData = {0};
SIZE_T deletedRecordCount = 0;
// Check that pointer arguments are not NULL.
if (!ARGUMENT_PRESENT(Pipeline) ||
!ARGUMENT_PRESENT(Identity))
{
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 the identity type.
if (Identity->Type != WINBIO_ID_TYPE_GUID &&
Identity->Type != WINBIO_ID_TYPE_SID &&
Identity->Type != WINBIO_ID_TYPE_WILDCARD)
{
hr = E_INVALIDARG;
goto cleanup;
}
if (Identity->Type == WINBIO_ID_TYPE_WILDCARD &&
Identity->Value.Wildcard != WINBIO_IDENTITY_WILDCARD)
{
hr = E_INVALIDARG;
goto cleanup;
}
// Some kind of sub-factor information is mandatory, even if it's
// just a wildcard.
if (SubFactor == WINBIO_SUBTYPE_NO_INFORMATION)
{
hr = E_INVALIDARG;
goto cleanup;
}
// Lock the database for writing (EXCLUSIVE ownership).
hr = _LockDatabase( Pipeline->StorageHandle, TRUE);
if (FAILED(hr))
{
goto cleanup;
}
lockAcquired = TRUE;
// Read the database header block into memory.
hr = _ReadFileHeader( Pipeline->StorageHandle, &fileHeader );
if (FAILED(hr))
{
goto cleanup;
}
// For this operation, you need to update only the record header
// area, not the index vector area.
recordHeaderSize = sizeof(struct _MY_ADAPTER_RECORD_HEADER);
recordHeader = (struct _MY_ADAPTER_RECORD_HEADER*)_AdapterAlloc( recordHeaderSize );
if (recordHeader == NULL)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
currentRecordOffset = _MY_ADAPTER_FIRST_RECORD_OFFSET;
remainingRecords = fileHeader.TotalRecordCount;
// Scan through all records looking for identity matches.
while (remainingRecords > 0)
{
SIZE_T recordSize = 0;
BOOLEAN match = FALSE;
hr = _ReadRecordHeader(
Pipeline->StorageHandle,
currentRecordOffset,
recordHeader,
recordHeaderSize
);
if (FAILED(hr))
{
goto cleanup;
}
recordSize = recordHeader->RecordSize;
// Ignore records already marked for deletion.
if ((recordHeader->Flags & _MY_ADAPTER_FLAG_RECORD_DELETED) == 0)
{
hr = _MatchIdentity(
Identity,
SubFactor,
&recordHeader->Identity,
recordHeader->SubFactor,
&match
);
if (FAILED(hr))
{
goto cleanup;
}
if (match == TRUE)
{
// Mark the record as deleted and call a custom function
// (_WriteRecordHeader) to write the record header to disk. Space
// occupied by deleted records should be reclaimed when the last
// thread that is using the database closes the file. Delaying
// reclamation until the last thread closes is necessary because
// there could be other threads whose result sets contain references
// to the deleted records.
recordHeader->Flags |= _MY_ADAPTER_FLAG_RECORD_DELETED;
hr = _WriteRecordHeader(
Pipeline->StorageHandle,
currentRecordOffset,
recordHeader,
recordHeaderSize
);
if (FAILED(hr))
{
goto cleanup;
}
++fileHeader.DeletedRecordCount;
++deletedRecordCount;
}
}
currentRecordOffset.QuadPart += recordSize;
--remainingRecords;
}
// Write the updated file header to disk.
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.
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 SecureZeroMemory function to overwrite the template encryption key
// on the stack.
SecureZeroMemory( &protectedData, sizeof(struct _MY_ADAPTER_DPAPI_DATA));
if (recordHeader != NULL)
{
_AdapterRelease(recordHeader);
recordHeader = NULL;
}
if (lockAcquired == TRUE)
{
_UnlockDatabase( Pipeline->StorageHandle);
lockAcquired = FALSE;
}
if (SUCCEEDED(hr))
{
if (deletedRecordCount == 0)
{
hr = WINBIO_E_DATABASE_NO_SUCH_RECORD;
}
}
return hr;
}
요구 사항
| 요구 사항 | 가치 |
|---|---|
| 지원되는 최소 클라이언트 | Windows 7 [데스크톱 앱만 해당] |
| 지원되는 최소 서버 | Windows Server 2008 R2 [데스크톱 앱만 해당] |
| 대상 플랫폼 | 윈도우즈 |
| Header | winbio_adapter.h(Winbio_adapter.h 포함) |