C# USB通信(调用Windows API)

 网上usb通信的案列有很多,或多或少的有点bug,我在做项目的时候,费了很大的功夫都是在调试bug,今天有空把usb通信的底层代码贴出来,方便大家使用。
 示例代码如下:

using System;
using System.Runtime.InteropServices;

namespace USB
{
public class Win32Usb
{
#region Structures
///
/// An overlapped structure used for overlapped IO operations. The structure is
/// only used by the OS to keep state on pending operations. You don’t need to fill anything in if you
/// unless you want a Windows event to fire when the operation is complete.
///
[StructLayout(LayoutKind.Sequential, Pack = 1)]
protected struct Overlapped
{
public uint Internal;
public uint InternalHigh;
public uint Offset;
public uint OffsetHigh;
public IntPtr Event;
}
///
/// Provides details about a single USB device
///
[StructLayout(LayoutKind.Sequential, Pack = 1)]
protected struct DeviceInterfaceData
{
public int Size;
public Guid InterfaceClassGuid;
public int Flags;
public IntPtr Reserved;
}
///
/// Provides the capabilities of a HID device
///
[StructLayout(LayoutKind.Sequential, Pack = 1)]
protected struct HidCaps
{
public ushort Usage;
public ushort UsagePage;
public ushort InputReportByteLength;
public ushort OutputReportByteLength;
public ushort FeatureReportByteLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
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;
}
///
/// Access to the path for a device
///
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DeviceInterfaceDetailData
{
public int Size;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string DevicePath;
}
///
/// Used when registering a window to receive messages about devices added or removed from the system.
///
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
public class DeviceBroadcastInterface
{
public int Size;
public int DeviceType;
public int Reserved;
public Guid ClassGuid;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Name;
}

    #region Constants
    /// <summary>Windows message sent when a device is inserted or removed</summary>
    public const int WM_DEVICECHANGE = 0x0219;
    /// <summary>WParam for above : A device was inserted</summary>
    public const int DEVICE_ARRIVAL = 0x8000;
    /// <summary>WParam for above : A device was removed</summary>
    public const int DEVICE_REMOVECOMPLETE = 0x8004;
    /// <summary>Used in SetupDiClassDevs to get devices present in the system</summary>
    protected const int DIGCF_PRESENT = 0x02;
    /// <summary>Used in SetupDiClassDevs to get device interface details</summary>
    protected const int DIGCF_DEVICEINTERFACE = 0x10;
    /// <summary>Used when registering for device insert/remove messages : specifies the type of device</summary>
    protected const int DEVTYP_DEVICEINTERFACE = 0x05;
    /// <summary>Used when registering for device insert/remove messages : we're giving the API call a window handle</summary>
    protected const int DEVICE_NOTIFY_WINDOW_HANDLE = 0;
    /// <summary>Purges Win32 transmit buffer by aborting the current transmission.</summary>
    protected const uint PURGE_TXABORT = 0x01;
    /// <summary>Purges Win32 receive buffer by aborting the current receive.</summary>
    protected const uint PURGE_RXABORT = 0x02;
    /// <summary>Purges Win32 transmit buffer by clearing it.</summary>
    protected const uint PURGE_TXCLEAR = 0x04;
    /// <summary>Purges Win32 receive buffer by clearing it.</summary>
    protected const uint PURGE_RXCLEAR = 0x08;
    /// <summary>CreateFile : Open file for read</summary>
    protected const uint GENERIC_READ = 0x80000000;
    /// <summary>CreateFile : Open file for write</summary>
    protected const uint GENERIC_WRITE = 0x40000000;
    /// <summary>CreateFile : file share for write</summary>
    protected const uint FILE_SHARE_WRITE = 0x2;
    /// <summary>CreateFile : file share for read</summary>
    protected const uint FILE_SHARE_READ = 0x1;
    /// <summary>CreateFile : Open handle for overlapped operations</summary>
    protected const uint FILE_FLAG_OVERLAPPED = 0x40000000;
    /// <summary>CreateFile : Resource to be "created" must exist</summary>
    protected const uint CREATE_NEW = 1;
    protected const uint CREATE_ALWAYS = 2;
    protected const uint OPEN_EXISTING = 3;
    /// <summary>CreateFile : Resource will be "created" or existing will be used</summary>
    protected const uint OPEN_ALWAYS = 4;
    /// <summary>ReadFile/WriteFile : Overlapped operation is incomplete.</summary>
    protected const uint ERROR_IO_PENDING = 997;
    /// <summary>Infinite timeout</summary>
    protected const uint INFINITE = 0xFFFFFFFF;
    /// <summary>Simple representation of a null handle : a closed stream will get this handle. Note it is public for comparison by higher level classes.</summary>
    public static IntPtr NullHandle = IntPtr.Zero;
    /// <summary>Simple representation of the handle returned when CreateFile fails.</summary>
    protected static IntPtr InvalidHandleValue = new IntPtr(-1);
    #endregion

    #region P/Invoke
    /// <summary>
    /// Gets the GUID that Windows uses to represent HID class devices
    /// </summary>
    /// <param name="gHid">An out parameter to take the Guid</param>
    [DllImport("hid.dll", SetLastError = true)]
    protected static extern void HidD_GetHidGuid(out Guid gHid);
    /// <summary>
    /// Allocates an InfoSet memory block within Windows that contains details of devices.
    /// </summary>
    /// <param name="gClass">Class guid (e.g. HID guid)</param>
    /// <param name="strEnumerator">Not used</param>
    /// <param name="hParent">Not used</param>
    /// <param name="nFlags">Type of device details required (DIGCF_ constants)</param>
    /// <returns>A reference to the InfoSet</returns>
    [DllImport("setupapi.dll", SetLastError = true)]
    protected static extern IntPtr SetupDiGetClassDevs(ref Guid gClass, [MarshalAs(UnmanagedType.LPStr)] string strEnumerator, IntPtr hParent, uint nFlags);
    /// <summary>
    /// Frees InfoSet allocated in call to above.
    /// </summary>
    /// <param name="lpInfoSet">Reference to InfoSet</param>
    /// <returns>true if successful</returns>
    [DllImport("setupapi.dll", SetLastError = true)]
    protected static extern int SetupDiDestroyDeviceInfoList(IntPtr lpInfoSet);
    /// <summary>
    /// Gets the DeviceInterfaceData for a device from an InfoSet.
    /// </summary>
    /// <param name="lpDeviceInfoSet">InfoSet to access</param>
    /// <param name="nDeviceInfoData">Not used</param>
    /// <param name="gClass">Device class guid</param>
    /// <param name="nIndex">Index into InfoSet for device</param>
    /// <param name="oInterfaceData">DeviceInterfaceData to fill with data</param>
    /// <returns>True if successful, false if not (e.g. when index is passed end of InfoSet)</returns>
    [DllImport("setupapi.dll", SetLastError = true)]
    protected static extern bool SetupDiEnumDeviceInterfaces(IntPtr lpDeviceInfoSet, uint nDeviceInfoData, ref Guid gClass, uint nIndex, ref DeviceInterfaceData oInterfaceData);
    /// <summary>
    /// SetupDiGetDeviceInterfaceDetail
    /// Gets the interface detail from a DeviceInterfaceData. This is pretty much the device path.
    /// You call this twice, once to get the size of the struct you need to send (nDeviceInterfaceDetailDataSize=0)
    /// and once again when you've allocated the required space.
    /// </summary>
    /// <param name="lpDeviceInfoSet">InfoSet to access</param>
    /// <param name="oInterfaceData">DeviceInterfaceData to use</param>
    /// <param name="lpDeviceInterfaceDetailData">DeviceInterfaceDetailData to fill with data</param>
    /// <param name="nDeviceInterfaceDetailDataSize">The size of the above</param>
    /// <param name="nRequiredSize">The required size of the above when above is set as zero</param>
    /// <param name="lpDeviceInfoData">Not used</param>
    /// <returns></returns>
    [DllImport("setupapi.dll", SetLastError = true)]
    protected static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr lpDeviceInfoSet, ref DeviceInterfaceData oInterfaceData, IntPtr lpDeviceInterfaceDetailData, uint nDeviceInterfaceDetailDataSize, ref uint nRequiredSize, IntPtr lpDeviceInfoData);
    /// <summary>
    /// SetupDiGetDeviceInterfaceDetail
    /// Gets the interface detail from a DeviceInterfaceData. This is pretty much the device path.
    /// You call this twice, once to get the size of the struct you need to send (nDeviceInterfaceDetailDataSize=0)
    /// and once again when you've allocated the required space.
    /// </summary>
    /// <param name="lpDeviceInfoSet">InfoSet to access</param>
    /// <param name="oInterfaceData">DeviceInterfaceData to use</param>
    /// <param name="oDetailData">DeviceInterfaceDetailData to fill with data</param>
    /// <param name="nDeviceInterfaceDetailDataSize">The size of the above</param>
    /// <param name="nRequiredSize">The required size of the above when above is set as zero</param>
    /// <param name="lpDeviceInfoData">Not used</param>
    /// <returns></returns>
    [DllImport("setupapi.dll", SetLastError = true)]
    protected static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr lpDeviceInfoSet, ref DeviceInterfaceData oInterfaceData, ref DeviceInterfaceDetailData oDetailData, uint nDeviceInterfaceDetailDataSize, ref uint nRequiredSize, IntPtr lpDeviceInfoData);
    /// <summary>
    /// Registers a window for device insert/remove messages
    /// </summary>
    /// <param name="hwnd">Handle to the window that will receive the messages</param>
    /// <param name="oInterface">DeviceBroadcastInterrface structure</param>
    /// <param name="nFlags">set to DEVICE_NOTIFY_WINDOW_HANDLE</param>
    /// <returns>A handle used when unregistering</returns>
    [DllImport("user32.dll", SetLastError = true)]
    protected static extern IntPtr RegisterDeviceNotification(IntPtr hwnd, DeviceBroadcastInterface oInterface, uint nFlags);
    /// <summary>
    /// Unregister from above.
    /// </summary>
    /// <param name="hHandle">Handle returned in call to RegisterDeviceNotification</param>
    /// <returns>True if success</returns>
    [DllImport("user32.dll", SetLastError = true)]
    protected static extern bool UnregisterDeviceNotification(IntPtr hHandle);
    /// <summary>
    /// Gets details from an open device. Reserves a block of memory which must be freed.
    /// </summary>
    /// <param name="hFile">Device file handle</param>
    /// <param name="lpData">Reference to the preparsed data block</param>
    /// <returns></returns>
    [DllImport("hid.dll", SetLastError = true)]
    protected static extern bool HidD_GetPreparsedData(IntPtr hFile, out IntPtr lpData);
    /// <summary>
    /// Frees the memory block reserved above.
    /// </summary>
    /// <param name="pData">Reference to preparsed data returned in call to GetPreparsedData</param>
    /// <returns></returns>
    [DllImport("hid.dll", SetLastError = true)]
    protected static extern bool HidD_FreePreparsedData(ref IntPtr pData);
    /// <summary>
    /// Gets a device's capabilities from the preparsed data.
    /// </summary>
    /// <param name="lpData">Preparsed data reference</param>
    /// <param name="oCaps">HidCaps structure to receive the capabilities</param>
    /// <returns>True if successful</returns>
    [DllImport("hid.dll", SetLastError = true)]
    protected static extern int HidP_GetCaps(IntPtr lpData, out HidCaps oCaps);
    /// <summary>
    /// Creates/opens a file, serial port, USB device... etc
    /// </summary>
    /// <param name="strName">Path to object to open</param>
    /// <param name="nAccess">Access mode. e.g. Read, write</param>
    /// <param name="nShareMode">Sharing mode</param>
    /// <param name="lpSecurity">Security details (can be null)</param>
    /// <param name="nCreationFlags">Specifies if the file is created or opened</param>
    /// <param name="nAttributes">Any extra attributes? e.g. open overlapped</param>
    /// <param name="lpTemplate">Not used</param>
    /// <returns></returns>
    [DllImport("kernel32.dll", SetLastError = true)]
    protected static extern IntPtr CreateFile([MarshalAs(UnmanagedType.LPStr)] string strName, uint nAccess, uint nShareMode, IntPtr lpSecurity, uint nCreationFlags, uint nAttributes, IntPtr lpTemplate);
    /// <summary>
    /// Closes a window handle. File handles, event handles, mutex handles... etc
    /// </summary>
    /// <param name="hFile">Handle to close</param>
    /// <returns>True if successful.</returns>
    [DllImport("kernel32.dll", SetLastError = true)]
    protected static extern int CloseHandle(IntPtr hFile);

    [Serializable,StructLayout(LayoutKind.Sequential,CharSet = CharSet.Auto),BestFitMapping(false)]
    public struct WIN32_FIND_DATA
    {
        public IntPtr dwFileAttributes;
        public int ftCreationTime_dwLowDateTime;
        public int ftCreationTime_dwHighDateTime;
        public int ftLastAccessTime_dwLowDateTime;
        public int ftLastAccessTime_dwHighDateTime;
        public int ftLastWriteTime_dwLowDateTime;
        public int ftLastWriteTime_dwHighDateTime;
        public int nFileSizeHigh;
        public int nFileSizeLow;
        public IntPtr dwReserved0;
        public IntPtr dwReserved1;
        [MarshalAs(UnmanagedType.ByValTStr,SizeConst = 260)]
        public string cFileName;
        [MarshalAs(UnmanagedType.ByValTStr,SizeConst = 14)]
        public string cAlternateFileName;
    }
    [DllImport("kernel32.dll", CharSet = CharSet.Auto,
    SetLastError = true)]
    public static extern IntPtr FindFirstFile(string pFileName, ref WIN32_FIND_DATA pFindFileData);
    [DllImport("kernel32.dll",CharSet = CharSet.Auto,
    SetLastError = true)]
    public static extern bool FindNextFile(IntPtr hndFindFile, ref WIN32_FIND_DATA lpFindFileData);
    #endregion

    #region Public methods
    /// <summary>
    /// Registers a window to receive windows messages when a device is inserted/removed. Need to call this
    /// from a form when its handle has been created, not in the form constructor. Use form's OnHandleCreated override.
    /// </summary>
    /// <param name="hWnd">Handle to window that will receive messages</param>
    /// <param name="gClass">Class of devices to get messages for</param>
    /// <returns>A handle used when unregistering</returns>
    public static IntPtr RegisterForUsbEvents(IntPtr hWnd, Guid gClass)
    {
        DeviceBroadcastInterface oInterfaceIn = new DeviceBroadcastInterface();
        oInterfaceIn.Size = Marshal.SizeOf(oInterfaceIn);
        oInterfaceIn.ClassGuid = gClass;
        oInterfaceIn.DeviceType = DEVTYP_DEVICEINTERFACE;
        oInterfaceIn.Reserved = 0;
        return RegisterDeviceNotification(hWnd, oInterfaceIn, DEVICE_NOTIFY_WINDOW_HANDLE);
    }
    /// <summary>
    /// Unregisters notifications. Can be used in form dispose
    /// </summary>
    /// <param name="hHandle">Handle returned from RegisterForUSBEvents</param>
    /// <returns>True if successful</returns>
    public static bool UnregisterForUsbEvents(IntPtr hHandle)
    {
        return UnregisterDeviceNotification(hHandle);
    }
    /// <summary>
    /// Helper to get the HID guid.
    /// </summary>
    public static Guid HIDGuid
    {
        get
        {
            Guid gHid;
            HidD_GetHidGuid(out gHid);
            return gHid;
        }
    }
    #endregion
}

}
usb在windows 系统里归结为了人体输入设备,那么它就有Vid(厂商号),Pid(产品号),所以在使用的时候必须的知道这个usb 的Vid和Pid,以下是usb的使用小案例:
示例代码下载地址:
https://github.com/myth158/usb.git

猜你喜欢

转载自blog.csdn.net/u011017980/article/details/54142954