2017-03-17 4 views
1

J'écris actuellement une liaison C# fine pour OpenGL. J'ai récemment implémenté la fonction OpenGL GenVertexArrays, qui a la signature suivante: OpenGL Documentation on glGenVertexArrays. Pour l'essentiel, vous lui transmettez un tableau dans lequel stocker les valeurs d'objet générées pour les tableaux de vertex créés par OpenGL. Pour créer la liaison, j'utilise des délégués car glGenVertexArrays est une fonction d'extension OpenGL, donc je dois la charger dynamiquement en utilisant wglGetProcAddress. La signature de délégué, je l'ai défini en C# ressemble à ceci:C# Le comportement Interp Marshaling pour les tableaux semble incompatible avec la documentation

[SuppressUnmanagedCodeSecurity] 
[UnmanagedFunctionPointer(CallingConvention.StdCall)] 
private delegate void glGenVertexArrays(uint amount, uint[] array); 

Le pointeur de fonction est récupéré et converti en ce délégué en utilisant Marshal.GetDelegateForFunctionPointer, comme ceci:

IntPtr proc = wglGetProcAddress(name); 

del = Marshal.GetDelegateForFunctionPointer(proc, delegateType); 

Quoi qu'il en soit, voici ce qui me dérange :

Dans tous les documents officiels que je peux trouver sur le comportement par défaut de triage pour les types de référence (qui comprend des réseaux), est la suivante:

Par défaut, les types de référence (classes, tableaux, chaînes et interfaces) transmis par valeur sont marshalés en tant que paramètres de performance . Vous ne voyez pas les modifications à ces types, sauf si vous appliquez InAttribute et OutAttribute (ou simplement OutAttribute) au paramètre de la méthode.

Il est récupéré de cette page MSDN: MSDN page on directional attributes

Cependant, comme on peut le voir de mes signatures de délégués, le [En] et [out] attributs directionnels n'ont pas été utilisés sur le tableau d'entiers non signés , ce qui signifie que lorsque j'appelle cette fonction, je ne devrais pas être en mesure de voir les valeurs d'objets générés que OpenGL aurait dû y stocker. Sauf, je suis. En utilisant cette signature, je peux le résultat suivant lors de l'exécution du débogueur:

Debugging Results is positive

Comme on le voit, l'appel n'a absolument effet le tableau, même si je n'ai pas utilisé explicitement l'attribut [Out]. Ce n'est pas, d'après ce que je comprends, un résultat auquel je devrais m'attendre.

Est-ce que quelqu'un sait la raison derrière cela? Je sais que cela peut sembler mineur, mais je suis très curieux de savoir pourquoi cela semble rompre le comportement de rassemblement par défaut décrit par Microsoft. Y a-t-il des trucs en coulisses lors de l'invocation de délégués par rapport à des prototypes d'invocation de plate-forme pure? Ou est-ce que j'interprète mal la documentation?

[EDIT]

Pour tous les curieux, la méthode publique qui invoque le délégué est défini sur une statique classe « GL », et est comme suit:

public static void GenVertexArrays(uint amount, uint[] array) 
{ 
    InvokeExtensionFunction<glGenVertexArrays>()(amount, array); 
} 

Répondre

1

Il ne figure pas sur la page de documentation vous liée, mais il est another topic dédié à la conversion des tableaux, où il est dit:

Avec épinglant optimisation, un tableau blittable peut sembler fonctionner comme In/Out paramètre lors de l'interaction avec des objets dans le même appartement.

Les deux conditions sont remplies dans votre cas: array of uint est blittable et il n'y a pas de marshaling de machine à machine. C'est toujours une bonne idée de le déclarer [Out], donc votre intention est documentée dans le code.

+0

Merci beaucoup! :) Réponse très utile! – CodingBeagle

1

La documentation est correcte dans le cas général. Mais uint est un peu spécial, c'est un type blittable. Un mot coûteux qui signifie que le marshaller pinvoke n'a rien de spécial à faire pour convertir les valeurs des éléments du tableau. Un uint en C# est exactement le même type qu'un int non signé en C. Ce n'est pas du tout une coïncidence, c'est le genre de type qu'un processeur peut gérer nativement. Par conséquent, le marshaller peut simplement épingler le tableau et passer un pointeur sur le premier élément du tableau en tant que second argument. Très rapide, toujours ce que vous voulez. Et la fonction griffonne directement dans le tableau géré, donc la copie des valeurs n'est pas nécessaire. Un peu dangereux aussi, vous ne voulez jamais mentir sur l'argument amount, la corruption de tas GC est un bug trop laid pour diagnostiquer.

La plupart des types de valeurs et structures simples des types de valeurs simples peuvent être validés. bool est une exception notable. Vous ne devrez jamais être désolé d'utiliser [Out], même si ce n'est pas nécessaire. Le marshaller l'ignore simplement ici.

+0

Merci beaucoup pour l'explication! J'ai accepté l'autre réponse, car il semble qu'elle a été postée juste avant la vôtre, et vos deux réponses étaient très précieuses, donc il était difficile de décider lequel marquer comme accepté :) Vos deux entrées sont très appréciées, cependant! À la votre! – CodingBeagle