Announcement

Collapse
No announcement yet.

ADO Connection unter OLE

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

  • ADO Connection unter OLE

    Hallo zusammen

    Ich bin nahe am verzweifeln mit folgendem Problem:
    Ich habe ein Testprojekt, welches über LoadLibrary und GetProcAddress eine Funktion in einer DLL aufruft. Diese Funktion führt dazu, dass eine Verbindung auf ein MSSQL Datenbank aufbaut. Gelöst wurde dies mit DataModul , ADOConnection und ADODataSet.
    Soweit funktioniert das ja auch. Wenn diese DLL nun von einer anderen Applikation verwendet wird (die eigentliche Zielapplikation) bleibt das Programm immer beim Öffnen der Verbindung hängen. Es gibt weder eine Fehlermeldung noch ein anderes Feedback. Das einzige was ich tun kann ist das Programm per Taskmanager zu schliessen. Und nun das Kuriose: dieser Fehler tritt nur unter Windows NT 4.0 SP6 auf, Windows 2000 läuft einwandfrei. ADO ist auf dem aktuellsten stand (V2.70).

    Weiss da jemand Rat?
    Vielen Dank
    Daniel

  • #2
    Hallo,

    >..Wenn diese DLL nun von einer anderen Applikation verwendet wird ..

    welches Apartment meldet diese andere Anwendung an? Hinter ADO stecken COM-Objekte, und vor dem ersten Zugriff auf ein COM-Interface muss der Prozess (Anwendung) bzw. der Thread sein Apartment beim Betriebssystem anmelden, damit der Marshaler die zu prüfenden Regeln kennt.

    >..beim Öffnen der Verbindung hängen. Es gibt weder eine Fehlermeldung ..

    Wie sieht diese Stelle im Sourcecode aus

    Comment


    • #3
      Soweit ich weiss verwendet es ein Apartment. Ich hab mir mal selber ein ActiveX Library mit einem Automation Object erstellt. Darin befindet sich eine Routine CreateLink, welche die Methode von der besagten DLL aufruft, um eine Verbindung zur DB zu erstellen. Von meiner Testapplikation habe ich dann mit
      <PRE>
      mIntf := CoRepitmobSimu.Create;
      mIntf.CreateLink;
      </PRE>
      das Objekt erstellt und initialisiert. Wie ich es vermutet habe funktioniert dies auf dem Testsystem einwandfrei.

      Die Stelle im Source sieht folgendermassen aus
      Datenmodul erstellen und initialisieren:
      <PRE>
      lDataModul := TDMAccess.Create(Nil);<BR>
      if not lDataModul.Init then begin<BR>
      </PRE>
      In Init Methode:
      <PRE>
      with conDefault do begin
      Close;
      ConnectionString := GetDefaultConnectionString;
      try
      CodeSite.SendMsg('vor open');
      Open;
      CodeSite.SendMsg('nach open');
      </PRE>
      Die CodeSite Message 'nach open' erscheint auf dem Testsystem nie, wenn ich die DLL mit der Zielapplikation verwende. Mit meinem kleinen Testprogram funktioniert das in allen Fällen (statisch gelinkt, dynamisch gelinkt mittels LoadLibrary und per OLE aufruf wie oben beschrieben

      Comment


      • #4
        Hallo,

        im Fall einer universell nutztbaren DLL ist es am Besten, für das Initialisieren eines Apartments eigene Schnittstellenfunktionen zu exportieren: <br>
        1. Client ruft zuerst die eigene DLL-Funktion <i>DBInit</I> auf, um dort über <b>
        CoInitialize(nil);</b> das Apartment anzumelden. <br>
        2. Client nutzt die DLL <br>
        3. Client meldet über die eigene DLL-Funktion <i>DBDone</i> das Apartment wieder ab.

        Über globale Variablen kann die DLL prüfen, was am Ende gemacht werden muss.
        <pre>
        var
        bDoCoUninitialize : Boolean;
        bDoDestroyDM_ADO : Boolean;
        </pre>
        <pre>
        function E_DBInit(const pNewMDBPath: PChar): Integer;
        var
        aCatalog : _Catalog;
        begin
        Result := 1;
        bDoCoUninitialize := False;
        bDoDestroyDM_ADO := False;
        try
        CoInitialize(nil);
        bDoCoUninitialize := True;
        DM_ADO := TDataModule_ADO.Create(nil);
        bDoDestroyDM_ADO := True;
        ...
        end;
        </pre>
        Die exportierte Schnittstellenprozedur DBDone könnte zu Beispiel so aussehen:
        <pre>
        function E_DBDone: Integer;
        begin
        Result := 1;
        try
        if bDoDestroyDM_ADO then
        DM_ADO.Free;
        if bDoCoUninitialize then
        CoUninitialize;
        except
        ShowExceptionMsg('E_DBDone-Fehler');
        Result := 0;
        end;
        end;
        </pre&gt

        Comment


        • #5
          Hallo

          Zuerst möchte ich mich mal bedanken, dass Sie sich dem so ausführlich annehmen.

          So, nun wieder zum eigentlichen Problem :-)
          Die von Ihnen gemachten Vorschläge würden Sinn machen, wenn ich dies in der Zwischenzeit nicht auch schon ausprobiert hätte. Ich hatte auch schon auf die ADO Komponenten verzichtet und eine direkte Connection erstellt, wie Sie das auch in Ihrem Buch beschreiben (CoConnection.Create...). Auch das Aufrufen von CoInitialize und CoInitializeEx brachte keine Lösung.

          Auch der Ablauf sieht im Originalen so aus, wie Sie das Vorschlagen.
          <PRE>
          CreateLink -> Verbindung aufbauen, Initialisieren von Objekten, etc.
          RequestData -> Daten werden beliebig oft angefragt. Dazu werden die Objekte verwendet, welche in CreateLink erstellt wurden
          DestroyLink -> Verbindung trennen, Objekte aufräumen.
          </PRE>

          Weiter hab ich noch herausgefunden, dass, wenn ich die ADO Connection erst zum Zeitpunkt der ersten Abfrage in RequestData initialisiere, funktioniert die ADO Verbindung. Irgend etwas wird zwischen CreateLink und RequestData von der Zielapplikation initialisiert, wodurch die ADO Connection ermöglicht wird.
          Wie gesagt: dies Verhalten konnte ich nur auf einem Windows NT 4 (SP6, ADO 2.7) entdecken. Auf Windows 2000 läuft alles einwandfrei.

          Im übrigen bin ich mit dem Entwickler der Zielapplikation das Problem ebenfalls am untersuchen. Leider bis jetzt auch ohne Erfolg.

          Daniel Wis

          Comment


          • #6
            Nochmals hallo

            Das Problem konnte nach langwierigen Test auf die Zielapplikation verschoben werden, da zum Zeitpunkt, wo CreateLink aufgerufen wird, gewisse Sachen unter bestimmten Umständen noch nicht initialisiert wurden.

            Nun hab ich die Initialisierung in die Funktion RequestData verschoben und mit einem Flag versehen, damit dies nur einmal geschieht. Leider hat sich nun ein weiteres Problem ergeben, welches definitiv in meiner DLL ist aber dazu mache ich ein neues Thema auf.

            Vielen Dank Herr Kosch für Ihre unterstützung
            Daniel Wis

            Comment

            Working...
            X