Search code examples
delphi64-bitusbhidjvcl

Enumerating USB HID Devices using SetupAPI in 64 bit app


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;

Solution

  • 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.