【WBF】非同期で生体認証ユニットの接続状態を監視する

# 使用する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

- Windows Biometric Frameworkの状態変化の監視を開始させる関数
  - WinBioAsyncMonitorFrameworkChanges<br>
    https://docs.microsoft.com/en-us/windows/win32/api/winbio/nf-winbio-winbioasyncmonitorframeworkchanges

- 取得した結果のメモリの解放
  - 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>

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

// ====================================================================================================
//  コールバック関数
// ====================================================================================================
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_UNIT_ARRIVAL)
        wprintf_s(L"生体認証ユニットが接続されました。\n");
    else if(AsyncResult->Operation == WINBIO_OPERATION_UNIT_REMOVAL)
        wprintf_s(L"生体認証ユニットが取り外されました。\n");

    // 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 = WinBioAsyncMonitorFrameworkChanges(FrameworkHandle, WINBIO_FRAMEWORK_CHANGE_UNIT);
        if (FAILED(hr))
        {
            wprintf_s(L"WinBioAsyncMonitorFrameworkChanges failed. hr = 0x%x\n", hr);
            throw hr;
        }

        wprintf_s(L"生体認証ユニットの監視を開始します。\n");
    }
    catch (HRESULT hrError) { hr = hrError; }
    catch (...) { hr = E_UNEXPECTED; }

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

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

    return 0;
}
```
上記コードを実行すると、ユーザーが何かキーを押すまで、生体認証ユニット(指紋センサーetc.)が監視され、USBから抜き差しする度にコールバック関数が呼ばれます。