yibo 7 years ago
parent
commit
2b553e16ad
20 changed files with 2064 additions and 1 deletions
  1. +19
    -0
      HidLibrary/Extensions.cs
  2. +17
    -0
      HidLibrary/HidAsyncState.cs
  3. +711
    -0
      HidLibrary/HidDevice.cs
  4. +21
    -0
      HidLibrary/HidDeviceAttributes.cs
  5. +43
    -0
      HidLibrary/HidDeviceCapabilities.cs
  6. +30
    -0
      HidLibrary/HidDeviceData.cs
  7. +49
    -0
      HidLibrary/HidDeviceEventMonitor.cs
  8. +157
    -0
      HidLibrary/HidDevices.cs
  9. +76
    -0
      HidLibrary/HidFastReadDevice.cs
  10. +44
    -0
      HidLibrary/HidFastReadEnumerator.cs
  11. +71
    -0
      HidLibrary/HidLibrary.csproj
  12. +75
    -0
      HidLibrary/HidReport.cs
  13. +47
    -0
      HidLibrary/Honeywell1902Series/Report1902.cs
  14. +154
    -0
      HidLibrary/Honeywell1902Series/Scanner1902.cs
  15. +99
    -0
      HidLibrary/IHidDevice.cs
  16. +57
    -0
      HidLibrary/IHidEnumerator.cs
  17. +344
    -0
      HidLibrary/NativeMethods.cs
  18. +36
    -0
      HidLibrary/Properties/AssemblyInfo.cs
  19. +12
    -0
      WinFormControl.sln
  20. +2
    -1
      WinFormControl/UScanPanel.cs

+ 19
- 0
HidLibrary/Extensions.cs View File

@ -0,0 +1,19 @@
using System.Text;
namespace HidLibrary
{
public static class Extensions
{
public static string ToUTF8String(this byte[] buffer)
{
var value = Encoding.UTF8.GetString(buffer);
return value.Remove(value.IndexOf((char)0));
}
public static string ToUTF16String(this byte[] buffer)
{
var value = Encoding.Unicode.GetString(buffer);
return value.Remove(value.IndexOf((char)0));
}
}
}

+ 17
- 0
HidLibrary/HidAsyncState.cs View File

@ -0,0 +1,17 @@
namespace HidLibrary
{
public class HidAsyncState
{
private readonly object _callerDelegate;
private readonly object _callbackDelegate;
public HidAsyncState(object callerDelegate, object callbackDelegate)
{
_callerDelegate = callerDelegate;
_callbackDelegate = callbackDelegate;
}
public object CallerDelegate { get { return _callerDelegate; } }
public object CallbackDelegate { get { return _callbackDelegate; } }
}
}

+ 711
- 0
HidLibrary/HidDevice.cs View File

