在 64 位应用程序中使用 SetupAPI 枚举 USB HID 设备

发布于 2024-12-14 06:58:16 字数 2871 浏览 3 评论 0原文

我正在使用 Delphi XE2 并尝试将我们的 usb comms dll 升级到 64 位。我们使用 JVCL SetupAPI 和 Hid 单元。使用 32 位编译器一切正常,并且可以看到我连接的 HID 设备。我切换到 64 位后,再也看不到任何我所知道的已连接的 HID 设备。

我遇到过有人提到需要针对 64 位调整某些数据结构的大小(请参阅 https:// /forums.embarcadero.com/thread.jspa?messageID=408473#408473)这有帮助,但我现在正式难住了。

目前我的代码返回从 SetupDiGetDeviceInterfaceDetail 函数读取的 0 字节。注释掉的 SizeOf() 适用于 32 位,但不适用于 64 位。

任何帮助将不胜感激。

repeat
  TmpDeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceData);
  TmpDeviceInterfaceData.cbSize := 32;  // SizeOf(TmpDeviceInterfaceData);
  TmpSuccess := SetupDiEnumDeviceInterfaces(TmpDevInfo, nil, TmpDevHidGuid, TmpDevn, TmpDeviceInterfaceData);
  if TmpSuccess then
  begin
    TmpDevData.cbSize := 32; //SizeOf(TmpDevData);
    showmessage(inttostr(tmpdevdata.cbsize));
    TmpBytesReturned := 0;
    SetupDiGetDeviceInterfaceDetail(TmpDevInfo, @TmpDeviceInterfaceData, nil, 0, TmpBytesReturned, @TmpDevData);
    showmessage('bytes returned = ' + inttostr(TmpBytesReturned));
    if (TmpBytesReturned <> 0) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
    begin
      // showmessage('hello');
      TmpFunctionClassDeviceData := AllocMem(TmpBytesReturned);
      TmpFunctionClassDeviceData.cbSize := sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);

      TmpFunctionClassDeviceData.cbSize := 8;
      // showmessage(inttostr(TmpFunctionClassDeviceData.cbSize));
      if SetupDiGetDeviceInterfaceDetail(TmpDevInfo, @TmpDeviceInterfaceData, TmpFunctionClassDeviceData, TmpBytesReturned, TmpBytesReturned, @TmpDevData) then
      begin
        // showmessage('here');
        try
          begin
          //try to obtain PID and VID information about the HID devices
          TmpDeviceHandle := CreateFile(@TmpFunctionClassDeviceData.DevicePath,
                            GENERIC_READ OR GENERIC_WRITE,
                            FILE_SHARE_READ OR FILE_SHARE_WRITE,
                            NIL, OPEN_EXISTING, 0 , 0);
          TmpAttributes.Size := Sizeof(TmpAttributes);
          HidD_GetAttributes(TmpDeviceHandle, TmpAttributes);
          If (vid = TmpAttributes.VendorID) then
          begin
            PIDlistStr := PIDlistStr + Inttostr(TmpAttributes.ProductID) + ',';
          end ;


          if TmpDeviceHandle <> INVALID_HANDLE_VALUE then
           begin
            CloseHandle(TmpDeviceHandle);
            TmpAttributes.ProductID := 0;
            TmpAttributes.VendorID := 0;
           end;
          TmpDeviceHandle := INVALID_HANDLE_VALUE;
          end
        except
          // ignore device if unreadable
        end;
        Inc(TmpDevn);
      end
    else
      showmessage('error in SetupDiGetDeviceInterfaceDetails');
      FreeMem(TmpFunctionClassDeviceData);
    end;
  end;
until not TmpSuccess;

I am using Delphi XE2 and attempting to upgrade our usb comms dll to 64 bit. We're using the JVCL SetupAPI and Hid units. All works perfectly using 32 bit compiler and can see my attached HID device. I switch to 64 bit and I can no longer see any of the HID devices that I know are attached.

