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