Nella mia applicazione C#, vorrei scrivere una parte del codice in C. Ho intenzione di scrivere una DLL che sarebbe interoperabile con .Net. Come posso farlo?Scrittura di una DLL in C/C++ per l'interoperabilità .Net
risposta
Ci sono essenzialmente tre modi giusti per farlo:
- Usare C++/CLI. Questo è il modo ottimale se questa DLL verrà utilizzata solo da .NET.
- Utilizzare un'API compatibile "
extern "C"
", come la stessa API di Windows. Questo è il più portatile, ma non è così conveniente per i chiamanti quanto l'utilizzo di un modello di classe per rappresentare i tuoi oggetti.- Questa è l'opzione migliore se si intende realmente scrivere in ANSI C (non in C++).
- Per questo percorso, si scrivono le proprie funzioni come
extern "C" returntype __stdcall __declspec(dllexport) func(params) { ... }
- Si consiglia inoltre di utilizzare un modello di memoria "chiamante-fornisce-il-buffer", anziché restituire un buffer allocato all'interno della libreria. Nei casi in cui è necessario allocare memoria per lo stato interno, il chiamante dovrebbe vederlo come un handle opaco e si dovrebbero fornire funzioni di accesso per il chiamante per estrarre i dati. In nessuna circostanza il chiamante dovrebbe rilasciare deallocate la memoria allocata all'interno della libreria, tuttavia è opportuno che il chiamante chieda alla libreria di effettuare la deallocazione.
- Utilizzare COM o un'API simile a COM. Qui si restituisce (spesso tramite il parametro out) un puntatore a un'interfaccia, che è una classe con funzioni virtuali pure, senza funzioni non virtuali e senza dati.
- L'implementazione è in classi concrete derivate da questa interfaccia astratta, possono avere a portata di mano dati e funzioni di supporto, poiché ciò non influisce sull'interfaccia binaria.
- Questo è molto più lavoro nella libreria, ma estremamente portatile e facile da usare per il consumatore.
E c'è una cosa assolutamente da non fare:
- uso
__declspec(dllexport)
sulle classi C++.
MODIFICA: Voglio anche illustrare alcune buone pratiche per l'opzione n. 2 che ottimizzerà la portabilità e rendere le parti native C/C++ utilizzabili anche da applicazioni non gestite.
si può fare che più facile con una macro, il solito modo di fare è:
Nel file di intestazione, tutte le dichiarazioni di funzione assomigliano
MYPROJECTAPI(returntype) PublicFunc(params);
Nel progetto, la definizione è
#define MYPROJECTAPI(returntype) \
extern "C" returntype __stdcall __declspec(dllexport)
Nei progetti di consumo
#define MYPROJECTAPI(returntype) \
extern "C" returntype __stdcall __declspec(dllimport)
e quindi è possibile definire la macro in modo diverso per altri compilatori come gcc che non utilizzano __declspec
.
La soluzione completa sarà simile (nel file di intestazione pubblico myproject.h
):
#if _WIN32
# if BUILDMYPROJECT
# define MYPROJECTAPI(returntype) \
extern "C" returntype __stdcall __declspec(dllexport)
# else
# define MYPROJECTAPI(returntype) \
extern "C" returntype __stdcall __declspec(dllimport)
# endif
#else
# define MYPROJECTAPI(returntype) extern "C" returntype
#endif
e quindi il progetto di Visual C++ causerebbe BUILDMYPROJECT
da definire quando si costruisce MyProject.dll
Attraverso il livello P/Invoke.
Questo non aiuta il processo di scrittura della DLL * affatto *, che è la domanda. –
Ok. La mia comprensione è che stava chiedendo un modo per comunicare con C/C++ dll da .NET. Il livello P/Invoke funziona. – Adi
Il modo in cui analizzo la domanda è "Come posso [scrivere una DLL che sia interoperabile]?" –
In poche parole:
(1) Creare un nuovo progetto di libreria C++/CLI.
(2) Scrivi il tuo codice. Per le classi che devono essere accessibili dal vostro progetto C#, fare in modo di creare loro come classi CLR:
public ref class R {/*...*/}; // CLR class
public value class V {/*...*/}; // CLR struct
public interface class I {/*...*/}; // CLR interface
(3) Compilare il progetto e aggiungere un riferimento ad esso nel vostro progetto C#.
come è possibile creare un progetto di libreria C++/CLI con Visual Studio 2010? –
@tinmaru: Al momento non ho installato VS 2010, ma secondo MSDN (http://msdn.microsoft.com/en-us/library/0fyc0azh.aspx), ci dovrebbe essere un "CLR/Libreria di classi "modello di progetto disponibile. – Heinzi
Di seguito è riportato un esempio per un'applicazione in cui dovevo fare proprio questo. Nel mio caso, avevo bisogno di una DLL per racchiudere le chiamate a funzioni che erano disponibili solo in un .lib. La parte chiave è la extern "C" __declspec (dllexport)
nella dichiarazione. Questo è praticamente tutto ciò di cui hai bisogno. Il resto era semplicemente usando dllimport
nell'app C# e ottenendo il marshalling giusto.
extern "C" __declspec (dllexport) LONG EstablishContext(DWORD dwScope,
LPCVOID pvReserved1,
LPCVOID pvReserved2,
LPSCARDCONTEXT phContext)
{
return SCardEstablishContext(dwScope, pvReserved1, pvReserved2, phContext);
}
Non dimenticare '__stdcall' (o in modo equivalente, usa la macro' WINAPI'). Questo semplificherà notevolmente le dichiarazioni p/invoke. –
come si può creare un progetto C++/CLI con Visual Studio 2010? –
File -> Nuovo -> Progetto, quindi Visual C++ -> CLR -> Libreria di classi –
Non viene creato. Ho il seguente errore: errore TRK0005: Impossibile localizzare: "CL.exe". –