Перечисление USB HID-устройств с использованием SetupAPI в 64-битном приложении - PullRequest
5 голосов
/ 08 ноября 2011

Я использую Delphi XE2 и пытаюсь обновить нашу usb-связь dll до 64 бит. Мы используем JVCL SetupAPI и Hid. Все работает отлично, используя 32-битный компилятор и может видеть мое подключенное устройство HID. Я переключаюсь на 64-разрядную версию и больше не вижу ни одного устройства HID, которое, как я знаю, подключено.

Я сталкивался с людьми, которые упоминали о необходимости изменить размер некоторых структур данных по-разному для 64-битных систем (см. https://forums.embarcadero.com/thread.jspa?messageID=408473#408473), и это помогло, но я теперь официально озадачен.

В настоящее время мой код возвращает 0 байтов, считанных из функции SetupDiGetDeviceInterfaceDetail. Закомментированный 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;

Ответы [ 2 ]

0 голосов
/ 13 июня 2012

Изменения внесены в JVCL, используйте последний SVN-контент.

По сути, необходимо было исправить SetupApi, чтобы он использовал «заполнитель» в x64 для выравнивания.

Это было проверено и хорошо работает здесь.

0 голосов
/ 10 ноября 2011

Итак, после большой кропотливой работы я получил эту работу.Возможное исправление не слишком сложное, хотя мне пришлось углубиться в модуль 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

Если кто-нибудь может сказать мне, почему DevicePath необходимо явно скопировать в локальную строку перед передачей в CreateFile, или почему я не могу использовать SizeOf для TmpFunctionClassDeviceData.cbSize, я был бы очень признателен.

...