I have come across people mentioning the need to resize some of the data structures differently for 64 bit (see https://forums.embarcadero.com/thread.jspa?messageID=408473#408473) and this has helped but I am now officially stumped.

Currently my code is returning 0 bytes read from the SetupDiGetDeviceInterfaceDetail function. The commented out SizeOf() were working for 32 bit but not for 64 bit.

Any help would be much appreciated.

repeat
  TmpDeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceData);
  TmpDeviceInterfaceData.cbSize := 32;  // SizeOf(TmpDeviceInterfaceData);
  TmpSuccess := SetupDiEnumDeviceInterfaces(TmpDevInfo, nil, TmpDevHidGuid, TmpDevn, TmpDeviceInterfaceData);
  if TmpSuccess then
  begin
    TmpDevData.cbSize := 32; //SizeOf(TmpDevData);
    showmessage(inttostr(tmpdevdata.cbsize));
    TmpBytesReturned := 0;
    SetupDiGetDeviceInterfaceDetail(TmpDevInfo, @TmpDeviceInterfaceData, nil, 0, TmpBytesReturned, @TmpDevData);
    showmessage('bytes returned = ' + inttostr(TmpBytesReturned));
    if (TmpBytesReturned <> 0) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
    begin
      // showmessage('hello');
      TmpFunctionClassDeviceData := AllocMem(TmpBytesReturned);
      TmpFunctionClassDeviceData.cbSize := sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);

      TmpFunctionClassDeviceData.cbSize := 8;
      // showmessage(inttostr(TmpFunctionClassDeviceData.cbSize));
      if SetupDiGetDeviceInterfaceDetail(TmpDevInfo, @TmpDeviceInterfaceData, TmpFunctionClassDeviceData, TmpBytesReturned, TmpBytesReturned, @TmpDevData) then
      begin
        // showmessage('here');
        try
          begin
          //try to obtain PID and VID information about the HID devices
          TmpDeviceHandle := CreateFile(@TmpFunctionClassDeviceData.DevicePath,
                            GENERIC_READ OR GENERIC_WRITE,
                            FILE_SHARE_READ OR FILE_SHARE_WRITE,
                            NIL, OPEN_EXISTING, 0 , 0);
          TmpAttributes.Size := Sizeof(TmpAttributes);
          HidD_GetAttributes(TmpDeviceHandle, TmpAttributes);
          If (vid = TmpAttributes.VendorID) then
          begin
            PIDlistStr := PIDlistStr + Inttostr(TmpAttributes.ProductID) + ',';
          end ;


          if TmpDeviceHandle <> INVALID_HANDLE_VALUE then
           begin
            CloseHandle(TmpDeviceHandle);
            TmpAttributes.ProductID := 0;
            TmpAttributes.VendorID := 0;
           end;
          TmpDeviceHandle := INVALID_HANDLE_VALUE;
          end
        except
          // ignore device if unreadable
        end;
        Inc(TmpDevn);
      end
    else
      showmessage('error in SetupDiGetDeviceInterfaceDetails');
      FreeMem(TmpFunctionClassDeviceData);
    end;
  end;
until not TmpSuccess;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

哽咽笑 2024-12-21 06:58:17

现在更改在JVCL中,请使用最新的SVN内容。

基本上,需要修复 SetupApi,以便它使用 x64 中的“填充程序”进行对齐。

这已经过测试并且在这里运行良好。

The changes now are in the JVCL, please use the latest SVN content.

Basically, there was a need to fix SetupApi so that it uses a "filler" in x64 for alignment.

This has been tested and works well here.

情深如许 2024-12-21 06:58:17

因此,经过艰苦的努力,我已经完成了这项工作。最终的修复并不太复杂,尽管我确实必须深入研究 JVCL SetupApi 单元并更改某些结构的变量类型。

repeat
  TmpDeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceData);
  // showmessage('TSPDeviceInterfaceData: ' + inttostr(SizeOf(TSPDeviceInterfaceData)));
  TmpSuccess := SetupDiEnumDeviceInterfaces(TmpDevInfo, nil, TmpDevHidGuid, TmpDevn, TmpDeviceInterfaceData);
  if TmpSuccess then
  begin
    TmpDevData.cbSize := SizeOf(TmpDevData);
    // showmessage('TmpDevData: ' + inttostr(tmpdevdata.cbsize));
    TmpBytesReturned := 0;
    SetupDiGetDeviceInterfaceDetail(TmpDevInfo, @TmpDeviceInterfaceData, nil, 0, TmpBytesReturned, @TmpDevData);
     //showmessage('bytes returned = ' + inttostr(TmpBytesReturned));  // = 170 in 32 bit app
    inc(i);
    if (TmpBytesReturned <> 0) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
    begin
      // showmessage('i did this ' + inttostr(i) + ' times');
      TmpFunctionClassDeviceData := AllocMem(TmpBytesReturned);

      {$ifdef CPUX64}
         TmpFunctionClassDeviceData.cbSize := 8;
         // showmessage('64 bit compiler used');
      {$else}
         TmpFunctionClassDeviceData.cbSize := 6;
         // showmessage('32 bit compiler used');
      {$endif}

      // showmessage('TmpFunctionClassDeviceData:' + inttostr(sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A)));
      if SetupDiGetDeviceInterfaceDetail(TmpDevInfo, @TmpDeviceInterfaceData, TmpFunctionClassDeviceData, TmpBytesReturned, TmpBytesReturned, @TmpDevData) then
      begin
        try
          begin
          //try to obtain PID and VID information about the HID devices

          s := '';
          for i := 0 to 999 do
           begin
             s := s + TmpFunctionClassDeviceData.DevicePath[i];
           end;

          TmpDeviceHandle := CreateFile(PChar(s),
                            GENERIC_READ OR GENERIC_WRITE,
                            FILE_SHARE_READ OR FILE_SHARE_WRITE,
                            0, OPEN_EXISTING, 0 , 0);

          TmpAttributes.Size := Sizeof(TmpAttributes);
          // showmessage('TmpAttributes: ' + inttostr(Sizeof(TmpAttributes)));

          HidD_GetAttributes(TmpDeviceHandle, TmpAttributes);

          // showmessage(inttostr(TmpAttributes.VendorID) + ' ; ' + inttostr(TmpAttributes.ProductID));

          If (vid = TmpAttributes.VendorID) then
          begin
            PIDlistStr := PIDlistStr + Inttostr(TmpAttributes.ProductID) + ',';
          end ;

          if TmpDeviceHandle <> INVALID_HANDLE_VALUE then
           begin
            CloseHandle(TmpDeviceHandle);
            TmpAttributes.ProductID := 0;
            TmpAttributes.VendorID := 0;
           end;
          TmpDeviceHandle := INVALID_HANDLE_VALUE;
          end
        except
          // ignore device if unreadable
        end;
        Inc(TmpDevn);
      end;
    //else
      //showmessage('bob ' + inttostr(GetLastError));
      FreeMem(TmpFunctionClassDeviceData);
    end;
  end;
