gcc öffnen - Kompilieren Sie eine DLL in C / C++, und rufen Sie sie dann von einem anderen Programm auf




datei dateien (5)

Ich möchte eine einfache, einfache DLL erstellen, die eine oder zwei Funktionen exportiert, und dann versuchen, sie von einem anderen Programm aus aufzurufen ... Überall, wo ich bisher gesucht habe, sind komplizierte Dinge, verschiedene Arten der Verknüpfung von Dingen, seltsame Probleme Ich habe noch nicht einmal angefangen zu realisieren, dass es sie gibt ... Ich möchte einfach anfangen, indem ich so etwas tue:

Machen Sie eine DLL, die einige Funktionen exportiert, wie

int add2(int num){
   return num + 2;
}

int mult(int num1, int num2){
   int product;
   product = num1 * num2;
   return product;
}

Ich kompiliere mit MinGW, ich möchte das in C machen, aber wenn es wirklich Unterschiede in C ++ gibt, würde ich das gerne auch wissen. Ich möchte wissen, wie man diese DLL in ein anderes C- (und C ++ -) Programm lädt und dann diese Funktionen von dort aufruft. Mein Ziel hier ist, nachdem ich ein wenig mit DLLs herumgespielt habe, ein VB Frontend für C (++) Code zu machen, indem ich DLLs in Visual Basic lade (ich habe Visual Studio 6, ich möchte nur einige Formulare machen und Ereignisse für die Objekte auf diesen Formularen, die die DLL aufrufen).

Ich muss wissen, wie man gcc (/ g ++) aufruft, um eine DLL zu erstellen, aber auch, wie man eine Exportdatei schreibt (/ erzeugt) ... und was ich in einer DLL machen kann / kann (wie kann ich das machen) Argumente per Zeiger / Referenz vom VB-Frontend? Kann die DLL eine theoretische Funktion im Frontend aufrufen? Oder habe eine Funktion einen "Funktionszeiger" (ich weiß nicht einmal, ob das möglich ist) von VB und Call es?) Ich bin mir ziemlich sicher, dass ich eine Variante nicht an die DLL weitergeben kann ... aber das ist alles, was ich wirklich weiß.

Update erneut

Okay, ich habe herausgefunden, wie man es mit gcc kompiliert, um die DLL zu erstellen

gcc -c -DBUILD_DLL dll.c
gcc -shared -o mydll.dll dll.o -Wl,--out-implib,libmessage.a

und dann hatte ich ein anderes Programm, um es zu laden und die Funktionen zu testen, und es funktionierte großartig, vielen Dank für den Rat, aber ich habe versucht, es mit VB6 zu laden, so

Public Declare Function add2 Lib "C:\c\dll\mydll.dll" (num As Integer) As Integer

dann habe ich einfach add2 (text1.text) von einem Formular aufgerufen, aber es gab mir einen Laufzeitfehler:

"Kann DLL-Einstiegspunkt Add2 in C: \ c \ dll \ mydll.dll nicht finden"

Dies ist der Code, den ich für die DLL kompiliert habe:

#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif

EXPORT int __stdcall add2(int num){
  return num + 2;
}

EXPORT int __stdcall mul(int num1, int num2){
  return num1 * num2;
}

es aus dem C-Programm wie folgt aufzurufen, funktionierte jedoch:

#include<stdio.h>
#include<windows.h>

int main(){

  HANDLE ldll;
  int (*add2)(int);
  int (*mul)(int,int);

  ldll = LoadLibrary("mydll.dll");
  if(ldll>(void*)HINSTANCE_ERROR){
    add2 = GetProcAddress(ldll, "add2");
    mul = GetProcAddress(ldll, "mul");
    printf("add2(3): %d\nmul(4,5): %d", add2(3), mul(4,5));
  } else {
    printf("ERROR.");
  }

}

irgendwelche Ideen?

Ich habe es gelöst

Um das vorherige Problem zu lösen, musste ich es einfach so kompilieren:

gcc -c -DBUILD_DLL dll.c
gcc -shared -o mydll.dll dll.o -Wl,--add-stdcall-alias

und verwenden Sie diesen API-Aufruf in VB6

Public Declare Function add2 Lib "C:\c\dll\mydll" _
    (ByVal num As Integer) As Integer

Ich habe gelernt, nicht zu vergessen, ByVal oder ByRef explizit anzugeben - ich habe gerade die Adresse des Arguments zurückbekommen, das ich übergeben habe, es sah aus wie -3048.


Answers

Die Sache, auf die man beim Schreiben von C ++ - DLLs achten sollte, ist der Name Mangling. Wenn Sie die Interoperabilität zwischen C und C ++ wünschen, sollten Sie besser nicht-gemangelte C-Style-Funktionen aus der DLL exportieren.

Sie haben zwei Möglichkeiten, eine DLL zu verwenden

  • Verwenden Sie entweder eine lib-Datei, um die Symbole zu verknüpfen - die dynamische Zeitkompilierung
  • Verwenden Sie LoadLibrary() oder eine geeignete Funktion, um die Bibliothek zu laden, einen Funktionszeiger ( GetProcAddress ) GetProcAddress und sie - dynamische Laufzeitverknüpfung - aufzurufen

