c# USB通信


首先,通信流程我們先擼一邊,打開USB設備-》發送數據庫-》接受數據-》關閉USB設備

根據USB規范的規定,所有的USB設備都有供應商ID(VID)和產品識別碼(PID),主機通過不同的VID和PID來區別不同的設備。

我們需要知道設備的VID和PID才能定位到我們需要打開的USB設備,那么我們怎么知道USB設備的VID和PID參數呢?

方法一:電腦上查看

 

方法二,代碼查看

大家可以自己百度下,很多文章都有寫。。。。。c# 查看所有USB信息

 

知道設備的VID和HID后,剩下的就好操作了。二話不說,直接上代碼。

注意:很重要

1:大家可以網上查看其它文章,有很多USB-HID通信文章,大家可以參考和借鑒,但是實際使用過程中需要注意的是人家的文章是用於HID的設備,如果你設備不是HID的那么就用不了。

那么怎么查自己的設備是什么類型的呢?windows是通過設備接口類的GUID來區分的

常用設備接口類GUID,大家可以自己查看自己的設備是什么類別的,比如

HID: "{4D1E55B2-F16F-11CF-88CB-001111000030}";
USB_DEVICE: "{A5DCBF10-6530-11D2-901F-00C04FB951ED}";
COMPORT: "{86E0D1E0-8089-11D0-9CE4-08003E301F73}";

我們需要根據設備接口類的GUID,獲取對應的設備列表,再通過VID和GUID去設備列表中匹配對應的設備,獲取設備的路徑,通過路徑打開設備進行通信。具體的自己分析代碼

using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace TPCL.USB
{
class UsbDevice
{
#region MyRegion
private FileStream DeviceIo = null; //異步IO流
private bool is_open = false;
private IntPtr device = new IntPtr(-1);

private const int MAX_USB_DEVICES = 64;
private static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
//常用設備接口類GUID
private const string HidGuid = "{4D1E55B2-F16F-11CF-88CB-001111000030}";
private const string UsbDevGuid = "{A5DCBF10-6530-11D2-901F-00C04FB951ED}";
private const string UsbComPort = "{86E0D1E0-8089-11D0-9CE4-08003E301F73}";

public static void GetAllUsbDevice(ref List<string> UsbDeviceList)
{
UsbDeviceList.Clear();
Guid guid = Guid.Parse(UsbDevGuid);
IntPtr deviceInfoSet = SetupDiGetClassDevs(ref guid, 0, IntPtr.Zero, DIGCF.DIGCF_PRESENT | DIGCF.DIGCF_DEVICEINTERFACE);
if (deviceInfoSet != IntPtr.Zero)
{
SP_DEVICE_INTERFACE_DATA interfaceInfo = new SP_DEVICE_INTERFACE_DATA();
interfaceInfo.cbSize = Marshal.SizeOf(interfaceInfo);
for (uint index = 0; index < 64; index++)
{
if (SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref guid, index, ref interfaceInfo))
{
// 取得接口詳細信息:第一次讀取錯誤,但可以取得信息緩沖區的大小
int buffsize = 0;
SetupDiGetDeviceInterfaceDetail(deviceInfoSet, 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));
if (IntPtr.Size == 8)
detail.cbSize = 8; // for 64 bit operating systems
else
detail.cbSize = 4 + Marshal.SystemDefaultCharSize; // for 32 bit operating systems
Marshal.StructureToPtr(detail, pDetail, false);
if (SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref interfaceInfo, pDetail, buffsize, ref buffsize, null))
{
UsbDeviceList.Add(Marshal.PtrToStringAuto((IntPtr)((int)pDetail + 4)));
}
//
Marshal.FreeHGlobal(pDetail);
}
}
}
SetupDiDestroyDeviceInfoList(deviceInfoSet);
}

public int OpenUsbDevice(UInt16 vID, UInt16 pID)
{
List<string> deviceList = new List<string>();
GetAllUsbDevice(ref deviceList);
if (deviceList.Count == 0)
return 0;

string VID = string.Format("{0:X4}", vID);
string PID = string.Format("{0:X4}", pID);

foreach (string item in deviceList)
{
if (item.ToLower().Contains(VID.ToLower()) && item.ToLower().Contains(PID.ToLower())) //指定設備
{
Debug.WriteLine(item);
if (is_open == false)
{
device = CreateFile(item, DESIREDACCESS.GENERIC_READ | DESIREDACCESS.GENERIC_WRITE,
0, 0, CREATIONDISPOSITION.OPEN_EXISTING, 0x40000000, 0);

if (device != INVALID_HANDLE_VALUE)
{
Debug.WriteLine("open");
DeviceIo = new FileStream(new SafeFileHandle(device, false), FileAccess.ReadWrite,40,true);
//DeviceIo = new FileStream(new SafeFileHandle(device, false), FileAccess.ReadWrite);
this.is_open = true;
return 1;
}
CloseHandle(device);
}
}
}
return 0;
}

public void CloseDevice()
{
if (is_open == true)
{
is_open = false;
DeviceIo.Close();
CloseHandle(device);
}
}

