⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jvhidcontrollerclass.pas

📁 通过delphi USB控件读写数据
💻 PAS
📖 第 1 页 / 共 5 页
字号:
                                    var Report; ReportLength: ULONG):               NTSTATUS;
    function  ReadFile             (var Report; ToRead:  DWORD; var BytesRead:    DWORD): Boolean;
    function  ReadFileEx           (var Report; ToRead:  DWORD;
                                    CallBack: TPROverlappedCompletionRoutine):            Boolean;
    function  WriteFile            (var Report; ToWrite: DWORD; var BytesWritten: DWORD): Boolean;
    function  WriteFileEx          (var Report; ToWrite: DWORD;
                                    CallBack: TPROverlappedCompletionRoutine):            Boolean;
  end;

  // controller class to manage all HID devices

  {$IFDEF USEJVCL}
  TJvHidDeviceController = class(TJvComponent)
  {$ELSE}
  TJvHidDeviceController = class(TComponent)
  {$ENDIF USEJVCL}
  private
    // internal properties part
    FHidGuid:              TGUID;
    FArrivalEvent:         TJvHidPlugEvent;
    FDeviceChangeEvent:    TNotifyEvent;
    FEnumerateEvent:       TJvHidEnumerateEvent;
    FDevDataEvent:         TJvHidDataEvent;
    FDevDataErrorEvent:    TJvHidDataErrorEvent;
    FDevUnplugEvent:       TJvHidUnplugEvent;
    FRemovalEvent:         TJvHidUnplugEvent;
    FDeviceChangeFired:    Boolean;
    FDevThreadSleepTime:   Integer;
    FVersion:              string;
    FDummy:                string;
    // internal list of all HID device objects
    FList:                 TList;
    // counters for the list
    FNumCheckedInDevices:  Integer;
    FNumCheckedOutDevices: Integer;
    FNumUnpluggedDevices:  Integer;
    // internal worker functions
    function  CheckThisOut(var HidDev: TJvHidDevice; Idx: Integer; Check: Boolean): Boolean;
    procedure FillInList  (var List: TList);
    function  EventPipe   (var Msg: TMessage): Boolean;

  protected
    procedure DoArrival(HidDev: TJvHidDevice);
    procedure DoRemoval(HidDev: TJvHidDevice);
    procedure DoDeviceChange;
    // internal event implementors
    function  DoEnumerate          (HidDev: TJvHidDevice; Idx: Integer): Boolean;
    procedure SetDeviceChangeEvent (const Notifier:       TNotifyEvent);
    procedure SetEnumerate         (const Enumerator:     TJvHidEnumerateEvent);
    procedure SetDevThreadSleepTime(const DevTime:        Integer);
    procedure SetDevData           (const DataEvent:      TJvHidDataEvent);
    procedure SetDevDataError      (const DataErrorEvent: TJvHidDataErrorEvent);
    procedure SetDevUnplug         (const Unplugger:      TJvHidUnplugEvent);

  public
    // just to be complete the GUID
    property HidGuid: TGUID read FHidGuid;

    // normal constructor/destructor
    constructor Create(AOwner: TComponent); override;
    destructor  Destroy;                    override;

    // methods to hand out HID device objects
    procedure CheckIn              (var HidDev: TJvHidDevice);
    function  CheckOut             (var HidDev: TJvHidDevice): Boolean;
    function  CheckOutByClass      (var HidDev: TJvHidDevice; const ClassName:   string):     Boolean;
    function  CheckOutByID         (var HidDev: TJvHidDevice; const Vid, Pid:    Integer):    Boolean;
    function  CheckOutByIndex      (var HidDev: TJvHidDevice; const Idx:         Integer):    Boolean;
    function  CheckOutByProductName(var HidDev: TJvHidDevice; const ProductName: WideString): Boolean;
    function  CheckOutByVendorName (var HidDev: TJvHidDevice; const VendorName:  WideString): Boolean;
    function  CheckOutByCallback   (var HidDev: TJvHidDevice; Check: TJvHidCheckCallback):    Boolean;
    // methods to count HID device objects
    function  CountByClass         (const ClassName:   string):     Integer;
    function  CountByID            (const Vid, Pid:    Integer):    Integer;
    function  CountByProductName   (const ProductName: WideString): Integer;
    function  CountByVendorName    (const VendorName:  WideString): Integer;
    function  CountByCallback      (Check: TJvHidCheckCallback):    Integer;
    // iterate over the HID devices
    function  Enumerate: Integer;
    class function HidVersion: string;

    property NumCheckedInDevices:  Integer read FNumCheckedInDevices;
    property NumCheckedOutDevices: Integer read FNumCheckedOutDevices;
    property NumUnpluggedDevices:  Integer read FNumUnpluggedDevices;

  published
    property DevThreadSleepTime: Integer              read FDevThreadSleepTime write SetDevThreadSleepTime default 100;
    property Version:            string               read FVersion            write FDummy stored False;
    property  OnArrival:         TJvHidPlugEvent      read FArrivalEvent       write FArrivalEvent;
    // the iterator event
    property  OnEnumerate:       TJvHidEnumerateEvent read FEnumerateEvent     write SetEnumerate;
    // the central event for HID device changes
    property  OnDeviceChange:    TNotifyEvent         read FDeviceChangeEvent  write SetDeviceChangeEvent;
    // these events are copied to TJvHidDevices on creation
    property  OnDeviceData:      TJvHidDataEvent      read FDevDataEvent       write SetDevData;
    property  OnDeviceDataError: TJvHidDataErrorEvent read FDevDataErrorEvent  write SetDevDataError;
    property  OnDeviceUnplug:    TJvHidUnplugEvent    read FDevUnplugEvent     write SetDevUnplug;
    property  OnRemoval:         TJvHidUnplugEvent    read FRemovalEvent       write FRemovalEvent;
    // to be callable at design time
    procedure DeviceChange;
  end;

