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

📄 hidcontrollerclass.pas

📁 Componente para Tratar USB
💻 PAS
📖 第 1 页 / 共 4 页
字号:

  FHidFileHandle := CreateFile(PChar(FDevicePath), GENERIC_READ or GENERIC_WRITE,
    FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
  if HidFileHandle = INVALID_HANDLE_VALUE then
    FHidFileHandle := CreateFile(PChar(FDevicePath), 0,
      FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
  if HidFileHandle <> INVALID_HANDLE_VALUE then
  begin
    // get all device data through HID functions
    // this eliminates the need to redeclare them as methods
    FDeviceID := DevID;
    FRegDescr := DevDesc;
    FRegClass := ClassDesc;
    FAttributes.Size := SizeOf(THIDDAttributes);
    HidD_GetPreparsedData(HidFileHandle, FPreparsedData);
    HidD_GetAttributes   (HidFileHandle, FAttributes);
    FConfiguration.cookie         := nil;
    FConfiguration.size           := 0;
    FConfiguration.RingBufferSize := 0;
    HidD_GetConfiguration(HidFileHandle, FConfiguration, SizeOf(THIDDConfiguration));
    HidP_GetCaps(FPreparsedData, FCaps);
    // calculate length of StringDescriptor 0
    FillChar(IDs, SizeOf(IDs), #0);
    Len := 0;
    for I := 0 to 256 do
    begin
      if HidD_GetIndexedString(HidFileHandle, 0, PWideChar(@IDs), I*SizeOf(WORD)) then
        Break;
      Inc(Len);
    end;
    // transform id into localized language name
    for I := 0 to Len - 1 do
    begin
      Name[0] := #0;
      if GetLocaleInfo(WORD(IDs[I]), LOCALE_SLANGUAGE, Name, SizeOf(Name)) <> 0 then
        FLanguageStrings.Add(Name)
      else
        FLanguageStrings.Add(Format('unknown Locale ID $%.4x',[WORD(IDs[I])]));
    end;
    if HidD_GetManufacturerString(HidFileHandle, Buffer, SizeOf(Buffer)) then
      FVendorName := WideCharToString(Buffer);
    if HidD_GetProductString(HidFileHandle, Buffer, SizeOf(Buffer)) then
      FProductName := WideCharToString(Buffer);
    if HidD_GetPhysicalDescriptor(HidFileHandle, Buffer, SizeOf(Buffer)) then
      FPhysicalDescriptor := WideCharToString(Buffer);
    // compensate for buggy function
    if HidD_GetSerialNumberString(HidFileHandle, Buffer, SizeOf(Buffer)) then
      for I := 0 to Len - 1 do
        if IDs[I] <> WORD(Buffer[I]) then
        begin
          FSerialNumber := WideCharToString(Buffer);
          Break;
        end;
    Len := FCaps.NumberLinkCollectionNodes;
    SetLength(FLinkCollection, Len);
    HidP_GetLinkCollectionNodes(@FLinkCollection[0], Len, FPreparsedData);
  end;
  // the file is closed to stop using up resources
  CloseFile;
end;

// If a TJvHidDevice is destroyed the TJvHidController has to be informed.
// If the device is plugged in this TJvHidDevice instance is destroyed,
// but another instance is created in the controller list

destructor TJvHidDevice.Destroy;
var
  I: Integer;
begin
  // to prevent strange problems
  OnUnplug := nil;
  // free the data which needs special handling
  CloseFile;
  CloseFileEx;
  HidD_FreePreparsedData(FPreparsedData);
  FLanguageStrings.Free;

  // if controller exists
  if FMyController <> nil then
    with FMyController do
    begin
      // delete device from controller list
      for I := 0 to FList.Count - 1 do
        if FList.Items[I] = Self then
        begin
          // if device is plugged in create a checked in copy
          if IsPluggedIn then
          begin
            FList.Items[I] := TJvHidDevice.Create(DevicePath, DeviceID,
              RegDescr, RegClass, FMyController);
            if IsCheckedOut then
            begin
              Dec(FNumCheckedOutDevices);
              Inc(FNumCheckedInDevices);
            end;
          end
          else
          begin
            FList.Delete(I);
            Dec(FNumUnpluggedDevices);
          end;
          Break;
        end;
    end;

  inherited Destroy;
end;

// if check changes change check only here

function TJvHidDevice.IsAccessible: Boolean;
begin
  Result := IsPluggedIn and (IsCheckedOut or FIsEnumerated);
end;

// open the device "file" (for the other methods)

function TJvHidDevice.OpenFile: Boolean;
begin
  // check if open allowed (propagates this state)
  if IsAccessible then
    if HidFileHandle = INVALID_HANDLE_VALUE then // if not already opened
    begin
      FNumInputBuffers := 0;
      FHidFileHandle   := CreateFile(PChar(FDevicePath), GENERIC_READ or GENERIC_WRITE,
        FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
      if HidFileHandle <> INVALID_HANDLE_VALUE then
        HidD_GetNumInputBuffers(HidFileHandle, FNumInputBuffers);
    end;
  Result := HidFileHandle <> INVALID_HANDLE_VALUE;
end;

// open second device "file" for ReadFileEx and WriteFileEx

function TJvHidDevice.OpenFileEx: Boolean;
begin
  // check if open allowed (propagates this state)
  if IsAccessible then
    if HidOverlappedHandle = INVALID_HANDLE_VALUE then // if not already opened
    begin
      FNumOverlappedBuffers := 0;
      FHidOverlappedHandle := CreateFile(PChar(FDevicePath), GENERIC_READ or GENERIC_WRITE,
        FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
      if FHidOverlappedHandle <> INVALID_HANDLE_VALUE then
        HidD_GetNumInputBuffers(FHidOverlappedHandle, FNumOverlappedBuffers);
    end;
  Result := FHidOverlappedHandle <> INVALID_HANDLE_VALUE;
end;

// implement OnUnplug event

procedure TJvHidDevice.DoUnplug;
begin
  CloseFile;
  CloseFileEx;
  FIsPluggedIn := False;
  // event even for checked in devices
  if Assigned(FUnplug) then
    FUnplug(Self);
  // guarantees that event is only called once
  OnUnplug := nil;
end;

// assign the OnUnplug event

procedure TJvHidDevice.SetUnplug(const Event: TJvHidUnplugEvent);
begin
  if @Event <> @FUnplug then
    FUnplug := Event;
end;

// implementing indexed properties read

function TJvHidDevice.GetDeviceString(Idx: Byte): string;
var
  Buffer: array [0..256] of WideChar;
begin
  Result := '';
  if Idx <> 0 then
    if OpenFile then
      if HidD_GetIndexedString(HidFileHandle, Idx, Buffer, SizeOf(Buffer)) then
        Result := WideCharToString(Buffer);
end;

function TJvHidDevice.GetLinkCollectionNode(Idx: WORD): THIDPLinkCollectionNode;
begin
  FillChar(Result, SizeOf(THIDPLinkCollectionNode), #0);
  if (Idx > 0) and (Idx <= Length(FLinkCollection)) then
    Result := FLinkCollection[Idx-1];
end;

// implementing properties write

procedure TJvHidDevice.SetNumInputBuffers(const Num: Integer);
begin
  if OpenFile then
  begin
    HidD_SetNumInputBuffers(HidFileHandle, Num);
    HidD_GetNumInputBuffers(HidFileHandle, FNumInputBuffers);
  end;
end;

procedure TJvHidDevice.SetNumOverlappedBuffers(const Num: Integer);
begin
  if OpenFileEx then
  begin
    HidD_SetNumInputBuffers(HidOverlappedHandle, Num);
    HidD_GetNumInputBuffers(HidOverlappedHandle, FNumOverlappedBuffers);
  end;
end;

// internal helper for the following functions

procedure TJvHidDevice.GetMax;
begin
  if IsAccessible then
  begin
    FMaxDataListLength   := HidP_MaxDataListLength  (ReportTypeParam, PreparsedData);
    FMaxUsageListLength  := HidP_MaxUsageListLength (ReportTypeParam, UsagePageParam, PreparsedData);
    FMaxButtonListLength := HidP_MaxButtonListLength(ReportTypeParam, UsagePageParam, PreparsedData);
  end;
end;

procedure TJvHidDevice.SetReportTypeParam(const ReportType: THIDPReportType);
begin
  FReportTypeParam := ReportType;
  GetMax;
end;

procedure TJvHidDevice.SetUsagePageParam(const UsagePage: TUsage);
begin
  FUsagePageParam := UsagePage;
  GetMax;
end;

procedure TJvHidDevice.SetConfiguration(Config: THIDDConfiguration);
begin
  if OpenFile then
    if HidD_SetConfiguration(HidFileHandle, Config, SizeOf(THIDDConfiguration)) then
      FConfiguration := Config;
end;

//-- TJvHidDevice methods -----------------------------------------------

// generally the parameter count of the methods is reduced with the Param properties
// first assign the Param properties the desired value then call a method
// normally you will address the same Usage, UsagePage, ReportType or LinkCollection
// with more than one method
//
// the methods will open the device file when needed
// this file is not closed until unplug or destruction to speed up access

// close the device "file"
// if you want to open the file directly close this
// to get undisturbed access

procedure TJvHidDevice.CloseFile;
begin
   if HidFileHandle <> INVALID_HANDLE_VALUE then
      CloseHandle(HidFileHandle);
   FNumInputBuffers := 0;
   FHidFileHandle   := INVALID_HANDLE_VALUE;
end;

// same for the other device "file"

procedure TJvHidDevice.CloseFileEx;
begin
   if HidOverlappedHandle <> INVALID_HANDLE_VALUE then
      CloseHandle(HidOverlappedHandle);
   FNumOverlappedBuffers := 0;
   FHidOverlappedHandle  := INVALID_HANDLE_VALUE;
end;

// all the methods which directly map to a HID-function

function TJvHidDevice.FlushQueue: Boolean;
begin
  Result := False;
  if OpenFile then
    Result := HidD_FlushQueue(HidFileHandle);
end;

function TJvHidDevice.GetFeature(var Report; const Size: Integer): Boolean;
begin
  Result := False;
  if OpenFile then
    Result := HidD_GetFeature(HidFileHandle, Report, Size);
end;

function TJvHidDevice.SetFeature(var Report; const Size: Integer): Boolean;
begin
  Result := False;
  if OpenFile then
    Result := HidD_SetFeature(HidFileHandle, Report, Size);
end;

function TJvHidDevice.GetSpecificButtonCaps(ButtonCaps: PHIDPButtonCaps; var Count: WORD): NTSTATUS;
begin
  Result := HIDP_STATUS_NULL;  // for not plugged in
  if IsAccessible then
    Result := HidP_GetSpecificButtonCaps(ReportTypeParam, UsagePageParam, LinkCollectionParam, UsageParam, ButtonCaps, Count, PreparsedData);
end;

function TJvHidDevice.GetButtonCaps(ButtonCaps: PHIDPButtonCaps; var Count: WORD): NTSTATUS;
begin
  Result := HIDP_STATUS_NULL;  // for not plugged in
  if IsAccessible then
    Result := HidP_GetButtonCaps(ReportTypeParam, ButtonCaps, Count, PreparsedData);
end;

function TJvHidDevice.GetSpecificValueCaps(ValueCaps: PHIDPValueCaps; var Count: WORD): NTSTATUS;
begin
  Result := HIDP_STATUS_NULL;  // for not plugged in
  if IsAccessible then
    Result := HidP_GetSpecificValueCaps(ReportTypeParam, UsagePageParam, LinkCollectionParam, UsageParam, ValueCaps, Count, PreparsedData);
end;

function TJvHidDevice.GetValueCaps(ValueCaps: PHIDPValueCaps; var Count: WORD): NTSTATUS;
begin
  Result := HIDP_STATUS_NULL;  // for not plugged in
  if IsAccessible then
    Result := HidP_GetValueCaps(ReportTypeParam, ValueCaps, Count, PreparsedData);
end;

function TJvHidDevice.GetData(DataList: PHIDPData; var DataLength: ULONG; var Report; ReportLength: ULONG): NTSTATUS;
begin
  Result := HIDP_STATUS_NULL;  // for not plugged in
  if IsAccessible then
    Result := HidP_GetData(ReportTypeParam, DataList, DataLength, PreparsedData, Report, ReportLength);
end;

function TJvHidDevice.SetData(DataList: PHIDPData; var DataLength: ULONG; var Report; ReportLength: ULONG): NTSTATUS;

⌨️ 快捷键说明

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