public void Send(string dataString)
{
if (DeviceIo == null)
{
Debug.WriteLine("USB Device not open");
return;
}
byte[] data = Encoding.GetEncoding("GBK").GetBytes(dataString); //打印機支持GBK中文
// byte[] data = System.Text.Encoding.ASCII.GetBytes(dataString);
DeviceIo.Write(data, 0, data.Length);
}

public void Read()
{
//DeviceIo.Read
}

public bool GetDeviceState()
{
return is_open;
}

#endregion

#region Win32_api
public enum DIGCF
{
DIGCF_DEFAULT = 0x00000001, //只返回與系統默認設備相關的設備。
DIGCF_PRESENT = 0x00000002, //只返回當前存在的設備。
DIGCF_ALLCLASSES = 0x00000004, //返回所有已安裝的設備。如果這個標志設置了,ClassGuid參數將被忽略
DIGCF_PROFILE = 0x00000008, //只返回當前硬件配置文件中的設備。
DIGCF_DEVICEINTERFACE = 0x00000010 //返回所有支持的設備。
}

/// <summary>
/// 接口數據定義
/// </summary>
public struct SP_DEVICE_INTERFACE_DATA
{
public int cbSize;
public Guid interfaceClassGuid;
public int flags;
public int reserved;
}
/// <summary>
/// 定義設備實例,該實例是設備信息集的成員
/// </summary>
public class SP_DEVINFO_DATA
{
public int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
public Guid classGuid = Guid.Empty; // temp
public int devInst = 0; // dumy
public int reserved = 0;
}

internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
internal int cbSize;
internal short devicePath;
}

/// <summary>
/// 獲取USB-HID設備的設備接口類GUID,即{4D1E55B2-F16F-11CF-88CB-001111000030}
/// </summary>
/// <param name="HidGuid"></param>
[DllImport("hid.dll")]
private static extern void HidD_GetHidGuid(ref Guid HidGuid);

/// <summary>
/// 獲取對應GUID的設備信息集(句柄)
/// </summary>
/// <param name="ClassGuid">設備設置類或設備接口類的guid</param>
/// <param name="Enumerator">指向以空結尾的字符串的指針,該字符串提供PNP枚舉器或PNP設備實例標識符的名稱</param>
/// <param name="HwndParent">用於用戶界面的頂級窗口的句柄</param>
/// <param name="Flags">一個變量,指定用於篩選添加到設備信息集中的設備信息元素的控制選項。</param>
/// <returns>設備信息集的句柄</returns>
[DllImport("setupapi.dll", SetLastError = true)]
private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, uint Enumerator, IntPtr HwndParent, DIGCF Flags);

/// <summary>
/// 根據句柄,枚舉設備信息集中包含的設備接口。
/// </summary>
/// <param name="deviceInfoSet"></param>
/// <param name="deviceInfoData"></param>
/// <param name="interfaceClassGuid"></param>
/// <param name="memberIndex"></param>
/// <param name="deviceInterfaceData"></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>
/// 獲取接口詳細信息,在第一次主要是讀取緩存信息,第二次獲取詳細信息(必須調用兩次)
/// </summary>
/// <param name="deviceInfoSet">指向設備信息集的指針,它包含了所要接收信息的接口。該句柄通常由SetupDiGetClassDevs函數返回。</param>
/// <param name="deviceInterfaceData">返回數據</param>
/// <param name="deviceInterfaceDetailData"></param>
/// <param name="deviceInterfaceDetailDataSize"></param>
/// <param name="requiredSize"></param>
/// <param name="deviceInfoData"></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>
/// 刪除設備信息並釋放內存。
/// </summary>
/// <param name="HIDInfoSet"></param>
/// <returns></returns>
[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern Boolean SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet);
#endregion

#region Open_Device
/// <summary>
/// 訪問權限
/// </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>
/// 如何創建
/// </summary>
static class CREATIONDISPOSITION
{
public const uint CREATE_NEW = 1;
public const uint CREATE_ALWAYS = 2;
public const uint OPEN_EXISTING = 3;
public const uint OPEN_ALWAYS = 4;
public const uint TRUNCATE_EXISTING = 5;
}

/// <summary>
///
/// </summary>
/// <param name="lpFileName">普通文件名或設備文件名</param>
/// <param name="desiredAccess">訪問模式(寫/讀) GENERIC_READ、GENERIC_WRITE </param>
/// <param name="shareMode">共享模式</param>
/// <param name="securityAttributes">指向安全屬性的指針</param>
/// <param name="creationDisposition">如何創建</param>
/// <param name="flagsAndAttributes">文件屬性</param>
/// <param name="templateFile">用於復制文件句柄</param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateFile(string lpFileName, uint desiredAccess, uint shareMode, uint securityAttributes, uint creationDisposition, uint flagsAndAttributes, uint templateFile);

/// <summary>
/// 關閉
/// </summary>
/// <param name="hObject">Handle to an open object</param>
/// <returns></returns>
[DllImport("kernel32.dll")]
private static extern int CloseHandle(IntPtr hObject);

#endregion
}
}

————————————————
版權聲明:本文為CSDN博主「毛小民°」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/xiejie0226/article/details/102582053


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM