2010-09-21 5 views
3

J'ai une application Windows qui exécute une routine simple pour déterminer si un jeton USB est présent. La méthode a toujours fonctionné correctement sur les machines 32 bits, mais lors des tests sur une machine 64 bits, nous avons commencé à voir des résultats inattendus.Taille de la structure, vérifiez si 64 bits ou 32 bits

J'appelle la méthode suivante

[StructLayout(LayoutKind.Sequential)] 
internal struct SP_DEVINFO_DATA 
{ 
    public Int32 cbSize; 
    public Guid ClassGuid; 
    public Int32 DevInst; 
    public UIntPtr Reserved; 
}; 

[DllImport("setupapi.dll")] 
internal static extern Int32 SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, Int32 MemberIndex, ref SP_DEVINFO_DATA DeviceInterfaceData); 

La documentation de la structure SP_DEVINFO_DATA nous dit que le cbSize est la taille, en octets, de la structure de SP_DEVINFO_DATA.

Si nous calculons cbSize pour une machine 32 bits, ce sera 28 et 32 ​​pour une machine 64 bits.

J'ai testé cela sur les deux machines en recompilant avec différentes valeurs cbSize, ce que je veux savoir, c'est comment puis-je calculer cela comme runtime? Mon application doit fonctionner sur les deux architectures.

internal static Int32 GetDeviceInfoData(Int32 iMemberIndex) 
{ 
    _deviceInfoData = new Win32DeviceMgmt.SP_DEVINFO_DATA 
    { 
     cbSize = ?? // 28 When 32-Bit, 32 When 64-Bit, 
     ClassGuid = Guid.Empty, 
     DevInst = 0, 
     Reserved = UIntPtr.Zero 
    }; 

    return Win32DeviceMgmt.SetupDiEnumDeviceInfo(_deviceInfoSet, iMemberIndex, ref _deviceInfoData); 
} 

Merci

Rohan

Répondre

9

Utilisation Marshal.SizeOf:

_deviceInfoData = new Win32DeviceMgmt.SP_DEVINFO_DATA 
    { 
     cbSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(Win32DeviceMgmt.SP_DEVINFO_DATA); 
     // etc.. 
    } 
+0

Hans, cela résout le problème de savoir comment passer dans la taille réelle, donc je suis upvoting. Cependant, je suis toujours un peu préoccupé par l'emballage. Aucun point passant la taille réelle quand c'est faux. –

+1

@Steven - Si le tassement est incorrect, régler cbSize sur une valeur constante est en fait une très mauvaise chose à faire. Cela ne permettra pas à l'API de détecter que vous vous êtes trompé et de signaler une bonne erreur. Il va juste échouer au hasard car il va lire les ordures. –

+0

@Hans - Cheers, fonctionne très bien! –

0

On dirait un problème d'alignement.

Essayez de définir la propriété Pack.

modifier

Je l'ai cherché: http://www.pinvoke.net/default.aspx/Structures/SP_DEVINFO_DATA.html

Il dit:

Sur les plateformes 32bits, toutes les structures SetupAPI sont emballés 1 octet. Sur les plates-formes 64 bits , les structures SetupApi sont sur 8 octets. IE pour 32 bits SP_DEVINFO_DATA.cbSize = 28, pour 64Bit SP_DEVINFO_DATA.cbSize = (28 + 4) = 32.SP_DEVINFO_DATA.cbSize = (28 + 4) = 32.

+0

J'ai essayé cette propriété mais cela n'a pas fonctionné. Si vous regardez la documentation de la structure SP_DEVINFO_DATA, vous devez spécifier cbSize comme taille de la structure. –

1

La taille des IntPtr changements sur 32 et 64 Essayez

cbsize = IntPtr.Size == 4 ? 28 : 32 

EDIT: Correction être IntPtr.Size, mais je l'aime Hans' mieux System.Runtime.InteropServices.Marshal.SizeOf(typeof(Win32DeviceMgmt.SP_DEVINFO_DATA); car il n'y a pas de chiffres magiques. Je ne savais pas que c'était là.

+0

Salut, je me rends compte que la taille des changements IntPtr, pensez-vous que cette méthode est la meilleure pratique? –

+0

Son IntPtr.Size –

1

Pourquoi ne pas Environment.Is64BitOperatingSystem ou Environment.Is64BitProcess.

+0

Contrairement à IntPtr.Size, ceux-ci se casseront lorsque nous aurons des processus 128 bits et 256 bits. –

+1

@Steven: Nous aurons 'Environment.Is128BitOperatingSystem' ou même' int Environment.GetOSBits() 'à ce moment-là. –

+0

Oui, et le code ne saura pas les appeler, donc il va se casser. D'un autre côté, s'il appelle IntPtr.Size et utilise la valeur, il ne se casse pas. –

Questions connexes