@ -0,0 +1,711 @@
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace HidLibrary
{
public class HidDevice : IHidDevice
{
public event InsertedEventHandler Inserted;
public event RemovedEventHandler Removed;
private readonly string _description;
private readonly string _devicePath;
private readonly HidDeviceAttributes _deviceAttributes;
private readonly HidDeviceCapabilities _deviceCapabilities;
private DeviceMode _deviceReadMode = DeviceMode.NonOverlapped;
private DeviceMode _deviceWriteMode = DeviceMode.NonOverlapped;
private ShareMode _deviceShareMode = ShareMode.ShareRead | ShareMode.ShareWrite;
private readonly HidDeviceEventMonitor _deviceEventMonitor;
private bool _monitorDeviceEvents;
protected delegate HidDeviceData ReadDelegate(int timeout);
protected delegate HidReport ReadReportDelegate(int timeout);
private delegate bool WriteDelegate(byte[] data, int timeout);
private delegate bool WriteReportDelegate(HidReport report, int timeout);
internal HidDevice(string devicePath, string description = null)
{
_deviceEventMonitor = new HidDeviceEventMonitor(this);
_deviceEventMonitor.Inserted += DeviceEventMonitorInserted;
_deviceEventMonitor.Removed += DeviceEventMonitorRemoved;
_devicePath = devicePath;
_description = description;
try
{
var hidHandle = OpenDeviceIO(_devicePath, NativeMethods.ACCESS_NONE);
_deviceAttributes = GetDeviceAttributes(hidHandle);
_deviceCapabilities = GetDeviceCapabilities(hidHandle);
CloseDeviceIO(hidHandle);
}
catch (Exception exception)
{
throw new Exception(string.Format("Error querying HID device '{0}'.", devicePath), exception);
}
}
public IntPtr Handle { get; private set; }
public bool IsOpen { get; private set; }
public bool IsConnected { get { return HidDevices.IsConnected(_devicePath); } }
public string Description { get { return _description; } }
public HidDeviceCapabilities Capabilities { get { return _deviceCapabilities; } }
public HidDeviceAttributes Attributes { get { return _deviceAttributes; } }
public string DevicePath { get { return _devicePath; } }
public bool MonitorDeviceEvents
{
get { return _monitorDeviceEvents; }
set
{
if (value & _monitorDeviceEvents == false) _deviceEventMonitor.Init();
_monitorDeviceEvents = value;
}
}
public override string ToString()
{
return string.Format("VendorID={0}, ProductID={1}, Version={2}, DevicePath={3}",
_deviceAttributes.VendorHexId,
_deviceAttributes.ProductHexId,
_deviceAttributes.Version,
_devicePath);
}
public void OpenDevice()
{
OpenDevice(DeviceMode.NonOverlapped, DeviceMode.NonOverlapped, ShareMode.ShareRead | ShareMode.ShareWrite);
}
public void OpenDevice(DeviceMode readMode, DeviceMode writeMode, ShareMode shareMode)
{
if (IsOpen) return;
_deviceReadMode = readMode;
_deviceWriteMode = writeMode;
_deviceShareMode = shareMode;
try
{
Handle = OpenDeviceIO(_devicePath, readMode, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, shareMode);
}
catch (Exception exception)
{
IsOpen = false;
throw new Exception("Error opening HID device.", exception);
}
IsOpen = Handle.ToInt32() != NativeMethods.INVALID_HANDLE_VALUE;
}
public void CloseDevice()
{
if (!IsOpen) return;
CloseDeviceIO(Handle);
IsOpen = false;
}
public HidDeviceData Read()
{
return Read(0);
}
public HidDeviceData Read(int timeout)
{
if (IsConnected)
{
if (IsOpen == false) OpenDevice(_deviceReadMode, _deviceWriteMode, _deviceShareMode);
try
{
return ReadData(timeout);
}
catch
{
return new HidDeviceData(HidDeviceData.ReadStatus.ReadError);
}
}
return new HidDeviceData(HidDeviceData.ReadStatus.NotConnected);
}
public void Read(ReadCallback callback)
{
Read(callback, 0);
}
public void Read(ReadCallback callback, int timeout)
{
var readDelegate = new ReadDelegate(Read);
var asyncState = new HidAsyncState(readDelegate, callback);
readDelegate.BeginInvoke(timeout, EndRead, asyncState);
}
public async Task<HidDeviceData> ReadAsync(int timeout = 0)
{
var readDelegate = new ReadDelegate(Read);
return await Task<HidDeviceData>.Factory.FromAsync(readDelegate.BeginInvoke, readDelegate.EndInvoke, timeout, null);
}
public HidReport ReadReport()
{
return ReadReport(0);
}
public HidReport ReadReport(int timeout)
{
return new HidReport(Capabilities.InputReportByteLength, Read(timeout));
}
public void ReadReport(ReadReportCallback callback)
{
ReadReport(callback, 0);
}
public void ReadReport(ReadReportCallback callback, int timeout)
{
var readReportDelegate = new ReadReportDelegate(ReadReport);
var asyncState = new HidAsyncState(readReportDelegate, callback);
readReportDelegate.BeginInvoke(timeout, EndReadReport, asyncState);
}
public async Task<HidReport> ReadReportAsync(int timeout = 0)
{
var readReportDelegate = new ReadReportDelegate(ReadReport);
return await Task<HidReport>.Factory.FromAsync(readReportDelegate.BeginInvoke, readReportDelegate.EndInvoke, timeout, null);
}
/// <summary>
/// Reads an input report from the Control channel. This method provides access to report data for devices that
/// do not use the interrupt channel to communicate for specific usages.
/// </summary>
/// <param name="reportId">The report ID to read from the device</param>
/// <returns>The HID report that is read. The report will contain the success status of the read request</returns>
///
public HidReport ReadReportSync(byte reportId)
{
byte[] cmdBuffer = new byte[Capabilities.InputReportByteLength];
cmdBuffer[0] = reportId;
bool bSuccess = NativeMethods.HidD_GetInputReport(Handle, cmdBuffer, cmdBuffer.Length);
HidDeviceData deviceData = new HidDeviceData(cmdBuffer, bSuccess ? HidDeviceData.ReadStatus.Success : HidDeviceData.ReadStatus.NoDataRead);
return new HidReport(Capabilities.InputReportByteLength, deviceData);
}
public bool ReadFeatureData(out byte[] data, byte reportId = 0)
{
if (_deviceCapabilities.FeatureReportByteLength <= 0)
{
data = new byte[0];
return false;
}
data = new byte[_deviceCapabilities.FeatureReportByteLength];
var buffer = CreateFeatureOutputBuffer();
buffer[0] = reportId;
IntPtr hidHandle = IntPtr.Zero;
bool success = false;
try
{
if (IsOpen)
hidHandle = Handle;
else
hidHandle = OpenDeviceIO(_devicePath, NativeMethods.ACCESS_NONE);
success = NativeMethods.HidD_GetFeature(hidHandle, buffer, buffer.Length);
if (success)
{
Array.Copy(buffer, 0, data, 0, Math.Min(data.Length, _deviceCapabilities.FeatureReportByteLength));
}
}
catch (Exception exception)
{
throw new Exception(string.Format("Error accessing HID device '{0}'.", _devicePath), exception);
}
finally
{
if (hidHandle != IntPtr.Zero && hidHandle != Handle)
CloseDeviceIO(hidHandle);
}
return success;
}
public bool ReadProduct(out byte[] data)
{
data = new byte[254];
IntPtr hidHandle = IntPtr.Zero;
bool success = false;
try
{
if (IsOpen)
hidHandle = Handle;
else
hidHandle = OpenDeviceIO(_devicePath, NativeMethods.ACCESS_NONE);
success = NativeMethods.HidD_GetProductString(hidHandle, ref data[0], data.Length);
}
catch (Exception exception)
{
throw new Exception(string.Format("Error accessing HID device '{0}'.", _devicePath), exception);
}
finally
{
if (hidHandle != IntPtr.Zero && hidHandle != Handle)
CloseDeviceIO(hidHandle);
}
return success;
}
public bool ReadManufacturer(out byte[] data)
{
data = new byte[254];
IntPtr hidHandle = IntPtr.Zero;
bool success = false;
try
{
if (IsOpen)
hidHandle = Handle;
else
hidHandle = OpenDeviceIO(_devicePath, NativeMethods.ACCESS_NONE);
success = NativeMethods.HidD_GetManufacturerString(hidHandle, ref data[0], data.Length);
}
catch (Exception exception)
{
throw new Exception(string.Format("Error accessing HID device '{0}'.", _devicePath), exception);
}
finally
{
if (hidHandle != IntPtr.Zero && hidHandle != Handle)
CloseDeviceIO(hidHandle);
}
return success;
}
public bool ReadSerialNumber(out byte[] data)
{
data = new byte[254];
IntPtr hidHandle = IntPtr.Zero;
bool success = false;
try
{
if (IsOpen)
hidHandle = Handle;
else
hidHandle = OpenDeviceIO(_devicePath, NativeMethods.ACCESS_NONE);
success = NativeMethods.HidD_GetSerialNumberString(hidHandle, ref data[0], data.Length);
}
catch (Exception exception)
{
throw new Exception(string.Format("Error accessing HID device '{0}'.", _devicePath), exception);
}
finally
{
if (hidHandle != IntPtr.Zero && hidHandle != Handle)
CloseDeviceIO(hidHandle);
}
return success;
}
public bool Write(byte[] data)
{
return Write(data, 0);
}
public bool Write(byte[] data, int timeout)
{
if (IsConnected)
{
if (IsOpen == false) OpenDevice(_deviceReadMode, _deviceWriteMode, _deviceShareMode);
try
{
return WriteData(data, timeout);
}
catch
{
return false;
}
}
return false;
}
public void Write(byte[] data, WriteCallback callback)
{
Write(data, callback, 0);
}
public void Write(byte[] data, WriteCallback callback, int timeout)
{
var writeDelegate = new WriteDelegate(Write);
var asyncState = new HidAsyncState(writeDelegate, callback);
writeDelegate.BeginInvoke(data, timeout, EndWrite, asyncState);
}
public async Task<bool> WriteAsync(byte[] data, int timeout = 0)
{
var writeDelegate = new WriteDelegate(Write);
return await Task<bool>.Factory.FromAsync(writeDelegate.BeginInvoke, writeDelegate.EndInvoke, data, timeout, null);
}
public bool WriteReport(HidReport report)
{
return WriteReport(report, 0);
}
public bool WriteReport(HidReport report, int timeout)
{
return Write(report.GetBytes(), timeout);
}
public void WriteReport(HidReport report, WriteCallback callback)
{
WriteReport(report, callback, 0);
}
public void WriteReport(HidReport report, WriteCallback callback, int timeout)
{
var writeReportDelegate = new WriteReportDelegate(WriteReport);
var asyncState = new HidAsyncState(writeReportDelegate, callback);
writeReportDelegate.BeginInvoke(report, timeout, EndWriteReport, asyncState);
}
/// <summary>
/// Handle data transfers on the control channel. This method places data on the control channel for devices
/// that do not support the interupt transfers
/// </summary>
/// <param name="report">The outbound HID report</param>
/// <returns>The result of the tranfer request: true if successful otherwise false</returns>
///
public bool WriteReportSync(HidReport report)
{
if (null != report)
{
byte[] buffer = report.GetBytes();
return (NativeMethods.HidD_SetOutputReport(Handle, buffer, buffer.Length));
}
else
throw new ArgumentException("The output report is null, it must be allocated before you call this method", "report");
}
public async Task<bool> WriteReportAsync(HidReport report, int timeout = 0)
{
var writeReportDelegate = new WriteReportDelegate(WriteReport);
return await Task<bool>.Factory.FromAsync(writeReportDelegate.BeginInvoke, writeReportDelegate.EndInvoke, report, timeout, null);
}
public HidReport CreateReport()
{
return new HidReport(Capabilities.OutputReportByteLength);
}
public bool WriteFeatureData(byte[] data)
{
if (_deviceCapabilities.FeatureReportByteLength <= 0) return false;
var buffer = CreateFeatureOutputBuffer();
Array.Copy(data, 0, buffer, 0, Math.Min(data.Length, _deviceCapabilities.FeatureReportByteLength));
IntPtr hidHandle = IntPtr.Zero;
bool success = false;
try
{
if (IsOpen)
hidHandle = Handle;
else
hidHandle = OpenDeviceIO(_devicePath, NativeMethods.ACCESS_NONE);
//var overlapped = new NativeOverlapped();
success = NativeMethods.HidD_SetFeature(hidHandle, buffer, buffer.Length);
}
catch (Exception exception)
{
throw new Exception(string.Format("Error accessing HID device '{0}'.", _devicePath), exception);
}
finally
{
if (hidHandle != IntPtr.Zero && hidHandle != Handle)
CloseDeviceIO(hidHandle);
}
return success;
}
protected static void EndRead(IAsyncResult ar)
{
var hidAsyncState = (HidAsyncState)ar.AsyncState;
var callerDelegate = (ReadDelegate)hidAsyncState.CallerDelegate;
var callbackDelegate = (ReadCallback)hidAsyncState.CallbackDelegate;
var data = callerDelegate.EndInvoke(ar);
if ((callbackDelegate != null)) callbackDelegate.Invoke(data);
}
protected static void EndReadReport(IAsyncResult ar)
{
var hidAsyncState = (HidAsyncState)ar.AsyncState;
var callerDelegate = (ReadReportDelegate)hidAsyncState.CallerDelegate;
var callbackDelegate = (ReadReportCallback)hidAsyncState.CallbackDelegate;
var report = callerDelegate.EndInvoke(ar);
if ((callbackDelegate != null)) callbackDelegate.Invoke(report);
}
private static void EndWrite(IAsyncResult ar)
{
var hidAsyncState = (HidAsyncState)ar.AsyncState;
var callerDelegate = (WriteDelegate)hidAsyncState.CallerDelegate;
var callbackDelegate = (WriteCallback)hidAsyncState.CallbackDelegate;
var result = callerDelegate.EndInvoke(ar);
if ((callbackDelegate != null)) callbackDelegate.Invoke(result);
}
private static void EndWriteReport(IAsyncResult ar)
{
var hidAsyncState = (HidAsyncState)ar.AsyncState;
var callerDelegate = (WriteReportDelegate)hidAsyncState.CallerDelegate;
var callbackDelegate = (WriteCallback)hidAsyncState.CallbackDelegate;
var result = callerDelegate.EndInvoke(ar);
if ((callbackDelegate != null)) callbackDelegate.Invoke(result);
}
private byte[] CreateInputBuffer()
{
return CreateBuffer(Capabilities.InputReportByteLength - 1);
}
private byte[] CreateOutputBuffer()
{
return CreateBuffer(Capabilities.OutputReportByteLength - 1);
}
private byte[] CreateFeatureOutputBuffer()
{
return CreateBuffer(Capabilities.FeatureReportByteLength - 1);
}
private static byte[] CreateBuffer(int length)
{
byte[] buffer = null;
Array.Resize(ref buffer, length + 1);
return buffer;
}
private static HidDeviceAttributes GetDeviceAttributes(IntPtr hidHandle)
{
var deviceAttributes = default(NativeMethods.HIDD_ATTRIBUTES);
deviceAttributes.Size = Marshal.SizeOf(deviceAttributes);
NativeMethods.HidD_GetAttributes(hidHandle, ref deviceAttributes);
return new HidDeviceAttributes(deviceAttributes);
}
private static HidDeviceCapabilities GetDeviceCapabilities(IntPtr hidHandle)
{
var capabilities = default(NativeMethods.HIDP_CAPS);
var preparsedDataPointer = default(IntPtr);
if (NativeMethods.HidD_GetPreparsedData(hidHandle, ref preparsedDataPointer))
{
NativeMethods.HidP_GetCaps(preparsedDataPointer, ref capabilities);
NativeMethods.HidD_FreePreparsedData(preparsedDataPointer);
}
return new HidDeviceCapabilities(capabilities);
}
private bool WriteData(byte[] data, int timeout)
{
if (_deviceCapabilities.OutputReportByteLength <= 0) return false;
var buffer = CreateOutputBuffer();
uint bytesWritten = 0;
Array.Copy(data, 0, buffer, 0, Math.Min(data.Length, _deviceCapabilities.OutputReportByteLength));
if (_deviceWriteMode == DeviceMode.Overlapped)
{
var security = new NativeMethods.SECURITY_ATTRIBUTES();
var overlapped = new NativeOverlapped();
var overlapTimeout = timeout <= 0 ? NativeMethods.WAIT_INFINITE : timeout;
security.lpSecurityDescriptor = IntPtr.Zero;
security.bInheritHandle = true;
security.nLength = Marshal.SizeOf(security);
overlapped.OffsetLow = 0;
overlapped.OffsetHigh = 0;
overlapped.EventHandle = NativeMethods.CreateEvent(ref security, Convert.ToInt32(false), Convert.ToInt32(true), "");
try
{
NativeMethods.WriteFile(Handle, buffer, (uint)buffer.Length, out bytesWritten, ref overlapped);
}
catch { return false; }
var result = NativeMethods.WaitForSingleObject(overlapped.EventHandle, overlapTimeout);
switch (result)
{
case NativeMethods.WAIT_OBJECT_0:
return true;
case NativeMethods.WAIT_TIMEOUT:
return false;
case NativeMethods.WAIT_FAILED:
return false;
default:
return false;
}
}
else
{
try
{
var overlapped = new NativeOverlapped();
return NativeMethods.WriteFile(Handle, buffer, (uint)buffer.Length, out bytesWritten, ref overlapped);
}
catch { return false; }
}
}
protected HidDeviceData ReadData(int timeout)
{
var buffer = new byte[] { };
var status = HidDeviceData.ReadStatus.NoDataRead;
IntPtr nonManagedBuffer;
if (_deviceCapabilities.InputReportByteLength > 0)
{
uint bytesRead = 0;
buffer = CreateInputBuffer();
nonManagedBuffer = Marshal.AllocHGlobal(buffer.Length);
if (_deviceReadMode == DeviceMode.Overlapped)
{
var security = new NativeMethods.SECURITY_ATTRIBUTES();
var overlapped = new NativeOverlapped();
var overlapTimeout = timeout <= 0 ? NativeMethods.WAIT_INFINITE : timeout;
security.lpSecurityDescriptor = IntPtr.Zero;
security.bInheritHandle = true;
security.nLength = Marshal.SizeOf(security);
overlapped.OffsetLow = 0;
overlapped.OffsetHigh = 0;
overlapped.EventHandle = NativeMethods.CreateEvent(ref security, Convert.ToInt32(false), Convert.ToInt32(true), string.Empty);
try
{
var success = NativeMethods.ReadFile(Handle, nonManagedBuffer, (uint)buffer.Length, out bytesRead, ref overlapped);
if (!success) {
var result = NativeMethods.WaitForSingleObject(overlapped.EventHandle, overlapTimeout);
switch (result)
{
case NativeMethods.WAIT_OBJECT_0:
status = HidDeviceData.ReadStatus.Success;
NativeMethods.GetOverlappedResult(Handle, ref overlapped, out bytesRead, false);
break;
case NativeMethods.WAIT_TIMEOUT:
status = HidDeviceData.ReadStatus.WaitTimedOut;
buffer = new byte[] { };
break;
case NativeMethods.WAIT_FAILED:
status = HidDeviceData.ReadStatus.WaitFail;
buffer = new byte[] { };
break;
default:
status = HidDeviceData.ReadStatus.NoDataRead;
buffer = new byte[] { };
break;
}
}
Marshal.Copy(nonManagedBuffer, buffer, 0, (int)bytesRead);
}
catch { status = HidDeviceData.ReadStatus.ReadError; }
finally {
CloseDeviceIO(overlapped.EventHandle);
Marshal.FreeHGlobal(nonManagedBuffer);
}
}
else
{
try
{
var overlapped = new NativeOverlapped();
NativeMethods.ReadFile(Handle, nonManagedBuffer, (uint)buffer.Length, out bytesRead, ref overlapped);
status = HidDeviceData.ReadStatus.Success;
Marshal.Copy(nonManagedBuffer, buffer, 0, (int)bytesRead);
}
catch { status = HidDeviceData.ReadStatus.ReadError; }
finally { Marshal.FreeHGlobal(nonManagedBuffer); }
}
}
return new HidDeviceData(buffer, status);
}
private static IntPtr OpenDeviceIO(string devicePath, uint deviceAccess)
{
return OpenDeviceIO(devicePath, DeviceMode.NonOverlapped, deviceAccess, ShareMode.ShareRead | ShareMode.ShareWrite);
}
private static IntPtr OpenDeviceIO(string devicePath, DeviceMode deviceMode, uint deviceAccess, ShareMode shareMode)
{
var security = new NativeMethods.SECURITY_ATTRIBUTES();
var flags = 0;
if (deviceMode == DeviceMode.Overlapped) flags = NativeMethods.FILE_FLAG_OVERLAPPED;
security.lpSecurityDescriptor = IntPtr.Zero;
security.bInheritHandle = true;
security.nLength = Marshal.SizeOf(security);
return NativeMethods.CreateFile(devicePath, deviceAccess, (int)shareMode, ref security, NativeMethods.OPEN_EXISTING, flags, 0);
}
private static void CloseDeviceIO(IntPtr handle)
{
if (Environment.OSVersion.Version.Major > 5)
{
NativeMethods.CancelIoEx(handle, IntPtr.Zero);
}
NativeMethods.CloseHandle(handle);
}
private void DeviceEventMonitorInserted()
{
if (!IsOpen) OpenDevice(_deviceReadMode, _deviceWriteMode, _deviceShareMode);
if (Inserted != null) Inserted();
}
private void DeviceEventMonitorRemoved()
{
if (IsOpen) CloseDevice();
if (Removed != null) Removed();
}
public void Dispose()
{
if (MonitorDeviceEvents) MonitorDeviceEvents = false;
if (IsOpen) CloseDevice();
}
}
}

