Domanda

Vorrei un semplice esempio di esportazione di una funzione da un C ++ DLL di Windows.

Mi piacerebbe vedere l'intestazione, il file cpp, e il file DEF (se assolutamente necessario).

Mi piacerebbe il nome esportato per essere non decorato . Mi piacerebbe utilizzare la convenzione di chiamata più standard (__stdcall?). Mi piacerebbe l'uso __ declspec (dllexport) e non è necessario utilizzare un file DEF.

Ad esempio:

  //header
  extern "C"
  {
   __declspec(dllexport) int __stdcall foo(long bar);
  }

  //cpp
  int __stdcall foo(long bar)
  {
    return 0;
  }

Sto cercando di evitare il linker sottolineatura e / o numeri (conteggi byte?) Aggiunto al nome.

Sto bene con non sostenere dllimport e dllexport utilizzando la stessa intestazione. Non voglio alcuna informazioni sull'esportazione di metodi di classe C ++, basta c-style funzioni globali.

UPDATE

Non compresa la convenzione di chiamata (e utilizzando extern "C"), mi dà i nomi di esportazione come mi piace, ma che cosa significa? È tutto ciò che di default convenzione di chiamata sto ottenendo quello che PInvoke (NET), dichiarare (VB6), e GetProcAddress si aspetta? (Credo che per GetProcAddress dipenderebbe la funzione puntatore del chiamante creato).

Voglio che questa DLL per essere utilizzato senza un file di intestazione, quindi non ho davvero bisogno di un sacco di # definisce fantasia per rendere l'intestazione utilizzabile da un chiamante.

Sono OK con una risposta è che devo utilizzare un file DEF.

È stato utile?

Soluzione

Se si desidera esportazioni C normale, utilizzare un progetto di C non C ++. C ++ DLL si affidano a nome-pressare per tutti i ismi C ++ (namespace, ecc ...). È possibile compilare il codice, come C andando in impostazioni del progetto in C / C ++ -> Avanzate, c'è l'opzione "Compila As", che cooresponds alle opzioni del compilatore / TP e / TC

.

esportazione / importazione DLL Libs in VC ++

Che cosa si vuole veramente fare è definire una macro condizionale in un colpo di testa che sarà incluso in tutti i file di origine nel progetto DLL:

#ifdef LIBRARY_EXPORTS
#    define LIBRARY_API __declspec(dllexport)
#else
#    define LIBRARY_API __declspec(dllimport)
#endif

Poi su una funzione che si desidera essere esportati si utilizza LIBRARY_API:

LIBRARY_API int GetCoolInteger();

Nel progetto di costruzione della libreria creare una definiscono LIBRARY_EXPORTS questo farà sì che le funzioni da esportare per la build DLL.

Dato che LIBRARY_EXPORTS non sarà definito in un progetto che consumano la DLL, quando quel progetto include il file di intestazione della libreria tutte le funzioni saranno importati al posto.

Se la libreria è quello di essere cross-platform è possibile definire LIBRARY_API come nulla se non su Windows:

#ifdef _WIN32
#    ifdef LIBRARY_EXPORTS
#        define LIBRARY_API __declspec(dllexport)
#    else
#        define LIBRARY_API __declspec(dllimport)
#    endif
#elif
#    define LIBRARY_API
#endif

Quando si utilizza dllexport / dllimport non è necessario utilizzare i file DEF, se si utilizzano i file DEF non è necessario utilizzare dllexport / dllimport. I due metodi eseguire la stessa operazione modi diversi, credo che dllexport / dllimport è il metodo consigliato fuori dei due.

Esportazione funzioni unmangled da un C ++ DLL per LoadLibrary / PInvoke

Se avete bisogno di questo per utilizzare LoadLibrary e GetProcAddress, o forse facendo PInvoke da NET è possibile utilizzare extern "C" in linea con il vostro dllexport. E dal momento che stiamo utilizzando GetProcAddress invece di dllimport non abbiamo bisogno di fare la danza ifdef dall'alto, solo un semplice dllexport:

Il codice:

#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)

EXTERN_DLL_EXPORT int getEngineVersion() {
  return 1;
}

