Announcement

Collapse
No announcement yet.

Forms in DLLs und MDI Childs

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

  • Forms in DLLs und MDI Childs

    Folgendes Problem!

    Ich hab ein MDIForm und viele DLLs! Diese DLLs beherbergen viele Fenster die meist als MDIChild geöffnet werden sollen.
    Dazu habe ich an die DLL beim Initialisieren das Application objekt übergeben! Wenn ich jetzt ein MDIChild erzeuge ( MDIForm := TMDIForm.Create(Application) ) tritt ein Merkwürdiger effekt auf!
    Und zwar kann man ja in einem MDIForm nachschauen wie viele Fenster geöffnet sind(Application.MainForm.MDIChildCount)! Mach ich das aus einer DLL die ein Fenster geöffnet hat dann seh ich nur die Fenster die aus der DLL Stammen! Im MDIForm selber (self.MDIChildCount) steht in der Variable eine 0 sprich es exsistieren keine MDI Fenster!

    Wo liegt hierbei der Fehler?
    Kann man das Application objekt noch anders übergeben??
    (Nur das handle übergeben funktioniert leider nicht!)

    Weiteres Problem!
    Wenn ich jetzt aus dem MDIForm (also der *.exe Datei) ein Fenster schließe welches von einer DLL geöffnet wurde bekommen ich Merkwürdiger weise immer andere Fehlermeldungen!
    Mal nach dem ich das Programm geschlossen hab und mal sofort ein Lesefehler an Addresse FFFFFFFFF oder 0000000000!
    Ich tipp mal das der Speicher nicht richtig freigegeben wird!
    Hat jemand eine Idee wie man das rausfinden kann?
    Im Debugger hab ich irgenwie sowas wie ne Auflistung der erzeugten Objekte leider nicht gefunden!

    MfG

    Marcel Schmied

  • #2
    Hallo Marcel,<p>
    versuchs mal auf http://www.delphi3000.com , da gibt es ein Beispiel, wie man ein MDI - Child in eine dll packt,<br>
    schau Dich aber vorher mal hier im Forum um, die Probleme die Du jetzt hast sind nur die "Spitze des Eisberges".<br>
    Unter "Packages, alles oder nichts" ist von Hagen Reddmann ein Posting, welches die Problematik gut erklärt.<br>
    Ich kann Dir aus Erfahrung sagen, dass das Thema MDI in DLL einiges an Arbeit und griffen in die Trickkiste erfordert.<br>
    Ich bin momentan etwas im Zeitdruck (warum wohl ?), sag nochmal "Bescheid" wenn Du noch Hilfe brauchst.<br>

    Gruß Ebb

    Comment


    • #3
      Hallo Ebby,

      das freut mich ja zu hören! Kann man irgenwo nachlesen wieso das nicht funktioniert? Nutzen die irgendeinen anderen verwaltungs Speicher?
      Die informationen die ich von den MDIChilds brauch übergeb ich mir einfach mit das ist nicht das problem! Im MDIForm kann ich dann auch die eigenschaften ändern! Nur leider schmiert die Kiste ab wenn ich das Formular schliesse, allerdings auch nicht immer! Mal nachdem ich es 5 mal geöffnet hab und dann alle schliesse und mal garnicht!<p>

      Ich sollte wohl noch sagen das ich dem Formularen eine neue OnClose Methode zuweise! In dieser wird das Fenster "abgemeldet" und mit Release geschlossen! Das habe ich mit verschiedenen methoden versucht!<br> 1. Ich hab den Zeiger auf das Fenster und rufe Direkt Release auf!<br> 2. Ich ruf eine Funktion in der DLL auf die das Fenster entfernt!<br> beides hat den selbe effekt! Mal gehts und mal nicht!<p>
      Irgendwie bin ich da etwas ratlos<p>
      Bye<p>Marcel Schmie

      Comment


      • #4
        Hallo Marcel,<p>
        ohne den Quellcode ist eine Fehleranalyse hier sehr schwer, ich kann Dir nur <br> einige vermutungen anbieten:<br>
        zu 1: Ich benutze nur das OnClose Ereignis mit 'Action:=caFree;' des Kindfensters <br> um das Formular aus dem Speicher zu entfernen.<br>
        Mir ist Aufgefallen, das Du das Kindfenster mit MyForm:=TMyFormCreate(Application) generierst.<br>
        Verwendest Du an dieser Stelle das Application - Objekt des Elternfensters ?<br> Ich übergebe das Elternfenster mit in die dll und erzeuge das Formular mit MyForm:=TMyForm.Create(ParentForm).<br>
        Wenn Du mit VCL - Objekten arbeitest muss in allen Units (auch im Projekt - Quelltext !) ShareMem eingebunden sein. <br> Das gilt auch für die Verwendung der Delphi String - Klasse.<br>
        Du kannst mir auch eine mail ([email protected]) schicken, wenn Dir das posten des Quellcodes zu umständlich ist.<p>

        Schöne Feiertage an Alle <br><br> Ebb

        Comment


        • #5
          Hi Ebby

          MyForm := TMyForm.Create(ParentForm) bringt in DLL's NICHTS, da das ParentForm ein Zeiger auf ein TForm Object ist das eine andere Klassendefinition als die der DLL nutzt. Somit ist Dein Aufruf identisch mit MyForm := TMyForm.Create(nil);
          Einzigst generische Windows-Handles (hWnd) können Application/DLL übergreifend genutzt werden (logisch da vom System verwaltet).

          Gruß Hage

          Comment


          • #6
            Hallo Hagen,<p>
            ist richtig mit "Create(nil)", mann kann mit Application.MainForm von der dll aus auch auf das Elternfenster zugreifen, ohne es als Parameter zu übergeben.<br> Asche auf mein Haupt ;-).<p>Gruß<br> Ebb

            Comment


            • #7
              Hi Ebby

              <b>"mann kann mit Application.MainForm von der dll aus auch auf das Elternfenster zugreifen"</b>

              Eben NICHT. Aus der DLL heraus greifts Du damit auf das in die DLL abgelegte Application Object zu. Dieses besitzt also NIEMALS ein gültiges Application.MainForm und schon garnicht das Form der übergeordneten EXE -> Processes. Ohne gemeinsamgenutztes Packages VCLxx.?pl stehen jeder DLL und der EXE jeweils ein eigenes Application und Screen Object zur Verfügung. Zwischen dieses eigenen "Kopien" besteht KEINERLEI Zusammenhang, auch der überschneidende Zugriff wäre "illegal".

              Z.B. ein an die DLL übergebenes Form würde bei folgender Abfrage IMMER False liefern.

              <pre>

              function CodeInDerDLL(Form: TForm): Bool; stdcall;
              begin
              Result := Form is TObject;
              end;

              </pre>

              Gruß Hage

              Comment


              • #8
                Ich habe der DLL das Application Objekt des Programmes übergeben und dann mit Application.MainForm.Caption := 'Geändert von DLL'; die Caption des Hauptprogrammes geändert!<p>Bye<p>Marcel Schmie

                Comment


                • #9
                  Hi

                  Jo, auf diese Antwort habe ich gewartet, danke <br>
                  Ja man kann so vorgehen. Probiere nun die DLL mit Delphi 3 zu erstellen und die Hauptanwendung mit Delphi 5. Eine DLL ist ja dazu da, daß man diese nicht ständig neu compilieren muß, als let's go and test it !

                  Gruß Hage

                  Comment


                  • #10
                    Hmm....
                    Ich hab aber nur Delphi 5 und das wird sich irgenwie auch nicht so schnell ändern!<br>Übrigens das mit dem ShareMem hilft wahnsinnig viel auch wenn das die Möglichkeit raubt eine andere Programmiersprache zu nehmen um die DLL's zu schreiben oder zu nutzen!<p>Bye<p>Marcel Schmie

                    Comment


                    • #11
                      Ok, dann probier folgenden Code in der DLL, nachdem Du die Application-Variable umgebogen hast:

                      <pre>

                      function IsApplication: Boolean;
                      begin
                      Result := Application is TApplication;
                      end;

                      </pre>

                      Wie gesagt der IS Operator wird häufig intern benutzt um die gültigkeit von Objecten zu testen.

                      Gruß Hage

                      Comment


                      • #12
                        Hi Marcel

                        <b>Ich hab ein MDIForm und viele DLLs! Diese DLLs beherbergen viele Fenster die meist als MDIChild geöffnet werden sollen. Dazu habe ich an die DLL beim Initialisieren das Application objekt übergeben! Wenn ich jetzt ein MDIChild erzeuge ( MDIForm := TMDIForm.Create(Application) ) tritt ein Merkwürdiger effekt auf! Und zwar kann man ja in einem MDIForm nachschauen wie viele Fenster geöffnet sind(Application.MainForm.MDIChildCount)! Mach ich das aus einer DLL die ein Fenster geöffnet hat dann seh ich nur die Fenster die aus der DLL Stammen! Im MDIForm selber (self.MDIChildCount) steht in der Variable eine 0 sprich es exsistieren keine MDI Fenster! </b>

                        Ganz genau, für eine DLL existieren NUR Fenster deren Klassentyp auch in der DLL definiert wurde und die auch in der DLL erstellt wurden. ShareMem kann hier nur bedingt abhelfen. Alle anderen Fenster aus anderen Modulen (EXE, andere DLL's) sind für die DLL NUR irgendwelche Zeiger auf irgendwelche Daten. Man kann diese Zeiger nun TypCasten also ein TForm(FormAusAndererDll).Caption := '...', ABER das funktioniert NUR weil das andere DLL-Form EXAKT mit der gleichen VCL also Typdefinition/Klassenstruktur versehen IST. Falls diese sich nur in einem Feld unterscheidet wird eine AV generiert.<br>

                        Eignetlich ist die Sache doch ganz einfach:
                        Stell Dir vor Du definierst einen Record mit verschiedenen Feldern. Diesen kannst Du auch DLL übergreifen nutzen, FALLS alle DLLs auch die gleiche Recorddefinition nutzen. Jetzt stell Dir vor die DLL soll auch den TYP dieses records überprüfen können. Damit das funktioniert muss der Compiler spezielle Typinformationen in die EXE/DLL etc. hineinlinken. Diese Typinformationen werden in dem Modul abgelegt in dem der Record definiert wurde, also im Codesegment der DLL. Benutzt Du also nun dynamisch agierende Typprüfungen wie Pointer IS RecordType oder access pointer AS RecordType muß der Compiler Code generieren der eine Typ Überprüfung durchführt. Dazu vergleicht er dynamisch dier Typinformationen im Codesegment vom definierten Record mit dem des Pointers, also:

                        <pre>

                        if Object is TComponent then.., generiert folgenen PseudoCode <br><br>

                        if (Object <> nil) and
                        (Object.GebeMirZeigerAufDeineTypDefinitionImCodeSe gement = CompilerSaveHierStaticReferenceAufKlassenTypOf(TCo mponent)) then ;

                        </pre>

                        Werden aber IN ALLEN Modulen die GLEICHEN Basis-Packages benutzt, wird jede RecordTypDefinition NUR EINMAL im entsprechenden Package MITGEFÜHRT. ALLE sich darauf beziehenden Module NUTZTEN ein und das selbe INTEFACE auf den Klassen/Record Typdefinition.

                        Gruß Hagen

                        Gruß Hage

                        Comment


                        • #13
                          Hab ich gemacht da komm TRUE raus!<p>Bye<p>Marcel Schmie

                          Comment


                          • #14
                            Hi Marcel

                            Ok, um es nochmal genauer zu beschreiben:

                            <pre>

                            exportierte funktionen der DLL<br>

                            function CreateForm(MainApplication: TApplication): TForm; stdcall;
                            begin
                            if Application <> MainApplication then
                            begin
                            Application.Free;
                            Application := MainApplication;
                            end;
                            Result := TForm1.Create(nil); // Form definiert in der DLL !

                            // hier zum test
                            if MainApplication is TApplication then
                            MessageBeep(0);
                            end;

                            <pre>

                            Nun rufts Du aus Deiner EXE die DLL Funktion DLLForm := CreateForm(Application); auf.<br>
                            1.) In CreateForm() der DLL sollte KEIN MessageBeep(0) aufgrufen werden<br>
                            2.) DLLForm is TForm sollte FALSE liefern<br>

                            Natürlich vorrausgesetzt das die EXE und die DLL ohne Laufzeitpackages compiliert wurden.

                            Gruß Hage

                            Comment

                            Working...
                            X