展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > C#中的USBHID设备通信全解

C#中的USBHID设备通信全解

在C#中与USBHID设备(比如键盘、鼠标、游戏手柄)打交道,本质上是一场与Windows底层API的对话。这个过程绕不开一个关键技术:P/Invoke。它就像一座桥梁,让托管在.NET环境下的C#代码能够调用那些用C语言写成的、直接与操作系统交互的非托管函数。本文将带你走通从枚举设备、建立连接到读

在C#中与USBHID设备(比如键盘、鼠标、游戏手柄)打交道,本质上是一场与Windows底层API的对话。这个过程绕不开一个关键技术:P/Invoke。它就像一座桥梁,让托管在.NET环境下的C#代码能够调用那些用C语言写成的、直接与操作系统交互的非托管函数。本文将带你走通从枚举设备、建立连接到读写数据的完整路径,并提供可直接使用的代码示例。

C#中的USBHID设备通信全解

1. USBHID概述和C#中的实现

USBHID,即人机接口设备,是USB标准中专门为交互设备定义的一类。相比老式的串口通信,它凭借即插即用、高传输速率和低错误率,成为了许多硬件交互的首选方案。

要在C#世界里驾驭USBHID设备,核心在于理解其工作原理和数据流,并熟练运用P/Invoke技术来调用Windows API。这为后续所有操作——发现设备、打开连接、收发数据——奠定了基础。

2. P/Invoke技术与Windows API调用

2.1 P/Invoke技术简介

2.1.1 P/Invoke技术的定义

简单来说,P/Invoke是.NET框架提供的一种机制,允许托管代码(如C#)安全地调用非托管代码库(如Windows系统DLL中的C函数)。这使得开发者能够利用大量成熟且功能强大的Windows API,同时也为旧有Win32应用程序的迁移和维护提供了便利。

2.1.2 P/Invoke技术的工作原理

其核心在于桥接两个世界:受公共语言运行时(CLR)管理的托管代码,和直接在操作系统层面运行的非托管代码。P/Invoke负责处理两者之间的差异,包括内存管理、数据类型转换和异常传递,让调用过程尽可能平滑。

2.2 Windows API在C#中的调用

2.2.1 Windows API的搜索与选择

动手之前,先得找到对的“工具”。你需要明确要完成什么功能,然后去查阅官方文档(如MSDN)来确定具体的API函数、它所在的DLL库、参数类型及顺序。这一步的准确性直接决定了后续代码能否成功运行。

2.2.2 在C#中声明和使用Windows API函数

找到API后,下一步就是在C#中声明它。这主要依靠 DllImport 属性。以下是一个调用系统消息框的经典示例:

using System;
using System.Runtime.InteropServices;

class Program
{
    // 使用DllImport属性指定DLL名和入口点
    [DllImport("user32.dll", SetLastError = true)]
    static extern int MessageBox(int hWnd, String text, String caption, uint type);

    static void Main()
    {
        // 调用MessageBox API
        MessageBox(0, "Hello World!", "My Message Box", 0);
    }
}

这段代码声明了位于 user32.dll 中的 MessageBox 函数,并指定了其参数和返回类型。这样,在C#中就可以像调用普通方法一样使用它了。

2.3 P/Invoke技术的深入分析

2.3.1 数据类型转换与映射

C#和C/C++的数据类型并非总是一一对应。因此,在跨平台调用时,数据类型的正确映射至关重要。P/Invoke通过 StructLayout、MarshalAs 等属性来确保结构体布局和数据类型能够被非托管代码正确识别。

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);

[StructLayout(LayoutKind.Sequential)]
struct MEMORY_BASIC_INFORMATION
{
    public IntPtr BaseAddress;
    public IntPtr AllocationBase;
    public uint AllocationProtect;
    public IntPtr RegionSize;
    public StateEnum State;
    public AllocationType Protect;
    public TypeEnum Type;
}

// 使用时
MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION();
// ...调用VirtualAllocEx获取信息...
VirtualQueryEx(hProcess, IntPtr.Zero, out mbi, (uint)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION)));

2.3.2 异常处理与资源管理

