2010-02-21 3 views
2

Mon application consiste en un code C# avec des appels C dll non gérés. Dans mon code C# j'ai un objet/classe où ses propriétés sont les deux types de systèmes tels que string et int et d'autres objets que j'ai définis.Passage d'objets entre C# et C

Je voudrais passer cet objet complexe (Graph.cs) à mon code C (dll), quelle implémentation suggéreriez-vous ici?

J'ai essayé des structures en mouvement mais je n'arrive pas à le faire avec autre chose que string et int.

Merci.

code:

public Class Grpah { 

    TupleCollection m_TupleCollection; 
    int m_nGeneralIndex;  
    bool m_bPrintWRF; 
    string m_sLink; 
} 

public Class TupleCollection { 

    IList<Tuple> _collection; 

}  

public Class Tuple { 

    Globals.TupleType m_ToppleType;   
    ArrayList m_Parameters; 

} 

public class TupleArgs { 

    public string Value { get; set; }  
    public Globals.PAS PAS; 
    public RefCollection RefCollection { get; set; } 
    public int Time{ get; set; }  

} 

public class RefCollection { 

    public List<int> SynSet{ get; set; } 
    public Globals.PAS PAS; 

} 
+1

vous devez fournir votre code pour que les gens puissent vous conseiller. – Benny

+0

J'ai ajouté le code, est-il possible d'envoyer l'objet graphique à un dll C? – user278002

+0

vous avez une faute de frappe :) –

Répondre

6

Essayez:

How to: Marshal Structures Using PInvoke

Je pense que la meilleure façon pour vous de faire des progrès est de modifier le code natif, ce qui lui donne la possibilité de travailler avec des types CLR .

Maintenant, vous utilisez presque certainement Visual Studio, et nous espérons que c'est VS2005 ou plus tard. Cela signifie que bien que votre code natif existant soit en C, vous avez la possibilité de vous plonger dans un peu de C++. Et pas seulement cela - vous avez aussi C++/CLI. Donc, je voudrais faire une nouvelle DLL C++/CLI, et lier votre bibliothèque C à celle-ci, afin qu'elle puisse appeler dans le code C. http://www.youtube.com/home.html Ensuite, écrivez une couche de traduction fine dans la bibliothèque C++/CLI: elle exposera les vraies classes CLR (écrites avec ref class) et appellera le code C natif.

par exemple. dans un en-tête C:

void do_something_with_foo_data(int a, int b, int c); 

En C++/CLI:

public ref class FooWrapper 
{ 
    static void DoSomethingWithFoo(Foo ^foo) 
    { 
     // pick apart the Foo class and pass the pieces on to the C function 

     do_something_with_foo_data(foo->A, foo->B, foo->C); 
    } 
}; 

En C#:

public class Foo 
{ 
    public int A { get; set; } 
    public int B { get; set; } 
    public int C { get; set; } 
} 

... 

var foo = new Foo { A = 1, B = 2, C = 3 }; 
FooWrapper.DoSomethingWithFoo(foo); 
+0

Merci, dans cet exemple, ils utilisent uniquement le type de données simple tel que int que je peux gérer, que diriez-vous de type de données C# liste? ou ListArray. – user278002

+0

Vous ne pouvez pas gérer les structures managées à partir du code non managé. Vous devez convertir ces structures en structures non gérées et les transmettre. Cette réponse est la plus valide que j'ai vue ici. –

+0

+1 J'aime cette approche! –

0

Votre modèle semble assez compliqué, et incomplète: Tuple.m_parameters est un ArrayList, donc il peut contenir à peu près tout, et le type Globals.PAS n'est pas défini ici. Peut-être que vous devriez penser à une stratégie différente: dans votre DLL, créez un petit modèle qui contient tout ce dont vous avez besoin dans votre code C, et rendez-le aussi simple que possible (mais pas plus simple!).

Puis, apprenez tout ce dont vous avez besoin pour assembler ce modèle C à partir de votre code managé et remplir le modèle à partir de votre classe Graph.cs. De préférence, Graph.cs ne devrait pas être responsable de le faire, votre code de triage devrait l'être.

2

Lorsque j'ai fait cela, j'ai utilisé Marshal exclusivement. C'était avec la norme C pour le code natif. Je ne voulais pas convertir mon code C en "C++ géré" ou tout ce qu'ils appellent :-)

La partie difficile et fastidieuse est que vous devez manuellement marshaler votre structure de données en quelque chose qui correspond directement à la réception C fonction. Dans mon cas, j'ai dû créer des structures séparées pour chaque classe de classe C# que je voulais envoyer. En substance, vous devez convertir votre belle hiérarchie d'objets C# en une forme plus basique composée de structures que vous puis marshal dans un morceau de mémoire que vous puis utiliser comme argument dans votre appel natif.

Vous devez utiliser la méthode Marshal.AllocHGlobal pour allocing mémoire et Marshal.StructureToPtr pour copier votre struct C# pour que la mémoire et Marshal.FreeHGlobal pour le libérer.

Une fois que vous avez votre IntPtr (de StructureToPtr), vous devriez pouvoir appeler votre C-dll avec ce pointeur comme argument. Notez que la structure que vous envoyez à votre fonction C doit avoir la même disposition que la structure C native, sinon vous obtiendrez des résultats très étranges.

Le retour de données est à peu près la même chose, mais vous utilisez plutôt les fonctions opposées (PtrToStructure etc.).

C'est la base de toute façon.

+0

+1 Je ne suis pas sûr d'aimer le son de cette pratique, mais il n'en est pas moins intéressant. –

+0

Hé, merci. Mais à moins que vous ne vouliez porter votre code natif existant ou écrire cette chose wrapper C++, c'est la seule façon d'avancer aussi loin que * I * sait. –

+0

Pure C, Pure C++, Mixed C et C++ sont tous d'accord pour moi. Je n'aime pas la version gérée de C++. –