Frage

Ich möchte ein einfaches Beispiel für eine Funktion aus einer C ++ Windows DLL zu exportieren.

Ich mag den Header, die CPP-Datei und die def-Datei, um zu sehen (wenn es unbedingt erforderlich).

Ich möchte die exportierte Namen undecorated sein. Ich möchte die meisten Standard-Aufrufkonvention verwenden (__stdcall?). Ich möchte die Verwendung __ declspec (dllexport) und nicht eine DEF-Datei verwenden.

Zum Beispiel:

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

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

Ich versuche, der Linker Unterstrichen hinzugefügt zu vermeiden und / oder Zahlen (Byte zählt?) Auf den Namen.

Ich bin OK mit nicht Dllimport Stütz- und Dllexport denselben Header verwendet wird. Ich habe keine Informationen wünschen über C ++ Klassenmethoden exportieren, nur c-Stil globale Funktionen.

UPDATE

Nicht enthalten ist die Aufrufkonvention (und mit extern „C“) gibt mir den Export Namen wie Ich mag, aber was bedeutet das? Ist was Standardaufrufkonvention Ich erhalte, was pinvoke (.NET), deklarieren (VB6) und GetProcAddress erwarten würde? (Ich denke, für GetProcAddress wäre es auf die Funktion verlassen auf den Anrufer Zeiger erstellt).

Ich möchte diese DLL ohne eine Header-Datei verwendet werden, so dass ich nicht wirklich brauchen, die eine Menge der Phantasie #defines von einem Anrufer der Header nutzbar zu machen.

Ich bin OK mit einer Antwort ist, dass ich eine DEF-Datei verwenden.

War es hilfreich?

Lösung

Wenn Sie Normal C Exporte wollen, verwenden Sie ein C-Projekt nicht C ++. C ++ DLLs stützen sich auf Namen-Mangeln für alle C ++ isms (Namespaces etc ...). Sie können den Code wie C, indem Sie in die Projekteinstellungen unter C / C ++ kompilieren -> Erweitert, gibt es eine Option "Compile As", die zu dem Compiler-Schalter cooresponds / TP und / TC

.

Export / Import von DLL-Bibliotheken in VC ++

Was Sie wirklich wollen, zu tun, ist eine bedingte Makro in einem Header zu definieren, die in all Quelldateien in Ihrem DLL-Projekt aufgenommen werden:

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

Dann auf eine Funktion, die Sie exportiert werden möchten, verwenden Sie LIBRARY_API:

LIBRARY_API int GetCoolInteger();

In der Bibliothek Build Projekt erstellen LIBRARY_EXPORTS definiert dies wird dazu führen, dass Funktionen für Ihre DLL Build exportiert werden.

Da LIBRARY_EXPORTS nicht in einem Projekt definiert werden, um die DLL raubend, wenn das Projekt alle Funktionen die Header-Datei Ihrer Bibliothek enthält stattdessen importiert werden.

Wenn Ihre Bibliothek ist plattformübergreifend sein, Sie LIBRARY_API als nichts definieren können, wenn sie nicht unter Windows:

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

Bei der Verwendung von dllexport / Dllimport Sie brauchen keine DEF-Dateien zu verwenden, wenn Sie DEF-Dateien verwenden Sie müssen nicht dllexport / Dllimport verwenden. Die beiden Verfahren erreichen die gleiche Aufgabe verschiedene Möglichkeiten, wie ich glaube, dass dllexport / Dllimport ist die empfohlene Methode aus den beiden.

Exportieren unmangled Funktionen aus einer C ++ DLL für Loadlibrary / PInvoke

Wenn Sie diese Loadlibrary und GetProcAddress zu verwenden, oder vielleicht tun PInvoke von .NET Sie extern "C" inline mit Ihrem Dllexport verwenden können. Und da wir GetProcAddress statt Dllimport verwenden wir nicht brauchen, von oben den ifdef Tanz zu tun, nur eine einfache Dllexport:

Der Code:

#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())
  );
}

Und hier ist es, was die Exporte aussehen mit Dumpbin / Exporte:

  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)

So dieser Code funktioniert:

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")
);

Andere Tipps

Für C ++:

ich konfrontiert gerade das gleiche Problem, und ich denke, es lohnt sich ein Problem zu erwähnen, kommt auf, wenn man beide __stdcall (oder WINAPI) und extern "C":

Wie Sie wissen extern "C" die Dekoration entfernt, so dass statt:

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

erhalten Sie einen Symbolnamen undecorated:

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

Doch die _stdcall (= Makro WINAPI, welche die Aufrufkonvention ändert) ziert auch die Namen, so dass, wenn wir beide verwenden wir erhalten:

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

und der Nutzen von extern "C" verloren, weil das Symbol verziert ist (mit _ @bytes)

  

Beachten Sie, dass diese nur für x86-Architektur tritt auf, weil   die __stdcall Konvention wird auf x64 ignoriert ( Msdn : auf x64 Architekturen, durch Konvention, werden die Argumente in Registern übergeben, wenn möglich, und nachfolgende Argumente auf dem Stack übergeben .).

Dies ist besonders heikel, wenn Sie beide x86 und x64-Plattformen ausgerichtet sind.


Zwei Lösungen

  1. Verwenden Sie eine Definitionsdatei. Aber das zwingt Sie den Zustand der def-Datei zu erhalten.

  2. Der einfachste Weg: das Makro definieren (siehe Msdn ):

  

#define EXPORT Kommentar (Linker "/ EXPORT:" __FUNCTION__ "="   __FUNCDNAME __)

und dann gehören die folgenden Pragma in dem Funktionskörper:

#pragma EXPORT

Voll Beispiel:

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

Damit wird die Funktion für x86- und x64 Ziele schmucklos exportieren, während der __stdcall Konvention für x86 zu erhalten. Die __declspec(dllexport) nicht in diesem Fall nicht erforderlich.

Ich hatte genau das gleiche Problem, war meine Lösung Moduldefinitionsdatei (.def) anstelle von __declspec(dllexport) verwenden Exporten zu definieren ( http://msdn.microsoft.com/en-us/library/d91k01sh.aspx ). Ich habe keine Ahnung, warum das funktioniert, aber es funktioniert

Ich denke, _naked könnte bekommen, was Sie wollen, aber es verhindert auch den Compiler von der Generierung der Stapel-Management-Code für die Funktion. extern "C" verursacht Name Dekoration C-Stil. Entfernen Sie das und das sollte loswerden Ihrer _ ist bekommen. Der Linker nicht die Unterstrichen hinzufügen, der Compiler tut. stdcall bewirkt, dass das Argument Stapelgröße angehängt werden.

Für mehr finden Sie unter: http://en.wikipedia.org/wiki/X86_calling_conventions http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx

Die größere Frage ist, warum tun Sie das tun wollen? Was ist los mit den verstümmelten Namen?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top