【WBF】非同期でWindows Biometric Framework関連の情報を列挙する

# 使用するWindows Biometric Frameworkの関数
- 非同期で情報を取得するためのフレームワークのハンドル処理
  -  WinBioAsyncOpenFramework : ハンドルの取得<br>
https://docs.microsoft.com/en-us/windows/win32/api/winbio/nf-winbio-winbioasyncopenframework
  - WinBioCloseFramework : ハンドルの破棄<br>
    https://docs.microsoft.com/en-us/windows/win32/api/winbio/nf-winbio-winbiocloseframework

- 取得したい情報ごとの関数
  - WinBioAsyncEnumServiceProviders : 生体認証サービスプロバイダー<br>
    https://docs.microsoft.com/en-us/windows/win32/api/winbio/nf-winbio-winbioasyncenumserviceproviders
  - WinBioAsyncEnumBiometricUnits : 生体認証ユニット<br>
    https://docs.microsoft.com/en-us/windows/win32/api/winbio/nf-winbio-winbioasyncenumbiometricunits
  - WinBioAsyncEnumDatabases : 生体情報データベース<br>
    https://docs.microsoft.com/en-us/windows/win32/api/winbio/nf-winbio-winbioasyncenumdatabases

- 取得した結果のメモリの解放
  - WinBioFree<br>
    https://docs.microsoft.com/en-us/windows/win32/api/winbio/nf-winbio-winbiofree

