📄 jvhidcontrollerclass.pas
字号:
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 + -