+ 21
- 0
HidLibrary/HidDeviceAttributes.cs View File

@ -0,0 +1,21 @@
namespace HidLibrary
{
public class HidDeviceAttributes
{
internal HidDeviceAttributes(NativeMethods.HIDD_ATTRIBUTES attributes)
{
VendorId = attributes.VendorID;
ProductId = attributes.ProductID;
Version = attributes.VersionNumber;
VendorHexId = "0x" + attributes.VendorID.ToString("X4");
ProductHexId = "0x" + attributes.ProductID.ToString("X4");
}
public int VendorId { get; private set; }
public int ProductId { get; private set; }
public int Version { get; private set; }
public string VendorHexId { get; set; }
public string ProductHexId { get; set; }
}
}

+ 43
- 0
HidLibrary/HidDeviceCapabilities.cs View File

@ -0,0 +1,43 @@
namespace HidLibrary
{
public class HidDeviceCapabilities
{
internal HidDeviceCapabilities(NativeMethods.HIDP_CAPS capabilities)
{
Usage = capabilities.Usage;
UsagePage = capabilities.UsagePage;
InputReportByteLength = capabilities.InputReportByteLength;
OutputReportByteLength = capabilities.OutputReportByteLength;
FeatureReportByteLength = capabilities.FeatureReportByteLength;
Reserved = capabilities.Reserved;
NumberLinkCollectionNodes = capabilities.NumberLinkCollectionNodes;
NumberInputButtonCaps = capabilities.NumberInputButtonCaps;
NumberInputValueCaps = capabilities.NumberInputValueCaps;
NumberInputDataIndices = capabilities.NumberInputDataIndices;
NumberOutputButtonCaps = capabilities.NumberOutputButtonCaps;
NumberOutputValueCaps = capabilities.NumberOutputValueCaps;
NumberOutputDataIndices = capabilities.NumberOutputDataIndices;
NumberFeatureButtonCaps = capabilities.NumberFeatureButtonCaps;
NumberFeatureValueCaps = capabilities.NumberFeatureValueCaps;
NumberFeatureDataIndices = capabilities.NumberFeatureDataIndices;
}
public short Usage { get; private set; }
public short UsagePage { get; private set; }
public short InputReportByteLength { get; private set; }
public short OutputReportByteLength { get; private set; }
public short FeatureReportByteLength { get; private set; }
public short[] Reserved { get; private set; }
public short NumberLinkCollectionNodes { get; private set; }
public short NumberInputButtonCaps { get; private set; }
public short NumberInputValueCaps { get; private set; }
public short NumberInputDataIndices { get; private set; }
public short NumberOutputButtonCaps { get; private set; }
public short NumberOutputValueCaps { get; private set; }
public short NumberOutputDataIndices { get; private set; }
public short NumberFeatureButtonCaps { get; private set; }
public short NumberFeatureValueCaps { get; private set; }
public short NumberFeatureDataIndices { get; private set; }
}
}

