Come posso chiamare C ++ / CLI da C #?

Ho una class implementata in C ++ che è responsabile per il calcolo aritmetico del programma e un’interfaccia che usa WPF. Elaboro l’input con C # ma come posso usare la mia class C ++?

Ho visto alcuni commenti su come far funzionare una class wrapper C ++ gestita, ma non so da dove iniziare. Né so come andrei a compilarlo insieme a tutti gli altri codici. Non riesco davvero a trovare un tutorial su questo, e la roba su Google show sul C ++ gestito non sembra davvero utile.

Qualcosa là fuori per aiutarmi? Questo non mi sembra irragionevole.

EDIT Provato soluzione m3rLinEz ma mi sta dando una BadImageFormatException, penso che sia perché la DLL non viene generata. Ho fatto tutto come detto, non so cosa sia successo. Qualche idea?

Hai dato un’occhiata a C ++ / CLI?

Lasciatemi fare un esempio molto breve. Ecco il file sorgente da un progetto Visual C ++ -> CLR -> Class Library. Praticamente ottiene il nome utente di Windows e lo restituisce.

Tieni presente che, per ottenere questo risultato, devi entrare nelle impostazioni del progetto e contrassegnare “Dipendenze aggiuntive” come “Eredita dal genitore” perché stiamo usando quelle lib di Windows (kernel32.lib, user32.lib, ..)

// CSCPP.h #pragma once #include "windows.h" using namespace System; namespace CSCPP { public ref class Class1 { // TODO: Add your methods for this class here. public: String^ GetText(){ WCHAR acUserName[100]; DWORD nUserName = sizeof(acUserName); if (GetUserName(acUserName, &nUserName)) { String^ name = gcnew String(acUserName); return String::Format("Hello {0} !", name); }else{ return gcnew String("Error!"); } } }; } 

Ora abbiamo creato un nuovo progetto C # e aggiungo il riferimento al nostro primo progetto di libreria di classi C ++ / CLI. E poi chiama il metodo di istanza.

 namespace CSTester { class Program { static void Main(string[] args) { CSCPP.Class1 instance = new CSCPP.Class1(); Console.WriteLine(instance.GetText()); } } } 

Ciò ha dato il seguente risultato sulla mia macchina:

Ciao m3rlinez!

C ++ / CLI è fondamentalmente un’estensione gestita su standard C ++. Consente di utilizzare classi CLR e tipi di dati nel progetto C ++ / CLI e di esporli anche al linguaggio gestito. Puoi creare un wrapper gestito per la tua vecchia libreria C ++ usando questo. Esistono alcune strane syntax come String^ per definire il tipo di riferimento su String CLR. Trovo che “Quick C ++ / CLI – Learn C ++ / CLI in meno di 10 minuti” sia utile qui.

Esistono almeno tre modi per chiamare il codice non gestito da gestito nello stesso processo:

  1. C ++ / CLI
  2. Platform Invoke
  3. Avvolgi il tuo C ++ in un object COM

Al lavoro usiamo C ++ / CLI per questo, sembra funzionare.

Creo una libreria di collegamento dinamico standard (non gestita / gestita) come descritto qui e quindi utilizzo l’ attributo DllImport ( richiamo piattaforma) nel codice c # per accedere alle funzioni esportate.

Il punto chiave di questo articolo:

Nota il modificatore __declspec (dllexport) nelle dichiarazioni del metodo in questo codice. Questi modificatori consentono al metodo di essere esportato dalla DLL in modo che possa essere utilizzato da altre applicazioni. Per ulteriori informazioni, consultare dllexport, dllimport.

Questa è un’alternativa più leggera rispetto a un effettivo wrapper di interoperabilità COM ed evita problemi come la registrazione ecc. (La DLL può semplicemente essere collocata nella directory dell’applicazione).

Un’altra alternativa è It Just Works (IJW). Questa è probabilmente una scelta migliore se hai gestito il codice C ++ e hai bisogno di accedervi da altri linguaggi .NET. Ma questa è solo un’opzione se sei in grado / felice di convertire il tuo C ++ non gestito in C ++ gestito.

Vorrei stare lontano da P / Invoke perché è piuttosto lento rispetto a IJW (funziona solo). Quest’ultimo consente di intrecciare perfettamente c ++ gestito e non gestito. Tutto quello che devi fare è creare un assembly c ++ gestito, scrivere una class gestita che sia visibile da c # e chiamare il codice non gestito.

Uhm … OK. Avevo l’impressione che le chiamate P / Invoke fossero più lente di quanto non lo fossero. Tuttavia, avendo il controllo esplicito sul marshalling, puoi rendere la tua versione C ++ / CLI più performante in molti casi.

Ecco l’articolo di Microsoft su entrambi i meccanismi:

http://msdn.microsoft.com/en-us/library/ms235282.aspx

Vantaggi di IJW

  • Non è necessario scrivere dichiarazioni dell’attributo DLLImport per le API non gestite utilizzate dal programma. Basta includere il file di intestazione e il collegamento con la libreria di importazione.
  • Il meccanismo IJW è leggermente più veloce (ad esempio, gli stub IJW non hanno bisogno di verificare la necessità di appuntare o copiare gli elementi dei dati perché ciò è esplicitamente fatto dallo sviluppatore).
  • Illustra chiaramente i problemi di prestazioni. In questo caso, il fatto che si sta traducendo da una stringa Unicode a una stringa ANSI e che si dispone di un’allocazione e deallocazione di memoria dell’operatore. In questo caso, uno sviluppatore che scrive il codice usando IJW realizzerebbe che chiamare _putws e usare PtrToStringChars sarebbe meglio per le prestazioni.
  • Se chiamate molte API non gestite utilizzando gli stessi dati, il marshalling di una sola volta e il passaggio della copia di marshalling è molto più efficiente del re-marshalling ogni volta.

Ci sono anche dei vantaggi estetici:

  • Il codice C # assomiglia al codice C # senza alcuna stranezza di interoperabilità.
  • Non è necessario definire DLLImport attributo DLLImport , non è necessario definire alcuna delle strutture dati (anche con p / invocare attributi specifici) che potrebbero avere il seguente aspetto:

    [StructLayout (LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct DevMode {[MarshalAs (UnmanagedType.ByValTStr, SizeConst = 32)] public string dmDeviceName; }

  • Non è necessario convertire tutti i tipi di parametri primitivi nelle rispettive controparti .NET (su questa pagina è presente una tabella che elenca i tipi gestiti per i tipi non gestiti).
  • Puoi lavorare con C ++ / CLI che è davvero divertente da imparare ed è davvero raffinato. Ha fatto molta strada rispetto a VS 2003 ed è ora un linguaggio .NET completo. La documentazione Microsoft è abbastanza buona, così come tutte le informazioni IJW.
  • Interop di C ++ in C ++ / CLI sembra molto naturale rispetto a C #. Questo è completamente soggettivo, ma preferirei molto preferire il marshalling di stringhe in C ++ che faccia Marshal.PtrToString(ptr) .
  • Se esponi un’API, probabilmente vorrai racchiudere tutte le cose P / Invoke in un altro livello, quindi non dovrai occuparti della bruttezza di P / Invoke. In questo modo hai il sovraccarico di tutto lo strato di marshalling AND C # attorno ad esso. Con C ++ / CLI il marshalling e l’astrazione di interoperabilità sono in un unico posto e puoi scegliere quanto marshalling hai bisogno.

IMHO se stai chiamando una funzione dispari in Windows SDK, vai con P / Invoke. Se stai esponendo una API C ++ moderatamente complessa al mondo gestito, sicuramente C ++ / CLI.