2011-11-08 126 views
5

我正在使用Delphi XE2並嘗試將我們的USB通信DLL升級到64位。我們正在使用JVCL SetupAPI和Hid單元。所有的作品完美的使用32位編譯器,並可以看到我附加的HID設備。我切換到64位,我不能再看到我知道連接的任何HID設備。在64位應用程序中使用SetupAPI枚舉USB 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; 

回答

0

現在的變化是在JVCL中,請使用最新的SVN內容。

基本上,有必要修復SetupApi,以便它使用x64中的「填充符」進行對齊。

這已經過測試,在這裏效果很好。

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

如果有人能告訴我爲什麼的DevicePath需要被傳遞到的CreateFile前到當地字符串複製明確,或者爲什麼我不能使用SizeOf作爲TmpFunctionClassDeviceData.cbSize,我會非常感激。

+0

>爲什麼DevicePath中需要顯式地複製 爲女士說,在這裏: http://msdn.microsoft.com/en-us/library/windows/hardware/ff552343%28v=vs.85%29 .aspx > DevicePath >包含設備接口路徑的以NULL結尾的字符串。此路徑可以傳遞給Win32函數,如CreateFile。 szDevicePath:= PChar(@TmpFunctionClassDeviceData.DevicePath [0]); 使用該值傳遞給CreateFile。 –