+ 30
- 0
HidLibrary/HidDeviceData.cs View File

@ -0,0 +1,30 @@
namespace HidLibrary
{
public class HidDeviceData
{
public enum ReadStatus
{
Success = 0,
WaitTimedOut = 1,
WaitFail = 2,
NoDataRead = 3,
ReadError = 4,
NotConnected = 5
}
public HidDeviceData(ReadStatus status)
{
Data = new byte[] {};
Status = status;
}
public HidDeviceData(byte[] data, ReadStatus status)
{
Data = data;
Status = status;
}
public byte[] Data { get; private set; }
public ReadStatus Status { get; private set; }
}
}

+ 49
- 0
HidLibrary/HidDeviceEventMonitor.cs View File

@ -0,0 +1,49 @@
using System;
using System.Threading;
namespace HidLibrary
{
internal class HidDeviceEventMonitor
{
public event InsertedEventHandler Inserted;
public event RemovedEventHandler Removed;
public delegate void InsertedEventHandler();
public delegate void RemovedEventHandler();
private readonly HidDevice _device;
private bool _wasConnected;
public HidDeviceEventMonitor(HidDevice device)
{
_device = device;
}
public void Init()
{
var eventMonitor = new Action(DeviceEventMonitor);
eventMonitor.BeginInvoke(DisposeDeviceEventMonitor, eventMonitor);
}
private void DeviceEventMonitor()
{
var isConnected = _device.IsConnected;
if (isConnected != _wasConnected)
{
if (isConnected && Inserted != null) Inserted();
else if (!isConnected && Removed != null) Removed();
_wasConnected = isConnected;
}
Thread.Sleep(500);
if (_device.MonitorDeviceEvents) Init();
}
private static void DisposeDeviceEventMonitor(IAsyncResult ar)
{
((Action)ar.AsyncState).EndInvoke(ar);
}
}
}

+ 157
- 0
HidLibrary/HidDevices.cs View File

@ -0,0 +1,157 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
namespace HidLibrary
{
public class HidDevices
{
private static Guid _hidClassGuid = Guid.Empty;
public static bool IsConnected(string devicePath)
{
return EnumerateDevices().Any(x => x.Path == devicePath);
}
public static HidDevice GetDevice(string devicePath)
{
return Enumerate(devicePath).FirstOrDefault();
}
public static IEnumerable<HidDevice> Enumerate()
{
return EnumerateDevices().Select(x => new HidDevice(x.Path, x.Description));
}
public static IEnumerable<HidDevice> Enumerate(string devicePath)
{
return EnumerateDevices().Where(x => x.Path == devicePath).Select(x => new HidDevice(x.Path, x.Description));
}
public static IEnumerable<HidDevice> Enumerate(int vendorId, params int[] productIds)
{
// var all = EnumerateDevices();
return EnumerateDevices().Select(x => new HidDevice(x.Path, x.Description)).Where(x => x.Attributes.VendorId == vendorId && productIds.Contains(x.Attributes.ProductId));
}
public static IEnumerable<HidDevice> Enumerate(int vendorId, int productId, ushort UsagePage)
{
return EnumerateDevices().Select(x => new HidDevice(x.Path, x.Description)).Where(x => x.Attributes.VendorId == vendorId && productId == (ushort)x.Attributes.ProductId && (ushort)x.Capabilities.UsagePage == UsagePage);
}
public static IEnumerable<HidDevice> Enumerate(int vendorId)
{
return EnumerateDevices().Select(x => new HidDevice(x.Path, x.Description)).Where(x => x.Attributes.VendorId == vendorId);
}
internal class DeviceInfo { public string Path { get; set; } public string Description { get; set; } }
internal static IEnumerable<DeviceInfo> EnumerateDevices()
{
var devices = new List<DeviceInfo>();
var hidClass = HidClassGuid;
var deviceInfoSet = NativeMethods.SetupDiGetClassDevs(ref hidClass, null, 0, NativeMethods.DIGCF_PRESENT | NativeMethods.DIGCF_DEVICEINTERFACE);
if (deviceInfoSet.ToInt64() != NativeMethods.INVALID_HANDLE_VALUE)
{
var deviceInfoData = CreateDeviceInfoData();
var deviceIndex = 0;
while (NativeMethods.SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, ref deviceInfoData))
{
deviceIndex += 1;
var deviceInterfaceData = new NativeMethods.SP_DEVICE_INTERFACE_DATA();
deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData);
var deviceInterfaceIndex = 0;
while (NativeMethods.SetupDiEnumDeviceInterfaces(deviceInfoSet, ref deviceInfoData, ref hidClass, deviceInterfaceIndex, ref deviceInterfaceData))
{
deviceInterfaceIndex++;
var devicePath = GetDevicePath(deviceInfoSet, deviceInterfaceData);
var description = GetBusReportedDeviceDescription(deviceInfoSet, ref deviceInfoData) ??
GetDeviceDescription(deviceInfoSet, ref deviceInfoData);
devices.Add(new DeviceInfo { Path = devicePath, Description = description });
}
}
NativeMethods.SetupDiDestroyDeviceInfoList(deviceInfoSet);
}
return devices;
}
private static NativeMethods.SP_DEVINFO_DATA CreateDeviceInfoData()
{
var deviceInfoData = new NativeMethods.SP_DEVINFO_DATA();
deviceInfoData.cbSize = Marshal.SizeOf(deviceInfoData);
deviceInfoData.DevInst = 0;
deviceInfoData.ClassGuid = Guid.Empty;
deviceInfoData.Reserved = IntPtr.Zero;
return deviceInfoData;
}
private static string GetDevicePath(IntPtr deviceInfoSet, NativeMethods.SP_DEVICE_INTERFACE_DATA deviceInterfaceData)
{
var bufferSize = 0;
var interfaceDetail = new NativeMethods.SP_DEVICE_INTERFACE_DETAIL_DATA { Size = IntPtr.Size == 4 ? 4 + Marshal.SystemDefaultCharSize : 8 };
NativeMethods.SetupDiGetDeviceInterfaceDetailBuffer(deviceInfoSet, ref deviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero);
return NativeMethods.SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref deviceInterfaceData, ref interfaceDetail, bufferSize, ref bufferSize, IntPtr.Zero) ?
interfaceDetail.DevicePath : null;
}
private static Guid HidClassGuid
{
get
{
if (_hidClassGuid.Equals(Guid.Empty)) NativeMethods.HidD_GetHidGuid(ref _hidClassGuid);
return _hidClassGuid;
}
}
private static string GetDeviceDescription(IntPtr deviceInfoSet, ref NativeMethods.SP_DEVINFO_DATA devinfoData)
{
var descriptionBuffer = new byte[1024];
var requiredSize = 0;
var type = 0;
NativeMethods.SetupDiGetDeviceRegistryProperty(deviceInfoSet,
ref devinfoData,
NativeMethods.SPDRP_DEVICEDESC,
ref type,
descriptionBuffer,
descriptionBuffer.Length,
ref requiredSize);
return descriptionBuffer.ToUTF8String();
}
private static string GetBusReportedDeviceDescription(IntPtr deviceInfoSet, ref NativeMethods.SP_DEVINFO_DATA devinfoData)
{
var descriptionBuffer = new byte[1024];
if (Environment.OSVersion.Version.Major > 5)
{
ulong propertyType = 0;
var requiredSize = 0;
var _continue = NativeMethods.SetupDiGetDeviceProperty(deviceInfoSet,
ref devinfoData,
ref NativeMethods.DEVPKEY_Device_BusReportedDeviceDesc,
ref propertyType,
descriptionBuffer,
descriptionBuffer.Length,
ref requiredSize,
0);
if (_continue) return descriptionBuffer.ToUTF16String();
}
return null;
}
}
}

