2011-11-08 3 views
5

J'utilise Delphi XE2 et tente de mettre à niveau notre interface de communication USB vers 64 bits. Nous utilisons les unités SetupAPI et Hid de JVCL. Tout fonctionne parfaitement en utilisant le compilateur 32 bits et peut voir mon périphérique HID attaché. Je passe à 64 bits et je ne peux plus voir aucun des dispositifs HID que je connais sont attachés.Énumération des périphériques HID USB à l'aide de SetupAPI dans l'application 64 bits

J'ai rencontré des personnes mentionnant le besoin de redimensionner différemment certaines structures de données pour 64 bits (voir https://forums.embarcadero.com/thread.jspa?messageID=408473#408473) et cela a aidé mais je suis maintenant officiellement perplexe.

Actuellement, mon code retourne 0 octets lus à partir de la fonction SetupDiGetDeviceInterfaceDetail. Les mis en commentaire SizeOf() travaillaient pour 32 bits mais pas pour 64 bits.

Toute aide serait grandement appréciée.

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; 

Répondre

0

Les changements sont maintenant dans la JVCL, veuillez utiliser le dernier contenu SVN.

Fondamentalement, il était nécessaire de réparer SetupApi afin qu'il utilise un "remplissage" en x64 pour l'alignement.

Cela a été testé et fonctionne bien ici.

0

Donc, après beaucoup de travail acharné, j'ai ce travail. Le correctif final n'est pas trop compliqué, bien que je devais me plonger dans l'unité SetupApi de JVCL et modifier les types de variables de certaines structures.

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; 

Pour que les modifications SetupAPI.pas voir mon entrée jedi numéro de suivi ici: http://issuetracker.delphi-jedi.org/view.php?id=5706

Si quelqu'un peut me dire pourquoi le DevicePath doit être copié explicitement dans une chaîne locale avant d'être passé à CreateFile , ou pourquoi je ne peux pas utiliser SizeOf pour TmpFunctionClassDeviceData.cbSize, je serais très obligé.

+0

> pourquoi le DevicePath doit être explicitement copié comme ms dit ici: http://msdn.microsoft.com/en-us/library/windows/hardware/ff552343%28v=vs.85%29 .aspx > DevicePath > Chaîne à terminaison NULL contenant le chemin de l'interface du périphérique. Ce chemin peut être transmis à des fonctions Win32 telles que CreateFile. szDevicePath: = PChar (@ TmpFunctionClassDeviceData.DevicePath [0]); utilisez cette valeur pour passer à CreateFile. –

Questions connexes