Informacja o niszczonych kontrolkach w WinApi

0

Witam, chciałem się zapytać, czy jest jakiś sposób, by przechwycić informację o niszczonej kontrolce w tym na skutek niszczenia okna-rodzica?
Chodzi mi o taką sytuację, że okno rodzic jest niszczony i to powoduje niszczenie wszystkich potomków w tym kontrolek. I teraz pytanie czy da się jakoś przechwycić informację o każdej kontrolce/oknie, które jest niszczone w danym momencie? Tzn. przede wszystkim uzyskać do nich uchwyt.

1

Zacznijmy od tego co w ogóle chcesz osiągnąć? Do czego Ci to potrzebne bo może nie trzeba tak kombinować? Podczas niszczenia okna głównego dostaje ono WM_DESTROY a potem okna potomne ale aby przechwycić ten komunikat dla okien potomnych musiałbyś użyć subclassingu dla wszystkich kontrolek (łatwo można by to zrobić w pętli tylko po co).

0

Chodzi o pewne zabezpieczenie. Robię wrappera na WinApi i każde okno i kontrolka mają funkcję Create(Window* parent). Kłopot w tym, że w tej funkcji jest zabezpieczenie przed ponownym utworzeniem okna tj. if(!m_window_handle). No i problem polega na tym, że jak ktoś utworzy okno z kontrolkami, a następnie z jakiś powodów zniszczy to okno (rodzica) to kontrolki się same zamkną, ale zmienna m_window_handle pozostanie niezerowa. I w przypadku chęci ponownego utworzenia okna kontrolki się nie utworzą.

Obecnie trochę skorygowałem kod, by ominąć ten problem a mianowicie gdy zmienna m_window_handle jest ustawiona to sprawdzam, czy takie okno w ogóle istnieje a jeśli tak to czy ma rodzica itd. Ale mam pewne obawy co do tego rozwiązania.

Inne rozwiązanie, które wymyśliłem, i które chyba będzie również ok to takie, by w wiadomości WM_DESTROY wyszukać wszystkich potomków i wtedy ustawić tą zmienną na NULL. Pytanie tylko, czy w tym czasie te okna nie będą już zniszczone?!...

Mam nadzieję, że jasno opisałem problem ;-).

0

Jeżeli dobrze zrozumiałem o co chodzi to przecież z powodzeniem możesz użyć funkcji IsWindow aby sprawdzić czy okno o podanym uchwycie istnieje.

0

No i problem polega na tym, że jak ktoś utworzy okno z kontrolkami, a następnie z jakiś powodów zniszczy to okno (rodzica) to kontrolki się same zamkną,

No i tu widzę problem. Jeśli kontrolki to obiekty twoich klas wrapujących, to musisz je ręcznie wszystkie pousuwać (musi się wykonać destruktor) na WM_DESTROY rodzica, a nie liczyć na to że "się same zamkną" - bo zamknie się kontrolka po stronie WinAPI, a nie twój obiekt.

Słowem: masz wyciek zasobów i pytasz jak go wykryć, zamiast mu zapobiec.

0
kAzek napisał(a):

możesz użyć funkcji IsWindow aby sprawdzić czy okno o podanym uchwycie istnieje.

Tak, właśnie tak to robię. Ale jeśli jakaś kontrolka jest zamykana to inna kontrolka lub inne okno może teoretycznie (prawdopodobieństwo małe, ale jest) otrzymać ten sam uchwyt. Dlatego bardziej mi zależy, by wyzerować uchwyt w trakcie zamykania kontrolki.

Azarien napisał(a):

No i problem polega na tym, że jak ktoś utworzy okno z kontrolkami, a następnie z jakiś powodów zniszczy to okno (rodzica) to kontrolki się same zamkną,

No i tu widzę problem. Jeśli kontrolki to obiekty twoich klas wrapujących, to musisz je ręcznie wszystkie pousuwać (musi się wykonać destruktor) na WM_DESTROY rodzica, a nie liczyć na to że "się same zamkną" - bo zamknie się kontrolka po stronie WinAPI, a nie twój obiekt.

Słowem: masz wyciek zasobów i pytasz jak go wykryć, zamiast mu zapobiec.