+ 76
- 0
HidLibrary/HidFastReadDevice.cs View File

@ -0,0 +1,76 @@
using System.Threading.Tasks;
namespace HidLibrary
{
public class HidFastReadDevice : HidDevice
{
internal HidFastReadDevice(string devicePath, string description = null)
: base(devicePath, description) { }
// FastRead assumes that the device is connected,
// which could cause stability issues if hardware is
// disconnected during a read
public HidDeviceData FastRead()
{
return FastRead(0);
}
public HidDeviceData FastRead(int timeout)
{
try
{
return ReadData(timeout);
}
catch
{
return new HidDeviceData(HidDeviceData.ReadStatus.ReadError);
}
}
public void FastRead(ReadCallback callback)
{
FastRead(callback, 0);
}
public void FastRead(ReadCallback callback, int timeout)
{
var readDelegate = new ReadDelegate(FastRead);
var asyncState = new HidAsyncState(readDelegate, callback);
readDelegate.BeginInvoke(timeout, EndRead, asyncState);
}
public async Task<HidDeviceData> FastReadAsync(int timeout = 0)
{
var readDelegate = new ReadDelegate(FastRead);
return await Task<HidDeviceData>.Factory.FromAsync(readDelegate.BeginInvoke, readDelegate.EndInvoke, timeout, null);
}
public HidReport FastReadReport()
{
return FastReadReport(0);
}
public HidReport FastReadReport(int timeout)
{
return new HidReport(Capabilities.InputReportByteLength, FastRead(timeout));
}
public void FastReadReport(ReadReportCallback callback)
{
FastReadReport(callback, 0);
}
public void FastReadReport(ReadReportCallback callback, int timeout)
{
var readReportDelegate = new ReadReportDelegate(FastReadReport);
var asyncState = new HidAsyncState(readReportDelegate, callback);
readReportDelegate.BeginInvoke(timeout, EndReadReport, asyncState);
}
public async Task<HidReport> FastReadReportAsync(int timeout = 0)
{
var readReportDelegate = new ReadReportDelegate(FastReadReport);
return await Task<HidReport>.Factory.FromAsync(readReportDelegate.BeginInvoke, readReportDelegate.EndInvoke, timeout, null);
}
}
}

+ 44
- 0
HidLibrary/HidFastReadEnumerator.cs View File

@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.Linq;
namespace HidLibrary
{
public class HidFastReadEnumerator : IHidEnumerator
{
public bool IsConnected(string devicePath)
{
return HidDevices.IsConnected(devicePath);
}
public IHidDevice GetDevice(string devicePath)
{
return Enumerate(devicePath).FirstOrDefault() as IHidDevice;
}
public IEnumerable<IHidDevice> Enumerate()
{
return HidDevices.EnumerateDevices().
Select(d => new HidFastReadDevice(d.Path, d.Description) as IHidDevice);
}
public IEnumerable<IHidDevice> Enumerate(string devicePath)
{
return HidDevices.EnumerateDevices().Where(x => x.Path == devicePath).
Select(d => new HidFastReadDevice(d.Path, d.Description) as IHidDevice);
}
public IEnumerable<IHidDevice> Enumerate(int vendorId, params int[] productIds)
{
return HidDevices.EnumerateDevices().Select(d => new HidFastReadDevice(d.Path, d.Description)).
Where(f => f.Attributes.VendorId == vendorId && productIds.Contains(f.Attributes.ProductId)).
Select(d => d as IHidDevice);
}
public IEnumerable<IHidDevice> Enumerate(int vendorId)
{
return HidDevices.EnumerateDevices().Select(d => new HidFastReadDevice(d.Path, d.Description)).
Where(f => f.Attributes.VendorId == vendorId).
Select(d => d as IHidDevice);
}
}
}

+ 71
- 0
HidLibrary/HidLibrary.csproj View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{41D547F1-D57D-4D50-9602-6EE65CA958B2}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>HidLibrary</RootNamespace>
<AssemblyName>HidLibrary</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Extensions.cs" />
<Compile Include="HidAsyncState.cs" />
<Compile Include="HidDevice.cs" />
<Compile Include="HidDeviceAttributes.cs" />
<Compile Include="HidDeviceCapabilities.cs" />
<Compile Include="HidDeviceData.cs" />
<Compile Include="HidDeviceEventMonitor.cs" />
<Compile Include="HidDevices.cs" />
<Compile Include="HidFastReadDevice.cs" />
<Compile Include="HidFastReadEnumerator.cs" />
<Compile Include="HidReport.cs" />
<Compile Include="Honeywell1902Series\Report1902.cs" />
<Compile Include="Honeywell1902Series\Scanner1902.cs" />
<Compile Include="IHidDevice.cs" />
<Compile Include="IHidEnumerator.cs" />
<Compile Include="NativeMethods.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 75
- 0
HidLibrary/HidReport.cs View File

@ -0,0 +1,75 @@
using System;
namespace HidLibrary
{
public class HidReport
{
private byte _reportId;
private byte[] _data = new byte[] {};
private readonly HidDeviceData.ReadStatus _status;
public HidReport(int reportSize)
{
Array.Resize(ref _data, reportSize - 1);
}
public HidReport(int reportSize, HidDeviceData deviceData)
{
_status = deviceData.Status;
Array.Resize(ref _data, reportSize - 1);
if ((deviceData.Data != null))
{
if (deviceData.Data.Length > 0)
{
_reportId = deviceData.Data[0];
Exists = true;
if (deviceData.Data.Length > 1)
{
var dataLength = reportSize - 1;
if (deviceData.Data.Length < reportSize - 1) dataLength = deviceData.Data.Length;
Array.Copy(deviceData.Data, 1, _data, 0, dataLength);
}
}
else Exists = false;
}
else Exists = false;
}
public bool Exists { get; private set; }
public HidDeviceData.ReadStatus ReadStatus { get { return _status; } }
public byte ReportId
{
get { return _reportId; }
set
{
_reportId = value;
Exists = true;
}
}
public byte[] Data
{
get { return _data; }
set
{
_data = value;
Exists = true;
}
}
public byte[] GetBytes()
{
byte[] data = null;
Array.Resize(ref data, _data.Length + 1);
data[0] = _reportId;
Array.Copy(_data, 0, data, 1, _data.Length);
return data;
}
}
}

