Announcement

Collapse
No announcement yet.

Nach Frames suchen

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

  • Nach Frames suchen

    Hallo,

    ich habe eine komplexe Anwendung die sehr viel mit Frames arbeitet. Ich möchte jetzt während der Laufzeit meine Anwendung nach allen Frames durchsuchen lassen. Leider kann ich mit dem Befehl Application.Componentencount die Frames nicht finden, da sie erst created werden wenn ich Sie benötige. Gibt es in Delphi eine Möglichkeit die
    verfügbaren Formulare (Frames) auszulesen.

    Gruß
    Frank

  • #2
    Meinst du die verfügbaren Formulare die schon erzeugt wurden oder meinst du die Formluar-Klassen die durch die verschiednenen Units eingebunden wurden ??<br>

    Beides wäre möglich. Für ersteres iteriert man durch Screen.CustomForms[] und nutzt Screen.CustomFormCount dazu.<br>
    Alle schon erzeugten Forms, egal ob sichtbar/unsichtbar sind dort verzeichnet.<br>

    Solange aber keine Form-Instance erzeugt wurden stellt Delphi keinen direkten Weg zur Verfügung. Es gibt also NUR die Klassendefinitionen, die sozusagen als Template für die Objectinstancen dienen. Aber man kann diese sich zu nutze machen. Ein Weg wäre so wie in RegisterClass() und GetClass() gezeigt. Über diese Liste werden die verfügbaren Klassen dem System bekannt gegeben.<br>

    Die andere, inoffizielle, Methode basiert auf dem Gedanken das im Codesegment jeder Anwednung alle Klassen die durch Units eingebunden wurden gespeichert wurden. Sprich die RTTI,VMT,DMT's usw. aller Klassen sind in der EXE gespeichert. Die entscheidende Frage ist ob man einen Weg findet über ALLE diese Klassen iterieren zu können. D.h. alle benutzten Datentypen, ob Integer, String, Enums oder eben Klassen/Interfaces, können durch eine Iterierfunktion aufgelistet werden.<br>

    In den Borland Newsgroups habe ich dafür schon Code gepostet.<br>

    Gruß Hage

    Comment


    • #3
      Hallo Hagen,

      danke für die Informationen. Bei kommt die 2. Variant in Frage, da
      die Frames erst zur Laufzeit generiert werden. Ich habe in den mir
      bekanntn Newsgroups gesucht und leider nichts gefunden. Vieleicht
      könntest Du mir mittilen wo ich den Code finden kann.

      Danke im voraus

      Gruß Fran

      Comment


      • #4
        Also für Variante zwei gibts zwei Wege

        <pre>

        <code><font size=2 face="Courier New"><b>unit </b>RegFrame;
        <br>
        <b>interface
        <br>
        var
        </b>FrameClasses: TList = <b>nil</b>;
        <br>
        <b>procedure </b>RegisterFrame(<b>const </b>Classes: <b>array of </b>TFrameClass);
        <br>
        <b>implementation
        <br>
        procedure </b>RegisterFrame(<b>const </b>Classes: <b>array of </b>TFrameClass);
        <b>var
        </b>I: Integer;
        <b>begin
        for </b>I := Low(Classes) <b>to </b>High(Classes) <b>do
        </b>FrameClasses.Add(Classes[I]);
        <b>end</b>;
        <br>
        <b>initialization
        </b>FrameClasses := TStringList.Create;
        <b>finalization
        </b>FreeAndNil(FrameClasses);
        <b>end</b>.
        <br>
        <i>// in der Unit die den Frame implementiert dann...
        <br>
        </i><b>uses </b>FrameReg, ...;
        <br>
        <b>type
        </b>TmyFrame = <b>class</b>(TFrame)
        <b>end</b>;
        <br>
        <b>implementation
        <br>
        initialization
        </b>RegisterFrame([TMyFrame]);
        <b>end</b>.
        <br>
        <i>// in der Unit die nach Frames suchen soll
        <br>
        </i><b>uses </b>FrameReg;
        <br>
        ...
        <br>
        <b>procedure </b>SucheErzeugeFrame;
        <b>var
        </b>I: Integer;
        Frame: TFrame;
        <b>begin
        for </b>I := 0 <b>to </b>FrameClasses.Count -1 <b>do
        with </b>TFrameClass(FrameClasses[I]) <b>do
        if </b>ClassName = 'TMyFrame' <b>then
        begin
        </b>Frame := Create(..);
        <b>end</b>;
        <b>end</b>;
        <br>
        </font>
        </code></pre&gt

        Comment


        • #5
          dies sollte der Standardweg sein, da er eben klar definiert ist.<br>
          Die Iteration über alle TypeInfo's des Modules basiert auf undokumentierten Strukturen. Ich schau mal ob ich sie auf meinem Rechner finde

          den zweiten Weg findest du http://groups.google.de/groups?hl=de&lr=&ie=UTF-8&threadm=3c0d4532%241_2%40dnews&rnum=1&prev=/groups%3Fhl%3Dde%26lr%3D%26ie%3DISO-8859-1%26q%3DEnumTypeInfo

          Gruß Hage

          Comment


          • #6
            Angepasst auf Dein Problem:

            <pre>

            <code><font size=2 face="Courier New"><b>type
            </b>TEnumTypeInfoCallback = <b>function</b>(UserData: Pointer; Info: PTypeInfo): Boolean; <b>register</b>;
            <br>
            <b>function </b>GetBaseOfCode(Module: hModule; <b>var </b>CodeStart, CodeEnd: PChar): Boolean;
            <b>asm </b><i>// get Codesegment pointers, check if module is a valid PE
            </i>PUSH EDI
            PUSH ESI
            AND EAX,not 3
            JZ @@2
            CMP Word Ptr [EAX],'ZM';
            JNE @@1
            MOV ESI,[EAX + 03Ch]
            CMP Word Ptr [ESI + EAX],'EP'
            JNE @@1
            MOV EDI,[EAX + ESI + 014h + 008h]
            ADD EAX,[EAX + ESI + 014h + 018h]
            ADD EDI,EAX
            MOV [EDX],EAX
            MOV [ECX],EDI
            XOR EAX,EAX
            @@1: SETE AL
            @@2: POP ESI
            POP EDI
            <b>end</b>;
            <br>
            <b>function </b>EnumTypeInfo(Module: hModule; Callback: TEnumTypeInfoCallback; UserData: Pointer): PTypeInfo;
            <b>var
            </b>P,E,K,N: PChar;
            L: Integer;
            <b>begin
            </b>Result := <b>nil</b>;
            <b>if </b>Assigned(Callback) <b>then
            try
            if </b>GetBaseOfCode(Module, P, E) <b>then
            while </b>P &lt; E <b>do
            begin
            </b>DWord(P) := DWord(P) <b>and not </b>3;
            K := P + 4;
            <b>if </b>(PDWord(P)^ = DWord(K)) <b>and </b>(PByte(K)^ &gt; 0) <b>and </b>(PByte(K)^ &lt; 18) <b>then
            </b><i>// Info.Kind in ValidRange.D6
            </i><b>begin
            </b>L := PByte(K + 1)^; <i>// length Info.Name
            </i>N := K + 2; <i>// @Info.Name[1]
            </i><b>if </b>(L &gt; 0) <b>and </b>(N^ <b>in </b>['_', 'a'..'z', 'A'..'Z']) <b>then </b><i>// valid ident ??
            </i><b>begin
            repeat
            </b>Inc(N);
            Dec(L);
            <b>until </b>(L = 0) <b>or not </b>(N^ <b>in </b>['_', 'a'..'z', 'A'..'Z', '0'..'9']);
            <b>if </b>L = 0 <b>then </b><i>// length and ident valid
            </i><b>if </b>Callback(UserData, Pointer(K)) <b>then
            </b><i>// tell it and if needed abort iteration
            </i><b>begin
            </b>Result := Pointer(K);
            Exit;
            <b>end else </b>K := N;
            <b>end</b>;
            <b>end</b>;
            P := K;
            <b>end</b>;
            <b>except
            end</b>;
            <b>end</b>;
            <br>
            <br>
            <b>procedure </b>Test;
            <br>
            <b>function </b>MyEnum(Data: Pointer; Info: PTypeInfo): Boolean; <b>register</b>;
            <i>// wir suchen nur Klassen abgeleitet von TFrame
            </i><b>begin
            </b>Result := False;
            <b>if </b>(Info.Kind = tkClass) <b>and </b>GetTypeData(Info).ClassType.InheritsFrom(TFrame ) <b>then
            </b>WriteLn( Info.Name );
            <b>end</b>;
            <br>
            <b>begin
            </b>EnumTypeInfo(MainInstance, @MyEnum, <b>nil</b>);
            <i>// or
            // EnumTypeInfo(GetModuleHandle('vcl50.bpl'), @MyEnum, nil);
            </i><b>end</b>;
            </font>
            </code></pre&gt

            Comment


            • #7
              Hallo Hagen,
              vielen Dank für die Hilfe und die Mühe die Du dir gemacht hast. Ich habe die 1. Variante bereits ausprobiert. Leider habe ich Probleme :

              1. Die von Dir benannte TFrameClass ist Delphi 7 nicht bekannt. Ich habe in der Hilfe sowie imm Handbuch gesucht und konnte diesbezüglich nichts finden.

              2. Der Befehl FrameClasses := TStringList.Create; funktioniert nicht. Der Compiler meldet : inkompatible Typen TList und TStrings. Wenn ich TStringList gegen TList.Create austausche erhalte ich keine Fehlermeldung.

              3. Ich habe Probleme mit der Unit die die Frames Initialisiert. Du machst ein Type TmyFrame = Class(TFrame). Ich wüsste jetzt nicht wo ich meine Frames deklarieren muss. Anbei ein Codebeispiel aus meinem Programm. Hier wird das Formular dynamisch aufgebaut. Ein Formular kann bis zu X Frames enthalten:<BR><BR>
              unit DTM_IncotermManager;<BR>
              <BR>
              interface<BR>
              <BR>
              uses<BR>
              DB, Classes, Dialogs, dxDBEditEco, SysUtils, SDEngine,...<BR>
              procedure ShowDTMIncoterm;<BR>
              <BR>
              var Abfrage : TDM_Incoterm;<BR>
              Formular : TF_StammMuster;<BR>
              Frame1 : TFrame_Page_Control;<BR>
              Frame2 : TFrame_StammLeiste;<BR>
              Frame3 : TFrame_Incoterm;<BR>
              Frame4 : TFrame_Incoterm_Grid;<BR>
              Query : TSDQuery;<BR>
              <BR>
              implementation<BR>
              <BR>
              uses DMStamm_lib;<BR>
              <BR>
              resourcestring<BR>
              Anzeige = 'incoterms';<BR>
              <BR>
              procedure ShowDTMIncoterm;<BR>
              begin<BR>
              Formular := TF_StammMuster.Create ( nil );<BR>
              Formular.Label_StammdatenMaske.Caption := Anzeige;<BR>
              Frame1 := TFrame_Page_Control.Create( Formular );<BR>
              Frame1.Parent := Formular;<BR>
              <BR>
              Frame2 := TFrame_StammLeiste.Create( Frame1.TabSheet_Detailansicht );<BR>
              Frame2.Parent := Frame1.TabSheet_Detailansicht;<BR>
              <BR>
              Frame3 := TFrame_Incoterm.Create( Frame1.TabSheet_Detailansicht );<BR>
              Frame3.Parent := Frame1.TabSheet_Detailansicht;<BR>
              <BR>
              Frame4 := TFrame_Incoterm_Grid.Create(Frame1.TabSheet_Uebers icht);<BR>
              Frame4.Parent := Frame1.TabSheet_Uebersicht;<BR>
              <BR>
              Abfrage := TDM_Incoterm.Create( Formular );<BR>
              Query := Abfrage.Query_Incoterm;<BR>
              <BR>
              Formular.DBProvider := Abfrage;<BR>
              Frame4.dxDBGrid_Incoterm.DataSource := Formular.DataSource_StammMuster;<BR>

              Forms_Field_Init(Frame3,Formular,'Incoterm');<BR> // Initialisierung der Felder<BR>
              F_Explorer.InitForms(Formular);<BR>
              Formular.Show;<BR>
              Frame3.Panel_Allgemein.Width := Formular.Width - 32;<BR>
              Frame3.Panel_Incoterm.Width := Formular.Width - 32;<BR>
              Frame3.Panel_Incoterm.Height := Formular.Height - Frame3.Panel_Allgemein.Height - 200;<BR>
              Frame2.ToolButton_Sprachtexte.Enabled := DMStamm_Lib.PruefeSprachtexte(Frame2, 'ST_INCO');<BR>
              FocusFeld := Frame3.dxDBEditEco_IDNR;<BR>
              end;<BR>
              <BR><BR>
              Muss ich die meine Frames im Type Abschnitt definieren ? :<BR>
              Type<BR>
              TMyFrame=class(Tframe)<BR>
              Frame1 : TFrame_Page_Control;<BR>
              Frame2 : TFrame_StammLeiste;<BR>
              Frame3 : TFrame_Incoterm;<BR>
              Frame4 : TFrame_Incoterm_Grid;<BR>
              end;<BR>
              <BR>
              4. Bei der 2. Variante habe ich das Problem wo die Funktionen gespeichert werden. Werden die in eine gesonderte Unit abgelegt?
              <BR>
              Gruß Frank<BR&gt

              Comment


              • #8
                1.) type TFrameClass = class of TFrame;<br>
                2.) TList.Create ist korrekt, ein Tipfehler von mir <br>
                4.) Du solltest eine eigene Unit erzeugen, so wie Unit FrameReg.<br>
                3.) Das hängt nun davon ab wie du vorgehen willst. In Deinem Code werden alle Frames statisch erzeugt. Dein Ziel ist es aber eine dynamische Ezeugung vorzunehmen, damit z.B. alle Frames mit bestimmten Type erzeugt werden oder aber Frames mit bekannten Klassennamen erzeugt werden.<br>

                Also muß meine Gegenfrage nochmal lauten: Was willst Du mit den dynamischen Frames erreichen ?
                Normalerweise will man verhindern das z.B. ein TForm das bestimmte Frames nutzen kann, aber nicht muß !, nur die in sich integriert die durch uns als Unit ins Projekt eingebunden wurden, ABER nicht in der uses Klauseln dieser TForm Unit erscheinen.<br>Mit dem Weg über die TypInfo Iteration bekommen wir da aber ein Problem. Da wir z.B. die betreffende TFrame Unit einfach nur als Unit in's project einbinden wir der Compiler diese Klasse weg optimieren, da sie ja nirgends statisch benutzt wird. D.h. dieser Weg ist sehr sinnvoll in Projekten die z.B. dynamisch ein Packages das unseren Frame enthält einbinden will. In Packages optimiert der Compiler solche nichtbenutzten Klassen nicht weg. In einem single EXE Projekt muß dagegen der Weg über Unit FrameReg gegangen werden. Da nun jede TFrame Unit in deren initialization Sektion RegisterFrame(TMyFrame) aufruft, darf der Compiler die Klasse TMyFrame NICHT wegoptimieren. Das liegt daran das für jede Unit die in ein Projekt eingebunden wird, egal ob die Unit benutzt wird oder nicht, deren Initialization/Finalization Sektionen aufgerufen werden.<br>
                Deshalb meinte ich ja das der Weg über eine eigene Registration besser ist.<br>

                Gruß Hage

                Comment


                • #9
                  Hallo Hagen,

                  zu der Frage mit den dynamischen Frames : Da in meiner Anwendung Maskenlayouts mehrfach vorkommen, habe ich diese als Frames erstellt und erzeuge Sie an den Stellen wo ich Sie benötige. Ich habe ebenfalls Frames für ToolLeisten und Reitertechnik. Somit erspare ich mir das mehrfache (bis zu 50 mal) erstellen von ähnlichen Layouts. Da die Software ein eigenes Rechtekonzept enthalten soll ( Zugriff auf Objekte, Menüs, Buttons und Datenfelder mit einstellbaren Optionen wie Pflichtfeld ja - nein und ähnliches) muss ich während der Laufzeit (nach erstellen des Benutzers) alle Frames suchen, damit ich die entsprechenden Zugriffsdateien erstellen und dort die Rechte einstellen kann.<BR>
                  <BR>
                  Leider Programmiere ich erst seit ca. 1 Jahr in Delphi und stosse immer wieder an meine Fachlichen Grenzen.<BR>
                  Deine Ausführungen habe ich leider nicht ganz verstanden. Wie Du das beschreibst ist meine Art die Frames zu erstellen für ein wiederfinden nicht entsprechend umgesetzt. Da mir immer noch nicht klar ist wie ich bei mir die Frames definieren muss habe ich mal die andere Möglichkeit von Dir ausprobiert.<BR>
                  Hier erhalte ich leider auch Fehlermeldungen die ich nicht beheben kann.<BR>
                  <BR>
                  In der Zeile <B>If<B> (PDWord(P)^ = DWord(K)) <B>and<B> (PByte(K)^ < 18) <B>then<B><BR>
                  <BR>
                  erhalte ich vom Compiler die Fehlermeldung das PDWord ein undefinierter Bezeichner ist und das ein Zeigertyp erwartet wird. Es wäre nett wenn Du mir nochmals unter die Arme greifen könntest.

                  Gruß Fran

                  Comment


                  • #10
                    <pre>

                    type
                    PDWord = ^DWord;

                    </pre>

                    Nochmals zu den Frames. Du hast ja jeden Frame in einer eigenen Unit. Dein problem ist nun das du an anderer Stelle wissen möchtest welche Frame-Units in dein Projekt eingebunden wurden. Statt nun alle Frames zu suchen, teilt jeder Frame einer globalen Registrierungsunit seine Existenz mit. Die Registrationsfunktion habe ich oben schon gepostet. Jeder Frame muß nun in seiner Unit, initialization Sektion der unit, diese Registration durchführen.<br>

                    Gruß Hage

                    Comment

                    Working...
                    X