C# 检测控制台应用程序外部的指纹读取器输入
因此,我需要制作一个Metro GUI应用程序,使用外部指纹读取器进行用户识别 我已经在C++中做了一个DLL,所以我可以调用一个我在C引用引用DLL的方法中调用的方法:<代码> CAPUTSRAMP()/CUL>。C# 检测控制台应用程序外部的指纹读取器输入,c#,wcf,windows-8,msmq,biometrics,C#,Wcf,Windows 8,Msmq,Biometrics,因此,我需要制作一个Metro GUI应用程序,使用外部指纹读取器进行用户识别 我已经在C++中做了一个DLL,所以我可以调用一个我在C引用引用DLL的方法中调用的方法: CAPUTSRAMP()/CUL>。CaptureSample()方法为我提供了一个字节数组,表示扫描的指纹(指纹读取器的灰度图像)。到目前为止还不错。其方法是使用Microsoft生物识别框架访问读卡器,等待读卡器检测到手指放在上面,然后将扫描指纹的数据发送回 这一切都很好。但是有一个缺点:我必须运行我作为管理员制作的任何应
CaptureSample()
方法为我提供了一个字节数组,表示扫描的指纹(指纹读取器的灰度图像)。到目前为止还不错。其方法是使用Microsoft生物识别框架访问读卡器,等待读卡器检测到手指放在上面,然后将扫描指纹的数据发送回
这一切都很好。但是有一个缺点:我必须运行我作为管理员制作的任何应用程序才能使用框架。这也是为什么我不能从Web服务运行框架的原因,因为Web服务是作为网络用户或类似用户运行的,这使得库在尝试使用它时拒绝任何访问。所以我必须制作一个额外的控制台程序来运行它
现在事情变得棘手了。为了使指纹读取器与Windows Metro GUI应用程序一起工作,您必须以管理员身份运行该应用程序。这是不可能的,因为所有Metro GUI应用程序都在沙箱中运行。我必须制作一个外部控制台应用程序,调用应用程序的DLL功能,然后将结果发送回应用程序
让事情变得更复杂的是,我发现.NET的Windows Phone子集没有MSMQ,而MSMQ本来可以很好地使用。因此,我创建了Metro应用程序需要调用的本地WCF服务,然后WCF服务通过MSMQ调用控制台程序,并在Metro GUI应用程序从控制台应用程序接收信息时将其发送回Metro GUI应用程序
到目前为止还不错。理论上。我在这个过程中遇到了一个问题,因为控制台应用程序确实在运行,并且在被询问时可以进行扫描。但当我扫描我的手指时,什么也没发生。控制台需要聚焦才能工作,这是不可能的,因为该应用程序就像一个信息亭一样运行,除非进行维护,否则不应该离开Metro GUI应用程序
我研究过各种检测C#应用程序外部键盘输入的解决方案,但我认为这不适用于指纹读取器,或者如果指纹读取器适用,我不知道该怎么做。有什么建议吗
为了更好地理解,我附带了一个工作流程图。(如果有人好奇,这是一款P5100 Zvetcobiometrics指纹读取器):
因此,我在Windows窗体中遇到了类似的问题,但与您描述的问题不完全相同 我知道我的解决方案对你来说不是预先编码好的轻松日解决方案,但我觉得经过一些小的修改,几年前我克服的一个障碍可能对你有用。如果你认为我的解决方案对你有帮助,我可以寄给你任何缺失的部分 我创建了一个利用条形码扫描仪的库存管理系统,我决定实现在某些C++类中通过编组来处理设备输入的能力,而不需要使用诸如文本框之类的输入控件。我需要应用程序能够处理条形码输入并做出决策,而无需任何额外的用户交互或需求。扫描一下就走。直接使用键盘/HID设备的输入是我认为此解决方案适合您问题的原因 在测试我编写的应用程序时,我能够进入一个全屏游戏,并且仍然能够像在windows窗体清单应用程序中预期的那样使用条形码扫描仪。这一功能在控制台环境中应该同样有效,因为控制台应用程序在后台时不会停止。您甚至可以将它设置为NT权限,并防止它在作为服务运行时显示在桌面上,并且它仍应继续运行 我所做的是使用Win32API通过设备进行反映,将设备与通过应用程序(用户选择)指定的设备进行匹配,并基本上为该特定设备建立了侦听器 您可以使用控制台应用程序触发指纹传感器,方法是将控制台应用程序作为本地服务帐户运行,或以编程方式获得必要的授权(这将允许您在提升权限下运行它,而无需UAC人员妨碍您)然后在你的metro应用程序中使用它来读取设备发送的输入 下面是一些代码文件,用于我所描述的内容,并已修改为特定于我的条形码扫描仪功能 同样,如果你想看到任何遗失的物品,请私下联系我 PS:从技术上讲,这可能被用作拦截密钥之类的黑客,因此我将为您提供一份免责声明,供您自行决定使用,我对愚蠢的人可能使用此代码所做的任何事情概不负责 条形码扫描程序ListenerInterophelper.h:
#include <winuser.h>
BEGIN_INTEROP_NAMESPACE
using namespace System;
using namespace System::Collections::Generic;
using namespace HFSLIB::Barcode;
using namespace HFSLIB::Barcode::Interop;
using namespace HFSLIB::Barcode::Infrastructure::BarcodeScannerListener;
/// <summary>
/// Provides some helper methods that help the BarcodeScannerListener use native
/// Windows APIs without resorting to P/Invoking from C#.
/// </summary>
public ref class BarcodeScannerListenerInteropHelper
{
public:
/// <summary>
/// Returns a dictionary of barcode device handles to information about
/// the device.
/// </summary>
/// <param name="hardwareIds">The enumerable of hardware IDs to filter by.</param>
/// <returns>The device handle-to-information mapping of the filtered hardware IDs.</returns>
Dictionary<IntPtr, BarcodeScannerDeviceInfo^>^ InitializeBarcodeScannerDeviceHandles(
IEnumerable<String^>^ hardwareIds);
/// <summary>
/// Registers ourselves to listen to raw input from keyboard-like devices.
/// </summary>
/// <param name="hwnd">the handle of the form that will receive the raw
/// input messages</param>
/// <exception cref="InvalidOperationException">if the call to register with the
/// raw input API fails for some reason</exception>
void HookRawInput(IntPtr hwnd);
/// <summary>
/// Gets information from a WM_INPUT message.
/// </summary>
/// <param name="rawInputHeader">The LParam from the WM_INPUT message.</param>
/// <param name="deviceHandle">[Out] The device handle that the message came from.</param>
/// <param name="handled">[Out] True if the message represents a keystroke from that device.</param>
/// <param name="buffer">[Out] If handled is true, this contains the characters that the keystroke represents.</param>
void GetRawInputInfo(
IntPtr rawInputHeader,
IntPtr% deviceHandle,
bool% handled,
String^% buffer);
private:
/// <summary>
/// Converts a native raw input type into our version.
/// </summary>
/// <param name="rawInputType">The raw input type.</param>
/// <returns>Our version of the type.</returns>
static BarcodeScannerDeviceType GetBarcodeScannerDeviceType(DWORD rawInputType);
};
END_INTEROP_NAMESPACE
#包括
开始\u互操作\u命名空间
使用名称空间系统;
使用命名空间System::Collections::Generic;
使用名称空间HFSLIB::Barcode;
使用名称空间HFSLIB::Barcode::Interop;
使用名称空间HFSLIB::Barcode::Infrastructure::BarcodeScannerListener;
///
///提供一些帮助器方法,帮助BarcodeScannerListener使用本机
///Windows API,而无需从C#调用P/Invoking。
///
公共引用类条形码扫描程序ListenerInterophelper
{
公众:
///
///返回条形码设备句柄的字典,以获取有关
///这个装置。
///
///要筛选的硬件ID的可枚举项。
///设备句柄到已过滤硬件ID的信息映射。
字典^InitializeBarcodeScannerDeviceHandles(
IEnumerable^ hardwareIds);
///
///登记我们自己去听
#include "BarcodeScannerListenerInteropHelper.h"
using namespace System::ComponentModel;
BEGIN_INTEROP_NAMESPACE
/// <summary>
/// Gets information from a WM_INPUT message.
/// </summary>
/// <param name="rawInputHeader">The LParam from the WM_INPUT message.</param>
/// <param name="deviceHandle">[Out] The device handle that the message came from.</param>
/// <param name="handled">[Out] True if the message represents a keystroke from that device.</param>
/// <param name="buffer">[Out] If handled is true, this contains the characters that the keystroke represents.</param>
void BarcodeScannerListenerInteropHelper::GetRawInputInfo(
IntPtr rawInputHeader,
IntPtr% deviceHandle,
bool% handled,
String^% buffer)
{
UINT cbSize;
HRAWINPUT hRawInput;
hRawInput = (HRAWINPUT)rawInputHeader.ToPointer();
if (GetRawInputData(hRawInput, RID_INPUT, NULL, &cbSize, sizeof(RAWINPUTHEADER)) == 0)
{
RAWINPUT* raw;
raw = (RAWINPUT*)malloc(cbSize);
if (GetRawInputData(hRawInput, RID_INPUT, raw, &cbSize, sizeof(RAWINPUTHEADER)) == cbSize)
{
deviceHandle = IntPtr(raw->header.hDevice);
handled = raw->header.dwType == RIM_TYPEKEYBOARD &&
raw->data.keyboard.Message == WM_KEYDOWN;
if (handled)
{
BYTE state[256];
// Force the keyboard status cache to update
GetKeyState(0);
// Note: GetKeyboardState only returns valid state when
// the application has focus -- this is why we weren't
// getting shift keys when the application was not focused
if (GetKeyboardState(state))
{
WCHAR unmanagedBuffer[64];
if (ToUnicode(raw->data.keyboard.VKey,
raw->data.keyboard.MakeCode,
state,
unmanagedBuffer,
64,
0) > 0)
{
buffer = gcnew String(unmanagedBuffer);
}
}
}
}
free(raw);
}
}
/// <summary>
/// Registers ourselves to listen to raw input from keyboard-like devices.
/// </summary>
/// <param name="hwnd">the handle of the form that will receive the raw
/// input messages</param>
/// <exception cref="InvalidOperationException">if the call to register with the
/// raw input API fails for some reason</exception>
void BarcodeScannerListenerInteropHelper::HookRawInput(IntPtr hwnd)
{
RAWINPUTDEVICE rid[1];
rid[0].dwFlags = 0;
rid[0].hwndTarget = (HWND)hwnd.ToPointer();
rid[0].usUsage = 0x06; // Keyboard Usage ID
rid[0].usUsagePage = 0x01; // USB HID Generic Desktop Page
if (!RegisterRawInputDevices(rid, 1, sizeof(RAWINPUTDEVICE)))
{
InvalidOperationException^ e;
e = gcnew InvalidOperationException(
"The barcode scanner listener could not register for raw input devices.",
gcnew Win32Exception());
throw e;
}
}
/// <summary>
/// Returns a dictionary of barcode device handles to information about
/// the device.
/// </summary>
Dictionary<IntPtr, BarcodeScannerDeviceInfo^>^ BarcodeScannerListenerInteropHelper::InitializeBarcodeScannerDeviceHandles(IEnumerable<String^>^ hardwareIds)
{
Dictionary<IntPtr, BarcodeScannerDeviceInfo^>^ devices;
UINT uiNumDevices;
UINT cbSize;
devices = gcnew Dictionary<IntPtr, BarcodeScannerDeviceInfo^>();
uiNumDevices = 0;
cbSize = sizeof(RAWINPUTDEVICELIST);
if (GetRawInputDeviceList(NULL, &uiNumDevices, cbSize) != -1)
{
PRAWINPUTDEVICELIST pRawInputDeviceList;
if (pRawInputDeviceList = (PRAWINPUTDEVICELIST)malloc(cbSize * uiNumDevices))
{
if (GetRawInputDeviceList(pRawInputDeviceList, &uiNumDevices, cbSize) != -1)
{
for (UINT i = 0; i < uiNumDevices; ++i)
{
UINT pcbSize;
RAWINPUTDEVICELIST rid;
rid = pRawInputDeviceList[i];
if (GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICENAME, NULL, &pcbSize) >= 0 &&
pcbSize > 0)
{
WCHAR* deviceName;
deviceName = (WCHAR*)malloc(sizeof(WCHAR) * (pcbSize + 1));
if (GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICENAME, deviceName, &pcbSize) >= 0)
{
bool add;
IntPtr deviceHandle;
BarcodeScannerDeviceInfo^ info;
String^ managedDeviceName;
add = false;
deviceHandle = IntPtr(rid.hDevice);
managedDeviceName = gcnew String(deviceName);
for each (String^ hardwareId in hardwareIds)
{
if (managedDeviceName->IndexOf(hardwareId, StringComparison::OrdinalIgnoreCase) >= 0)
{
add = true;
break;
}
}
if (add)
{
info = gcnew BarcodeScannerDeviceInfo(
managedDeviceName,
BarcodeScannerListenerInteropHelper::GetBarcodeScannerDeviceType(rid.dwType),
deviceHandle);
devices->Add(deviceHandle, info);
}
}
free(deviceName);
}
}
}
free(pRawInputDeviceList);
}
}
return devices;
}
/// <summary>
/// Converts a native raw input type into our version.
/// </summary>
/// <param name="rawInputType">The raw input type.</param>
/// <returns>Our version of the type.</returns>
BarcodeScannerDeviceType BarcodeScannerListenerInteropHelper::GetBarcodeScannerDeviceType(DWORD rawInputType)
{
BarcodeScannerDeviceType type;
switch (rawInputType)
{
case RIM_TYPEHID:
type = BarcodeScannerDeviceType::HumanInterfaceDevice;
break;
case RIM_TYPEKEYBOARD:
type = BarcodeScannerDeviceType::Keyboard;
break;
default:
type = BarcodeScannerDeviceType::Unknown;
break;
}
return type;
}
END_INTEROP_NAMESPACE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Windows.Forms;
using HFSLIB.Barcode.Infrastructure.BarcodeScannerListener;
using HFSLIB.Barcode.Interop;
namespace HFSLIB.Barcode
{
/// <summary>
/// This class uses Windows's native Raw Input API to listen for input from
/// a certain set of barcode scanners and devices. This way, the application
/// can receive input from a barcode scanner without the user having to
/// worry about whether or not a certain text field has focus, which was a
/// big problem
/// </summary>
public class BarcodeScannerListener : NativeWindow
{
/// <summary>
/// A mapping of device handles to information about the barcode scanner
/// devices.
/// </summary>
private Dictionary<IntPtr, BarcodeScannerDeviceInfo> devices;
/// <summary>
/// The WM_KEYDOWN filter.
/// </summary>
private BarcodeScannerKeyDownMessageFilter filter;
/// <summary>
/// The barcode currently being read.
/// </summary>
private StringBuilder keystrokeBuffer;
/// <summary>
/// The interop helper.
/// </summary>
private BarcodeScannerListenerInteropHelper interopHelper =
new BarcodeScannerListenerInteropHelper();
/// <summary>
/// Event fired when a barcode is scanned.
/// </summary>
public event EventHandler BarcodeScanned;
/// <summary>
/// Attaches the listener to the given form.
/// </summary>
/// <param name="form">The form to attach to.</param>
public void Attach(Form form)
{
IntPtr hwnd;
if (form == null)
{
throw new ArgumentNullException("form");
}
hwnd = form.Handle;
this.keystrokeBuffer = new StringBuilder();
this.InitializeBarcodeScannerDeviceHandles();
this.interopHelper.HookRawInput(hwnd);
this.HookHandleEvents(form);
this.AssignHandle(hwnd);
this.filter = new BarcodeScannerKeyDownMessageFilter();
Application.AddMessageFilter(this.filter);
}
/// <summary>
/// Hook into the form's WndProc message. We listen for WM_INPUT and do
/// special processing on the raw data.
/// </summary>
/// <param name="m">the message</param>
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case NativeMethods.WM_INPUT:
if (this.ProcessRawInputMessage(m.LParam))
{
this.filter.FilterNext = true;
}
break;
}
base.WndProc(ref m);
}
/// <summary>
/// Fires the barcode scanned event.
/// </summary>
/// <param name="deviceInfo">information about the device that generated
/// the barcode</param>
private void FireBarcodeScanned(BarcodeScannerDeviceInfo deviceInfo)
{
string barcode;
EventHandler handler;
barcode = this.keystrokeBuffer.ToString();
if (barcode != null && barcode.Length > 0)
{
handler = this.BarcodeScanned;
this.keystrokeBuffer = new StringBuilder();
if (handler != null)
{
handler(this, new BarcodeScannedEventArgs(barcode, deviceInfo));
}
}
}
/// <summary>
/// Hooks into the form's HandleCreated and HandleDestoryed events
/// to ensure that we start and stop listening at appropriate times.
/// </summary>
/// <param name="form">the form to listen to</param>
private void HookHandleEvents(Form form)
{
form.HandleCreated += this.OnHandleCreated;
form.HandleDestroyed += this.OnHandleDestroyed;
}
/// <summary>
/// Initializes the barcode scanner device handles.
/// </summary>
private void InitializeBarcodeScannerDeviceHandles()
{
BarcodeScannerListenerConfigurationSection config;
BarcodeScannerListenerConfigurationElementCollection hardwareIdsConfig;
IEnumerable<string> hardwareIds;
config = BarcodeScannerListenerConfigurationSection.GetConfiguration();
hardwareIdsConfig = config.HardwareIds;
hardwareIds = from hardwareIdConfig in hardwareIdsConfig.Cast<BarcodeScannerListenerConfigurationElement>()
select hardwareIdConfig.Id;
this.devices = this.interopHelper.InitializeBarcodeScannerDeviceHandles(hardwareIds);
}
/// <summary>
/// When the form's handle is created, let's hook into it so we can see
/// the WM_INPUT event.
/// </summary>
/// <param name="sender">the form whose handle was created</param>
/// <param name="e">the event arguments</param>
private void OnHandleCreated(object sender, EventArgs e)
{
this.AssignHandle(((Form)sender).Handle);
}
/// <summary>
/// When the form's handle is destroyed, let's unhook from it so we stop
/// listening and allow the OS to free up its resources.
/// </summary>
/// <param name="sender">the form whose handle was destroyed</param>
/// <param name="e">the event arguments</param>
private void OnHandleDestroyed(object sender, EventArgs e)
{
this.ReleaseHandle();
}
/// <summary>
/// Process the given WM_INPUT message.
/// </summary>
/// <param name="rawInputHeader">the rawInputHeader of the message</param>
/// <returns>whether or not the keystroke was handled</returns>
private bool ProcessRawInputMessage(IntPtr rawInputHeader)
{
BarcodeScannerDeviceInfo deviceInfo;
bool handled;
bool keystroke;
string localBuffer;
IntPtr rawInputDeviceHandle;
handled = false;
keystroke = false;
localBuffer = string.Empty;
rawInputDeviceHandle = IntPtr.Zero;
this.interopHelper.GetRawInputInfo(
rawInputHeader,
ref rawInputDeviceHandle,
ref keystroke,
ref localBuffer);
if (this.devices.TryGetValue(rawInputDeviceHandle, out deviceInfo) && keystroke)
{
handled = true;
if (localBuffer.Length == 1 && localBuffer[0] == 0xA)
{
this.FireBarcodeScanned(deviceInfo);
}
else
{
this.keystrokeBuffer.Append(localBuffer);
}
}
return handled;
}
}
}