+ 47
- 0
HidLibrary/Honeywell1902Series/Report1902.cs View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HidLibrary.Honeywell1902Series
{public class Report1902
{
private readonly byte[] _data;
private readonly HidDeviceData.ReadStatus _status;
public Report1902(HidReport hidReport)
{
_status = hidReport.ReadStatus;
ReportId = hidReport.ReportId;
Exists = hidReport.Exists;
if (hidReport.Data.Length > 0) Length = hidReport.Data[0];
if (hidReport.Data.Length > 1) AimSymbologyId0 = hidReport.Data[1];
if (hidReport.Data.Length > 2) AimSymbologyId1 = hidReport.Data[2];
if (hidReport.Data.Length > 3) AimSymbologyId2 = hidReport.Data[3];
if (hidReport.Data.Length > Length + 3)
{
Array.Resize(ref _data, Length);
Array.Copy(hidReport.Data, 4, _data, 0, Length);
}
if (hidReport.Data.Length > 60) HhpSymbologyId = hidReport.Data[60];
if (hidReport.Data.Length > 61) Reserved = hidReport.Data[61];
if (hidReport.Data.Length > 62) MoreData = hidReport.Data[62] == 1;
}
public HidDeviceData.ReadStatus ReadStatus { get { return _status; } }
public byte[] Data { get { return _data; } }
public bool Exists { get; private set; }
public byte ReportId { get; private set; }
public byte Length { get; private set; }
public byte AimSymbologyId0 { get; private set; }
public byte AimSymbologyId1 { get; private set; }
public byte AimSymbologyId2 { get; private set; }
public byte HhpSymbologyId { get; private set; }
public byte Reserved { get; private set; }
public bool MoreData { get; private set; }
}
}

+ 154
- 0
HidLibrary/Honeywell1902Series/Scanner1902.cs View File

@ -0,0 +1,154 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace HidLibrary.Honeywell1902Series
{
public class Scanner1902 : IDisposable
{
private const int HidReportId = 0x4;
private const int ErrorBeepMessage = 0x20;
private const int SuccessBeepMessage = 0x40;
private const int StartScanMessage = 0x4;
private const int EndScanMessage = 0x1;
public event InsertedEventHandler Inserted;
public event RemovedEventHandler Removed;
public event DataRecievedEventHandler DataRecieved;
public delegate void InsertedEventHandler();
public delegate void RemovedEventHandler();
public delegate void DataRecievedEventHandler(byte[] data);
private readonly HidDevice _scanner;
private int _isReading;
public Scanner1902(string devicePath) : this(HidDevices.GetDevice(devicePath)) { }
public Scanner1902(HidDevice hidDevice)
{
_scanner = hidDevice;
_scanner.Inserted += ScannerInserted;
_scanner.Removed += ScannerRemoved;
if (!_scanner.IsOpen) _scanner.OpenDevice();
_scanner.MonitorDeviceEvents = true;
BeginReadReport();
}
public string DevicePath { get { return _scanner.DevicePath; } }
public bool IsListening { get; private set; }
public bool IsConnected { get { return _scanner.IsConnected; } }
public static IEnumerable<Scanner1902> Enumerate(int vid, int pid)
{
return HidDevices.Enumerate(vid, pid).Select(x => new Scanner1902(x));
}
public void ErrorBeep()
{
var report = _scanner.CreateReport();
report.ReportId = HidReportId;
report.Data[0] = ErrorBeepMessage;
_scanner.WriteReport(report);
}
public void SuccessBeep()
{
var report = _scanner.CreateReport();
report.ReportId = HidReportId;
report.Data[0] = SuccessBeepMessage;
_scanner.WriteReport(report);
}
public void StartScan()
{
var report = _scanner.CreateReport();
report.ReportId = HidReportId;
report.Data[0] = StartScanMessage;
_scanner.WriteReport(report);
}
public void EndScan()
{
var report = _scanner.CreateReport();
report.ReportId = HidReportId;
report.Data[0] = EndScanMessage;
_scanner.WriteReport(report);
}
public void StartListen() { IsListening = true; }
public void StopListen() { IsListening = false; }
private void BeginReadReport()
{
if (Interlocked.CompareExchange(ref _isReading, 1, 0) == 1) return;
_scanner.ReadReport(ReadReport);
}
private void ReadReport(HidReport report)
{
var scannerReport = new Report1902(report);
var data = new byte[] { };
var currentPosition = 0;
var readRequired = false;
if (scannerReport.Length > 0 & scannerReport.ReadStatus == HidDeviceData.ReadStatus.Success)
{
do
{
if (scannerReport.MoreData && readRequired) scannerReport = new Report1902(_scanner.ReadReport());
else readRequired = true;
if (!scannerReport.Exists) continue;
Array.Resize(ref data, data.GetUpperBound(0) + scannerReport.Data.Length + 1);
Array.Copy(scannerReport.Data, 0, data, currentPosition, scannerReport.Data.Length);
currentPosition += scannerReport.Data.Length;
} while (scannerReport.MoreData && scannerReport.Exists);
if (IsListening && data.Length > 0 && DataRecieved != null) DataRecieved(data);
}
if (scannerReport.ReadStatus != HidDeviceData.ReadStatus.NotConnected) _scanner.ReadReport(ReadReport);
else _isReading = 0;
}
private void ScannerInserted()
{
BeginReadReport();
if (Inserted != null) Inserted();
}
private void ScannerRemoved()
{
if (Removed != null) Removed();
}
public void Dispose()
{
_scanner.CloseDevice();
GC.SuppressFinalize(this);
}
~Scanner1902()
{
Dispose();
}
}
}

+ 99
- 0
HidLibrary/IHidDevice.cs View File

@ -0,0 +1,99 @@
using System;
using System.Threading.Tasks;
namespace HidLibrary
{
public delegate void InsertedEventHandler();
public delegate void RemovedEventHandler();
public enum DeviceMode
{
NonOverlapped = 0,
Overlapped = 1
}
[Flags]
public enum ShareMode
{
Exclusive = 0,
ShareRead = NativeMethods.FILE_SHARE_READ,
ShareWrite = NativeMethods.FILE_SHARE_WRITE
}
public delegate void ReadCallback(HidDeviceData data);
public delegate void ReadReportCallback(HidReport report);
public delegate void WriteCallback(bool success);
public interface IHidDevice : IDisposable
{
event InsertedEventHandler Inserted;
event RemovedEventHandler Removed;
IntPtr Handle { get; }
bool IsOpen { get; }
bool IsConnected { get; }
string Description { get; }
HidDeviceCapabilities Capabilities { get; }
HidDeviceAttributes Attributes { get; }
string DevicePath { get; }
bool MonitorDeviceEvents { get; set; }
void OpenDevice();
void OpenDevice(DeviceMode readMode, DeviceMode writeMode, ShareMode shareMode);
void CloseDevice();
HidDeviceData Read();
void Read(ReadCallback callback);
void Read(ReadCallback callback, int timeout);
Task<HidDeviceData> ReadAsync(int timeout = 0);
HidDeviceData Read(int timeout);
void ReadReport(ReadReportCallback callback);
void ReadReport(ReadReportCallback callback, int timeout);
Task<HidReport> ReadReportAsync(int timeout = 0);
HidReport ReadReport(int timeout);
HidReport ReadReport();
bool ReadFeatureData(out byte[] data, byte reportId = 0);
bool ReadProduct(out byte[] data);
bool ReadManufacturer(out byte[] data);
bool ReadSerialNumber(out byte[] data);
void Write(byte[] data, WriteCallback callback);
bool Write(byte[] data);
bool Write(byte[] data, int timeout);
void Write(byte[] data, WriteCallback callback, int timeout);
Task<bool> WriteAsync(byte[] data, int timeout = 0);
void WriteReport(HidReport report, WriteCallback callback);
bool WriteReport(HidReport report);
bool WriteReport(HidReport report, int timeout);
void WriteReport(HidReport report, WriteCallback callback, int timeout);
Task<bool> WriteReportAsync(HidReport report, int timeout = 0);
HidReport CreateReport();
bool WriteFeatureData(byte[] data);
}
}