until not TmpSuccess;

有关对 SetupAPI.pas 的更改,请参阅我的 jedi 问题跟踪器条目:http:// issuestracker.delphi-jedi.org/view.php?id=5706

如果有人可以告诉我为什么在传递给 CreateFile 之前需要将 DevicePath 显式复制到本地字符串中,或​​者为什么我不能使用SizeOf 为 TmpFunctionClassDeviceData.cbSize,我将非常感激。

So, after much hard work I have got this working. The eventual fix is not overly complicated, although I did have to delve in to the JVCL SetupApi unit and change some structure's variable types.

repeat
  TmpDeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceData);
  // showmessage('TSPDeviceInterfaceData: ' + inttostr(SizeOf(TSPDeviceInterfaceData)));
  TmpSuccess := SetupDiEnumDeviceInterfaces(TmpDevInfo, nil, TmpDevHidGuid, TmpDevn, TmpDeviceInterfaceData);
  if TmpSuccess then
  begin
    TmpDevData.cbSize := SizeOf(TmpDevData);
    // showmessage('TmpDevData: ' + inttostr(tmpdevdata.cbsize));
    TmpBytesReturned := 0;
    SetupDiGetDeviceInterfaceDetail(TmpDevInfo, @TmpDeviceInterfaceData, nil, 0, TmpBytesReturned, @TmpDevData);
     //showmessage('bytes returned = ' + inttostr(TmpBytesReturned));  // = 170 in 32 bit app
    inc(i);
    if (TmpBytesReturned <> 0) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
    begin
      // showmessage('i did this ' + inttostr(i) + ' times');
      TmpFunctionClassDeviceData := AllocMem(TmpBytesReturned);

      {$ifdef CPUX64}
         TmpFunctionClassDeviceData.cbSize := 8;
         // showmessage('64 bit compiler used');
      {$else}
         TmpFunctionClassDeviceData.cbSize := 6;
         // showmessage('32 bit compiler used');
      {$endif}

      // showmessage('TmpFunctionClassDeviceData:' + inttostr(sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A)));
      if SetupDiGetDeviceInterfaceDetail(TmpDevInfo, @TmpDeviceInterfaceData, TmpFunctionClassDeviceData, TmpBytesReturned, TmpBytesReturned, @TmpDevData) then
      begin
        try
          begin
          //try to obtain PID and VID information about the HID devices

          s := '';
          for i := 0 to 999 do
           begin
             s := s + TmpFunctionClassDeviceData.DevicePath[i];
           end;

          TmpDeviceHandle := CreateFile(PChar(s),
                            GENERIC_READ OR GENERIC_WRITE,
                            FILE_SHARE_READ OR FILE_SHARE_WRITE,
                            0, OPEN_EXISTING, 0 , 0);

          TmpAttributes.Size := Sizeof(TmpAttributes);
          // showmessage('TmpAttributes: ' + inttostr(Sizeof(TmpAttributes)));

          HidD_GetAttributes(TmpDeviceHandle, TmpAttributes);

          // showmessage(inttostr(TmpAttributes.VendorID) + ' ; ' + inttostr(TmpAttributes.ProductID));

          If (vid = TmpAttributes.VendorID) then
          begin
            PIDlistStr := PIDlistStr + Inttostr(TmpAttributes.ProductID) + ',';
          end ;

          if TmpDeviceHandle <> INVALID_HANDLE_VALUE then
           begin
            CloseHandle(TmpDeviceHandle);
            TmpAttributes.ProductID := 0;
            TmpAttributes.VendorID := 0;
           end;
          TmpDeviceHandle := INVALID_HANDLE_VALUE;
          end
        except
          // ignore device if unreadable
        end;
        Inc(TmpDevn);
      end;
    //else
      //showmessage('bob ' + inttostr(GetLastError));
      FreeMem(TmpFunctionClassDeviceData);
    end;
  end;
until not TmpSuccess;

For the changes to SetupAPI.pas see my jedi issue tracker entry here: http://issuetracker.delphi-jedi.org/view.php?id=5706

If anyone can tell me why the DevicePath needs to be explicitly copied in to a local string before being passed to CreateFile, or why I can't use SizeOf for TmpFunctionClassDeviceData.cbSize, I would be much obliged.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文