Form in Klasse in DLL....unresolved external!
-
Hallo,
ich schonwieder!

Habe nun meine übung etwas verstärkt, und wollte über eine klasse eine form aus einer dll verwalten:
DLL.h
#ifndef __FILE1_H #define __FILE1_H #include "Unit2.h" class MyForm { public: MyForm(); ~MyForm(); void ShowIt(); private: TForm2* Form2; }; #endifdll.cpp
#pragma argsused int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { return 1; } //--------------------------------------------------------------------------- MyForm::MyForm() { Form2 = new TForm2(0); } MyForm::~MyForm() { if(Form2) delete Form2; } void MyForm::ShowIt() { Form2->Show(); } extern "C" __declspec(dllexport)MyForm* GetMyForm() { return new MyForm; } extern "C" __declspec(dllexport)void FreeMyForm(MyForm* my) { delete my; }Aufrufendes Programm
#include <vcl.h> #pragma hdrstop #include "Main.h" #include "File1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { HINSTANCE h = LoadLibrary("Project1.dll"); if(h) { typedef MyForm*(*pFunc)(); pFunc myformFunc; MyForm* mForm; myformFunc = (pFunc)GetProcAddress(h,"_GetMyForm"); if(myformFunc) { mForm = myformFunc(); mForm->ShowIt(); } else ShowMessage("Klasse konnte nicht geladen werden"); } else { ShowMessage("Project1.dll konnte nicht geladen werden"); } } //---------------------------------------------------------------------------bekomme immer fehler.: unaufgelöste externe MyForm::ShowIt()! Wieso?
-
Hallo,
Woher soll deine Anwendung MyForm::ShowIt auch kennen, du importierst diese Klasse ja nicht aus der dll in dein Projekt.
Man kann eine Wrapperklasse für die dll-Funktionen schreiben aber
1. Diese Wrapperklasse muß dem Hauptprogramm vollständig bekannt sein (Deklaration und Definition)
2. Die in der Klasse verwendeten Funktionen bzw. Klassen aus der dll müssen auch alle aus der dll heraus importiert werden.Ich mach sowas normalerweise so.
Die Wrapperklasse lädt die dll im Konstruktor (oder bei der ersten verwendung einer memberfunktion).
Sie hält Pointer auf alle von der dll importierten Funktionen (werden ebenfalls vor der ersten Verwendung initialisiert).
Die Memberfunktionen dieser Klasse rufen dann die aus der dll importierten Funktionen auf.
Die dll wird im Destruktor wieder entladen.Bei dir würde es erstmal reicher aus ShowIt eine exportierbare dll-Funktion zu machen.
-
und eine frage habe ich gleich noch:
im Destr der Klasse wird ja der speicher der form2 freigegeben!
Ist das eine gute möglichkeit? Was würde passieren, wenn ich im OnClose der Form2 caFree setze?Dann kann ich ja die Form mit der Klasseninstanz nicht mehr verwenden (nochmal öffnen oder ähnliches), da ja nur im Konstruktor meiner Klasse der speicher geholt wird oder?
Wie ist hier die richtige vorgehensweise?Sicherlich mit dem Destruktor der Klasse welche die Form2 anzeigt oder?Und sollte der Zeiger auf die Klasse im aufrufenden Programm, besser ein Member der Form1 Klasse sein?
-
hm...ganz klar ist mir deine erklärung nicht ganz

kannst du das vielleicht an meinem code etwas konkretisieren?
Mit wrapperklasse meinst du hier diese MyForm oder?
-
Ja, meine ich.
Konkret:
Du hast MyForm::ShowIt in der dll.h deklariert. Dieser headerdatei inkludierst du sicher irgendwo in deinem Hauptprogramm.
Da aber die Definition von MyForm::ShowIt in deiner dll steckt und du MyForm nicht exportierst kann der Linker beim Hauptprogramm so nichts finden.
Lass diese Klasse MyForm erstmal weg und erzeuge dir zusätzlich noch eine eigene Showfunktion die du exportierst.
-
Hier nun mal ein Vorschlag für eine Wrapperklasse wie ich sie oben meinte.
dll.cpp#include "Unit2.h" #pragma argsused int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { return 1; } //--------------------------------------------------------------------------- extern "C" __declspec(dllexport)TForm2* GetForm2() { return new TForm2(0); } extern "C" __declspec(dllexport)void FreeForm2(TForm2* form) { delete form; } extern "C" __declspec(dllexport)void ShowForm2(TForm2* form) { form->ShowModal(); }dll.h
class TForm2; typedef TForm2 *(*getForm)(); typedef void (*useForm)(); class MyForm { private: TForm2* form; getForm getForm2; useForm freeForm2, showForm2; HINSTANCE hdll; bool valid; public: MyForm() : valid(false), form(0) { hdll = LoadLibrary("Project1.dll"); if( hdll ) { getForm2 = (getForm)GetProcAddress(h,"_GetForm2"); freeForm2 = (useForm)GetProcAddress(h,"_FreeForm2"); showForm2 = (useForm)GetProcAddress(h,"_ShowForm2"); if( getForm2 && freeForm2 && showForm2 ) { valid = true; form = getForm2(); } } } ~MyForm() { if( valid ) freeForm2(form); if( hdll ) FreeLibrary(hdll); } ShowIt() { if( valid ) showForm2(); } bool isValid() { return valid; } }Hauptprogramm
#include <vcl.h> #pragma hdrstop #include "Main.h" #include "File1.h" #include "dll.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { MyForm myform; if( myform.isValid ) { MyForm.ShowIt(); } else { ShowMessage("Project1.dll konnte nicht geladen werden"); } } //---------------------------------------------------------------------------
-
dieses laden der Project1.dll verwirrt mich grad!
Project1.dll ist doch die dll selbst (dll.h und .cpp) oder?
Sie würde sich praktisch selbst laden, oder ist dies hier nur eine header und code datei (diese dll.h und .cpp) welche die dll lädt?
-
Das liegt hier nur an den Namen. Benenn die dll.h in meinem Code einfach mal um. Die kommt nicht in dein dll-Projekt, sondern nur in das aufrufende Programm.
-
also ist es nur eine "schnittstellendatei"?
habe noch eine frage:
ich möchte eine art plugin realisieren
d.h ich möchte zusätzliche funktionen über dlls hinzufügen!
meine frage ist nun, wie muss ich eine funktion in der dll deklarieren, damit sie einem OnClick - Konvention eines MenüItems enstpricht?Hintergund: ich möchte einem MenüItem als OnClick eine Funktion aus der DLL zuordnen, dynamisch!
-
Ja, das ist eine Art Schnittstellenklasse, die die Funktionen der dll kapselt. Das mach meiner Meinung nach die Bedienung einfacher.
Zu PlugIns gab es hier mal so eine Art Tutorial. Ich finde das derzeit nicht, du kannst aber mal suchen.
Direkt eine Funktion aus einer dll zu OnClick zuordnen wird wohl nichts. Die Funktionen die du dort verwendest sind Memberfunktionen der entsprechenden Form. Sowas kannst du nicht aus einer dll importieren. Du kannst aber z.Bsp. eine zentrale OnClick-Funktion für alle Menüitems erzeugen und dort in einem switch je nach Sender (Menüitem) entscheiden welche freie Funktion du aufrufst. Ich denke das ist so am Einfachsten.