Announcement

Collapse
No announcement yet.

Aufruf eines LocalSevrers aus einer DLL zur "Einbindzeit"

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

  • Aufruf eines LocalSevrers aus einer DLL zur "Einbindzeit"

    Hallo!

    Ich würde gern aus einer DLL heraus eine Verbindung zu einem local Server aufbauen. Ich erzeuge also die Instanz der Klasse und führe einige Operationen durch. Dies schreibe ich nun in eine Prozedur (in der DLL) und rufe diese Prozedur aus einer Anwendung heraus auf (also binde die DLL ein und rufe dann diese Prozedur, welche die Verbindung zum Local Sevrer herstellt und Daten sendet, auf) -> alles funktioniert wunderbar. Ich brauche dies allerdings so, dass die Verbindung zum Local-Server aufgebaut wird, wenn die DLL geladen wird, also habe ich versucht die prozedur, welche das managt, direkt im begin..end-Teil meiner DLL aufzurufen mit einem negativen Ergebnis: Es kommt keine Verbindung zustande! Ich versuche also eine Verbindung zu einem LocalServer aus einer DLL heraus zu deren "Einbindzeit" herzustellen.
    Binde ich diese DLL, welche die Verbindung zur Einbindzeit herstellen sollte, in ein Programm statisch ein (also so dass die DLL beim starten des Programms in den Addressraum geladne wird), so erhalte ich eine Access Violation. Binde ich die DLL dynamisch über LoadLibrary ein, so "hängt" die DLL beim Aufruf von "DLL := CoDLL.Create" (DLL ist vom Typ IDLL und CoDLL ist die zugehörige CoClass).

    Kann mir jemand helfen?

    Hier einmal der Code meiner Test-DLL:
    <PRE>library SaintSecureTestDLL;


    uses
    SysUtils,
    Classes,
    SaintSecureServer_TLB in '..\SaintSecureServer_TLB.pas'; // die TLB, in der IDLL deklariert ist
    {$R *.res}


    function StartTest: Word; stdcall;
    var
    DLL : IDLL;
    wLogLevel,
    wID : Word;
    bDecryptOnCopy : byte;
    begin
    DLL := CoDLL.Create;
    wID := DLL.Login('TESTDLL', wLogLevel, bDecryptOnCopy);
    DLL.Log(wID, $FFFF, 'Testmessage');
    DLL.Logout(wID);
    DLL := nil;
    end;


    exports StartTest;


    begin
    // StartTest; // &lt;- wenn ich hier einkommentiere, bekomme ich zur Einbindzeit KEINE Verbindung, sondern mein Programm (welches die DLL eingebunden hat) hängt
    end.
    </PRE>

    MfG

    Bastian Glöckle

  • #2
    Hallo,

    &gt;..sondern mein Programm (welches die DLL eingebunden hat) hängt.

    dies passiert immer dann, wenn sich das Programm nicht an die Win32-Regeln hält :-)

    Wenn man auf den Ladevorgang der DLL reagieren will, muss die Variable <b>DLLProc</b> aus der System-Unit von Delphi auf die Adresse der eigenen Handler-Prozedur gesetzt werden, die auf die von Win32 ausgelösten Aufrufe reagiert:
    <pre>
    DLLProc := @DLLHandler;
    </pre>
    Ein Beispiel für das Auswerten der von Win32 ausgelösten Aufrufe könnte so aussehen:
    <pre>
    <b>procedure</b> DLLHandler(aReason : Integer);
    <b>var</b>
    szInfo : <b>array</b>[0..29] <b>of</b> Char;
    <b>begin</b>
    <b>case</b> aReason <b>of</b>
    DLL_Process_Detach : szInfo := <font color="#9933CC">'DLL wird entladen.'</font>;
    DLL_Thread_Attach : szInfo := <font color="#9933CC">'Thread wird zugewiesen'</font>;
    DLL_Thread_Detach : szInfo := <font color="#9933CC">'Thread wird abgekoppelt.'</font>;
    <b>end</b>;
    MessageBox(0, szInfo, <font color="#9933CC">'DLL-Handler'</font>, mb_IconInformation);
    <b>end</b>;
    </pre>
    Aber auch dann muss man ganz genau in der Hilfedatei des <i>Microsoft Platform SDK</i> nachlesen, <b>welche</b> Aufrufe dort erlaubt und welche <b>nicht</b> erlaubt sind. Es ist somit das Einfachste, eine separate Interface-Methode vorzusehen, um diese Funktion von Außen anzustoßen. Außerdem muss vor dem ersten Zugriff auf eine COM-Funktion das Apartment definiert werden, indem zum Beispiel die Win32-API-Funtion <b>CoInitialize</b> aufgerufen wird

    Comment


    • #3
      Guten mittag!

      Vielen Dank ersteinmal für ihre Antwort!

      > Es ist somit das Einfachste, eine separate Interface-Methode vorzusehen, um diese Funktion von Außen anzustoßen

      Das ist leider in meinem Fall nicht möglich, da die DLL über einen API-Hook in viele Prozesse verteilt wird (sie existiert also nicht nur einmal) und da möchte ich halt, dass sich diese "Hook"-DLLs per COM am COM-Server anmelden, dass ich weiß in welchen Prozessen meine DLL steckt..
      Leider habe ich momentan nicht genug Ruhe, das auszuprobieren, werde das aber heute abend nachholen und meie Ergebnisse hier für all die anderen User, die vielleicth mal dieses Problem haben, posten...

      >Außerdem muss vor dem ersten Zugriff auf eine COM-Funktion das Apartment definiert werden, indem zum Beispiel die Win32-API-Funtion CoInitialize aufgerufen wird.

      Hmm, aber wieso funktioniert die Prozedur ohne CoInitialize dann wenn ich sie z.B. nach einem ButtonClick aufrufe? Das verstehe ich nicht ganz.. Aber ich gebe mich ihnen geschlagen Sie haben wohl definitiv mehr Ahnung von COM als ich sie habe

      MfG

      Bastian Glöckl

      Comment


      • #4
        Hallo,

        &gt;...nach einem ButtonClick aufrufe?

        wenn der Button in einem Delphi-Programm (EXE) steckt, hat der Initialize-Aufruf von TApplication dies bereits erledigt :-)
        <pre>
        begin
        Application.Initialize;
        Application.CreateForm(TFormMain, Form1);
        Application.Run;
        end.
        </pre>
        Ein Apartment muss je Thread angemeldet werden. Im Fall einer Delphi-EXE macht das Delphi für den primären Thread der VCL automatisch

        Comment


        • #5
          So, ich habe mein Problem nun gelöst und es funktioniert auch soweit wunderbar! Der Code meiner DLL:

          <PRE>library SaintSecureTestDLL;

          uses
          SysUtils,
          Classes,
          ActiveX,
          Windows,
          SaintSecureServer_TLB in '..\SaintSecureServer_TLB.pas';

          {$R *.res}

          var
          cThreadID : Cardinal;
          booDone : boolean;

          const
          THREAD_TERMINATE = 1; // konstante aus Win SDK

          function StartTest: Word; stdcall;
          var
          DLL : IDLL;
          wLogLevel,
          wID : Word;
          bDecryptOnCopy : byte;
          begin
          CoInitialize(nil);
          DLL := CoDLL.Create;
          wID := DLL.Login('TESTDLL', wLogLevel, bDecryptOnCopy);
          DLL.Log(wID, $FFFF, 'TestMessage');
          DLL.Logout(wID);
          DLL := nil;
          CoUninitialize;
          booDone := true;
          end;

          procedure CheckThread; stdcall;
          var
          cThreadSTartTestID,
          cThreadHandle : Cardinal;
          begin
          booDone := false;
          repeat
          cThreadHandle := CreateThread(nil, 0, @StartTest, nil, THREAD_TERMINATE, cThreadStarttestID);
          WaitForSingleObjectEx(cThreadHandle, 3000, false);
          TerminateThread(cThreadHandle, 1);
          until booDone;
          end;

          exports StartTest;

          begin
          DisableThreadLibraryCalls(GetModuleHandle('SaintSe cureTestDLL.dll'));
          CreateThread(nil, 0, @CheckThread, nil, 0, cThreadID);
          end.</PRE>

          Ich erzeuge also nun beim Initialisieren der DLL einen Thread (Prozedur CheckThread). dieser Thread erzeugt wieder einen Thread, der dann versucht das COM-Objekt zu erzeugen. Sollte dieser das nicht innerhalb von 3 Sekunden geschafft haben (diese Zeitspanne werde ich noch erhöhen, wir wollen ja die wirklich-langsam-PCs nicht außen vor lassen ), so wird der Thread abgeschossen und ein neuer Anlauf wird gestartet.
          Zu beachten ist allerdings, dass die Variable "DLL" nun auch nur in diesem einen Thread (der in der Prozedur StartTest) verfügbar ist! Möchte man dieses durch den Thread erzeugte Interfac auch in anderen Threads (z.B. dem Mainthread) benutzen, so muss man es per Hand marshalen (siehe z.B. Buch COM/DCOM/COM+ (von Andreas Kosch) Kapitel 4.7 ab Seite 219)!

          Ich möchte mich nocheinmal bei Herrn Kosch bedanken, auch für dieses Buch!

          MfG

          Bastian Glöckl

          Comment

          Working...
          X