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

📄 jvhidcontrollerclass.pas

📁 human interface devices.zip 一套组件
💻 PAS
📖 第 1 页 / 共 5 页
字号:
    FHWnd: HWND;
    // internal worker functions
    function CheckThisOut(var HidDev: TJvHidDevice; Idx: Integer; Check: Boolean): Boolean;
    procedure EventPipe(var Msg: TMessage);
    // internal event implementors
    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);
  protected
    procedure DoArrival(HidDev: TJvHidDevice);
    procedure DoRemoval(HidDev: TJvHidDevice);
    procedure DoDeviceChange;
    function DoEnumerate(HidDev: TJvHidDevice; Idx: Integer): Boolean;
  public
    // 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;
    // just to be complete the GUID
    property HidGuid: TGUID read FHidGuid;
    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}

{$IFDEF USEJVCL}
{$IFDEF UNITVERSIONING}
const
  UnitVersioning: TUnitVersionInfo = (
    RCSfile: '$RCSfile: JvHidControllerClass.pas,v $';
    Revision: '$Revision: 1.31 $';
    Date: '$Date: 2005/09/20 10:38:13 $';
    LogPath: 'JVCL\run'
  );
{$ENDIF UNITVERSIONING}
{$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';
  RsEHIDBooleanError = 'HID Error: a boolean function failed';

{$ENDIF USEJVCL}

const
  Kernel32DllName = 'kernel32.dll';

//=== 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.CreateRes(@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 DummyReadCompletion(ErrorCode: DWORD; Count: DWORD; Ovl: POverlapped); stdcall;
begin
end;

procedure TJvHidDeviceReadThread.Execute;
var
  SleepRet: DWORD;
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, @DummyReadCompletion) 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
  inherited Create;
  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;
  inherited Destroy;
end;

function TJvHidPnPInfo.GetCompatibleIDs: TStrings;
begin
  Result := FCompatibleIDs;
end;

function TJvHidPnPInfo.GetHardwareID: TStrings;
begin
  Result := FHardwareID;
end;

function TJvHidPnPInfo.GetLowerFilters: TStrings;
begin
  Result := FLowerFilters;
end;

function TJvHidPnPInfo.GetUpperFilters: TStrings;
begin
  Result := FUpperFilters;
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..1023] of Char;
begin
  BytesReturned := 0;
  RegDataType := 0;
  Buffer[0] := #0;
  SetupDiGetDeviceRegistryPropertyA(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
  BytesReturned: DWORD;
  RegDataType: DWORD;
  Buffer: array [0..16383] of Char;
  P: PChar;
begin
  BytesReturned := 0;
  RegDataType := 0;
  Buffer[0] := #0;
  SetupDiGetDeviceRegistryPropertyA(PnPHandle, DevData, Prop,
    RegDataType, PBYTE(@Buffer[0]), SizeOf(Buffer), BytesReturned);
  Result := TStringList.Create;
  P := @Buffer[0];
  while P[0] <> #0 do
  begin
    Result.Add(P);
    P := P + StrLen(P) + 1;
  end;
end;

function TJvHidPnPInfo.GetRegistryPropertyDWord(PnPHandle: HDEVINFO;
  const DevData: TSPDevInfoData; Prop: DWORD): DWORD;
var
  BytesReturned: DWORD;
  RegDataType: DWORD;
begin
  BytesReturned := 0;
  RegDataType := 0;
  Result := 0;
  SetupDiGetDeviceRegistryProperty(PnPHandle, DevData, Prop,
    RegDataType, PBYTE(@Result), SizeOf(Result), BytesReturned);
end;

//=== { TJvHidDevice } =======================================================

// dummy constructor to catch invalid Create calls

constructor TJvHidDevice.Create;
begin
  inherited Create;
  FHidFileHandle := INVALID_HANDLE_VALUE;
  FHidOverlappedRead := INVALID_HANDLE_VALUE;
  FHidOverlappedWrite := INVALID_HANDLE_VALUE;
  raise EControllerError.CreateRes(@RsEDirectHidDeviceCreationNotAllowed);
end;

// create and fill in a HidDevice object
// the constructor is only accessible from TJvHidController
// PnPInfo contains all info the JvHidDeviceController collected
// Controller is the devices controller object to be referenced
// internally

constructor TJvHidDevice.CtlCreate(const APnPInfo: TJvHidPnPInfo; const Controller: TJvHidDeviceController);
begin
  inherited Create;

  // initialize private data
  FPnPInfo := APnPInfo;
  FMyController := Controller;
  FIsPluggedIn := True;
  FIsCheckedOut := False;
  FIsEnumerated := False;
  FHidOverlappedRead := INVALID_HANDLE_VALUE;
  FHidOverlappedWrite := INVALID_HANDLE_VALUE;
  FVendorName := '';
  FProductName := '';
  FPreparsedData := nil;
  SetLength(FPhysicalDescriptor, 0);
  FSerialNumber := '';
  FLanguageStrings := TStringList.Create;
  FNumInputBuffers := 0;
  FNumOverlappedBuffers := 0;
  SetLength(FLinkCollection, 0);

⌨️ 快捷键说明

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