// helpers to check the HID function and method results
function HidCheck(const RetVal: NTSTATUS): NTSTATUS; overload;
function HidCheck(const RetVal: LongBool): LongBool; overload;
function HidError(const RetVal: NTSTATUS): NTSTATUS;
function HidErrorString(const RetVal: NTSTATUS): string;

{$IFNDEF USEJVCL}

// to register the component in the palette
procedure Register;

{$ENDIF USEJVCL}

implementation

{$IFDEF USEJVCL}

uses
  JvResources, JvTypes;

type
  EControllerError = class(EJVCLException);
  EHidClientError  = class(EJVCLException);

{$ELSE}

type
  EControllerError = class(Exception);
  EHidClientError  = class(Exception);

resourcestring
  RsUnknownLocaleIDFmt = 'unknown Locale ID $%.4x';
  RsHIDP_STATUS_NULL = 'device not plugged in';
  RsHIDP_STATUS_INVALID_PREPARSED_DATA = 'invalid preparsed data';
  RsHIDP_STATUS_INVALID_REPORT_TYPE = 'invalid report type';
  RsHIDP_STATUS_INVALID_REPORT_LENGTH = 'invalid report length';
  RsHIDP_STATUS_USAGE_NOT_FOUND = 'usage not found';
  RsHIDP_STATUS_VALUE_OUT_OF_RANGE = 'value out of range';
  RsHIDP_STATUS_BAD_LOG_PHY_VALUES = 'bad logical or physical values';
  RsHIDP_STATUS_BUFFER_TOO_SMALL = 'buffer too small';
  RsHIDP_STATUS_INTERNAL_ERROR = 'internal error';
  RsHIDP_STATUS_I8042_TRANS_UNKNOWN = '8042 key translation impossible';
  RsHIDP_STATUS_INCOMPATIBLE_REPORT_ID = 'incompatible report ID';
  RsHIDP_STATUS_NOT_VALUE_ARRAY = 'not a value array';
  RsHIDP_STATUS_IS_VALUE_ARRAY = 'is a value array';
  RsHIDP_STATUS_DATA_INDEX_NOT_FOUND = 'data index not found';
  RsHIDP_STATUS_DATA_INDEX_OUT_OF_RANGE = 'data index out of range';
  RsHIDP_STATUS_BUTTON_NOT_PRESSED = 'button not pressed';
  RsHIDP_STATUS_REPORT_DOES_NOT_EXIST = 'report does not exist';
  RsHIDP_STATUS_NOT_IMPLEMENTED = 'not implemented';
  RsUnknownHIDFmt = 'unknown HID error %x';
  RsHIDErrorPrefix = 'HID Error: ';

  RsEDirectThreadCreationNotAllowed = 'Direct creation of a TJvDeviceReadThread object is not allowed';
  RsEDirectHidDeviceCreationNotAllowed = 'Direct creation of a TJvHidDevice object is not allowed';
  RsEDeviceCannotBeIdentified = 'device cannot be identified';
  RsEDeviceCannotBeOpened = 'device cannot be opened';
  RsEOnlyOneControllerPerProgram = 'Only one TJvHidDeviceController allowed per program';
  RsEHIDBooleanError = 'HID Error: a boolean function failed';