调用非托管代码时,错误可能发生在“墙的另一边”。P/Invoke提供了 Marshal.GetLastWin32Error() 方法来捕获这些错误。同时,必须谨慎管理非托管资源(如文件句柄、内存指针),通常使用 try-finally 或 using 模式来确保资源被正确释放,避免内存泄漏。

IntPtr handle = IntPtr.Zero;
try
{
    handle = CreateFile("somefile.txt", GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
    if (handle == INVALID_HANDLE_VALUE)
    {
        int errorCode = Marshal.GetLastWin32Error();
        throw new IOException("Unable to open file", errorCode);
    }
    // ...使用文件...
}
finally
{
    if (handle != IntPtr.Zero && handle != INVALID_HANDLE_VALUE)
    {
        CloseHandle(handle);
    }
}

以上示例确保了无论文件操作是否成功,句柄最终都会被安全关闭。

3. 枚举USBHID设备的步骤

3.1 USBHID设备枚举概念

3.1.1 枚举设备的重要性

枚举,简单说就是“发现并认识”设备的过程。对于USBHID设备,这是通信的第一步。主机通过枚举获取设备的供应商ID、产品ID、设备类等关键信息,没有这一步,后续的打开和读写都无从谈起。

3.1.2 枚举过程中的关键技术点

枚举过程依赖于一系列Windows API,如 SetupDiGetClassDevs、SetupDiEnumDeviceInterfaces 等。核心在于使用正确的设备接口GUID(全局唯一标识符)来定位HID设备,并妥善处理可能出现的错误,例如设备未连接或驱动异常。

3.2 枚举USBHID设备的操作步骤

3.2.1 使用Windows API枚举设备

枚举通常从获取设备信息集开始。以下代码展示了如何遍历系统中所有已连接的HID设备:

using System;
using System.Runtime.InteropServices;

class UsbHidEnumeration
{
    const int DIGCF_PRESENT = 0x2;
    const int DIGCF_DEVICEINTERFACE = 0x10;

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern IntPtr SetupDiGetClassDevs(ref Guid classGuid, IntPtr enumerator, IntPtr hwndParent, int flags);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiEnumDeviceInterfaces(IntPtr deviceInfoSet, IntPtr deviceInfoData, ref Guid interfaceClassGuid, int memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);

    static Guid HidGuid = new Guid(0x4d1e55b2, 0xf16f, 0x11cf, 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30);

    public static void EnumerateHidDevices()
    {
        IntPtr deviceInfoSet = SetupDiGetClassDevs(ref HidGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

        SP_DEVICE_INTERFACE_DATA deviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();
        deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData);

        for (int memberIndex = 0; SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref HidGuid, memberIndex, ref deviceInterfaceData); memberIndex++)
        {
            // 处理每一个找到的设备接口
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    struct SP_DEVICE_INTERFACE_DATA
    {
        public int cbSize;
        public Guid InterfaceClassGuid;
        public int Flags;
        public IntPtr Reserved;
    }
}

代码首先通过 SetupDiGetClassDevs 获取HID设备列表,然后循环调用 SetupDiEnumDeviceInterfaces 遍历每个设备接口。

3.2.2 枚举设备时的常见问题及解决方案

枚举失败通常有几个原因:驱动问题、权限不足或物理连接故障。对应的解决思路也很直接:

  • 驱动问题:确保设备驱动程序已正确安装且为最新版本。
  • 权限问题:尝试以管理员身份运行程序。
  • 连接问题:检查USB线缆和端口,尝试重新插拔或更换端口。

在代码层面,务必检查API调用的返回值,并通过 GetLastError 获取详细错误码,这是调试的关键。

if (deviceInfoSet == IntPtr.Zero)
{
    int errorCode = Marshal.GetLastWin32Error();
    throw new Exception("无法获取设备信息集。错误代码: " + errorCode);
}

4. 打开和关闭USBHID设备的方法

成功枚举到设备后,下一步就是与之建立连接(打开)并在完成后妥善断开(关闭)。

4.1 打开USBHID设备的步骤

4.1.1 设备句柄的获取

打开设备的本质是获取一个代表该设备的句柄。在Windows中,这通常通过 CreateFile 函数完成,尽管它的名字看起来像是用于文件操作。

using System;
using System.Runtime.InteropServices;

class UsbHidDevice
{
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr CreateFile(
        string lpFileName,
        uint dwDesiredAccess,
        uint dwShareMode,
        IntPtr lpSecurityAttributes,
        uint dwCreationDisposition,
        uint dwFlagsAndAttributes,
        IntPtr hTemplateFile);
    // USB设备的路径和访问权限等参数
    private static readonly string DevicePath = "\\.\HIDI001";
    private static readonly uint GenericRead = 0x80000000;

    public static IntPtr OpenDevice()
    {
        IntPtr deviceHandle = CreateFile(
            DevicePath,
            GenericRead,
            0,
            IntPtr.Zero,
            0x3, // OPEN_EXISTING
            0,
            IntPtr.Zero);
        if(deviceHandle == IntPtr.Zero || deviceHandle == new IntPtr(-1))
        {
            throw new System.ComponentModel.Win32Exception();
        }

        return deviceHandle;
    }
}

4.1.2 打开设备时的异常处理

打开操作可能因设备被占用、路径错误或权限问题而失败。使用 try-catch 块来捕获并处理这些异常是保证程序健壮性的必要措施。

try
{
    IntPtr deviceHandle = UsbHidDevice.OpenDevice();
    // 使用设备句柄进行后续操作
}
catch (System.ComponentModel.Win32Exception ex)
{
    // 处理异常情况,例如用户没有足够的权限或设备不存在
    Console.WriteLine($"Error opening device: {ex.Message}");
}

4.2 关闭USBHID设备的策略

4.2.1 设备关闭的条件和时机

一个良好的习惯是:在程序结束或不再需要设备时,立即关闭其句柄以释放系统资源。通常放在 finally 块或 Dispose 方法中执行。

// 在程序结束前关闭设备句柄
if(deviceHandle != IntPtr.Zero)
{
    CloseHandle(deviceHandle);
}

4.2.2 关闭设备前的清理工作

关闭前,应确保所有进行中的数据操作(如读写)已经完成或已被妥善取消。这可以避免数据丢失或设备状态异常。记录关闭日志也有助于后续的问题追踪。

// 示例代码,确保设备已断开所有连接
if( // 设备正在传输数据的条件判断)
{
    // 等待数据传输完成或取消传输
}

5. 发送和接收数据的机制

与设备建立连接后,核心任务就是数据交换。理解USBHID的数据包结构和通信模式是关键。

5.1 数据通信的基本概念

5.1.1 数据包的结构和格式

USBHID设备通过“报告”来传输数据,报告的结构由设备固件中的报告描述符定义。主要分为三类:

  • 输入报告:从设备流向主机,例如键盘按下的键值、鼠标移动的坐标。
  • 输出报告:从主机发送到设备,例如设置键盘背光、控制游戏手柄震动。
  • 特征报告:用于双向配置,通常用来获取或设置设备的特定属性。

5.1.2 数据传输的同步和异步方式

数据传输有两种模式:

  • 同步传输:调用会阻塞当前线程,直到数据传输完成。简单直接,但可能影响程序响应。
  • 异步传输:调用后立即返回,数据传输在后台进行。效率更高,但编程模型相对复杂。

5.2 实现数据发送和接收的策略

5.2.1 利用Windows API实现数据通信

在C#中,读写数据主要依靠 ReadFile 和 WriteFile 这两个API。以下是一个简化的类结构展示:

public class HidDevice
{
    public const int HidImports.HidGuid = 0x4d1e55b2, 0xafa6, 0x4fad, 0x9c, 0x85, 0x19, 0xb8, 0x80, 0xee, 0xca, 0x8b;

    [DllImport("hid.dll")]
    private static extern bool HidD_GetAttributes(IntPtr HidDeviceObject, out HidAttributes Attributes);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode,
        IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes,
        IntPtr hTemplateFile);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead,
        out uint lpNumberOfBytesRead, IntPtr lpOverlapped);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite,
        out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
    ...
}

5.2.2 数据传输中的错误检测与处理

ReadFile 和 WriteFile 会返回布尔值指示成功与否。失败时,应立即调用 Marshal.GetLastWin32Error() 获取错误码。常见的错误包括设备意外移除、缓冲区不足或访问被拒绝。健全的错误处理逻辑是确保应用程序稳定性的最后一道防线。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
作者最新文章
编程开发
相关文章 更多
精品专题 更多
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

PDF教程

正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

IOS软件

正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

AI

正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

Mac软件 更多
WPS Office macOS版
WPS Office macOS版

WPS Office是一款面向macOS用户的综合办公套件,将文字处理、电子表格、演示文稿、PDF工具、模板与云协作整合在同一应用中。它兼容常见Microsoft Office格式,支持Intel及Apple芯片Mac,基础功能可免费使用,

Shapr3D macOS版
Shapr3D macOS版

Shapr3D是一款面向工业设计、机械工程、建筑概念和三维打印工作流的CAD软件。Mac版采用Parasolid建模内核,支持草图约束、实体建模、工程图、可视化渲染及常见CAD格式交换,并可通过账户在多台设备之间同步项目。

REAPER macOS版
REAPER macOS版

REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。

Ableton Live macOS版
Ableton Live macOS版

Ableton Live 是面向音乐制作人与现场表演者的数字音频工作站,提供编曲视图、独具特色的现场视图、音频录制、MIDI创作、实时变速、乐器及效果器。Mac版原生支持Apple芯片,并可连接音频接口、MIDI控制器和第三方插件。

Adobe After Effects macOS版
Adobe After Effects macOS版

Adobe After Effects 是面向动态图形、影视特效与视频合成的专业创作软件。它提供关键帧动画、遮罩抠像、运动跟踪、三维空间、文字动画和表达式等工具,并可与 Premiere Pro、Photoshop、Illustrator

Adobe Audition macOS版
Adobe Audition macOS版

Adobe Audition 是面向播客、影视后期、音乐制作及内容创作者的专业音频工作站,提供波形精修、多轨录制与混音、频谱编辑、降噪修复、响度匹配和效果处理工具,并可与 Adobe Premiere 协同完成视频声音制作。

Adobe Bridge macOS版
Adobe Bridge macOS版

Adobe Bridge 是面向摄影师、设计师及内容团队的免费数字资产管理工具,可集中预览照片、视频和 Adobe 项目文件,并利用评级、标签、关键词、元数据、筛选与收藏集完成分类检索。它还支持批量重命名、格式导出、相机导入及 Camera

Adobe Illustrator macOS版
Adobe Illustrator macOS版

Adobe Illustrator 是 Adobe 推出的专业矢量图形设计软件,适合在 Mac 上制作标志、图标、插画、包装、信息图及印刷版面。它以路径和锚点构建可无损缩放的图形,并提供钢笔、形状、文字、图像描摹、渐变、画板及生成式功能。

Adobe InDesign macOS版
Adobe InDesign macOS版

Adobe InDesign 是面向印刷品与数字出版物的专业版面设计软件,可在 Mac 上制作书籍、杂志、宣传册、海报、报告及交互式文档。它提供精细的文字样式、网格、母版、长文档管理和印前输出能力。

Adobe Lightroom Classic macOS版
Adobe Lightroom Classic macOS版

Adobe Lightroom Classic 是面向桌面摄影工作流的照片管理与后期处理软件,可将原始照片保存在本地硬盘,通过目录、关键词、评分和收藏夹高效整理图库,并提供 RAW 冲印、蒙版、镜头校正、批量同步及多格式导出等功能。

Adobe Media Encoder macOS版
Adobe Media Encoder macOS版

Adobe Media Encoder 是 Adobe 推出的专业音视频编码与转码工具,可通过队列、预设和监视文件夹批量完成格式转换、代理文件创建及多平台成片输出,并与 Premiere Pro、After Effects 等软件紧密协作。

Adobe Photoshop macOS版
Adobe Photoshop macOS版

Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理软件,提供图层、蒙版、选区、修复、调色、文字排版、智能对象及生成式编辑等能力。Mac 版支持 Intel 与 Apple Silicon 处理器。

WINDOWS 更多
Adobe Photoshop Windows版
Adobe Photoshop Windows版

Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理工具,可在 Windows 上完成照片修饰、选区抠图、图层合成、文字排版、绘画及生成式编辑。软件采用订阅授权,由 Creative Cloud 管理安装、更新与许

Adobe InDesign Windows版
Adobe InDesign Windows版

Adobe InDesign 是面向印刷与数字出版的专业页面排版工具,可制作书籍、杂志、宣传册、海报、交互式 PDF 和电子书。它提供精细的文字样式、多页面管理、印前检查及多格式输出能力,并能与 Photoshop、Illustrator

Adobe Illustrator Windows版
Adobe Illustrator Windows版

Adobe Illustrator 是用于绘制矢量图形、插画、图标、徽标和版式的专业设计工具。它以路径和锚点为核心,作品放大后仍能保持清晰,并提供画板、文字、渐变、图像描摹及精确变换等功能,适合品牌视觉、印刷物料、数字界面和商业插画创作。

Adobe Bridge Windows版
Adobe Bridge Windows版

Adobe Bridge 是 Adobe 推出的创意资产管理工具,可集中预览、分类和查找照片、视频、PDF及多种设计文件,并支持元数据、关键词、评级、批量重命名和格式导出。它可与 Photoshop、Illustrator 等应用衔接,

Affinity Photo Windows版
Affinity Photo Windows版

Affinity Photo 是一款面向摄影师、修图师和视觉设计人员的桌面图像编辑工具,提供 RAW 显影、多图层合成、蒙版、实时滤镜、批处理和色彩管理等功能。原独立产品已停止销售,其照片编辑能力已延续至免费的新 Affinity 应用;

Adobe Lightroom Classic Windows版
Adobe Lightroom Classic Windows版

Adobe Lightroom Classic 是面向 Windows 桌面摄影工作流的照片管理与无损编辑工具,可通过目录集中整理大型图库,并完成 RAW 显影、局部蒙版、批量调整、打印和多格式导出。它强调本地文件管理与精细控制,

Figma Windows版
Figma Windows版

Figma 是面向产品设计与开发团队的云端协作平台,可在 Windows 桌面客户端中完成界面绘制、组件管理、交互原型、评论评审和开发交付。文件保存在云端,多名成员能够同步编辑并共享设计系统;官方同时提供免费 Starter 方案及按席位计

Affinity Designer Windows版
Affinity Designer Windows版

Affinity Designer 是面向矢量图形、数字插画和界面设计的专业创作工具,可在矢量、像素与导出工作区之间快速切换。它提供曲线编辑、形状构建、画板、排版、图层和专业色彩管理,并支持常见设计文件的导入及多种印刷、网页格式输出。

Capture One Pro Windows版
Capture One Pro Windows版

Capture One Pro 是面向摄影师和影像团队的专业桌面照片处理工具,提供相机定制色彩配置、RAW转换、图层与蒙版、联机拍摄、目录及会话管理等功能。它适合棚拍、人像、商业产品、婚礼和风光摄影,

Adobe Acrobat Pro Windows版
Adobe Acrobat Pro Windows版

Adobe Acrobat Pro 是面向专业 PDF 工作的综合解决方案,可在 Windows 中创建、编辑、转换、比较、整理和保护文档,并支持表单、电子签名、扫描件文字识别及敏感信息永久遮盖。订阅还包含网页、移动服务和云端协作能力,

Adobe After Effects Windows版
Adobe After Effects Windows版

Adobe After Effects 是面向动态图形、动画与影视视觉特效制作的专业工具,可完成关键帧动画、图层合成、遮罩跟踪、抠像、文字动画和二维三维元素整合。Windows 版通过 Adobe Creative Cloud 安装及更新,

DaVinci Resolve Windows版
DaVinci Resolve Windows版

DaVinci Resolve是Blackmagic Design推出的一体化影视后期工具,将素材管理、非线性剪辑、专业调色、Fusion视觉特效、Fairlight音频处理和成片交付整合在统一工程中。免费版已覆盖多数个人创作需求,