Question Manière correcte de rassembler SIZE_T *?


J'ai la définition de fonction C ++ suivante, que j'essaye d'appeler via PInvoke à partir du code managé:

bool FooBar(SIZE_T* arg1);

Ma déclaration gérée ressemblait à ceci:

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref uint arg1);

Certains d'entre vous ont peut-être remarqué le même bug que j'ai finalement fait. Ce n'est pas portable 64 bits. SIZE_T est de taille variable (32-64 bits) comme le fait le pointeur. Sur la taille gérée, le pointeur se traduit correctement en 64 bits, mais ce n’est pas le cas, et vous pouvez vous retrouver avec une corbeille dans les bits supérieurs de arg1. C'était une erreur particulièrement persistante puisque la corbeille était souvent juste des zéros :(

La seule solution que j'ai mise au travail est la déclaration gérée suivante:

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref IntPtr arg1);

Cela fonctionne bien sûr car IntPtr peut modifier sa taille correctement. Dans mon code, je traite simplement IntPtr comme un entier et cela fonctionne, même si cela ressemble à un hack moche. Il me semble qu'il devrait y avoir un moyen de spécifier ceci correctement, peut-être en utilisant UnmanagedType.SysUInt, mais je n'ai pas pu trouver d'autre solution de travail.


16
2017-08-21 00:13


origine


Réponses:


En utilisant IntPtr et / ou UIntPtr  est le faire correctement - les types sont là spécifiquement pour cela! Je ne comprends pas pourquoi vous le considérez comme un "hack laid". Je ne suis pas sûr non plus de votre alternative proposée - tout type d’attribut permettant de mapper les valeurs sur uint serait intrinsèquement mal, car C # uint est garanti 32 bits, quelle que soit l’architecture, et donc, sur une plate-forme 64 bits, pour qu’elle soit correctement configurée, elle doit en couper la moitié, perdre des données et rendre le résultat inutilisable.


19
2017-08-21 00:19



UIntPtr est le type correct à utiliser.

size_t est un entier non signé de la taille d'un pointeur et c'est exactement ce que signifie UIntPtr. Le "ptr" dans le nom peut être un peu déroutant, je suis d'accord. Cela ne signifie pas réellement "ceci est un pointeur", cela signifie "ceci est un pointeur entier ". Donc votre déclaration serait:

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref UIntPtr arg1);

13
2017-08-21 01:32