{$ENDIF USEJVCL}

const
  Kernel32DllName = 'kernel32.dll';

var
  // counter to prevent a second TJvHidDeviceController instance
  GlobalInstanceCount: Integer = 0;

//== these are declared inconsistent in Windows.pas ============================

function ReadFileEx(hFile: THandle; var Buffer; nNumberOfBytesToRead: DWORD;
  var Overlapped: TOverlapped; lpCompletionRoutine: TPROverlappedCompletionRoutine): BOOL; stdcall;
  external Kernel32DllName name 'ReadFileEx';
function WriteFileEx(hFile: THandle; var Buffer; nNumberOfBytesToWrite: DWORD;
  var Overlapped: TOverlapped; lpCompletionRoutine: TPROverlappedCompletionRoutine): BOOL; stdcall;
 external Kernel32DllName name 'WriteFileEx';

//== TJvHidDeviceReadThread ====================================================

constructor TJvHidDeviceReadThread.CtlCreate(const Dev: TJvHidDevice);
begin
  inherited Create(True);
  Device := Dev;
  NumBytesRead := 0;
  SetLength(Report, Dev.Caps.InputReportByteLength);
end;

//------------------------------------------------------------------------------

constructor TJvHidDeviceReadThread.Create(CreateSuspended: Boolean);
begin
  raise EControllerError.Create(RsEDirectThreadCreationNotAllowed);
end;

//------------------------------------------------------------------------------

procedure TJvHidDeviceReadThread.DoData;
begin
  Device.OnData(Device, Report[0], @Report[1], NumBytesRead-1);
end;

//------------------------------------------------------------------------------

procedure TJvHidDeviceReadThread.DoDataError;
begin
  if Assigned(Device.FDataError) then
    Device.FDataError(Device, FErr);
end;

//------------------------------------------------------------------------------

procedure TJvHidDeviceReadThread.Execute;
var
  SleepRet: DWORD;

  procedure Dummy(ErrorCode: DWORD; Count: DWORD; Ovl: POverlapped); stdcall;
  begin
  end;

