2009-04-22 8 views
4

Comment déclarer en C# une fonction C qui renvoie un pointeur vers une structure?p/invoque une fonction C qui renvoie un pointeur vers une structure

Je crois que suivre est une façon de le faire, suivie par Marshal.PtrToStructure pour obtenir la valeur de structure réelle.

// C-function 
SimpleStruct * Function(void); 

// C# import 
[DllImport("MyDll.dll")] 
public static extern IntPtr Function(); 
  1. Ai-je raison à ce sujet?
  2. Existe-t-il d'autres façons d'accomplir la même chose? (Il serait bon de récupérer struct par valeur)

Répondre

4

Étant donné que la fonction renvoie un pointeur (nous espérons qu'il ne s'agit pas d'un pointeur local?), Il est préférable de le marshaler manuellement (via Marshal.PtrToStructure).

S'il s'agissait d'un paramètre, vous pouvez créer une version gérée de la structure à l'aide de PInvoke Interop Assistant, puis la transmettre via ref ou out.

+0

Les pointeurs de marshalling manuelles ne sont presque jamais nécessaires. Habituellement, vous pouvez travailler directement avec les structures. –

+0

Je crois que vous vous trompez. Il existe un certain nombre de grandes classes de problèmes d'interopérabilité qui nécessitent un marshaling manuel des pointeurs. Les structures et structures de tailles variables contenant des réseaux de structures ne sont que deux des plus communes. –

+0

J'ai mis en place un exemple de marshaling une structure contenant un tableau de structures à http://arnshea.blogspot.com/2009/04/interop-with-struct-that-contains-array.html. Il est assez rare que vous deviez manuellement marshaler des données pour interop ... –

0

Je ne suis pas un expert du tout, mais il se trouve que je regarde un morceau de code (que je ne comprends pas complètement) que fait la même chose.

Voici ce qu'ils font

[DllImport("")] 
private static extern short MethodName([In,Out] ref StructureName variable); 

puis sur la structure qu'ils ont l'attribut suivant

[StructLayout(LayoutKind.Sequential, Size = #)] 
public struct StructureName {} 

Je pense que la pièce que vous recherchez est la partie [In, Out] , et comme il est passé via ref, vous devriez récupérer les mêmes données.

marqué comme wiki de la communauté afin que les gens puissent résoudre ce problème s'ils se trompent.

+0

Ceci est une importation pour la signature suivante: short MethodName (StructureName * struct); Je suis assez shure je vais obtenir "ESP est foutu" exception ici. –

4

caveat: cela ne fonctionnera que si le pointeur renvoyé est à la mémoire déjà géré par le CLR

Je crois que ce que vous cherchez est

// C# import 
[DllImport("MyDll.dll")] 
[return : MarshalAs(UnmanagedType.LPStruct)] 
public static extern StructureName Function(); 

[StructLayout(LayoutKind.Sequential)] 
public class StructureName {} 

Cela devrait éliminer la nécessité d'une manuel Marshal.PtrToStructure appels. En fonction de ce que contient votre structure, vous devrez peut-être marquer certains champs avec les attributs MarshalAs selon le cas. MSDN a un bon exemple de cela.

+0

+1, Hmm, je ne suis pas sûr à 100% de la version de la classe. La classe dans invoke est généralement traitée comme un type de pointeur alors que struct est une valeur. Je ne suis pas sûr si combiner un type de classe avec LPStruct fonctionnera dans tous les scénarios. – JaredPar

+0

** MarshalAs (LPStruct) ** décrit le mieux ce que je veux. Bien que LPStruct en retour soit incompatible avec P/Invoke: "Impossible de rassembler la valeur de retour": combinaison de types gérés/non gérés non valides ... " –

+0

J'ai fait un peu de test, et c'est une structure marshalée comme" LPStruct "qui ne fonctionne pas. travail - Je vais éditer le poste de manière appropriée. De plus, il y a une autre mise en garde (assez importante): La mémoire pointée vers (le SimpleStruct * dans le code C) doit avoir été allouée par le CLR, car elle ajoute une référence à celle-ci et essaiera de la récupérer. Je vais ajouter cela à la poste aussi. Donc, il semble que vous devrez suivre l'approche IntPtr. –

Questions connexes