Formular in BPL wird automatisch zerstört



  • Hallo zusammen,

    Mein Problem:

    Die Hauptanwendung (exe) lädt ein Package(p1.bpl) welches ein Formular (TForm1) enthält, das so erzeugt wird:

    THandle H = LoadPackage("p1.bpl");
    TClass C = GetClass("TForm1");
    TForm* F;
    Application->CreateForm(C, &F);
    

    Wenn ich die Andwendung beende, wird sofort der Destruktor des Formular des Package p1.bpl aufgerufen.

    Im Aufruf-Stack wird die CC32150MT.DLL als Aufrufer angezeigt:

    :056991D6 TCANopenForm::~TCANopenForm(this=:01FDCF00)
    :5005ed67 rtl200.@System@TObject@Free$qqrv + 0xb
    :32f9944b ; C:\Windows\SysWOW64\CC32150MT.DLL
    :32f9949a ; C:\Windows\SysWOW64\CC32150MT.DLL
    :32f96408 CC32150MT._exit + 0x10
    :32f99839 ; C:\Windows\SysWOW64\CC32150MT.DLL

    Wenn nach dem Erzeugen des Formulars Form 1 mit

    Application->RemoveComponent(Form1)
    

    das Formular aus der Komponentenliste der Anwendung entfernt wird, wird der Destruktor von Form1 nicht automatisch aufgerufen.

    Kann mir jemand erklären, wieso die VCL das so macht? Ich hätte erwartet, dass das Formular im Package erst zerstört wird, wenn ich das Package entlade.

    Gruß
    Kerem



  • Offensichtlich scheint das schon so zu passen. Schließlich ist das Formular in der Komponentenliste von Application und wird somit auch von dort aus gelöscht.

    Nach dem Aufruf

    Application->RemoveComponent(Form1)
    

    erhalte ich die Möglichkeit das Formular manuell zu löschen.

    Habe mich selbst etwas verwirrt 🙄

    Kennt jemand eine andere Möglichkeit, um den Zeitpunkt des Löschens des Formulars
    zu beeinflussen?



  • NULL als Owner übergeben und in einen smart Pointer (z.B. boost::scoped_ptr) verpacken.



  • Danke für den Hinweis 👍

    Auf boost muss ich momentan leider noch verzichten...

    Da das Formular über

    Application->CreateForm(...)
    

    erzeugt wird, sehe ich keine Möglichkeit NULL als Owner zu übergeben.
    Oder irre ich mich?



  • Gut, da kenn ich mich jetzt nicht mehr aus, ich lasse in meinen Anwendungen nur das Hauptfenster automatisch erzeugen und die übrigen erzeuge ich manuell dann, wenn ich sie brauche.
    Geht das nicht auch für die importierten Formulare? Also einfach per new dann erzeugen, wenn man sie braucht?

    Edit:
    Und für deine Zwecke brauchst du wahrscheinlich auch keinen ausgewachsenen scoped_ptr , da reicht auch einfach eine kleine Klasse, die das wegkapselt:

    template<typename T>
    class ScopedHolder
    {
    public:
       ScopedHolder() : Held_( 0 )
       {
       }
    
       ScopedHolder( T* h ) : Held_( h )
       {
       }
    
       T* operator->()
       {
          return Held_;
       }
    
       T& operator*()
       {
          return *Held_;
       }
    
       T* get()
       {
          return Held_;
       }
    
       void reset( T* h )
       {
          if( Held_ ) delete Held_;
          Held_ = h;
       }
    
       ~ScopedHolder()
       {
          reset( NULL );
       }
    
    private:
       T*	Held_;
    
       ScopedHolder( const ScopedHolder& other );
       ScopedHolder& operator=( const ScopedHolder& other );
    };
    


  • DocShoe schrieb:

    da reicht auch einfach eine kleine Klasse, die das wegkapselt

    Die gibts auch schon unter dem Namen std::auto_ptr<> , kein Grund, das selber zu machen.



  • Die boost Leute werden schon ihren Grund gehabt haben...
    auto_ptr kann zB. in einen std::vector gesteckt werden, ScopedHolder nicht. Kann man vermeiden, wenn man´s weiß, aber im Allgemeinen wird von auto_ptr abgeraten.



  • auto_ptr sollte man nicht in einen vector packen. Siehe hierzu auch
    http://stackoverflow.com/questions/111478/why-is-it-wrong-to-use-stdauto-ptr-with-standard-containers
    Wenn das nicht nötig ist und der Pointer nur lokal verwaltet werden soll oder Member einer Klasse ist geht das schon mit auto_ptr. Man muss eben nur im Hinterkopf behalten das auto_ptr besitzend ist und bei einer Kopie oder Zuweisung eine Besitzübertragung erfolgt.



  • Guten Morgen!

    Ich erzeuge Formulare, die in Packages liegen nicht mit new, weil ich diese Formulare nicht in andere Packages einbinden möchte. Also in die, die das Formular erzeugen.

    Mit smart pointern und co. habe ich mich bisher nicht auseinandergesetzt, da kein C++11 Compiler verfügbar und boost nicht verwendbar.

    Den Zeitpunkt des löschen muss ich selber bestimmen können. Sind die von euch genannten Konstrukte nicht dafür da, dass man sich um das löschen eben nicht kümmern braucht?



  • Kerem schrieb:

    Ich erzeuge Formulare, die in Packages liegen nicht mit new, weil ich diese Formulare nicht in andere Packages einbinden möchte. Also in die, die das Formular erzeugen.

    Ja und? Das erzeugen mit new bindet die Formulare erstmal nirgendwo ein es erzeugt sie nur. Bei Bedarf kannst du da einen Owner angeben der für das Löschen zuständig ist. Oder eben 0 als Owner und du musst selber löschen.

    Kerem schrieb:

    Den Zeitpunkt des löschen muss ich selber bestimmen können. Sind die von euch genannten Konstrukte nicht dafür da, dass man sich um das löschen eben nicht kümmern braucht?

    Ja, das ist so und damit für dich nicht nötig. Es ist eben mehr die Frage das man das Löschen nicht vergisst.



  • Also mein Linker meckert, wenn ich sowas mache... Über virtuelle Konstruktoren brauchen wir uns jetzt nicht unterhalten. Oder wie stellst du dir das vor?



  • Dein Linker meckert was an?



  • Wenn ich aus einem Package eine nicht virtuelle Klassenmethode aufrufe, ohne dass der Quellcode der Klasse in diesem Package verfügbar ist.

    In diesem Fall konkret: "Error: Nicht auflösbares externes...".

    Ist doch klar, oder??



  • Irgendwie reden wir aneinander vorbei. Ein Package ist doch erstmal nichts weiter als eine speziell verpackte dll. Wenn deine Formklasse exportiert wurde, registriert ist und dann das Package geladen ist sollte doch eigentlich alles da sein.
    Ich muss zugeben dass ich noch nie ein Package dynamisch geladen habe weswegen ich am besten jetzt hier aufhöre was zu diesem Thema posten. Bisher habe ich entweder statisch gelinkt oder bei dynamischen linken nur dlls verwendet und auch dort nur Funktionen mit C-Interface exportiert. Da gibt es solche Probleme natürlich nicht.
    Ich denke dass audacia dir da eher helfen kann.



  • Soweit stimmt deine Argumentation ja auch. Bloß meckert eben der Linker, wenn ich den Konstruktor der Formularklasse aufrufe, ohne dass ich die dazugehörige Unit in die aufrufende Exe bzw. in ein anderes Package inkludiere. Das ist ja auch ok so.

    Im Prinzip hat sich meine Frage geklärt.

    Danke für deinen Beitrag.


Log in to reply