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

Delphi 在64位应用程序中使用SetupAPI枚举USB HID设备,delphi,64-bit,usb,hid,jvcl,Delphi,64 Bit,Usb,Hid,Jvcl,我正在使用Delphi XE2并尝试将usb通信dll升级到64位。我们正在使用JVCL SetupAPI和Hid单元。使用32位编译器,所有这些都可以完美地工作,并且可以看到我连接的HID设备。我切换到64位,我再也看不到我知道连接的任何HID设备 我遇到过一些人提到需要以不同的方式调整某些数据结构的大小,使其达到64位(请参阅),这对我有所帮助,但我现在被官方难倒了 当前,我的代码返回从SetupDiGetDeviceInterfaceDetail函数读取的0字节。注释掉的SizeOf()适

我正在使用Delphi XE2并尝试将usb通信dll升级到64位。我们正在使用JVCL SetupAPI和Hid单元。使用32位编译器,所有这些都可以完美地工作,并且可以看到我连接的HID设备。我切换到64位,我再也看不到我知道连接的任何HID设备

我遇到过一些人提到需要以不同的方式调整某些数据结构的大小,使其达到64位(请参阅),这对我有所帮助,但我现在被官方难倒了

当前,我的代码返回从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;
重复
TmpDeviceInterfaceData.cbSize:=SizeOf(TSPDeviceInterfaceData);
TmpDeviceInterfaceData.cbSize:=32;//SizeOf(TmpDeviceInterfaceData);
tmpsucess:=setupDienumDeviceInterface(TmpDevInfo、nil、TmpDevHidGuid、TmpDevn、TmpDeviceInterfaceData);
如果TMPSUCESS,则
开始
TmpDevData.cbSize:=32//SizeOf(TmpDevData);
showmessage(inttostr(tmpdevdata.cbsize));
tmpBytes返回值:=0;
SetupDiGetDeviceInterfaceDetail(TmpDevInfo、@TmpDeviceInterfaceData、nil、0、tmpBytes返回、@TmpDevData);
showmessage('bytes returned='+inttostr(TmpBytesReturned));
如果(tmpBytes返回0)和(GetLastError=ERROR\u缓冲区不足),则
开始
//showmessage(“你好”);
TmpFunctionClassDeviceData:=AllocMem(tmpBytes返回);
TmpFunctionClassDeviceData.cbSize:=sizeof(SP_设备_接口_细节_数据_A);
TmpFunctionClassDeviceData.cbSize:=8;
//showmessage(inttostr(TmpFunctionClassDeviceData.cbSize));
如果SetupDiGetDeviceInterfaceDetail(TmpDevInfo、@TmpDeviceInterfaceData、TmpFunctionClassDeviceData、TMPBytesReturn、TMPBytesReturn、@TmpDevData),则
开始
//showmessage(“此处”);
尝试
开始
//尝试获取有关HID设备的PID和VID信息
TmpDeviceHandle:=CreateFile(@TmpFunctionClassDeviceData.DevicePath,
一般读取或一般写入,
文件共享读取或文件共享写入,
零,开放的,0,0);
TmpAttributes.Size:=Sizeof(TmpAttributes);
HidD_GetAttributes(TmpDeviceHandle、TmpAttributes);
如果(vid=TmpAttributes.VendorID),则
开始
PIDlistStr:=PIDlistStr+Inttostr(TmpAttributes.ProductID)+',';
结束;
如果TmpDeviceHandle的值无效,则
开始
CloseHandle(TmpDeviceHandle);
TmpAttributes.ProductID:=0;
TmpAttributes.VendorID:=0;
结束;
TmpDeviceHandle:=无效的\u句柄\u值;
结束
除了
//如果无法读取,则忽略设备
结束;
公司(TmpDevn);
结束
其他的
showmessage('SetupDiGetDeviceInterfaceDetails中的错误');
FreeMem(TmpFunctionClassDeviceData);
结束;
结束;
直到TMPSUCESS不成功;

所以,经过大量的努力,我已经完成了这项工作。最终的修复并不太复杂,尽管我必须深入研究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;
重复
TmpDeviceInterfaceData.cbSize:=SizeOf(TSPDeviceInterfaceData);
//showmessage('TSPDeviceInterfaceData:'+inttostr(SizeOf(TSPDeviceInterfaceData)));
tmpsucess:=setupDienumDeviceInterface(TmpDevInfo、nil、TmpDevHidGuid、TmpDevn、TmpDeviceInterfaceData);
如果TMPSUCESS,则
开始
TmpDevData.cbSize:=SizeOf(TmpDevData);
//showmessage('TmpDevData:'+inttostr(TmpDevData.cbsize));
tmpBytes返回值:=0;
SetupDiGetDeviceInterfaceDetail(TmpDevInfo、@TmpDeviceInterfaceData、nil、0、tmpBytes返回、@TmpDevData);
//showmessage('bytes returned='+inttostr(TmpBytesReturned));//=32位应用程序中的170
公司(一);
如果(tmpBytes返回0)和(GetLastError=ERROR\u缓冲区不足),则
开始
//showmessage(‘我做了这个’+inttostr(i)+‘次’);
TmpFunctionClassDeviceData:=AllocMem(tmpBytes返回);
{$ifdef CPUX64}
TmpFunctionClassDeviceData.cbSize:=8;
//showmessage(“使用64位编译器”);
{$else}
TmpFunctionClassDeviceData.cbSize:=6;
//showmessage(“使用了32位编译器”);
{$endif}
//showmessage('TmpFunctionClassDeviceData:'+inttostr(大小(SP_设备_接口_细节_数据_A));
如果SetupDiGetDeviceInterfaceDetail(TmpDevInfo、@TmpDeviceInterfaceData、TmpFunctionClassDeviceData、TMPBytesReturn、TMPBytesReturn、@TmpDevData),则
开始
尝试
开始
//尝试获取有关HID设备的PID和VID信息
s:='';
对于i:=0到999 do
开始
s:=s+TmpFunctionClassDeviceData.DevicePath[i];
结束;
TmpDeviceHandle:=创建文件(PChar),
一般读取或一般写入,
文件共享读取或文件共享写入,
0,打开现有的,0,0);
TmpAttributes.Size:=Sizeof(TmpAttributes);
//showmessage('TmpAttributes:'+inttostr(Sizeof(TmpAttributes)));
HidD_GetAttributes(TmpDeviceHandle、TmpAttributes);
//showmessage(inttostr(TmpAttributes.VendorID)+';'+inttostr(TmpAttributes.ProductID));
如果(vid=TmpAttributes.VendorID),则
开始
PIDlistStr:=PIDlistStr+Inttostr(TmpAttributes.ProductID)+',';
结束;
如果TmpDeviceHandle的值无效,则
开始
CloseHandle(TmpDeviceHandle);
TmpAttributes.ProductID:=0;
TmpAttributes.VendorID:=0;
结束;
TmpDeviceHandle:=无效的\u句柄\u值;
结束
除了
//如果无法读取,则忽略设备