使用C#使用Windows的HID通信
本文转载于:https://blog.csdn.net/u010875635/article/details/73321066
Windows使用HID通信相对比较简单,HID都是通过PID、VID信息来查找连接的,相比于串口,几乎无变化,连接无需人工选择,十分方便,也不需要驱动。
下面上实例,PID为0x003f,VID为0x04D8,支持发送接收数据显示到UI,使用C#来编写,调用的是windows api(create file、read file、write file)。
本实例将HID接口分成3层,支持自动连接、断开状态通知,异步收发数据,单个数据包大小为64bytes(因为从设备的数据包设定为64bytes,保持一致)。
接口分为两层,第一层将create file、read file、write file封装,第二层再封装自动连接、异步收发。
Hid.cs -> HIDInterface.cs -> 应用
注意,这里所有数据都是64bytes,但是有用数据并非这么多,所以设定为第一个数据为后面数据实际长度,若需要修改定义,请在HIDInterface.cs的Send与HidDataReceived函数中修改处理方法即可。
Hid.cs
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.IO;
using Microsoft.Win32.SafeHandles;
using System.Windows; namespace HID_SIMPLE.HID
{
public class report : EventArgs
{
public readonly byte reportID;
public readonly byte[] reportBuff;
public report(byte id, byte[] arrayBuff)
{
reportID = id;
reportBuff = arrayBuff;
}
}
public class Hid : object
{
private IntPtr INVALID_HANDLE_VALUE = new IntPtr(-);
private const int MAX_USB_DEVICES = ;
private bool deviceOpened = false;
private FileStream hidDevice = null;
private IntPtr hHubDevice; int outputReportLength;//输出报告长度,包刮一个字节的报告ID
public int OutputReportLength { get { return outputReportLength; } }
int inputReportLength;//输入报告长度,包刮一个字节的报告ID
public int InputReportLength { get { return inputReportLength; } } /// <summary>
/// 打开指定信息的设备
/// </summary>
/// <param name="vID">设备的vID</param>
/// <param name="pID">设备的pID</param>
/// <param name="serial">设备的serial</param>
/// <returns></returns>
public HID_RETURN OpenDevice(UInt16 vID, UInt16 pID, string serial)
{
if (deviceOpened == false)
{
//获取连接的HID列表
List<string> deviceList = new List<string>();
GetHidDeviceList(ref deviceList);
if (deviceList.Count == )
return HID_RETURN.NO_DEVICE_CONECTED;
for (int i = ; i < deviceList.Count; i++)
{
IntPtr device = CreateFile(deviceList[i],
DESIREDACCESS.GENERIC_READ | DESIREDACCESS.GENERIC_WRITE,
,
,
CREATIONDISPOSITION.OPEN_EXISTING,
FLAGSANDATTRIBUTES.FILE_FLAG_OVERLAPPED,
);
if (device != INVALID_HANDLE_VALUE)
{
HIDD_ATTRIBUTES attributes;
IntPtr serialBuff = Marshal.AllocHGlobal();
HidD_GetAttributes(device, out attributes);
HidD_GetSerialNumberString(device, serialBuff, );
string deviceStr = Marshal.PtrToStringAuto(serialBuff);
Marshal.FreeHGlobal(serialBuff);
if (attributes.VendorID == vID && attributes.ProductID == pID && deviceStr.Contains(serial))
{
IntPtr preparseData;
HIDP_CAPS caps;
HidD_GetPreparsedData(device, out preparseData);
HidP_GetCaps(preparseData, out caps);
HidD_FreePreparsedData(preparseData);
outputReportLength = caps.OutputReportByteLength;
inputReportLength = caps.InputReportByteLength; hidDevice = new FileStream(new SafeFileHandle(device, false), FileAccess.ReadWrite, inputReportLength, true);
deviceOpened = true;
BeginAsyncRead(); hHubDevice = device;
return HID_RETURN.SUCCESS;
}
}
}
return HID_RETURN.DEVICE_NOT_FIND;
}
else
return HID_RETURN.DEVICE_OPENED;
} /// <summary>
/// 关闭打开的设备
/// </summary>
public void CloseDevice()
{
if (deviceOpened == true)
{
deviceOpened = false;
hidDevice.Close();
}
} /// <summary>
/// 开始一次异步读
/// </summary>
private void BeginAsyncRead()
{
byte[] inputBuff = new byte[InputReportLength];
hidDevice.BeginRead(inputBuff, , InputReportLength, new AsyncCallback(ReadCompleted), inputBuff);
} /// <summary>
/// 异步读取结束,发出有数据到达事件
/// </summary>
/// <param name="iResult">这里是输入报告的数组</param>
private void ReadCompleted(IAsyncResult iResult)
{
byte[] readBuff = (byte[])(iResult.AsyncState);
try
{
hidDevice.EndRead(iResult);//读取结束,如果读取错误就会产生一个异常
byte[] reportData = new byte[readBuff.Length - ];
for (int i = ; i < readBuff.Length; i++)
reportData[i - ] = readBuff[i];
report e = new report(readBuff[], reportData);
OnDataReceived(e); //发出数据到达消息
if (!deviceOpened) return;
BeginAsyncRead();//启动下一次读操作
}
catch //读写错误,设备已经被移除
{
//MyConsole.WriteLine("设备无法连接,请重新插入设备");
EventArgs ex = new EventArgs();
OnDeviceRemoved(ex);//发出设备移除消息
CloseDevice(); }
} public delegate void DelegateDataReceived(object sender, report e);
//public event EventHandler<ConnectEventArg> StatusConnected; public DelegateDataReceived DataReceived; /// <summary>
/// 事件:数据到达,处理此事件以接收输入数据
/// </summary> protected virtual void OnDataReceived(report e)
{
if (DataReceived != null) DataReceived(this, e);
} /// <summary>
/// 事件:设备断开
/// </summary> public delegate void DelegateStatusConnected(object sender, EventArgs e);
public DelegateStatusConnected DeviceRemoved;
protected virtual void OnDeviceRemoved(EventArgs e)
{
if (DeviceRemoved != null) DeviceRemoved(this,e);
} /// <summary>
///
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
public HID_RETURN Write(report r)
{
if (deviceOpened)
{
try
{
byte[] buffer = new byte[outputReportLength];
buffer[] = r.reportID;
int maxBufferLength = ;
if (r.reportBuff.Length < outputReportLength - )
maxBufferLength = r.reportBuff.Length;
else
maxBufferLength = outputReportLength - ; for (int i = ; i < maxBufferLength; i++)
buffer[i + ] = r.reportBuff[i];
hidDevice.Write(buffer, , OutputReportLength);
return HID_RETURN.SUCCESS;
}
catch
{
EventArgs ex = new EventArgs();
OnDeviceRemoved(ex);//发出设备移除消息
CloseDevice();
return HID_RETURN.NO_DEVICE_CONECTED;
}
}
return HID_RETURN.WRITE_FAILD;
} /// <summary>
/// 获取所有连接的hid的设备路径
/// </summary>
/// <returns>包含每个设备路径的字符串数组</returns>
public static void GetHidDeviceList(ref List<string> deviceList)
{
Guid hUSB = Guid.Empty;
uint index = ; deviceList.Clear();
// 取得hid设备全局id
HidD_GetHidGuid(ref hUSB);
//取得一个包含所有HID接口信息集合的句柄
IntPtr hidInfoSet = SetupDiGetClassDevs(ref hUSB, , IntPtr.Zero, DIGCF.DIGCF_PRESENT | DIGCF.DIGCF_DEVICEINTERFACE);
if (hidInfoSet != IntPtr.Zero)
{
SP_DEVICE_INTERFACE_DATA interfaceInfo = new SP_DEVICE_INTERFACE_DATA();
interfaceInfo.cbSize = Marshal.SizeOf(interfaceInfo);
//查询集合中每一个接口
for (index = ; index < MAX_USB_DEVICES; index++)
{
//得到第index个接口信息
if (SetupDiEnumDeviceInterfaces(hidInfoSet, IntPtr.Zero, ref hUSB, index, ref interfaceInfo))
{
int buffsize = ;
// 取得接口详细信息:第一次读取错误,但可以取得信息缓冲区的大小
SetupDiGetDeviceInterfaceDetail(hidInfoSet, ref interfaceInfo, IntPtr.Zero, buffsize, ref buffsize, null);
//构建接收缓冲
IntPtr pDetail = Marshal.AllocHGlobal(buffsize);
SP_DEVICE_INTERFACE_DETAIL_DATA detail = new SP_DEVICE_INTERFACE_DETAIL_DATA();
detail.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DETAIL_DATA));
Marshal.StructureToPtr(detail, pDetail, false);
if (SetupDiGetDeviceInterfaceDetail(hidInfoSet, ref interfaceInfo, pDetail, buffsize, ref buffsize, null))
{
deviceList.Add(Marshal.PtrToStringAuto((IntPtr)((int)pDetail + )));
}
Marshal.FreeHGlobal(pDetail);
}
}
}
SetupDiDestroyDeviceInfoList(hidInfoSet);
//return deviceList.ToArray();
} #region<连接USB返回的结构体信息>
/// <summary>
/// 连接USB返回的结构体信息
/// </summary>
public enum HID_RETURN
{
SUCCESS = ,
NO_DEVICE_CONECTED,
DEVICE_NOT_FIND,
DEVICE_OPENED,
WRITE_FAILD,
READ_FAILD }
#endregion // 以下是调用windows的API的函数
/// <summary>
/// The HidD_GetHidGuid routine returns the device interface GUID for HIDClass devices.
/// </summary>
/// <param name="HidGuid">a caller-allocated GUID buffer that the routine uses to return the device interface GUID for HIDClass devices.</param>
[DllImport("hid.dll")]
private static extern void HidD_GetHidGuid(ref Guid HidGuid); /// <summary>
/// The SetupDiGetClassDevs function returns a handle to a device information set that contains requested device information elements for a local machine.
/// </summary>
/// <param name="ClassGuid">GUID for a device setup class or a device interface class. </param>
/// <param name="Enumerator">A pointer to a NULL-terminated string that supplies the name of a PnP enumerator or a PnP device instance identifier. </param>
/// <param name="HwndParent">A handle of the top-level window to be used for a user interface</param>
/// <param name="Flags">A variable that specifies control options that filter the device information elements that are added to the device information set. </param>
/// <returns>a handle to a device information set </returns>
[DllImport("setupapi.dll", SetLastError = true)]
private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, uint Enumerator, IntPtr HwndParent, DIGCF Flags); /// <summary>
/// The SetupDiDestroyDeviceInfoList function deletes a device information set and frees all associated memory.
/// </summary>
/// <param name="DeviceInfoSet">A handle to the device information set to delete.</param>
/// <returns>returns TRUE if it is successful. Otherwise, it returns FALSE </returns>
[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern Boolean SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet); /// <summary>
/// The SetupDiEnumDeviceInterfaces function enumerates the device interfaces that are contained in a device information set.
/// </summary>
/// <param name="deviceInfoSet">A pointer to a device information set that contains the device interfaces for which to return information</param>
/// <param name="deviceInfoData">A pointer to an SP_DEVINFO_DATA structure that specifies a device information element in DeviceInfoSet</param>
/// <param name="interfaceClassGuid">a GUID that specifies the device interface class for the requested interface</param>
/// <param name="memberIndex">A zero-based index into the list of interfaces in the device information set</param>
/// <param name="deviceInterfaceData">a caller-allocated buffer that contains a completed SP_DEVICE_INTERFACE_DATA structure that identifies an interface that meets the search parameters</param>
/// <returns></returns>
[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr deviceInfoSet, IntPtr deviceInfoData, ref Guid interfaceClassGuid, UInt32 memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData); /// <summary>
/// The SetupDiGetDeviceInterfaceDetail function returns details about a device interface.
/// </summary>
/// <param name="deviceInfoSet">A pointer to the device information set that contains the interface for which to retrieve details</param>
/// <param name="deviceInterfaceData">A pointer to an SP_DEVICE_INTERFACE_DATA structure that specifies the interface in DeviceInfoSet for which to retrieve details</param>
/// <param name="deviceInterfaceDetailData">A pointer to an SP_DEVICE_INTERFACE_DETAIL_DATA structure to receive information about the specified interface</param>
/// <param name="deviceInterfaceDetailDataSize">The size of the DeviceInterfaceDetailData buffer</param>
/// <param name="requiredSize">A pointer to a variable that receives the required size of the DeviceInterfaceDetailData buffer</param>
/// <param name="deviceInfoData">A pointer buffer to receive information about the device that supports the requested interface</param>
/// <returns></returns>
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr deviceInfoSet, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, IntPtr deviceInterfaceDetailData, int deviceInterfaceDetailDataSize, ref int requiredSize, SP_DEVINFO_DATA deviceInfoData); /// <summary>
/// The HidD_GetAttributes routine returns the attributes of a specified top-level collection.
/// </summary>
/// <param name="HidDeviceObject">Specifies an open handle to a top-level collection</param>
/// <param name="Attributes">a caller-allocated HIDD_ATTRIBUTES structure that returns the attributes of the collection specified by HidDeviceObject</param>
/// <returns></returns>
[DllImport("hid.dll")]
private static extern Boolean HidD_GetAttributes(IntPtr hidDeviceObject, out HIDD_ATTRIBUTES attributes);
/// <summary>
/// The HidD_GetSerialNumberString routine returns the embedded string of a top-level collection that identifies the serial number of the collection's physical device.
/// </summary>
/// <param name="HidDeviceObject">Specifies an open handle to a top-level collection</param>
/// <param name="Buffer">a caller-allocated buffer that the routine uses to return the requested serial number string</param>
/// <param name="BufferLength">Specifies the length, in bytes, of a caller-allocated buffer provided at Buffer</param>
/// <returns></returns>
[DllImport("hid.dll")]
private static extern Boolean HidD_GetSerialNumberString(IntPtr hidDeviceObject, IntPtr buffer, int bufferLength); /// <summary>
/// The HidD_GetPreparsedData routine returns a top-level collection's preparsed data.
/// </summary>
/// <param name="hidDeviceObject">Specifies an open handle to a top-level collection. </param>
/// <param name="PreparsedData">Pointer to the address of a routine-allocated buffer that contains a collection's preparsed data in a _HIDP_PREPARSED_DATA structure.</param>
/// <returns>HidD_GetPreparsedData returns TRUE if it succeeds; otherwise, it returns FALSE.</returns>
[DllImport("hid.dll")]
private static extern Boolean HidD_GetPreparsedData(IntPtr hidDeviceObject, out IntPtr PreparsedData); [DllImport("hid.dll")]
private static extern Boolean HidD_FreePreparsedData(IntPtr PreparsedData); [DllImport("hid.dll")]
private static extern uint HidP_GetCaps(IntPtr PreparsedData, out HIDP_CAPS Capabilities); /// <summary>
/// This function creates, opens, or truncates a file, COM port, device, service, or console.
/// </summary>
/// <param name="fileName">a null-terminated string that specifies the name of the object</param>
/// <param name="desiredAccess">Type of access to the object</param>
/// <param name="shareMode">Share mode for object</param>
/// <param name="securityAttributes">Ignored; set to NULL</param>
/// <param name="creationDisposition">Action to take on files that exist, and which action to take when files do not exist</param>
/// <param name="flagsAndAttributes">File attributes and flags for the file</param>
/// <param name="templateFile">Ignored</param>
/// <returns>An open handle to the specified file indicates success</returns>
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateFile(string fileName, uint desiredAccess, uint shareMode, uint securityAttributes, uint creationDisposition, uint flagsAndAttributes, uint templateFile); /// <summary>
/// This function closes an open object handle.
/// </summary>
/// <param name="hObject">Handle to an open object</param>
/// <returns></returns>
[DllImport("kernel32.dll")]
private static extern int CloseHandle(IntPtr hObject); /// <summary>
/// This function reads data from a file, starting at the position indicated by the file pointer.
/// </summary>
/// <param name="file">Handle to the file to be read</param>
/// <param name="buffer">Pointer to the buffer that receives the data read from the file </param>
/// <param name="numberOfBytesToRead">Number of bytes to be read from the file</param>
/// <param name="numberOfBytesRead">Pointer to the number of bytes read</param>
/// <param name="lpOverlapped">Unsupported; set to NULL</param>
/// <returns></returns>
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern bool ReadFile(IntPtr file, byte[] buffer, uint numberOfBytesToRead, out uint numberOfBytesRead, IntPtr lpOverlapped); /// <summary>
/// This function writes data to a file
/// </summary>
/// <param name="file">Handle to the file to be written to</param>
/// <param name="buffer">Pointer to the buffer containing the data to write to the file</param>
/// <param name="numberOfBytesToWrite">Number of bytes to write to the file</param>
/// <param name="numberOfBytesWritten">Pointer to the number of bytes written by this function call</param>
/// <param name="lpOverlapped">Unsupported; set to NULL</param>
/// <returns></returns>
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern bool WriteFile(IntPtr file, byte[] buffer, uint numberOfBytesToWrite, out uint numberOfBytesWritten, IntPtr lpOverlapped); /// <summary>
/// Registers the device or type of device for which a window will receive notifications
/// </summary>
/// <param name="recipient">A handle to the window or service that will receive device events for the devices specified in the NotificationFilter parameter</param>
/// <param name="notificationFilter">A pointer to a block of data that specifies the type of device for which notifications should be sent</param>
/// <param name="flags">A Flags that specify the handle type</param>
/// <returns>If the function succeeds, the return value is a device notification handle</returns>
[DllImport("User32.dll", SetLastError = true)]
private static extern IntPtr RegisterDeviceNotification(IntPtr recipient, IntPtr notificationFilter, int flags); /// <summary>
/// Closes the specified device notification handle.
/// </summary>
/// <param name="handle">Device notification handle returned by the RegisterDeviceNotification function</param>
/// <returns></returns>
[DllImport("user32.dll", SetLastError = true)]
private static extern bool UnregisterDeviceNotification(IntPtr handle);
}
#region
/// <summary>
/// SP_DEVICE_INTERFACE_DATA structure defines a device interface in a device information set.
/// </summary>
public struct SP_DEVICE_INTERFACE_DATA
{
public int cbSize;
public Guid interfaceClassGuid;
public int flags;
public int reserved;
} /// <summary>
/// SP_DEVICE_INTERFACE_DETAIL_DATA structure contains the path for a device interface.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = )]
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
internal int cbSize;
internal short devicePath;
} /// <summary>
/// SP_DEVINFO_DATA structure defines a device instance that is a member of a device information set.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public class SP_DEVINFO_DATA
{
public int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
public Guid classGuid = Guid.Empty; // temp
public int devInst = ; // dumy
public int reserved = ;
}
/// <summary>
/// Flags controlling what is included in the device information set built by SetupDiGetClassDevs
/// </summary>
public enum DIGCF
{
DIGCF_DEFAULT = 0x00000001, // only valid with DIGCF_DEVICEINTERFACE
DIGCF_PRESENT = 0x00000002,
DIGCF_ALLCLASSES = 0x00000004,
DIGCF_PROFILE = 0x00000008,
DIGCF_DEVICEINTERFACE = 0x00000010
}
/// <summary>
/// The HIDD_ATTRIBUTES structure contains vendor information about a HIDClass device
/// </summary>
public struct HIDD_ATTRIBUTES
{
public int Size;
public ushort VendorID;
public ushort ProductID;
public ushort VersionNumber;
} public struct HIDP_CAPS
{
public ushort Usage;
public ushort UsagePage;
public ushort InputReportByteLength;
public ushort OutputReportByteLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = )]
public ushort[] Reserved;
public ushort NumberLinkCollectionNodes;
public ushort NumberInputButtonCaps;
public ushort NumberInputValueCaps;
public ushort NumberInputDataIndices;
public ushort NumberOutputButtonCaps;
public ushort NumberOutputValueCaps;
public ushort NumberOutputDataIndices;
public ushort NumberFeatureButtonCaps;
public ushort NumberFeatureValueCaps;
public ushort NumberFeatureDataIndices;
}
/// <summary>
/// Type of access to the object.
///</summary>
static class DESIREDACCESS
{
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const uint GENERIC_EXECUTE = 0x20000000;
public const uint GENERIC_ALL = 0x10000000;
}
/// <summary>
/// Action to take on files that exist, and which action to take when files do not exist.
/// </summary>
static class CREATIONDISPOSITION
{
public const uint CREATE_NEW = ;
public const uint CREATE_ALWAYS = ;
public const uint OPEN_EXISTING = ;
public const uint OPEN_ALWAYS = ;
public const uint TRUNCATE_EXISTING = ;
}
/// <summary>
/// File attributes and flags for the file.
/// </summary>
static class FLAGSANDATTRIBUTES
{
public const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;
public const uint FILE_FLAG_OVERLAPPED = 0x40000000;
public const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
public const uint FILE_FLAG_RANDOM_ACCESS = 0x10000000;
public const uint FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
public const uint FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
public const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
public const uint FILE_FLAG_POSIX_SEMANTICS = 0x01000000;
public const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
public const uint FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
public const uint FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000;
}
/// <summary>
/// Serves as a standard header for information related to a device event reported through the WM_DEVICECHANGE message.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct DEV_BROADCAST_HDR
{
public int dbcc_size;
public int dbcc_devicetype;
public int dbcc_reserved;
}
/// <summary>
/// Contains information about a class of devices
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DEV_BROADCAST_DEVICEINTERFACE
{
public int dbcc_size;
public int dbcc_devicetype;
public int dbcc_reserved;
public Guid dbcc_classguid;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = )]
public string dbcc_name;
}
#endregion
}
HIDInterface.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms; namespace HID_SIMPLE.HID
{
public class HIDInterface : IDisposable
{ public enum MessagesType
{
Message,
Error
} public struct ReusltString
{
public bool Result;
public string message;
} public struct HidDevice
{
public UInt16 vID;
public UInt16 pID;
public string serial;
}
HidDevice lowHidDevice = new HidDevice(); public delegate void DelegateDataReceived(object sender, byte[] data);
public DelegateDataReceived DataReceived; public delegate void DelegateStatusConnected(object sender, bool isConnect);
public DelegateStatusConnected StatusConnected; public bool bConnected = false; public Hid oSp = new Hid();
private static HIDInterface m_oInstance; public struct TagInfo
{
public string AntennaPort;
public string EPC;
} public HIDInterface()
{
m_oInstance = this;
oSp.DataReceived = HidDataReceived;
oSp.DeviceRemoved = HidDeviceRemoved;
} protected virtual void RaiseEventConnectedState(bool isConnect)
{
if (null != StatusConnected) StatusConnected(this, isConnect);
} protected virtual void RaiseEventDataReceived(byte[] buf)
{
if(null != DataReceived) DataReceived(this, buf);
} public void AutoConnect(HidDevice hidDevice)
{
lowHidDevice = hidDevice;
ContinueConnectFlag = true;
ReadWriteThread.DoWork += ReadWriteThread_DoWork;
ReadWriteThread.WorkerSupportsCancellation = true;
ReadWriteThread.RunWorkerAsync(); //Recommend performing USB read/write operations in a separate thread. Otherwise,
} public void StopAutoConnect()
{
try
{
ContinueConnectFlag = false;
Dispose();
}
catch
{ }
} ~HIDInterface()
{
Dispose();
} public bool Connect(HidDevice hidDevice)
{
ReusltString result = new ReusltString(); Hid.HID_RETURN hdrtn = oSp.OpenDevice(hidDevice.vID, hidDevice.pID, hidDevice.serial); if (hdrtn == Hid.HID_RETURN.SUCCESS)
{ bConnected = true; #region 消息通知
result.Result = true;
result.message = "Connect Success!";
RaiseEventConnectedState(result.Result);
#endregion return true;
} bConnected = false; #region 消息通知
result.Result = false;
result.message = "Device Connect Error";
RaiseEventConnectedState(result.Result); #endregion
return false;
} public bool Send(byte[] byData)
{
byte[] sendtemp = new byte[byData.Length + ];
sendtemp[] = (byte)byData.Length;
Array.Copy(byData, , sendtemp, , byData.Length); Hid.HID_RETURN hdrtn = oSp.Write(new report(, sendtemp)); if (hdrtn != Hid.HID_RETURN.SUCCESS)
{
return false;
}
return true;
} public bool Send(string strData)
{
//获得报文的编码字节
byte[] data = Encoding.Unicode.GetBytes(strData);
return Send(data);
} public void DisConnect()
{
bConnected = false; Thread.Sleep();
if (oSp != null)
{
oSp.CloseDevice();
}
} void HidDeviceRemoved(object sender, EventArgs e)
{
bConnected = false;
#region 消息通知
ReusltString result = new ReusltString();
result.Result = false;
result.message = "Device Remove";
RaiseEventConnectedState(result.Result);
#endregion
if (oSp != null)
{
oSp.CloseDevice();
} } public void HidDataReceived(object sender, report e)
{ try
{
//第一个字节为数据长度,因为Device 的HID数据固定长度为64字节,取有效数据
byte[] buf = new byte[e.reportBuff[]];
Array.Copy(e.reportBuff, , buf, , e.reportBuff[]); //推送数据
RaiseEventDataReceived(buf);
}
catch
{
#region 消息通知
ReusltString result = new ReusltString();
result.Result = false;
result.message = "Receive Error";
RaiseEventConnectedState(result.Result);
#endregion
} } public void Dispose()
{
try
{
this.DisConnect();
oSp.DataReceived -= HidDataReceived;
oSp.DeviceRemoved -= HidDeviceRemoved;
ReadWriteThread.DoWork -= ReadWriteThread_DoWork;
ReadWriteThread.CancelAsync();
ReadWriteThread.Dispose();
}
catch
{ }
} Boolean ContinueConnectFlag = true;
private BackgroundWorker ReadWriteThread = new BackgroundWorker();
private void ReadWriteThread_DoWork(object sender, DoWorkEventArgs e)
{
while (ContinueConnectFlag)
{
try
{
if (!bConnected)
{
Connect(lowHidDevice); }
Thread.Sleep();
}
catch { }
}
} }
}
调用如下:
#region parameter Define
HIDInterface hid = new HIDInterface(); struct connectStatusStruct
{
public bool preStatus;
public bool curStatus;
} connectStatusStruct connectStatus = new connectStatusStruct(); //推送连接状态信息
public delegate void isConnectedDelegate(bool isConnected);
public isConnectedDelegate isConnectedFunc; //推送接收数据信息
public delegate void PushReceiveDataDele(byte[] datas);
public PushReceiveDataDele pushReceiveData; #endregion //第一步需要初始化,传入vid、pid,并开启自动连接
public void Initial()
{ hid.StatusConnected = StatusConnected;
hid.DataReceived = DataReceived; HIDInterface.HidDevice hidDevice = new HIDInterface.HidDevice();
hidDevice.vID =0x04D8;
hidDevice.pID = 0x003F;
hidDevice.serial = "";
hid.AutoConnect(hidDevice); } //不使用则关闭
public void Close()
{
hid.StopAutoConnect();
} //发送数据
public bool SendBytes(byte[] data)
{ return hid.Send(data); } //接受到数据
public void DataReceived(object sender, byte[] e)
{
if (pushReceiveData != null)
pushReceiveData(e);
} //状态改变接收
public void StatusConnected(object sender, bool isConnect)
{
connectStatus.curStatus = isConnect;
if (connectStatus.curStatus == connectStatus.preStatus) //connect
return;
connectStatus.preStatus = connectStatus.curStatus; if(connectStatus.curStatus)
{
isConnectedFunc(true);
//ReportMessage(MessagesType.Message, "连接成功");
}
else //disconnect
{
isConnectedFunc(false);
//ReportMessage(MessagesType.Error, "无法连接");
}
}
使用C#使用Windows的HID通信的更多相关文章
- 书.Windows网络与通信程序设计
1.PDF&源码 保存到了 我的网盘fivez79513-->"PDF&源码" 目录中 “Windows网络与通信程序设计(第2版) 完整带书签PDF+源码. ...
- 小练习:用socket实现Linux和Windows之间的通信
在日常生活中,绝大部分人使用的机器通常是windows系统,可是对于研发人员,开发.编译等工作往往是建立在linux机器上.其实.在服务器方面,Linux.UNIX和WindowsServer占领了市 ...
- c++ windows与linux通信中文乱码问题解决方法
在linux中默认编码方式是UTF-8,在Windows下默认编码方式时GB2312.因此,在Windows和Linux进行通信的时候,如果没有进行转码则会出现乱码问题.因此,需要进行UTF-8和GB ...
- [Windows] Windows API 串口通信
Windows 中通过Windows API 进行串口通信主要有以下步骤: 打开串口 配置串口 读写串口 关闭串口 打开串口 关键API: CreateFile Windows 中进行设备的操作,第一 ...
- Windows线程+进程通信
一 Windows线程进程 1)定义 按照MS的定义, Windows中的进程简单地说就是一个内存中的可执行程序, 提供程序运行的各种资源. 进程拥有虚拟的地址空间, 可执行代码, 数据, 对象句柄集 ...
- 转:windows下多线程通信方法
多线程知识简介 同一进程中可以包含多个线程,由于进程中的多个线程可以共享进程中的资源,所以使同一进程中的多个线程之间通信相对比较简单. 当需要有多个线程来访问一个全局变量时,通常我们会在这个全局变量前 ...
- 实现虚拟机上面的linux系统和windows主机的通信
一:配置静态ip 1:使用startx命名切换到图形化用户界面: 2:在“开始”——“系统设置”——“网络”——eth0 将通过dchp自动获取ip改为静态绑定ip ip地址:填入你要给的ip,需要与 ...
- 驱动开发利器Microsoft Windows Driver Kit 7.1.0下载
在Windows 2000 与Windows XP 系统采用是WINDDK来开发WINDOWS驱动程序,我手头也有WINDDK,可是从Windows Vista开始之后,一般采用Microsoft W ...
- STM32 USB-HID通信移植步骤
大家可以使用压缩包中的UsbApp.exe调试本软件idVendor为:0483 idProduct为5750. 今天太晚了,明天还要上半天班,上位机软件找个时间在写一篇文章.请关注我的博客.压缩包 ...
随机推荐
- JavaSE学习笔记(6)---异常
JavaSE学习笔记(6)---异常 软件程序在运行过程中,非常可能遇到问题,我们称之为异常,英文是:Exception,意思是例外.遇到这些例外情况,或者叫异常,我们怎么让写的程序做出合理的处理 ...
- 使用faker 生成测试数据
测试数据生成 faker基础使用 from faker import Faker f=Faker(locale='zh_CN') print(f.name()) address 地址 person 人 ...
- Android_SharedPreferences实现的自动登录和记住密码
效果: 先贴一个SharedPreferences工具类: package com.example.didida_corder.ToolClass; import android.content.Co ...
- WPF实现高仿统计标题卡
飘哇~~~,在家数瓜子仁儿,闲来无事,看东看西,也找点儿,最近正在看看WPF动画,光看也是不行,需要带着目的去学习,整合知识碎片,恰巧,看到Github中一个基于Ant Designer设计风格的后台 ...
- BZOJ 3438 小M的礼物
BZOJ 3438 小M的礼物 Description 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子 有1个(就是可以种一棵作物)(用1. ...
- 532-数组中的K-diff数对
532-数组中的K-diff数对 给定一个整数数组和一个整数 k, 你需要在数组里找到不同的 k-diff 数对.这里将 k-diff 数对定义为一个整数对 (i, j), 其中 i 和 j 都是数组 ...
- Common Subsequence POJ - 1458 最长公共子序列 线性DP
#include <iostream> #include <algorithm> #include <string> #include <cstring> ...
- 打包Windowsform项目出现File 'Cognex.VisionPro3D.dll' targeting 'AMD64' is not compatible with the project's target platform 'x86'错误
错误信息: 个人理解此错误的大概意思是:打包的文件是64位的但是打包后的文件设置的是32位的,就出现冲突了. 解决方案:选择打包程序项目的属性窗口设置TargetPlatform属性为对应的值,本项目 ...
- 任务调度问题(贪心) hdu4864
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4864 The company hopes to maximize the number of the t ...
- python3练习100题——037
原题链接:http://www.runoob.com/python/python-exercise-example37.html 题目:对10个数进行排序. 程序分析:可以利用选择法,即从后9个比较过 ...