Announcement

Collapse
No announcement yet.

Datenmodul in DLL

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Datenmodul in DLL

    Hallo,

    bin dabei eine App in handliche DLL's zu zerlegen.

    Wo ist die Ursache dafür zu finden, das SQL-Befehle eines Datenmoduls (in einer DLL)
    nicht ausgeführt werden, andere Dinge wie Meldungen aber klappen. Weis das jemand?

    (D6-1-Prof, M$-sqls 7)

    Gruß, Kde

  • #2
    Hallo,

    prinzipiell liegt das nicht am Datenmodul in der DLL. In einer mehrschichtigen Datenbankanwendung für COM+ liegen alle Objekte als DLL vor, wobei dort auch Datenmodule verwendet werden können. Das Anwendungsprogramm (EXE oder ASP) greift über die COM-Interfaces auf diese DLL zu, wobei die DLL die Ergebnismenge zurückliefert. Wenn man ADO (bzw. ADO Express) für den Zugriff auf die Datenbank verwendet, gibt es keine Probleme. Da sich hinter ADO intern ebenfalls COM-Objekte verbergen, kann der Marshaler des Betriebssystems die Verbindung DLL <--> EXE problemlos herstellen (es spielt dabei keine Rolle, auf welchem Rechner die DLL liegt).

    Allerdings macht es immer dann einen Unterschied, wenn die <b>BDE</b> im Spiel ist. Im Fall der BDE sind Vorbereitungen in der DLL notwendig. Die BDE nutzt den direkten Zeigerzugriff im Adressraum des Prozesses und erwartet eine bestimmte Initialisierungsreihenfolge (damit dies klappt).

    Da Borland die BDE seit einiger Zeit offiziell zum "alten Eisen" gelegt hat, würde ich die Aufteilung der Anwendungsfunktionalität in separate Module ebenfalls über den COM-Weg (Interfaces) implementieren. In diesem Fall spielt es überhaupt keine Rolle, in welchem Modul (eingebundene DLL oder fremde EXE) der Datenbankzugriff erfolgt

    Comment


    • #3
      Hallo,

      besten Dank für Ihre Antwort. Von der BDE werde ich Ihren Rat befolgend nun Abschied nehmen.

      Leider ist das DLL-Problem auch mit ADO von mir nicht in den
      Griff zu bekommen. In Ihrem Buch: Client/Server habe ich dazu
      - schade - auch nichts Näheres hierzu finden können.

      Auf das Datenmodul in der DLL möchte ich nicht verzichten,
      da es organisatorisch ein großes Plus ist.

      Die DLL ohne Datenmodul läuft einwandfrei. Mit Datenmodul
      werden zwar "Meldungen" im Datenmodul angezeigt aber die
      Verbindung klappt nicht. Die Verbindung innerhalb der DLL
      ohne Datenmodul klappt ebenfalls einwandfrei. ADO löst das
      Problem leider nicht.

      Trotzdem, besten Dank.

      Gruß, Kd

      Comment


      • #4
        Hallo,

        ADO taucht erst in meinem COM+ Buch auf, wobei mein neues Buch sich ausschliesslich um ADO kümmert. Wenn der ADO-Zugriff über ein Datenmodul in der DLL nicht funktioniert, wie sieht ein kurzes Beispiel aus, mit dem dieser Effekt jederzeit reproduzierbar ist

        Comment


        • #5
          Hallo,

          sofern ein Fehler nicht aus meinem Programmablauf ersichtlich ist,
          mache ich mir gerne die Mühe ein Beispielprogrämmchen zu senden.

          Der extrahierte Code sieht so aus: Hauptprogramm:

          <PRE>

          //***** PROVISIONEN ******
          procedure TFrmMenue.m_ProvisionenClick(Sender: TObject);
          type
          TShowProvis = Procedure(Aform:TForm);
          var
          DLLInstance :THandle;
          ShowProvis :TShowProvis;
          gPfad: PChar;
          begin

          gPfad := PChar (ucLocalPfad + 'Provisionen.DLL');
          DLLInstance := LoadLibrary(gPfad);

          if DLLInstance = 0 then begin
          KdeMessi('Info', 'Provisions-Prg steht nicht zur Verfügung !');
          EXIT;
          end;

          @ShowProvis := getProcAddress(dllInstance,'ShowProvis');

          ShowProvis(Self);

          FreeLibrary(DLLInstance);

          end;
          //***** END PROVISIONEN ******

          //***** library Provisionen; ******
          uses
          ShareMem,
          SysUtils,
          Classes,
          Forms,
          Provis_Main in 'Provisionen\Provis_Main.pas' {FrmProvision},
          Provis_DM in 'Provisionen\Provis_DM.pas' {FrmProvis_DM: TDataModule};

          {$R *.res}

          Function ShowProvis: Integer; stdcall;
          var
          Form :TFrmProvision;

          begin
          Form :=TFrmProvision.Create(Application);
          Result :=Form.ShowModal;
          Form.Free;
          end;

          exports
          ShowProvis;

          begin
          //
          end.
          //***** END library Provisionen; ******

          //***** unit Provis_Main; ******
          ...

          procedure TFrmProvision.FormShow(Sender: TObject);
          begin
          FrmProvis_DM.OpenQRYs; // Das haut NICHT hin
          // Qry_Berater.Open; // Das haut hin
          end;
          ...

          //***** END unit Provis_Main; ******

          //***** unit Provis_DM; ******
          // Das Datenmodul
          ...

          Procedure TFrmProvis_DM.OpenQRYs;
          Begin
          // Abfragen öffnen
          Application.Messagebox( 'Öffnen der Querys', '1. Provi_DM');
          // Die Meldung kommt!

          Qry_Berater.Open; //--> Patsch Aua! )*

          // Application.Messagebox( 'Hi', 'Ende1 Provi_DM');
          End;
          ...
          //***** END unit Provis_DM; ******

          </PRE>

          )* Bei Qry_Berater.Open erhalte ich die Meldung:
          "Zugriffsverletzung bei Adresse 03FEE5C7 in Modul 'Provisionen.DLL'
          Lesen von Adresse 0000005C."

          Wenn Qry_Berater.Open in unit Provis_Main geöffnet wird, exakt gleiche
          Bedingungen, geht alles gut. ADO ändert hieran leider nichts.

          Danke für Ihre Zeit.

          Gruß, Kd

          Comment


          • #6
            Hallo,

            sorry, der Code war nicht schön. Hier hoffentlich besser:

            Sofern ein Fehler nicht aus meinem Programmablauf ersichtlich ist, mache ich mir gerne die Mühe ein Beispielprogrämmchen zu senden.

            Der extrahierte Code sieht so aus: Hauptprogramm:

            //***** PROVISIONEN ******
            procedure TFrmMenue.m_ProvisionenClick(Sender: TObject);
            type
            TShowProvis = Procedure(Aform:TForm);
            var
            DLLInstance :THandle;
            ShowProvis :TShowProvis;
            gPfad: PChar;

            begin

            gPfad := PChar (ucLocalPfad + 'Provisionen.DLL');
            DLLInstance := LoadLibrary(gPfad);

            if DLLInstance = 0 then begin
            KdeMessi('Info', 'Provisions-Prg steht nicht zur Verfügung !');
            EXIT;
            end;

            @ShowProvis := getProcAddress(dllInstance,'ShowProvis');

            ShowProvis(Self);

            FreeLibrary(DLLInstance);

            end;

            //***** END PROVISIONEN ******

            //***** library Provisionen; ******
            uses
            ShareMem,
            SysUtils,
            Classes,
            Forms,
            Provis_Main in 'Provisionen\Provis_Main.pas' {FrmProvision},
            Provis_DM in 'Provisionen\Provis_DM.pas' {FrmProvis_DM:
            DataModule};

            {$R *.res}

            Function ShowProvis: Integer; stdcall;
            var
            Form :TFrmProvision;

            begin
            Form :=TFrmProvision.Create(Application);
            Result :=Form.ShowModal;
            Form.Free;
            end;

            exports
            ShowProvis;

            begin
            //
            end.
            //***** END library Provisionen; ******

            //***** unit Provis_Main; ******
            ...

            procedure TFrmProvision.FormShow(Sender: TObject);
            begin
            FrmProvis_DM.OpenQRYs; // Das haut NICHT hin
            // Qry_Berater.Open; // Das haut hin
            end;
            ...

            //***** END unit Provis_Main; ******

            //***** unit Provis_DM; ******
            ...

            Procedure TFrmProvis_DM.OpenQRYs;
            Begin
            // Abfragen öffnen
            Application.Messagebox( 'Öffnen der Querys', '1. Provi_DM');
            // Die Meldung wird angezeigt!

            Qry_Berater.Open; //--> Patsch Aua!

            // Application.Messagebox( 'Hi', 'Ende1 Provi_DM');
            End;
            ...

            //***** END unit Provis_DM; ******

            Bei Qry_Berater.Open erhalte ich die Meldung:
            "Zugriffsverletzung bei Adresse 03FEE5C7 in Modul 'Provisionen.DLL'
            Lesen von Adresse 0000005C."


            Wenn Qry_Berater.Open in unit Provis_Main geöffnet wird,
            exakt gleiche Bedingungen, geht alles gut.
            ADO ändert hieran leider nichts.

            Danke für Ihre Zeit.

            Gruß, Kd

            Comment


            • #7
              Hallo,

              &gt;sofern ein Fehler nicht aus meinem Programmablauf ersichtlich ist

              in dem o.g. Beispiel vermisse ich die Programmzeile, die für Erzeugen der Instanz des Datenmoduls zuständig ist.

              Mit dem folgenden Beispiel kann ich ein Datenmodul in einer DLL problemlos verwenden. Die DLL sieht so aus, wobei im Datenmodul nur TADOConnection und TADODataSet verwendet wird und keine einzige Programmzeile dort von Hand geändert wurde:
              <pre>
              library ADOinDLL;

              uses
              SysUtils, Windows, Classes, ActiveX,
              ADOinDLL_DM in 'ADOinDLL_DM.pas' {DataModule1: TDataModule};

              {$R *.res}

              procedure ShowData; stdcall;
              var
              iCount : Integer;
              begin
              CoInitialize(nil);
              try
              DataModule1 := TDataModule1.Create(nil);
              try
              DataModule1.ADOConnection1.Connected := True;
              DataModule1.ADODataSet1.Active := True;
              iCount := DataModule1.ADODataSet1COLUMN1.Value;
              DataModule1.ADODataSet1.Active := False;
              DataModule1.ADOConnection1.Connected := False;
              finally
              DataModule1.Free;
              end;
              finally
              CoUninitialize;
              end;
              MessageBox(0, PChar(IntToStr(iCount)), 'SELECT Count(*) FROM Categories', 0);
              end;

              exports
              ShowData;

              begin
              end.
              </pre>
              Der Client ruft die exportierte Schnittstellenprozedur der dynamisch importierten DLL auf:
              <pre>
              type
              TShowData = procedure;
              var
              aShowData : TShowData;

              procedure TForm1.Button1Click(Sender: TObject);
              var
              hDLL : THandle;
              begin
              hDLL := LoadLibrary('C:\Ablage\ADOinDLL.dll');
              if hDLL = 0 then
              begin
              ShowMessage('DLL kann nicht geladen werden');
              Abort;
              end;
              @aShowData := GetProcAddress(hDLL, 'ShowData');
              if Assigned(aShowData) then
              aShowData;
              FreeLibrary(hDLL);
              end;
              </pre&gt

              Comment


              • #8
                Hallo,

                > in dem o.g. Beispiel vermisse ich die Programmzeile, die für
                > Erzeugen der Instanz des Datenmoduls zuständig ist.

                Wo und wie wäre die unterzubringen? Da in der normalen App. die Verbindung scheinends selbst generiert wird, habe ich es mir in der
                DLL auch so vorgestellt. Da es nicht so ist, fehlt mir hier der Einstieg etwas.

                Ihr Programmbeispiel ist problemlos verwendbar aber > ich vermisse die Programmzeile die für das Erzeugen der Instanz des Formulars zuständig ist. <

                Denn so ist es leider auch nur "die halbe Miete".
                Mein Vorhaben ist das Programm in Module zu teilen, die in den DLL's sind. Die Module sollen praktisch abgeschlossene Programme sein. Schlicht gesagt eine für die Adressenverwaltung (mit Forms und Datenmodul...), eine für das Artikelwesen usw.

                Die DLL nun soll Forms und Datenmodule haben. Eine Form innerhalb der DLL soll auf das Datenmodul der gleichen DLL zugreifen können und auf andere.

                Nun weis ich wie man DLL's macht mit Forms, Grids etc. die funktionieren und wie man DLL's macht mit Datamodulen die funktionieren. Letzteres von Ihnen. Danke.

                Ich weis aber nicht, wie beides zusammen funktioniert.
                Und nun? ;-)

                > und keine einzige Programmzeile dort von Hand geändert wurde:

                Das ist schon genial. Auch Ihr Programmaufbau gefällt mir sehr gut.

                In der Library musste ich allerdings schon ein paar Zeilen von Hand ändern. :-)

                Gruss, Kd

                Comment


                • #9
                  Lieber Herr Kosch,

                  natürlich hat mir die Sache keine Ruhe gelassen - und manchmal sieht man den Wald vor lauter Bäumen nicht - ich denke, Sie kennen das.

                  Es haut nun Oberklasse hin.

                  In einem früheren Thema, rieten Sie mir Abstand von TTable zu nehmen.
                  Bei uns steckt der SQL-Server 7.0 dahinter und z.T. viele tausend Datensätze in den normierten Tabellen.

                  Damit werde ich mich jetzt beschäftigen. Nochmals besten Dank.
                  Schönes Wochenende und bis demnächst!

                  Gruß, Kd

                  Comment

                  Working...
                  X