Chyba źle się zrozumieliśmy.
Kontrolka z automatu jest niszczona, gdy niszczone jest okno nadrzędne w stosunku do niej (jej Parent) - dlatego nie może być wycieku zasobów. Natomiast moja klasa obudowuje taką kontrolkę - przechowuje do niej uchwyt, wskaźnik do okna nadrzędnego i inne informacje.
W klasie Window w procedurze okna przy komunikacie WM_DESTROY mam m.in. zerowanie zmiennej przechowującej uchwyt do danego okna. Natomiast z kontrolkami jest inaczej, bo one mają swoją procedurę okna.
W destruktorze klasy Window mam wywołanie funkcji Close(), która m.in. niszczy okno, jeśli jest ono otwarte (dot. to również kontrolek) i zeruje uchwyt. Jednak obiekt kontrolki (klasy Control) nie musi być zawsze niszczony razem z niszczeniem okna/kontrolki. Innymi słowy: obiekt klasy Window może wywołać funkcję Close(), która zamknie okno, ale sam obiekt klasy Window nie będzie zniszczony i będzie mógł ponownie wywołać funkcję Create().

0

Chyba źle się zrozumieliśmy.
Kontrolka z automatu jest niszczona, gdy niszczone jest okno nadrzędne w stosunku do niej (jej Parent) - dlatego nie może być wycieku zasobów. Natomiast moja klasa obudowuje taką kontrolkę - przechowuje do niej uchwyt, wskaźnik do okna nadrzędnego i inne informacje.

Rozumiemy się dobrze. Wszelkie niszczenie kontrolek musi się odbywać w twoim kodzie. Nie licz na to że Windows zniszczy kontrolki, bo zniszczy tylko swoje wewnętrzne struktury - a nie obiekty twojej klasy.
Więc:

  • w WM_DESTROY okna musisz przeiterować po kolekcji wszystkich twoich kontrolek, i dla każdej z nich wykonać destruktor (zapewne przez delete)
  • w destruktorze każdej kontrolki robisz DestroyWindow na tej kontrolce.
  • nie interesuje cię uchwyt niszczonego okna, bo opakowujący je obiekt jest niszczony.

Próbujesz robić to jakoś na około - licząc że to Windows ci pousuwa kontrolki, ale kto ci pousuwa opakowujące obiekty? i potem zadajesz sobie nienaturalne pytanie skąd wiedzieć które uchwyty są prawidłowe.

0

@Azarien czyli jednak źle się rozumiemy ;-).
O obiekty mojej klasy to ja się w ogóle nie martwię, bo zdaję sobie sprawę, że to co alokuję dynamicznie muszę zwolnić. Kontrolki mogą być jednak częścią składową innego obiektu.
Zwróć uwagę, jak chcę, żeby to mniej więcej wyglądało:

class MyButton : public Button
    {
    void OnClick()  //virtual
        {
        DWORD style = GetParent()->GetBasicStyle(); //pobiera style okna nadrzędnego
        if(style & WS_BORDER)   //jeśli jest ustawione obramowanie
            GetParent()->SetBasicStyle(style &~WS_BORDER);  //to je usówa
        else
            GetParent()->SetBasicStyle(style | WS_BORDER);  //jak nie to je ustawia
        }
    //...
    }

class MojeOkno : public Window
    {
    public:
        void OnCreate()
            {
            button.SetPosition(10, 10);
            button.SetSize(100, 30);
            button.Create(this);    //m_parent = this;
            }

        OnClose()
            {
            button.Close(); //CHODZI O TO, BY NIE BYĆ ZMUSZANYM TEGO WYWOŁYWAĆ RĘCZNIE (BY SAMO SIĘ WYKONAŁO W MOMENCIE ZAMKNIĘCIA OKNA)
            }

    private:
        MyButton button;    /*to może być również wskaźnik do którego w konstruktorze lub funkcji OnCreate przypiszemy dynamiczny obiekt*/

    };

Problem jest taki, że funkcja SetBasicStyle(DWORD style) - zgodnie z Twoją uwagą w innym poście dot. zmiany stylów w WinApi - zamyka okno i tworzy je na nowo z nowymi stylami. Obiekt MyButton jest ciągle w pamięci i być powinien - chyba, że komuś się zechce zrobić sobie wskaźnik do niego i alokować go w konstruktorze lub funkcji OnCreate() i zwalniać odpowiednio w destruktorze lub funkcji OnClose lub ew. OnDestroy().

1

No to przecież musisz obsługiwać komunikaty WM_CLOSE, WM_DESTROY czy co tam chcesz w przypadku okien potomnych normalnie nie obsłużysz tych komunikatów aby to zrobić musisz zastosować subclassing (czyli podmiana procedury obsługi okna) lub superclassing (tworzenie nowej klasy na bazie istniejącej).

EDIT// Po prostu w konstruktorze tworzysz okno i od razu subclassujesz, czywiście procedura obsługi okien może być wspólna jeżeli masz tak samo reagować na dane komunikaty przy wszystkich kontrolkach.

0

Tego Subclassingu chciałem uniknąć, bo nie chce mi się pisać procedur dla każdej możliwej kontrolki :P
No nic, dzięki za udział w dyskusji ;-). Jeszcze nad tym pomyślę.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0