EXTERN_DLL_EXPORT void registerPlugin(Kernel &K) {
  K.getGraphicsServer().addGraphicsDriver(
    auto_ptr<GraphicsServer::GraphicsDriver>(new OpenGLGraphicsDriver())
  );
}

Ed ecco che cosa esportazioni assomigliano con DUMPBIN / export:

  Dump of file opengl_plugin.dll

  File Type: DLL

  Section contains the following exports for opengl_plugin.dll

    00000000 characteristics
    49866068 time date stamp Sun Feb 01 19:54:32 2009
        0.00 version
           1 ordinal base
           2 number of functions
           2 number of names

    ordinal hint RVA      name

          1    0 0001110E getEngineVersion = @ILT+265(_getEngineVersion)
          2    1 00011028 registerPlugin = @ILT+35(_registerPlugin)

Quindi, questo codice funziona bene:

m_hDLL = ::LoadLibrary(T"opengl_plugin.dll");

m_pfnGetEngineVersion = reinterpret_cast<fnGetEngineVersion *>(
  ::GetProcAddress(m_hDLL, "getEngineVersion")
);
m_pfnRegisterPlugin = reinterpret_cast<fnRegisterPlugin *>(
  ::GetProcAddress(m_hDLL, "registerPlugin")
);

Altri suggerimenti

Per C ++:

Ho appena affrontato lo stesso problema e penso che vale la pena ricordare un problema si presenta quando si usano entrambi __stdcall (o WINAPI) e extern "C":

Come sapete extern "C" rimuove la decorazione in modo che invece di:

__declspec(dllexport) int Test(void)                        --> dumpbin : ?Test@@YaHXZ

si ottiene un nome di simbolo non decorato:

extern "C" __declspec(dllexport) int Test(void)             --> dumpbin : Test

Tuttavia il _stdcall (= macro WINAPI, che modifica la convenzione di chiamata) decora anche nomi in modo che se usiamo entrambi otteniamo:

   extern "C" __declspec(dllexport) int WINAPI Test(void)   --> dumpbin : _Test@0

e il beneficio della extern "C" si perde perché il simbolo è decorata (con _ @bytes)

  

Si noti che questo solo si verifica per l'architettura x86, perché   la convenzione __stdcall viene ignorato su x64 ( MSDN : su x64 architetture, per convenzione, gli argomenti vengono passati nei registri quando possibile, e successive argomenti sono passati sullo stack .).

Questo è particolarmente difficile se si prendono di mira entrambe le piattaforme x86 e x64.


due soluzioni

  1. Utilizzare un file di definizione. Ma questo ti costringe a mantenere lo stato del file def.

  2. il modo più semplice: definire la macro (vedi MSDN ):

  

Commento #define EXPORT (linker, "/ EXPORT:" __FUNCTION__ "="   __FUNCDNAME __)

e quindi includere il seguente pragma nel corpo della funzione:

#pragma EXPORT

Esempio completa:

 int WINAPI Test(void)
{
    #pragma EXPORT
    return 1;
}

In questo modo esportare la funzione non decorato per entrambi i target x86 e x64, preservando la convenzione __stdcall per x86. Il __declspec(dllexport) non è necessaria in questo caso.

Ho avuto esattamente lo stesso problema, la mia soluzione era quella di utilizzare file di definizione di modulo (DEF), invece di __declspec(dllexport) per definire le esportazioni ( http://msdn.microsoft.com/en-us/library/d91k01sh.aspx ). Non ho idea del perché questo funziona, ma lo fa

Credo _naked potrebbe ottenere ciò che si vuole, ma impedisce anche il compilatore di generare il codice di gestione dello stack per la funzione. extern "C" provoca nome decorazione in stile C. Rimuovere questo e che dovrebbe sbarazzarsi del vostro _ di. Il linker non aggiunge le sottolineature, il compilatore fa. stdcall causa la dimensione stack degli argomenti da aggiungere.

Per ulteriori informazioni, consultare: http://en.wikipedia.org/wiki/X86_calling_conventions http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx

La domanda più importante è perché vuoi farlo? Cosa c'è di sbagliato con i nomi alterati?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top