TADODataSet und TDataSource aus dynamischer DLL
-
Hallo zusammen,
ich hätte da mal eine Frage bezüglich der Übergabe von Datenbankkomponenten welche sich auf einem Datenmodul befinden welches wiederum in einer DLL steckt.
Die DLL wird zur Laufzeit dynamisch in die Anwendung eingebunden. Ich habe mir Übergabefunktionen gemacht, die scheinbar funktionieren, aber doch nicht wirklich. Zumindest wird in dem DBGrid des Testprojektes nichts angezeigt.
Header-Datei des Datenmoduls:
//--------------------------------------------------------------------------- #ifndef dmDLLmainH #define dmDLLmainH //--------------------------------------------------------------------------- #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ADODB.hpp> #include <DB.hpp> //--------------------------------------------------------------------------- class TdmDLL : public TDataModule { __published: // IDE-verwaltete Komponenten TADOConnection *Connection; TADODataSet *DataSet; TDataSource *DataSource; private: // Benutzer Deklarationen public: // Benutzer Deklarationen __fastcall TdmDLL(TComponent* Owner); }; //--------------------------------------------------------------------------- extern PACKAGE TdmDLL *dmDLL; //--------------------------------------------------------------------------- #endif
Source-Code Datei des Datenmoduls:
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "dmDLLmain.h" #include "vclDLLinc.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TdmDLL *dmDLL; //--------------------------------------------------------------------------- __fastcall TdmDLL::TdmDLL(TComponent* Owner) : TDataModule(Owner) { // die 'Connection' Komponente vorinitialisieren Connection->Close(); Connection->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=DLLtest.mdb"; Connection->CursorLocation = clUseClient; Connection->KeepConnection = true; Connection->LoginPrompt = false; Connection->Open(); // 'Dataset1' mit 'Datasource1' und 'Connection' verbinden und vorinitialisieren DataSet->Active = false; DataSet->CursorLocation = clUseClient; DataSet->ParamCheck = false; DataSet->Connection = Connection; DataSource->Enabled = false; DataSource->DataSet = DataSet; } //--------------------------------------------------------------------------- bool InitDLL(TComponent* Owner) { dmDLL = new TdmDLL(Owner); return (dmDLL); } //--------------------------------------------------------------------------- void DeleteDLL(void) { delete dmDLL; dmDLL = NULL; } //--------------------------------------------------------------------------- TADODataSet *DLLDataSet(void) { return dmDLL->DataSet; } //--------------------------------------------------------------------------- TDataSource *DLLDataSource(void) { return dmDLL->DataSource; }
Export Header-Datei für die DLL:
#ifndef _VCLDLLINC #define _VCLDLLINC #ifdef __DLL__ #define __EXPORT_TYPE __declspec(dllexport) #else #define __EXPORT_TYPE __declspec(dllimport) #endif //----------------------------------------------------------------------------- extern "C" __EXPORT_TYPE bool InitDLL(TComponent* Owner); extern "C" __EXPORT_TYPE void DeleteDLL(void); extern "C" __EXPORT_TYPE TADODataSet *DLLDataSet(void); extern "C" __EXPORT_TYPE TDataSource *DLLDataSource(void); //----------------------------------------------------------------------------- #endif
Header-Datei der Hauptanwendung:
//--------------------------------------------------------------------------- #ifndef mainH #define mainH //--------------------------------------------------------------------------- #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ADODB.hpp> #include <DB.hpp> #include <DBGrids.hpp> #include <Grids.hpp> //--------------------------------------------------------------------------- class TfrmMain : public TForm { __published: // IDE-verwaltete Komponenten TDBGrid *DBGrid; void __fastcall FormDestroy(TObject *Sender); private: // Benutzer Deklarationen HMODULE testDLL; typedef bool TInitDLL(TComponent* Owner); TInitDLL *InitDLL; typedef void TDeleteDLL(void); TDeleteDLL *DeleteDLL; typedef TADODataSet *TDLLDataSet(void); TDLLDataSet *DLLDataSet; typedef TDataSource *TDLLDataSource(void); TDLLDataSource *DLLDataSource; public: // Benutzer Deklarationen __fastcall TfrmMain(TComponent* Owner); }; //--------------------------------------------------------------------------- extern PACKAGE TfrmMain *frmMain; //--------------------------------------------------------------------------- #endif
Source-Code Datei der Hauptanwendung:
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "main.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TfrmMain *frmMain; //--------------------------------------------------------------------------- __fastcall TfrmMain::TfrmMain(TComponent* Owner) : TForm(Owner) { testDLL = LoadLibrary("vclDLL.dll"); InitDLL = (TInitDLL*) GetProcAddress(testDLL, "_InitDLL"); InitDLL((TComponent*)Owner); DLLDataSet = (TDLLDataSet*) GetProcAddress(testDLL, "_DLLDataSet"); DLLDataSet()->CommandType = cmdText; DLLDataSet()->CommandText = "SELECT * FROM Employees"; DLLDataSet()->Active = true; // DLLDataSource = (TDLLDataSource*) GetProcAddress(testDLL,"_DLLDataSource"); DLLDataSource()->Enabled = true; DBGrid->DataSource = DLLDataSource(); // DeleteDLL = (TDeleteDLL*) GetProcAddress(testDLL, "_DeleteDLL"); DeleteDLL(); } } //--------------------------------------------------------------------------- void __fastcall TfrmMain::FormDestroy(TObject *Sender) { if (testDLL) { FreeLibrary(testDLL); testDLL = NULL; } } //---------------------------------------------------------------------------
Scheinbar funktioniert die Verbindung, denn wenn ich im CommandText des DataSets eine nicht vorhandene Tabelle angebe, kommt vom Jet-Datenbankmodul eine Meldung, das die Eingangstabelle oder die Abfrage nicht gefunden wurde.
Soweit scheint es zu funktionieren. Nur leider wird im DBGrid nichts angezeigt.Wäre nett wenn mir jemand erklären könnte warum das so nicht geht, bzw. wo mein Denkfehler liegt.
Vielen Dank schonmal, Grüße Netzschleicher
-
Hallo
Ich weiß nicht, ob deine Anwendung von GetProcAddress zur Übergabe einer Objektinstanz wirklich korrekt ist, oder nicht doch undefinirtes Verhalten verursacht. Auf jedenfall ist das nicht portabel : deine DLL wird so nicht von anderen Compilern verwendet werden können, und das kann auch verschiedene Versionen des Builder-Compilers betreffen.
Unabhängig davon siehst du in deinen DBGrid nichts, weil du zwar im Konstruktor des Forms die Datenbankverbindung öffnest, aber gleich auch wieder schließt. Nach dem Konstruktor zur Laufzeit ist also dein DBGrid auf jedenfall leer, egal was du im Konstruktor für Abfragen machst. Du must die Datenbankverbindung die ganze Laufzeot über aufrechthalten (bzw. solange wie das DBGrid etwas anzeigen soll). Verschiebe den Aufruf von DeleteDLL mit in den Destruktor des Forms.bis bald
akari
-
Danke, hast recht. Das 'DeleteDLL' sollte dort eigentlich nicht hin. Habs mal in das OnClose-Event verschoben. Jetzt sehe ich auch meine Beispieldaten im DBGrid.
Ob das So richtig ist weis ich selbst nicht. Deshalb hab ich das Testprojekt ja mal einfach so zusammengesteckt. Das die DLL mit dem Datenmodul in meiner 'richtigen Anwendung' ist statisch gebunden und die DB-komponenten mache ich über eine entsprechende Header-Datei bekannt in welcher einfach die gesamte Klasse des Datenmoduls exportiert wird. Das funktioniert wunderbar.
Ich dachte mir dann eben wie sowas wohl mit einer dynamisch angebundenen DLL funktionieren müsste und habs mal ausprobiert.Hatte ja auch geschrieben, falls ich da mit dem exportieren dieser Komponenten einen Fehler mache, wäre es nett wenn mir jemand erklären könnte wie man bei einer dynamisch gebundenen DLL das richtig macht.
Aber bis jetzt funktioniert es. Zumindest Augenscheinlich.
Danke für den Stubser mit dem 'DeleteDLL'.