begin
  SleepRet := WAIT_IO_COMPLETION;
  while not Terminated do
  begin
    // read data
    SleepRet := WAIT_IO_COMPLETION;
    FillChar(Report[0], Device.Caps.InputReportByteLength, #0);
    if Device.ReadFileEx(Report[0], Device.Caps.InputReportByteLength, @Dummy) then
    begin
      // wait for read to complete
      repeat
        SleepRet := SleepEx(Device.ThreadSleepTime, True);
      until Terminated or (SleepRet = WAIT_IO_COMPLETION);
      // show data read
      if not Terminated then
      begin
        NumBytesRead := Device.HidOverlappedReadResult;
        if NumBytesRead > 0 then
          Synchronize(DoData);
      end;
    end
    else
    begin
      FErr := GetLastError;
      Synchronize(DoDataError);
    end;
  end;
  // cancel ReadFileEx call or the callback will
  // crash your program
  if SleepRet <> WAIT_IO_COMPLETION then
    Device.CancelIO(omhRead);
end;

//== TJvHidPnPInfo =============================================================

constructor TJvHidPnPInfo.Create(APnPHandle: HDEVINFO; ADevData: TSPDevInfoData; ADevicePath: PChar);
begin
  FDeviceID   := ADevData.DevInst;
  FDevicePath := ADevicePath;

  // primary information
  FCapabilities    := GetRegistryPropertyDWord     (APnPHandle, ADevData, SPDRP_CAPABILITIES);
  FClassDescr      := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_CLASS);
  FClassGUID       := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_CLASSGUID);
  FCompatibleIDs   := GetRegistryPropertyStringList(APnPHandle, ADevData, SPDRP_COMPATIBLEIDS);
  FConfigFlags     := GetRegistryPropertyDWord     (APnPHandle, ADevData, SPDRP_CONFIGFLAGS);
  FDeviceDescr     := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_DEVICEDESC);
  FDriver          := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_DRIVER);
  FFriendlyName    := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_FRIENDLYNAME);
  FHardwareID      := GetRegistryPropertyStringList(APnPHandle, ADevData, SPDRP_HARDWAREID);
  FLowerFilters    := GetRegistryPropertyStringList(APnPHandle, ADevData, SPDRP_LOWERFILTERS);
  FMfg             := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_MFG);
  FUpperFilters    := GetRegistryPropertyStringList(APnPHandle, ADevData, SPDRP_UPPERFILTERS);
  FService         := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_SERVICE);

  // secondary information not all likely to exist for a HID device
  FAddress         := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_ADDRESS);
  FBusNumber       := GetRegistryPropertyDWord     (APnPHandle, ADevData, SPDRP_BUSNUMBER);
  FBusType         := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_BUSTYPEGUID);
  FCharacteristics := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_CHARACTERISTICS);
  FDevType         := GetRegistryPropertyDWord     (APnPHandle, ADevData, SPDRP_DEVTYPE);
  FEnumeratorName  := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_ENUMERATOR_NAME);
  FExclusive       := GetRegistryPropertyDWord     (APnPHandle, ADevData, SPDRP_EXCLUSIVE);
  FLegacyBusType   := GetRegistryPropertyDWord     (APnPHandle, ADevData, SPDRP_LEGACYBUSTYPE);
  FLocationInfo    := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_LOCATION_INFORMATION);
  FPhysDevObjName  := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME);
  FSecuritySDS     := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_SECURITY_SDS);
  FUINumber        := GetRegistryPropertyDWord     (APnPHandle, ADevData, SPDRP_UI_NUMBER);
  FUINumberFormat  := GetRegistryPropertyString    (APnPHandle, ADevData, SPDRP_UI_NUMBER_DESC_FORMAT);
end;

//------------------------------------------------------------------------------

destructor TJvHidPnPInfo.Destroy;
begin
  FCompatibleIDs.Free;
  FHardwareID.Free;
  FLowerFilters.Free;
  FUpperFilters.Free;
end;

//------------------------------------------------------------------------------

// internal helpers to read values from a devices registry area

function TJvHidPnPInfo.GetRegistryPropertyString(PnPHandle: HDEVINFO; const DevData: TSPDevInfoData; Prop: DWORD): string;
var
  BytesReturned: DWORD;
  RegDataType:   DWORD;
  Buffer:        array [0..256] of Char;
begin
  BytesReturned := 0;
  RegDataType   := 0;
  Buffer[0]     := #0;
  SetupDiGetDeviceRegistryProperty(PnPHandle, DevData, Prop,
    RegDataType, PBYTE(@Buffer[0]), SizeOf(Buffer), BytesReturned);
  Result := Buffer;
end;

//------------------------------------------------------------------------------

function TJvHidPnPInfo.GetRegistryPropertyStringList(PnPHandle: HDEVINFO; const DevData: TSPDevInfoData; Prop: DWORD): TStringList;
var

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -