下面是访问 USB 设备的类单元文件: { Usb通讯操作助手 Date: 2008-7-10 Version: 1.0 Author: zlz (47953@163.com) } unit TUsbUtil_U; interface uses Windows, Messages, SysUtils, Variants, Classes, StdCtrls,Dialogs,SetupApi; const MAX_PATH = 260; //文件名最大长度 MAX_DATA_BUFFER = 1024; //缓冲区大小 Type //数据缓存 TDataBuffer = record DataBuffer:array[0..MAX_DATA_BUFFER] of byte; //缓存数据 DataSize :Integer; //缓存数据长度 end; //串口操作助手 TUsbUtil = class(TObject) public function Open(usbguid:String) :boolean; //打开USB设备 procedure Close(); //关闭USB设备 procedure WriteBytes(bs:TDataBuffer); //向USB设备发送字节数组 function ReadBytes():TDataBuffer; //从USB设备读取数据 private hUsbHandle : THandle; //打开一个设备 function OpenOneDevice(hDvcInfo:HDEVINFO; DvcInfoData:PSPDeviceInterfaceData ; sDevNameBuf:pchar) :THandle; //打开指定的USB设备 function OpenUsbDevice(pGuid :TGUID; sDevNameBuf :pchar):THandle; end; implementation { TUsbUtil } procedure TUsbUtil.Close; begin CloseHandle(hUsbHandle); end; function TUsbUtil.Open(usbguid: String): boolean; var DeviceName: array[0..MAX_PATH] of char; USB_GUID : TGUID; begin Result := false; USB_GUID := StringToGuid('{' + usbguid + '}'); hUsbHandle := OpenUsbDevice(USB_GUID, DeviceName); if (hUsbHandle = INVALID_HANDLE_VALUE) then begin raise Exception.Create('无法打开指定的USB设备'); end; Result := True; end; function TUsbUtil.OpenOneDevice(hDvcInfo: HDEVINFO; DvcInfoData: PSPDeviceInterfaceData; sDevNameBuf: pchar): THandle; var iReqLen : dword; iDevDataLen : DWord; pDevData : PSPDeviceInterfaceDetailDataA ; hOut: THandle; begin hOut := INVALID_HANDLE_VALUE; iReqLen := 0; SetupDiGetDeviceInterfaceDetail(hDvcInfo,DvcInfoData, nil, 0, iReqLen, nil); iDevDataLen := DWORD(integer(iReqLen)); GetMem(pDevData, iDevDataLen); pDevData.cbSize := sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); if (SetupDiGetInterfaceDeviceDetail(hDvcInfo, DvcInfoData, pDevData, iDevDataLen, @iReqLen, nil)) then begin strcopy(sDevNameBuf, pDevData.DevicePath); hOut := CreateFile(pDevData.DevicePath,GENERIC_WRITE or GENERIC_READ, FILE_SHARE_WRITE or FILE_SHARE_READ, nil,OPEN_EXISTING,0,0); end; FreeMem(pDevData); Result := hOut; end; function TUsbUtil.OpenUsbDevice(pGuid: TGUID; sDevNameBuf: pchar): THandle; var hDevInfo1 : HDEVINFO; deviceInfoData : TSPDeviceInterfaceData ; nGuessCount : Dword; iDevIndex :DWord; hOut: THandle; begin hDevInfo1 := SetupDiGetClassDevs(@pGuid, nil,0, DIGCF_PRESENT or DIGCF_DEVICEINTERFACE); deviceInfoData.cbSize := sizeof(TSPDeviceInterfaceData); nGuessCount := MAXLONG; for iDevIndex :=0 to nGuessCount do begin if(SetupDiEnumDeviceInterfaces(hDevInfo1,nil,pGuid,iDevIndex,deviceInfoData)) then begin hOut := OpenOneDevice(hDevInfo1, @deviceInfoData, sDevNameBuf); if (hOut <> INVALID_HANDLE_VALUE) then begin break; end else if (GetLastError() = ERROR_NO_MORE_ITEMS) then begin break; end; end; end; SetupDiDestroyDeviceInfoList(hDevInfo1); Result := hOut; end; function TUsbUtil.ReadBytes: TDataBuffer; var nBytesReaded:LongWord; bs: TDataBuffer; begin ReadFile(self.hUsbHandle,bs.DataBuffer,MAX_DATA_BUFFER, nBytesReaded, nil); bs.DataSize := nBytesReaded; Result := bs; end; procedure TUsbUtil.WriteBytes(bs: TDataBuffer); var nBytesWritten:LongWord; begin WriteFile(self.hUsbHandle, bs.DataBuffer, bs.DataSize, nBytesWritten, nil); end; end. 有了上面的类就可以与USB设备进行通讯了 procedure TUsbUtil.Test; var bs:TDataBuffer; objUsb:TUsbUtil; begin objUsb := TUsbUtil.Create(); //打开USB设备,参数是驱动程序的GUID值, 这里我乱写的数 objUsb.Open('A5DCBF10-6530-11D2-901F-00C04FB951ED'); //写入数据 bs.DataBuffer[0] := $1B; bs.DataBuffer[1] := $10; bs.DataBuffer[2] := $00; bs.DataBuffer[3] := $00; bs.DataBuffer[4] := $05; bs.DataBuffer[5] := $44; bs.DataBuffer[6] := $D0; bs.DataSize := 7; objUsb.WriteBytes(bs); //读取数据 bs := objUsb.ReadBytes(); //关闭设备 objUsb.Close(); end; USB 设备、USB 驱动、USB 应用程序 1.USB 设备硬件部分 a.这个硬件的标识是用的 Vender ID 和 Product ID, 即“厂家标识”和“产品标识” b.这个硬件规定了各个 End Point (端点) 的性质, 读/写 及 类型 (Control/Interrupt/Bulk/Isochronous) c.这个硬件的固件里面有 DeviceIoControl 的实现部分, 规定了这个函数的具体参数和动作 2.USB 设备驱动 ①硬件接口 a.需要识别 Vender ID 和 Product ID b.对每个 EndPoint 的每个 I/O 分配一个 Pipe, 并且起一个名字作为软件接口 c.做 DeviceIoControl 的接口 ②软件接口 a.GUID, 驱动程序的标识, 每个驱动程序使用不同的 GUID, GUID 是识别驱动的, 与硬件无关 (驱动程序升级版本 GUID 不能修改) b.硬件接口里面的 b: Pipe 名字是软件接口, 这个 Pipe 名字纯粹由驱动定义的, 和硬件无关, 升级驱动不能改 Pipe 的名字 c.硬件接口里面的 c 的各个参数也是软件的接口, 这些参数是由硬件带来的, 不是驱动规定的, 当然也可以在驱动里面转义, 隐藏设备的真实情况 ③这个驱动程序是用 WinDDK 编译的, 可以用文本编辑器或其他开发工具的编辑器编程序代码, 然后调用 WinDDK 编译 3.读写 USB 口的程序 ①与驱动的接口 a.利用驱动程序里面的 GUID 找出设备的文件名, 用 CreateFile 函数打开设备。我前面的程序里面的 OpenUsbDevice 就是这个作用 b.通过 a.得到的设备文件名和驱动程序里面的 Pipe 名打开 Pipe, 访问这个 Pipe 对应的 USB 端点 (读写数据) c.使用 a.的 CreateFile 得到的句柄, 通过 DeviceIoControl 实现设备规定的动作 ②有关需要的资料 a.Vender ID, Product ID 和 GUID 一般在驱动程序的 .inf 文件里面能看到, 如果找不到就需要和厂家联系 b.Pipe 的名字是驱动程序规定的, 需要有驱动程序的资料才能知道 c.DeviceIoControl 的参数需要有驱动程序的资料或者硬件资料才能知道 ③这个程序一般用 C/C++ 直接编写, 如果使用其他语言(VB/PB等)需要调用 C/C++ 编的 DLL 其他相关内容: USB 驱动程序可以到注册表里面找到: "HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Enum\\USB\\Vid_厂家标识&Pid_产品标识\\驱动程序" 里面的 ClassGUID 就是驱动程序的 GUID 标识, 例如 {36FC9E60-C465-11CF-8056-444553540000} 相当于程序的: DEFINE_GUID(USB_DRIVER_GUID, 0x36FC9E60,0xC465,0x11CF,0x80,0x56,0x44,0x45,0x53,0x54,0x00,0x00); 另外在这个注册表键里面还可找到有关设备的其他描述, 例如 DeviceDesc = "USB Mass Storage Device" 等 |
|
来自: Gavin-book > 《DELPHI》