Announcement

Collapse
No announcement yet.

DLL in fremden Kontext; Callback procedure

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

  • DLL in fremden Kontext; Callback procedure

    Hallo,<p>
    ich bin momentan mit folgendem Problem konfrontiert:<br>
    Ich habe eine DLL, die zu einem Teil im Kontext eines fremden Prozesses läuft. Innerhalb dieser DLL kommuniziere ich über MMF.<br>
    Nun möchte ich so schnell wie möglich in meinem Programm wissen, ob die ausgeführte Operation (im Kontext des fremden Prozesses) erfolgreich war (oder eben nicht).<p>
    Dafür würde ich am liebsten eine Callback procedure benutzen, doch leider kann ich diese nicht aufrufen, da sie in einem anderen Speicherbereich läuft.<p>
    Ist es in diesem Fall wirklich unmöglich eine Callback procedure zu benutzen?<br>
    Sollte ich evtl. auf Messages zurückgreifen? Ich habe damit noch nicht angefangen, weil mir vor geraumer Zeit (ohne Begründung) abgeraten wurde zwischen Hook-DLL und Programminstanz zu kommunizieren.<p>
    Wer weiß Rat?<p>
    Viele Grüße,<br>
    Markus

  • #2
    Das heist Du hast eine Interprocesskomunikation über MMF's gemacht, gut. Was dir noch fehlt wären das Locking des MMF's und das Eventhandling. Neben dem MMF benötigst Du also noch global gültige Semaphore für's Locking und globale Event's, SetEvent(), CreateEvent() für die Benachrichtigungen. Die DLL erzeugt also ein benamtes globales Event, mit CreateEvent() zum MMF. Die Processes die nun die Daten aus dem MMF lesen sollen müssen einen Thread erzeugen der auf das Globale MMF-Event wartet.<br>
    Der Thread wiederum könnte per Synchronization eine Callback im Context des Mainthreads deines Processes aufrufen.<br>
    Allerdings rate ich von dieser Synchronization ab, falls es sich vermeiden lässt, da z.B. mit Delphi's TThread's einigie schwerwiegende Änderung ab D6 vorgenommen wurden.<bR>

    Gruß Hage

    Comment


    • #3
      Hi Hagen!<p>
      Danke für die klasse Antwort!<br>
      Ich stelle mir nun natürlich die Frage, warum ich nicht gleich mit RegisterWindowMessage eine bzw. zwei globale Messages registriere (OperationSucceeded, OperationFailed) und diese dann von der DLL (aus dem fremden Kontext) zu meiner "MainForm" schicke. Klar, ich habe nach einer Lösung mir einer Callback procedure gefragt aber diese Frage ist nochmal zum Verständnis und um die bestmögliche Lösung in meine DLL implementieren zu können.<p>
      Viele Grüße,<br>
      Marku

      Comment


      • #4
        Weil der Weg über Events auch ohne Fenster funktioniert. Angenommen es soll ein Service Processs auf das MMF reagieren, dann hat der Service keinerlei GUI, kann nicht auf's User Interface zugreifen und somit existieren keienrlei Fensterhandles.<br>

        Die Frage ist ganz einfach: soll der Aufwand nur einmal betrieben werden und Fensterhandles sind garantiert vorhanden, oder soll ein solches Processsharing auch in Zukunft für andere Dinge in eine komfortable Komponente ausgelagert werden.<br>
        Natürlich ist der Weg über Messages einfacher, man muß dann aber nicht unbedingt mit RegisterWindowMessage() arbeiten.<br>

        Gruß Hage

        Comment


        • #5
          Dankeschön Hagen!<br>
          Ich werde versuchen das in naher Zukunft umzusetzen (ohne TThread, pure Win32 API ).<p>
          Gruß,<br>
          Marku

          Comment


          • #6
            Ich habe gehofft, dass ich es alleine schaffe... Momentan sieht es aber eher nicht danach aus.<br>
            Muss ich bei SetEvent und/oder CreateThread mit den <i>SECURITY_ATTRIBUTES</i> arbeiten? Falls ja, könnte mir das jemand näher bringen?<br>
            Ich arbeite mit Win2000.<p>
            Viele Grüße,<br>
            Markus<p&gt

            Comment


            • #7
              Oh, die Fehlerbeschreibung fehlt:<br>
              CreateEvent gibt ein korrektes Handle zurück. Der Thread in der DLL "steht". Ich "feuere" das Event aus dem fremden Prozesskontext, mein WaitForSingleObject scheint das aber nicht zu interessieren :

              Comment


              • #8
                Hi

                Im dr MMF-DLL werden mit CreateFileMapping(.., 'MyMMF1234567') und mit CreateEvent(nil, False, False, 'MyMMFEvent1234567'); die beiden Handles erzeugt. Sie müssen einen Namen haben damit sie global verfügbar sind.<br>

                Dein Thread sollte so aussehen:

                <pre>

                var
                FinishEvent: THandle = 0;
                ThreadHandle: THandle = 0;<br>

                procedure DoMMFChanged;
                var
                MMF: THandle;
                MMFData: Pointer;
                begin
                MMF := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, 'MyMMF1234567');
                if MMF <> 0 then
                begin
                MMFData := MapViewOfFile(MMF, FILE_MAP_ALL_ACCESS, 0, 0, 0);
                if MMFData <> nil then
                begin
                // Access to MMFData

                UnmapViewOfFile(MMFData);
                end;
                CloseHandle(MMF);
                end;
                end;<br>

                function MyThreadProc(Param: Pointer): DWord; stdcall;
                var
                Events: array[0..1] of THandle;
                begin
                FinishEvent := CreateEvent(nil, False, False, nil);
                Events[0] := FinishEvent;
                Events[1] := OpenEvent(SYNCHRONIZE, False, 'MyMMFEvent1234567');
                if Events[1] <> 0 then
                repeat
                case WaitForMultipleObjects(2, @Events, False, INFINITE) of
                WAIT_OBJECT_0: Break; // Thread soll terminieren
                WAIT_OBJECT_0 +1: DoMMFChanged;
                else
                Break; // Abnormal termination
                end;
                until False;
                CloseHandle(FinishEvent);
                CloseHandle(ThreadHandle);
                FinishEvent := 0;
                ThreadHandle := 0;
                end;<br>

                function StartThread: Boolean;
                var
                ThreadID: DWord;
                begin
                if ThreadHandle = 0 then
                ThreadHandle := CreateThread(nil, 0, @MyThreadProc, nil, 0, ThreadID);
                Result := ThreadHandle <> 0;
                end;<br>

                function StopThread: Boolean;
                begin
                Result := FinishEvent <> 0;
                if Result then
                begin
                SetEvent(FinishEvent);
                // evntl.
                WaitForSingleObject(ThreadHandle, INFINITE);
                // oder
                MsgWaitForSingleObject();
                end;
                end;

                </pre>

                Gruß Hage

                Comment


                • #9
                  Jetzt müsste noch in DoMMFChanged() per Locking das MMF geschützt werden.<br>
                  Beachte das DoMMFChanged() im Context unseres Threads ausgeführt wird. Meistens ist dies sinnvoll da dadurch ein Hintergrundprocessing möglich wird. Ich mache es immer so das ich bei Änderungen eine globale Variable MMFChanged := True setze. In meiner Application polle ich MMFChanged in der Messageschleife, oder per Timer, oder per ApplicationEvents.OnIdle();<br>
                  Oder der Thread setzt einfach MMFChanged := True, und die Application die MMFChanged pollt ruft DoMMFChanged() auf um die daten im Mainthread zu lesen.<br>
                  Je nachdem was man erreichen möchte.

                  Gruß Hage

                  Comment


                  • #10
                    Danke!<br>
                    Es scheint zu funktionieren! <br>
                    Wer kein OpenEvent() benutzt, muss sich eben nicht wundern, wenn die verschiedenen Prozesse nicht auf die Events reagieren...<p>
                    Viele Grüße,<br>
                    Marku

                    Comment


                    • #11
                      Übrigens Markus, der Thread muß auch nicht unbedingt sein. Das geöffnete Event hält solange seinen Status bis es abgefragt wird. D.h. man kann auch den Thread verzichten, und mit WaitForSingleObject(Event, 10) innerhalb des Haupthreades pollen. Es hängt halt davon ab was man haben möchte. Soll das geänderte MMF nicht im Hintergrund parallel im Process bearbeitet werden, dann kann man auch auf den Thread verzichten und gleich das Event pollen.

                      Gruß Hage

                      Comment


                      • #12
                        Hi Hagen!<p>
                        Kaum zu glauben, heute habe ich das 1. Mal wieder Zeit zu antworten <br>
                        Nochmals Danke für Deinen nachträglichen Tip!<br>
                        Ich habe mich entschieden jetzt erstmal alles soweit fertig zu machen wie ich es angefangen habe. Später werde ich dann Tests machen wie es ohne den Thread läuft.<br>
                        Ich bin momentan eben nur am Überlegen wie sich die DLL verhält bzw. verhalten sollte, wenn zwei Applicationen gleichzeitig auf sie zugreifen. Ich glaube das wird die nächste Nuss, die es zu knacken gilt...<p>
                        So long. Gruß,<br>
                        Marku

                        Comment


                        • #13
                          Betrachte die DLL wie jeden anderen Client der auf das MMF zugreifen will. Deshalb das globale Semaphore-Handle. Am besten du codest dieses Locking in der DLL und exportierst diese Funktion. Alle anderen Client's der DLL, und das können sehr viele sein, müssen dann diese Funktion nutzen bevor sie auf das MMF zugreifen.<br>
                          Wichtig ist dabei folgendes begriffen zu haben:<br>
                          Ein globaler Hook sitzt in einer DLL damit Windows bei der Installation des Hook's diese DLL automatische in jeden laufenden und vom Hook betroffenen Prozess laden kann. D.h. angenommen 10 Prozesse laufen inkulsive Deiner Anwendung. Diese lädt die DLL und die DLL installiert ihren systemweiten Hook. In diesem Moment, oder aber spätestens wenn der Hook in einem anderen Prozess greifen muss, wird die die DLL zusätzlich in die anderen Prozesse geladen. Damit existieren in unserem Falle 10 eigene DLL-Datensegment im System. ALLE Zugriffe auf's MMF, egal aus welchem Prozesscontext heraus, müssen nun geblockt ablaufen. So wie du das globale Event erzeugt hast sollte nun eine globale Semaphore bei der Installation des Hook's erzeugt werden. In der exportierten Locking-Funktion wird nun mit OpenSemaphore diese Semaphore geöffent. Eine andere Möglichkeit ist es eine globale Variable anzulegen in der das Semaphorehandle gespeichert wird. Da die DLL zu jedem Prozerss ihr eigenes Datensegemnt zugeordnet bekommt, würde diese globale variable also 10 mal im System vorkommen, und jeder process sein eigenes Semaphorehandle besitzen. Wird nun diese Var als Threadvar deklariert wäre das Locking sogar innerhalb der Prozesse Threadsafe.<br>
                          Den Code musst du aber nur einmal in der DLL coden.<bR>
                          ich würde auch mit den Event's so verfahren, und die Pollingfunktion in die DLL verlagern.<br>

                          gruß Hage

                          Comment


                          • #14
                            Und wieder mal kräftig dazugelernt!<br>
                            Nach langem und ausgiebigem Testen kann ich nun behaupten, dass die Variante ohne Thread definitiv die bessere ist in meinem Fall. Die DLL läuft wie geschmiert. ;-)<p>
                            Nochmals vielen herzlichen Dank, Hagen!<p>
                            Gruß,<br>
                            Marku

                            Comment

                            Working...
                            X