5

我正在使用 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;
4

2 回答 2

0

所以,经过艰苦的工作,我得到了这个工作。最终的修复并不过分复杂,尽管我确实必须深入研究 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 的更改,请参阅我的绝地问题跟踪器条目:http: //issuetracker.delphi-jedi.org/view.php ?id=5706

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

于 2011-11-10T15:29:24.250 回答
0

现在改动的是JVCL,请使用最新的SVN内容。

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

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

于 2012-06-13T14:22:16.297 回答