Я написал программу, которая работает в Windows 8.1 & 10 для проверки отпечатка пальца по идентификатору текущего пользователя, вошедшего в систему, с помощью WinBioVerify. Я делаю это асинхронно, начиная сеанс с WinBioAsyncOpenSession. Я попытался запустить ту же программу в Windows 7, и оказалось, что WinBioAsyncOpenSession не существует в Win7-версии WinBio.dll.
Это не должно было быть проблемой, поскольку было достаточно легко создать отдельный EXE-файл для Win7, который обычно открывал сеанс и вместо этого вызывал WinBioVerifyWithCallback. Проблема, с которой я столкнулся, теперь имеет те же симптомы, что и в том случае, если исходная программа неправильно настраивала фокус окна приложения: при касании загорается блок отпечатка пальца, но результат не возвращается в код.
Поиск Google обнаруживает некоторые ссылки на то, что SetForegroundWindow () ненадежен в Win7, но ни одна из опробованных мною альтернатив не сработала (BringWindowToTop, AttachThreadInput, WinBioAcquireFocus), предполагая, что фокус — даже проблема.
Кто-нибудь имеет или знает какие-либо рабочие примеры WinBioVerifyWithCallback на Windows 7?
ИЗМЕНЕНО ДЛЯ ДОБАВЛЕНИЯ:
Вот код, который работает (на Win8.1 / Win10):
unsigned int verifyUser(string &userName) {
string libPath;
OutputDebugString("verifyUser: getApplicationPath");
libPath = getApplicationPath();
try {
//Make sure path ends with backslash
if (libPath[libPath.length()-1] != '\\') libPath += "\\";
string userHash = getHash(userName);
//Get timeout from globals
int timeoutValue = globals.timeout * 1000;
//Check to see if we need an infinite timeout
if (globals.disable_timeout)
{
timeoutValue = 1000 * 60 * 5;
}
TotalTickCount = timeoutValue; //5 minutes
startTick = GetTickCount();
globals.last_scan_result = BIO_INPROGRESS;
countdownTimer = SetTimer(hMainWnd, ID_COUNTDOWN, 1000, NULL);
CString lsr;
lsr.Format("globals.last_scan_result = %d", globals.last_scan_result);
OutputDebugString(lsr);
sessionHandle = NULL;
HRESULT hr = WinBioAsyncOpenSession(
WINBIO_TYPE_FINGERPRINT, // Service provider
WINBIO_POOL_SYSTEM, // Pool type
WINBIO_FLAG_DEFAULT, // Configuration and access
NULL, // Array of biometric unit IDs
0, // Count of biometric unit IDs
NULL, // Database ID
WINBIO_ASYNC_NOTIFY_MESSAGE,// Notification method
hMainWnd, // Target window
WM_APP+BIO_INPROGRESS, // Message code
NULL, // Callback routine
NULL, // User data
FALSE, // Asynchronous open
&sessionHandle // [out] Session handle
);
if (FAILED(hr))
{
CString s;
s.Format("WinBioAsyncOpenSession failed. hr = 0x%x\n", hr);
OutputDebugString(s);
KillTimer(hMainWnd, countdownTimer);
ShowWindow(hMainWnd, SW_HIDE);
LockSetForegroundWindow(LSFW_UNLOCK);
if (sessionHandle != NULL)
{
WinBioCloseSession(sessionHandle);
sessionHandle = NULL;
}
return BIO_ERROR;
}
// Find the identity of the user.
WINBIO_IDENTITY identity = { 0 };
hr = GetCurrentUserIdentity(&identity);
if (FAILED(hr))
{
CString s;
s.Format("User identity not found. hr = 0x%x\n", hr);
OutputDebugString(s);
KillTimer(hMainWnd, countdownTimer);
ShowWindow(hMainWnd, SW_HIDE);
LockSetForegroundWindow(LSFW_UNLOCK);
if (sessionHandle != NULL)
{
WinBioCloseSession(sessionHandle);
sessionHandle = NULL;
}
return BIO_USER_NOT_ENROLLED;
}
// Verify a biometric sample.
WINBIO_UNIT_ID unitId = 0;
WINBIO_REJECT_DETAIL rejectDetail = 0;
BOOLEAN match = FALSE;
OutputDebugString("Calling WinBioVerify");
SetWindowText(hStaticWnd, "To sign in, scan your finger on the fingerprint reader.");
UpdateWindow(hStaticWnd);
ShowWindow(hMainWnd, SW_SHOW);
SetForegroundWindow(hMainWnd);
LockSetForegroundWindow(LSFW_LOCK);
hr = WinBioVerify(
sessionHandle,
&identity,
WINBIO_SUBTYPE_ANY,
&unitId,
&match,
&rejectDetail
);
CString msg;
msg.Format("Swipe processed - Unit ID: %d\n", unitId);
OutputDebugString(msg);
lsr.Format("globals.last_scan_result = %d", globals.last_scan_result);
OutputDebugString(lsr);
while (globals.last_scan_result == BIO_INPROGRESS)
{
OutputDebugString("Waiting for verify...");
lsr.Format("globals.last_scan_result = %d", globals.last_scan_result);
OutputDebugString(lsr);
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else if (globals.last_scan_result == BIO_INPROGRESS)
{
WaitMessage();
}
}
OutputDebugString("Waiting for verify DONE.");
if (globals.last_scan_result == BIO_INPROGRESS)
{
globals.last_scan_result = BIO_CANCEL;
}
lsr.Format("globals.last_scan_result = %d", globals.last_scan_result);
OutputDebugString(lsr);
ShowWindow(hMainWnd, SW_HIDE);
LockSetForegroundWindow(LSFW_UNLOCK);
if (sessionHandle != NULL)
{
/*
if (globals.last_scan_result == BIO_CANCEL || globals.last_scan_result == BIO_TIMEOUT)
{
WinBioCancel(sessionHandle);
//WinBioWait(sessionHandle);
}
*/
WinBioCloseSession(sessionHandle);
sessionHandle = NULL;
}
return globals.last_scan_result;
} catch (...) {
OutputDebugString("Verify catch Error");
}
return BIO_ERROR;
}
Вот код, который не работает на Win7:
unsigned int verifyUser7(string &userName) {
string libPath;
OutputDebugString("verifyUser7: getApplicationPath");
libPath = getApplicationPath();
// HWND capwnd;try {
//Make sure path ends with backslash
if (libPath[libPath.length() - 1] != '\\') libPath += "\\";
string userHash = getHash(userName);
//Get timeout from globals
int timeoutValue = globals.timeout * 1000;
//Check to see if we need an infinite timeout
if (globals.disable_timeout)
{
timeoutValue = 1000 * 60 * 5;
}
TotalTickCount = timeoutValue; //5 minutes
startTick = GetTickCount();
globals.last_scan_result = BIO_INPROGRESS;
countdownTimer = SetTimer(hMainWnd, ID_COUNTDOWN, 1000, NULL);
CString lsr;
lsr.Format("globals.last_scan_result = %d", globals.last_scan_result);
OutputDebugString(lsr);
sessionHandle = NULL;
HRESULT hr = WinBioOpenSession(
WINBIO_TYPE_FINGERPRINT, // Service provider
WINBIO_POOL_SYSTEM, // Pool type
WINBIO_FLAG_DEFAULT, // Configuration and access
NULL, // Array of biometric unit IDs
0, // Count of biometric unit IDs
NULL, // Database ID
&sessionHandle // [out] Session handle
);
if (FAILED(hr))
{
CString s;
s.Format("WinBioOpenSession failed. hr = 0x%x\n", hr);
OutputDebugString(s);
KillTimer(hMainWnd, countdownTimer);
ShowWindow(hMainWnd, SW_HIDE);
LockSetForegroundWindow(LSFW_UNLOCK);
if (sessionHandle != NULL)
{
WinBioCloseSession(sessionHandle);
sessionHandle = NULL;
}
return BIO_ERROR;
}
// Find the identity of the user.
WINBIO_IDENTITY identity = { 0 };
hr = GetCurrentUserIdentity(&identity);
if (FAILED(hr))
{
CString s;
s.Format("User identity not found. hr = 0x%x\n", hr);
OutputDebugString(s);
KillTimer(hMainWnd, countdownTimer);
ShowWindow(hMainWnd, SW_HIDE);
LockSetForegroundWindow(LSFW_UNLOCK);
if (sessionHandle != NULL)
{
WinBioCloseSession(sessionHandle);
sessionHandle = NULL;
}
return BIO_USER_NOT_ENROLLED;
}
// Verify a biometric sample.
WINBIO_UNIT_ID unitId = 0;
WINBIO_REJECT_DETAIL rejectDetail = 0;
BOOLEAN match = FALSE;
OutputDebugString("Calling WinBioVerifyWithCallback");
SetWindowText(hStaticWnd, "To sign in, scan your finger on the fingerprint reader.");
UpdateWindow(hStaticWnd);
ShowWindow(hMainWnd, SW_SHOW);
SetForegroundWindow(hMainWnd);
LockSetForegroundWindow(LSFW_LOCK);
hr = WinBioVerifyWithCallback(
sessionHandle,
&identity,
WINBIO_SUBTYPE_ANY,
VerifyCallback, // Callback function
NULL // Optional context
);
CString msg;
//msg.Format("Swipe processed - Unit ID: %d\n", unitId);
//OutputDebugString(msg);
lsr.Format("globals.last_scan_result = %d", globals.last_scan_result);
OutputDebugString(lsr);
while (globals.last_scan_result == BIO_INPROGRESS)
{
OutputDebugString("Waiting for verify...");
lsr.Format("globals.last_scan_result = %d", globals.last_scan_result);
OutputDebugString(lsr);
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else if (globals.last_scan_result == BIO_INPROGRESS)
{
WaitMessage();
}
}
OutputDebugString("Waiting for verify DONE.");
if (globals.last_scan_result == BIO_INPROGRESS)
{
globals.last_scan_result = BIO_CANCEL;
}
lsr.Format("globals.last_scan_result = %d", globals.last_scan_result);
OutputDebugString(lsr);
ShowWindow(hMainWnd, SW_HIDE);
WinBioReleaseFocus();
//LockSetForegroundWindow(LSFW_UNLOCK);
if (sessionHandle != NULL)
{
WinBioCloseSession(sessionHandle);
sessionHandle = NULL;
}
return globals.last_scan_result;
}
catch (...) {
OutputDebugString("Verify catch Error");
}
return BIO_ERROR;
}
Решается добавлением SetFocus () после SetForegroundWindow (). Не уверен, почему этот дополнительный шаг необходим в Windows 7.
Других решений пока нет …