# サンプルコード
```C++
// ====================================================================================================
//  インクルード
// ====================================================================================================
#include <Windows.h>
#include <stdio.h>
#include <conio.h>
#include <WinBio.h>
#include <locale.h>
#include <string>

// ====================================================================================================
//  ライブラリ
// ====================================================================================================
#pragma comment(lib, "WinBio.lib")
#pragma comment(lib, "Rpcrt4.lib")

// ====================================================================================================
//  GUIDを文字列に変換する
// ====================================================================================================
std::wstring GuidToString( GUID* pGuid )
{
    // 下記を参考にしました
    // https://www.wabiapp.com/WabiSampleSource/windows/uuid_from_string.html
}

// ====================================================================================================
//  コールバック関数
// ====================================================================================================
void CALLBACK WINBIO_ASYNC_COMPLETION_CALLBACK(PWINBIO_ASYNC_RESULT AsyncResult)
{
    // 共通の結果出力
    wprintf_s(L"Operation Type [%d]\n", AsyncResult->Operation);
    wprintf_s(L"Sequence Number [%lld]\n", AsyncResult->SequenceNumber);

    FILETIME stFileTime;
    stFileTime.dwHighDateTime = (DWORD)(AsyncResult->TimeStamp >> 32);
    stFileTime.dwLowDateTime = (DWORD)(AsyncResult->TimeStamp & 0xFFFFFFFF);

    SYSTEMTIME stSystemTime;
    FileTimeToSystemTime(&stFileTime, &stSystemTime);

    wprintf_s(L"Time Stamp [%d/%02d/%02d(%d) %02d:%02d:%02d.%03d]\n", 
        stSystemTime.wYear, stSystemTime.wMonth, stSystemTime.wDay, stSystemTime.wDayOfWeek,
        stSystemTime.wHour, stSystemTime.wMinute, stSystemTime.wSecond, stSystemTime.wMilliseconds);

    wprintf_s(L"API Status [0x%08X]\n", AsyncResult->ApiStatus);
    wprintf_s(L"Unit ID [%d]\n", AsyncResult->UnitId);

    // 対応する関数ごとの結果出力
    if (AsyncResult->Operation == WINBIO_OPERATION_ENUM_SERVICE_PROVIDERS)
    {
        // "WinBioAsyncEnumServiceProviders"関数の結果
        wprintf_s(L"BSP Count [%lld]\n", AsyncResult->Parameters.EnumServiceProviders.BspCount);
        for (int i = 0; i < AsyncResult->Parameters.EnumServiceProviders.BspCount; i++)
        {
            WINBIO_BSP_SCHEMA* stBSPSchema = &(AsyncResult->Parameters.EnumServiceProviders.BspSchemaArray[i]);
            wprintf_s(L" BSP ID [%ws]\n", GuidToString(&stBSPSchema->BspId).c_str());
            wprintf_s(L"  Biometric Factor [%d]\n", stBSPSchema->BiometricFactor);
            wprintf_s(L"  Description [%ws]\n", stBSPSchema->Description);
            wprintf_s(L"  Vendor [%ws]\n", stBSPSchema->Vendor);
            wprintf_s(L"  Version [%d.%d]\n", stBSPSchema->Version.MajorVersion, stBSPSchema->Version.MinorVersion);
        }
    }
    else if (AsyncResult->Operation == WINBIO_OPERATION_ENUM_BIOMETRIC_UNITS)
    {
        // "WinBioAsyncEnumBiometricUnits"関数の結果
        wprintf_s(L"Unit Count [%lld]\n", AsyncResult->Parameters.EnumBiometricUnits.UnitCount);
        for (int i = 0; i < AsyncResult->Parameters.EnumBiometricUnits.UnitCount; i++)
        {
            WINBIO_UNIT_SCHEMA* stUnitSchema = &(AsyncResult->Parameters.EnumBiometricUnits.UnitSchemaArray[i]);
            wprintf_s(L" Unit ID [%d]\n", stUnitSchema->UnitId);
            wprintf_s(L"  Pool Type [%d]\n", stUnitSchema->PoolType);
            wprintf_s(L"  Biometric Factor [%d]\n", stUnitSchema->BiometricFactor);
            wprintf_s(L"  Sensor Sub Type [%d]\n", stUnitSchema->SensorSubType);
            wprintf_s(L"  Capabilities [%d]\n", stUnitSchema->Capabilities);
            wprintf_s(L"  Device Instance ID [%ws]\n", stUnitSchema->DeviceInstanceId);
            wprintf_s(L"  Description [%ws]\n", stUnitSchema->Description);
            wprintf_s(L"  Manufacturer [%ws]\n", stUnitSchema->Manufacturer);
            wprintf_s(L"  Model [%ws]\n", stUnitSchema->Model);
            wprintf_s(L"  Serial Number [%ws]\n", stUnitSchema->SerialNumber);
            wprintf_s(L"  Firmware Version [%d.%d]\n", stUnitSchema->FirmwareVersion.MajorVersion, stUnitSchema->FirmwareVersion.MinorVersion);
        }
    }
    else if (AsyncResult->Operation == WINBIO_OPERATION_ENUM_DATABASES)
    {
        // "WinBioAsyncEnumDatabases"関数の結果
        wprintf_s(L"Storage Count [%lld]\n", AsyncResult->Parameters.EnumDatabases.StorageCount);
        for (int i = 0; i < AsyncResult->Parameters.EnumDatabases.StorageCount; i++)
        {
            WINBIO_STORAGE_SCHEMA* stStorageSchema = &(AsyncResult->Parameters.EnumDatabases.StorageSchemaArray[i]);
            wprintf_s(L" Database ID [%ws]\n", GuidToString(&stStorageSchema->DatabaseId).c_str());
            wprintf_s(L"  Biometric Factor [%d]\n", stStorageSchema->BiometricFactor);
            wprintf_s(L"  Data Format [%ws]\n", GuidToString(&stStorageSchema->DataFormat).c_str());
            wprintf_s(L"  Attributes [%d]\n", stStorageSchema->Attributes);
            wprintf_s(L"  File Path [%ws]\n", stStorageSchema->FilePath);
            wprintf_s(L"  Connection String [%ws]\n", stStorageSchema->ConnectionString);
        }
    }

    // WINBIO_ASYNC_RESULT構造体の解放
    WinBioFree(AsyncResult);
}

// ====================================================================================================
//  エントリーポイント
// ====================================================================================================
int main()
{
    HRESULT hr = S_OK;
    WINBIO_FRAMEWORK_HANDLE FrameworkHandle = NULL;

    try
    {
        // 標準出力に日本語を出力できるようにする
        setlocale(LC_ALL, "Japanese"); 

        // 生体認証フレームワークへのハンドルを取得する
        hr = WinBioAsyncOpenFramework(WINBIO_ASYNC_NOTIFY_CALLBACK, NULL, 0, WINBIO_ASYNC_COMPLETION_CALLBACK, NULL, FALSE, &FrameworkHandle);
        if (FAILED(hr))
        {
            wprintf_s(L"WinBioAsyncOpenFramework failed. hr = 0x%x\n", hr);
            throw hr;
        }

        // インストールされている指紋認証サービスプロバイダーに関する情報を非同期で列挙する
        hr = WinBioAsyncEnumServiceProviders(FrameworkHandle, WINBIO_TYPE_FINGERPRINT);
        if (FAILED(hr))
        {
            wprintf_s(L"WinBioAsyncEnumServiceProviders failed. hr = 0x%x\n", hr);
            throw hr;
        }

        // アタッチされたすべての指紋認証ユニットを非同期で列挙する
        hr =  WinBioAsyncEnumBiometricUnits(FrameworkHandle, WINBIO_TYPE_FINGERPRINT);
        if (FAILED(hr))
        {
            wprintf_s(L"WinBioAsyncEnumBiometricUnits failed. hr = 0x%x\n", hr);
            throw hr;
        }

       // 登録済みのすべての指紋情報データベースを非同期で列挙する
        hr = WinBioAsyncEnumDatabases(FrameworkHandle, WINBIO_TYPE_FINGERPRINT);
        if (FAILED(hr))
        {
            wprintf_s(L"WinBioAsyncEnumDatabases failed. hr = 0x%x\n", hr);
            throw hr;
        }
    }
    catch (HRESULT hrError) { hr = hrError; }
    catch (...) { hr = E_UNEXPECTED; }

    // ユーザーの入力待ち
    _getch();

    // フレームワークを閉じる
    if (FrameworkHandle != NULL)
        WinBioCloseFramework(FrameworkHandle);

    return 0;
}
```