+ 57
- 0
HidLibrary/IHidEnumerator.cs View File

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace HidLibrary
{
public interface IHidEnumerator
{
bool IsConnected(string devicePath);
IHidDevice GetDevice(string devicePath);
IEnumerable<IHidDevice> Enumerate();
IEnumerable<IHidDevice> Enumerate(string devicePath);
IEnumerable<IHidDevice> Enumerate(int vendorId, params int[] productIds);
IEnumerable<IHidDevice> Enumerate(int vendorId);
}
// Instance class that wraps HidDevices
// The purpose of this is to allow consumer classes to create
// their own enumeration abstractions, either for testing or
// for comparing different implementations
public class HidEnumerator : IHidEnumerator
{
public bool IsConnected(string devicePath)
{
return HidDevices.IsConnected(devicePath);
}
public IHidDevice GetDevice(string devicePath)
{
return HidDevices.GetDevice(devicePath) as IHidDevice;
}
public IEnumerable<IHidDevice> Enumerate()
{
return HidDevices.Enumerate().
Select(d => d as IHidDevice);
}
public IEnumerable<IHidDevice> Enumerate(string devicePath)
{
return HidDevices.Enumerate(devicePath).
Select(d => d as IHidDevice);
}
public IEnumerable<IHidDevice> Enumerate(int vendorId, params int[] productIds)
{
return HidDevices.Enumerate(vendorId, productIds).
Select(d => d as IHidDevice);
}
public IEnumerable<IHidDevice> Enumerate(int vendorId)
{
return HidDevices.Enumerate(vendorId).
Select(d => d as IHidDevice);
}
}
}

+ 344
- 0
HidLibrary/NativeMethods.cs View File