Das Exportieren von Klassen funktioniert nicht, wenn Sie der zweiten Methode folgen.


Es gibt nur einen Unterschied. Sie müssen aufpassen oder Mangling Win C ++ nennen. Aber unter Windows muss man aufpassen, 1) die zu exportierenden Funktionen aus der DLL zu deklarieren 2) eine sog. .def-Datei zu schreiben, die alle exportierten Symbole auflistet.

In Windows muss beim Kompilieren eine DLL verwendet werden

__declspec (dllexport)

aber während Sie es verwenden, müssen Sie __declspec (dllimport) schreiben

Die übliche Art, das zu tun, ist so etwas wie

#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif

Die Benennung ist ein wenig verwirrend, weil sie oft EXPORT genannt wird. Aber das finden Sie in den meisten Headern. Also in deinem Fall würdest du schreiben (mit dem obigen #define)

int DLL_EXPORT hinzufügen .... int DLL_EXPORT mehr ...

Denken Sie daran, dass Sie beim Erstellen der gemeinsam genutzten Bibliothek die Präprozessordirektive BUILD_DLL hinzufügen müssen.

Grüße Friedrich


Hier ist, wie Sie es machen:

In .h

#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif

extern "C" // Only if you are using C++ rather than C
{    
  EXPORT int __stdcall add2(int num);
  EXPORT int __stdcall mult(int num1, int num2);
}

in .cpp

extern "C" // Only if you are using C++ rather than C
{    
EXPORT int __stdcall add2(int num)
{
  return num + 2;
}


EXPORT int __stdcall mult(int num1, int num2)
{
  int product;
  product = num1 * num2;
  return product;
}
}

Das Makro teilt Ihrem Modul (dh Ihren CPP-Dateien) mit, dass sie das Dll-Zeug für die Außenwelt bereitstellen. Personen, die Ihre .h-Datei einbinden, möchten die gleichen Funktionen importieren, also verkaufen sie EXPORT, indem sie dem Linker mitteilen, dass er importieren soll. Sie müssen BUILD_DLL zu den Projekt-Kompilierungsoptionen hinzufügen, und Sie sollten es möglicherweise in etwas umbenennen, das offensichtlich für Ihr Projekt spezifisch ist (falls eine DLL Ihre DLL verwendet).

Sie müssen möglicherweise auch eine .def-Datei erstellen , um die Funktionen umzubenennen und die Namen zu entfernen (C / C ++ mischt diese Namen). Dieser Blogeintrag könnte ein interessanter Startpunkt dafür sein.

Das Laden eigener benutzerdefinierter DLLs entspricht dem Laden von System-DLLs. Stellen Sie nur sicher, dass sich die DLL in Ihrem Systempfad befindet. C: \ Windows \ oder das Arbeitsverzeichnis Ihrer Anwendung sind ein einfacher Ort, um Ihre DLL zu platzieren.


Für VB6:

Sie müssen Ihre C-Funktionen als __stdcall deklarieren, andernfalls erhalten Sie Fehler vom Typ "Ungültige Aufrufkonvention". Über andere Ihre Fragen:

kann ich Argumente per Zeiger / Referenz vom VB-Frontend nehmen?

Ja, verwenden Sie ByRef / ByVal Modifikatoren.

Kann die DLL eine theoretische Funktion im Frontend aufrufen?

Ja, verwenden Sie die AddressOf-Anweisung. Sie müssen den Funktionszeiger vorher an dll übergeben.

Oder habe eine Funktion einen "Funktionszeiger" (ich weiß nicht einmal, ob das möglich ist) von VB und rufe es an?)

Ja, verwenden Sie die AddressOf-Anweisung.

Update (mehr Fragen erschienen :)):

Um es in VB zu laden, mache ich nur die übliche Methode (was würde ich tun, um winsock.ocx oder eine andere Laufzeit zu laden, sondern finde stattdessen meine DLL) oder setze ich einen API-Aufruf in ein Modul?

Sie müssen die API-Funktion im VB6-Code wie folgt entpacken:

Private Declare Function SHGetSpecialFolderLocation Lib "shell32" _
   (ByVal hwndOwner As Long, _
    ByVal nFolder As Long, _
    ByRef pidl As Long) As Long

In Visual C ++ können Sie diese Notation auch im Konstruktor verwenden: this-> Classname :: Classname (Parameter eines anderen Konstruktors). Siehe ein Beispiel unten:

class Vertex
{
 private:
  int x, y;
 public:
  Vertex(int xCoo, int yCoo): x(xCoo), y(yCoo) {}
  Vertex()
  {
   this->Vertex::Vertex(-1, -1);
  }
};

Ich weiß nicht, ob es woanders funktioniert, ich habe es nur in Visual C ++ 2003 und 2008 getestet. Sie können auch mehrere Konstruktoren auf diese Weise aufrufen, wie in Java und C #.

PS: Ehrlich gesagt war ich überrascht, dass dies nicht früher erwähnt wurde.





c++ c dll gcc vb6