2010-09-16 10 views

risposta

19

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

+0

come si può creare un progetto C++/CLI con Visual Studio 2010? –

+0

File -> Nuovo -> Progetto, quindi Visual C++ -> CLR -> Libreria di classi –

+0

Non viene creato. Ho il seguente errore: errore TRK0005: Impossibile localizzare: "CL.exe". –

1
+0

Questo non aiuta il processo di scrittura della DLL * affatto *, che è la domanda. –

+0

Ok. La mia comprensione è che stava chiedendo un modo per comunicare con C/C++ dll da .NET. Il livello P/Invoke funziona. – Adi

+0

Il modo in cui analizzo la domanda è "Come posso [scrivere una DLL che sia interoperabile]?" –

4

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#.

+0

come è possibile creare un progetto di libreria C++/CLI con Visual Studio 2010? –

+0

@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

1

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); 
} 
+0

Non dimenticare '__stdcall' (o in modo equivalente, usa la macro' WINAPI'). Questo semplificherà notevolmente le dichiarazioni p/invoke. –