@ -0,0 +1,344 @@
using System;
using System.Runtime.InteropServices;
namespace HidLibrary
{
internal static class NativeMethods
{
internal const int FILE_FLAG_OVERLAPPED = 0x40000000;
internal const short FILE_SHARE_READ = 0x1;
internal const short FILE_SHARE_WRITE = 0x2;
internal const uint GENERIC_READ = 0x80000000;
internal const uint GENERIC_WRITE = 0x40000000;
internal const int ACCESS_NONE = 0;
internal const int INVALID_HANDLE_VALUE = -1;
internal const short OPEN_EXISTING = 3;
internal const int WAIT_TIMEOUT = 0x102;
internal const uint WAIT_OBJECT_0 = 0;
internal const uint WAIT_FAILED = 0xffffffff;
internal const int WAIT_INFINITE = -1;
[StructLayout(LayoutKind.Sequential)]
internal struct OVERLAPPED
{
public int Internal;
public int InternalHigh;
public int Offset;
public int OffsetHigh;
public int hEvent;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
static internal extern bool CancelIo(IntPtr hFile);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
static internal extern bool CancelIoEx(IntPtr hFile, IntPtr lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
static internal extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
static internal extern bool CancelSynchronousIo(IntPtr hObject);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static internal extern IntPtr CreateEvent(ref SECURITY_ATTRIBUTES securityAttributes, int bManualReset, int bInitialState, string lpName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static internal extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, ref SECURITY_ATTRIBUTES lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
static internal extern bool ReadFile(IntPtr hFile, IntPtr lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, [In] ref System.Threading.NativeOverlapped lpOverlapped);
[DllImport("kernel32.dll")]
static internal extern uint WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);
[DllImport("kernel32.dll", SetLastError = true)]
static internal extern bool GetOverlappedResult(IntPtr hFile, [In] ref System.Threading.NativeOverlapped lpOverlapped, out uint lpNumberOfBytesTransferred, bool bWait);
[DllImport("kernel32.dll")]
static internal extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, [In] ref System.Threading.NativeOverlapped lpOverlapped);
internal const int DBT_DEVICEARRIVAL = 0x8000;
internal const int DBT_DEVICEREMOVECOMPLETE = 0x8004;
internal const int DBT_DEVTYP_DEVICEINTERFACE = 5;
internal const int DBT_DEVTYP_HANDLE = 6;
internal const int DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 4;
internal const int DEVICE_NOTIFY_SERVICE_HANDLE = 1;
internal const int DEVICE_NOTIFY_WINDOW_HANDLE = 0;
internal const int WM_DEVICECHANGE = 0x219;
internal const short DIGCF_PRESENT = 0x2;
internal const short DIGCF_DEVICEINTERFACE = 0x10;
internal const int DIGCF_ALLCLASSES = 0x4;
internal const int MAX_DEV_LEN = 1000;
internal const int SPDRP_ADDRESS = 0x1c;
internal const int SPDRP_BUSNUMBER = 0x15;
internal const int SPDRP_BUSTYPEGUID = 0x13;
internal const int SPDRP_CAPABILITIES = 0xf;
internal const int SPDRP_CHARACTERISTICS = 0x1b;
internal const int SPDRP_CLASS = 7;
internal const int SPDRP_CLASSGUID = 8;
internal const int SPDRP_COMPATIBLEIDS = 2;
internal const int SPDRP_CONFIGFLAGS = 0xa;
internal const int SPDRP_DEVICE_POWER_DATA = 0x1e;
internal const int SPDRP_DEVICEDESC = 0;
internal const int SPDRP_DEVTYPE = 0x19;
internal const int SPDRP_DRIVER = 9;
internal const int SPDRP_ENUMERATOR_NAME = 0x16;
internal const int SPDRP_EXCLUSIVE = 0x1a;
internal const int SPDRP_FRIENDLYNAME = 0xc;
internal const int SPDRP_HARDWAREID = 1;
internal const int SPDRP_LEGACYBUSTYPE = 0x14;
internal const int SPDRP_LOCATION_INFORMATION = 0xd;
internal const int SPDRP_LOWERFILTERS = 0x12;
internal const int SPDRP_MFG = 0xb;
internal const int SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = 0xe;
internal const int SPDRP_REMOVAL_POLICY = 0x1f;
internal const int SPDRP_REMOVAL_POLICY_HW_DEFAULT = 0x20;
internal const int SPDRP_REMOVAL_POLICY_OVERRIDE = 0x21;
internal const int SPDRP_SECURITY = 0x17;
internal const int SPDRP_SECURITY_SDS = 0x18;
internal const int SPDRP_SERVICE = 4;
internal const int SPDRP_UI_NUMBER = 0x10;
internal const int SPDRP_UI_NUMBER_DESC_FORMAT = 0x1d;
internal const int SPDRP_UPPERFILTERS = 0x11;
[StructLayout(LayoutKind.Sequential)]
internal class DEV_BROADCAST_DEVICEINTERFACE
{
internal int dbcc_size;
internal int dbcc_devicetype;
internal int dbcc_reserved;
internal Guid dbcc_classguid;
internal short dbcc_name;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal class DEV_BROADCAST_DEVICEINTERFACE_1
{
internal int dbcc_size;
internal int dbcc_devicetype;
internal int dbcc_reserved;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 16)]
internal byte[] dbcc_classguid;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
internal char[] dbcc_name;
}
[StructLayout(LayoutKind.Sequential)]
internal class DEV_BROADCAST_HANDLE
{
internal int dbch_size;
internal int dbch_devicetype;
internal int dbch_reserved;
internal int dbch_handle;
internal int dbch_hdevnotify;
}
[StructLayout(LayoutKind.Sequential)]
internal class DEV_BROADCAST_HDR
{
internal int dbch_size;
internal int dbch_devicetype;
internal int dbch_reserved;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SP_DEVICE_INTERFACE_DATA
{
internal int cbSize;
internal System.Guid InterfaceClassGuid;
internal int Flags;
internal IntPtr Reserved;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SP_DEVINFO_DATA
{
internal int cbSize;
internal Guid ClassGuid;
internal int DevInst;
internal IntPtr Reserved;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
internal int Size;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
internal string DevicePath;
}
[StructLayout(LayoutKind.Sequential)]
internal struct DEVPROPKEY
{
public Guid fmtid;
public ulong pid;
}
internal static DEVPROPKEY DEVPKEY_Device_BusReportedDeviceDesc =
new DEVPROPKEY { fmtid = new Guid(0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2), pid = 4 };
[DllImport("setupapi.dll", EntryPoint = "SetupDiGetDeviceRegistryProperty")]
public static extern bool SetupDiGetDeviceRegistryProperty(IntPtr deviceInfoSet, ref SP_DEVINFO_DATA deviceInfoData, int propertyVal, ref int propertyRegDataType, byte[] propertyBuffer, int propertyBufferSize, ref int requiredSize);
[DllImport("setupapi.dll", EntryPoint = "SetupDiGetDevicePropertyW", SetLastError = true)]
public static extern bool SetupDiGetDeviceProperty(IntPtr deviceInfo, ref SP_DEVINFO_DATA deviceInfoData, ref DEVPROPKEY propkey, ref ulong propertyDataType, byte[] propertyBuffer, int propertyBufferSize, ref int requiredSize, uint flags);
[DllImport("setupapi.dll")]
static internal extern bool SetupDiEnumDeviceInfo(IntPtr deviceInfoSet, int memberIndex, ref SP_DEVINFO_DATA deviceInfoData);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static internal extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, IntPtr notificationFilter, Int32 flags);
[DllImport("setupapi.dll")]
internal static extern int SetupDiCreateDeviceInfoList(ref Guid classGuid, int hwndParent);
[DllImport("setupapi.dll")]
static internal extern int SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet);
[DllImport("setupapi.dll")]
static internal extern bool SetupDiEnumDeviceInterfaces(IntPtr deviceInfoSet, ref SP_DEVINFO_DATA deviceInfoData, ref Guid interfaceClassGuid, int memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
static internal extern IntPtr SetupDiGetClassDevs(ref System.Guid classGuid, string enumerator, int hwndParent, int flags);
[DllImport("setupapi.dll", CharSet = CharSet.Auto, EntryPoint = "SetupDiGetDeviceInterfaceDetail")]
static internal extern bool SetupDiGetDeviceInterfaceDetailBuffer(IntPtr deviceInfoSet, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, IntPtr deviceInterfaceDetailData, int deviceInterfaceDetailDataSize, ref int requiredSize, IntPtr deviceInfoData);
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
static internal extern bool SetupDiGetDeviceInterfaceDetail(IntPtr deviceInfoSet, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData, int deviceInterfaceDetailDataSize, ref int requiredSize, IntPtr deviceInfoData);
[DllImport("user32.dll")]
static internal extern bool UnregisterDeviceNotification(IntPtr handle);
internal const short HIDP_INPUT = 0;
internal const short HIDP_OUTPUT = 1;
internal const short HIDP_FEATURE = 2;
[StructLayout(LayoutKind.Sequential)]
internal struct HIDD_ATTRIBUTES
{
internal int Size;
internal ushort VendorID;
internal ushort ProductID;
internal short VersionNumber;
}
[StructLayout(LayoutKind.Sequential)]
internal struct HIDP_CAPS
{
internal short Usage;
internal short UsagePage;
internal short InputReportByteLength;
internal short OutputReportByteLength;
internal short FeatureReportByteLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
internal short[] Reserved;
internal short NumberLinkCollectionNodes;
internal short NumberInputButtonCaps;
internal short NumberInputValueCaps;
internal short NumberInputDataIndices;
internal short NumberOutputButtonCaps;
internal short NumberOutputValueCaps;
internal short NumberOutputDataIndices;
internal short NumberFeatureButtonCaps;
internal short NumberFeatureValueCaps;
internal short NumberFeatureDataIndices;
}
[StructLayout(LayoutKind.Sequential)]
internal struct HIDP_VALUE_CAPS
{
internal short UsagePage;
internal byte ReportID;
internal int IsAlias;
internal short BitField;
internal short LinkCollection;
internal short LinkUsage;
internal short LinkUsagePage;
internal int IsRange;
internal int IsStringRange;
internal int IsDesignatorRange;
internal int IsAbsolute;
internal int HasNull;
internal byte Reserved;
internal short BitSize;
internal short ReportCount;
internal short Reserved2;
internal short Reserved3;
internal short Reserved4;
internal short Reserved5;
internal short Reserved6;
internal int LogicalMin;
internal int LogicalMax;
internal int PhysicalMin;
internal int PhysicalMax;
internal short UsageMin;
internal short UsageMax;
internal short StringMin;
internal short StringMax;
internal short DesignatorMin;
internal short DesignatorMax;
internal short DataIndexMin;
internal short DataIndexMax;
}
[DllImport("hid.dll")]
static internal extern bool HidD_FlushQueue(IntPtr hidDeviceObject);
[DllImport("hid.dll")]
static internal extern bool HidD_GetAttributes(IntPtr hidDeviceObject, ref HIDD_ATTRIBUTES attributes);
[DllImport("hid.dll")]
static internal extern bool HidD_GetFeature(IntPtr hidDeviceObject, byte[] lpReportBuffer, int reportBufferLength);
[DllImport("hid.dll")]
static internal extern bool HidD_GetInputReport(IntPtr hidDeviceObject, byte[] lpReportBuffer, int reportBufferLength);
[DllImport("hid.dll")]
static internal extern void HidD_GetHidGuid(ref Guid hidGuid);
[DllImport("hid.dll")]
static internal extern bool HidD_GetNumInputBuffers(IntPtr hidDeviceObject, ref int numberBuffers);
[DllImport("hid.dll")]
static internal extern bool HidD_GetPreparsedData(IntPtr hidDeviceObject, ref IntPtr preparsedData);
[DllImport("hid.dll")]
static internal extern bool HidD_FreePreparsedData(IntPtr preparsedData);
[DllImport("hid.dll")]
static internal extern bool HidD_SetFeature(IntPtr hidDeviceObject, byte[] lpReportBuffer, int reportBufferLength);
[DllImport("hid.dll")]
static internal extern bool HidD_SetNumInputBuffers(IntPtr hidDeviceObject, int numberBuffers);
[DllImport("hid.dll")]
static internal extern bool HidD_SetOutputReport(IntPtr hidDeviceObject, byte[] lpReportBuffer, int reportBufferLength);
[DllImport("hid.dll")]
static internal extern int HidP_GetCaps(IntPtr preparsedData, ref HIDP_CAPS capabilities);
[DllImport("hid.dll")]
static internal extern int HidP_GetValueCaps(short reportType, ref byte valueCaps, ref short valueCapsLength, IntPtr preparsedData);
[DllImport("hid.dll", CharSet = CharSet.Unicode)]
internal static extern bool HidD_GetProductString(IntPtr hidDeviceObject, ref byte lpReportBuffer, int ReportBufferLength);
[DllImport("hid.dll", CharSet = CharSet.Unicode)]
internal static extern bool HidD_GetManufacturerString(IntPtr hidDeviceObject, ref byte lpReportBuffer, int ReportBufferLength);
[DllImport("hid.dll", CharSet = CharSet.Unicode)]
internal static extern bool HidD_GetSerialNumberString(IntPtr hidDeviceObject, ref byte lpReportBuffer, int reportBufferLength);
}
}

+ 36
- 0
HidLibrary/Properties/AssemblyInfo.cs View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的常规信息通过以下
// 特性集控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("HidLibrary")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("HidLibrary")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 使此程序集中的类型
// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
// 则将该类型上的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("72aa9d31-9202-4f22-907e-3894735c9f06")]
// 程序集的版本信息由下面四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

+ 12
- 0
WinFormControl.sln View File

@ -7,6 +7,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinFormControl", "WinFormControl\WinFormControl.csproj", "{5F1AC749-68DB-43E2-8895-886ECC04D7DA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfTest", "WpfTest\WpfTest.csproj", "{C9032639-3618-4F11-B6A5-54B28A5AAAC4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HidLibrary", "HidLibrary\HidLibrary.csproj", "{41D547F1-D57D-4D50-9602-6EE65CA958B2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -21,6 +25,14 @@ Global
{5F1AC749-68DB-43E2-8895-886ECC04D7DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F1AC749-68DB-43E2-8895-886ECC04D7DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F1AC749-68DB-43E2-8895-886ECC04D7DA}.Release|Any CPU.Build.0 = Release|Any CPU
{C9032639-3618-4F11-B6A5-54B28A5AAAC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C9032639-3618-4F11-B6A5-54B28A5AAAC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C9032639-3618-4F11-B6A5-54B28A5AAAC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C9032639-3618-4F11-B6A5-54B28A5AAAC4}.Release|Any CPU.Build.0 = Release|Any CPU
{41D547F1-D57D-4D50-9602-6EE65CA958B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{41D547F1-D57D-4D50-9602-6EE65CA958B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41D547F1-D57D-4D50-9602-6EE65CA958B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{41D547F1-D57D-4D50-9602-6EE65CA958B2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE


+ 2
- 1
WinFormControl/UScanPanel.cs View File

@ -70,7 +70,8 @@ namespace WinFormControl
}
else
{
reading = true;
if (!reading)
reading = true;
e.Handled = true;
_scarText += e.KeyChar.ToString();
}


Loading…
Cancel
Save