WM_DESTROY okna potomnego niszczy także okno główne

0

Witam. Dysponuję uchwytem do kontrolki potomnej (hWndChild) oraz uchwytem do okna głównego (hWndParent). Moim zadaniem jest usunąć okno potomne (dodam, że w procedurze okna potomnego usuwam bitmapy i inne struktury). Niestety, po użyciu funkcji DestriyWindow(hWndChild); zamyka mi się cały program.

Pogrzebałem troszkę: https://msdn.microsoft.com/pl-pl/library/windows/desktop/ms632682%28v=vs.85%29.aspx i wychodzi na to, że bez flagi rozszerzonej WS_EX_NOPARENTNOTIFY na oknie-dziecku komunikat WM_DESTROY będzie też przekazywany do nadrzędnego. Tak więc czym prędzej dodałem te flagę ale nic się nie zmieniło. teraz jestem w czarnej kropce :<

0

masz buga, pokaż kod

0

Miałem buga. W oknie potomnym funkcją CallWindowProc przekazywałem dalej komunikat do okna rodzica -,- Debil ze mnie. Zabawne jest to, że dopiero takie rzeczy zauważam jak napisze tu post...

0

Tak całkiem prawidłowo powinieneś nie zamykać okna z zewnątrz, tylko kazać mu się zamknąć: czyli wysłać przez SendMessage albo PostMessage komunikat WM_CLOSE. Standardowe WM_CLOSE wywołuje DestroyWindow na sobie.

wychodzi na to, że bez flagi rozszerzonej WS_EX_NOPARENTNOTIFY na oknie-dziecku komunikat WM_DESTROY będzie też przekazywany do nadrzędnego

Błąd, jest tam napisane

If the window being destroyed is a child window that does not have the WS_EX_NOPARENTNOTIFY style, a WM_PARENTNOTIFY message is sent to the parent.

Przekazywane do parenta jest WM_PARENTNOTIFY, a nie WM_DESTROY.

0

Bo mam kupe kontrolek co się Tworzą od czasu do czasu i musze je usuwać, czy wysyłam DestroyWindow(hwnd_child).
Tworząc hwnd_child dodaję wspomnianą flagę, i od teraz jak to ma wyglądać?

Wysyłam DestroyWindow(hwnd_child) gdzieś w jakiejś funkcji i przechwytując komunikat WM_DESTROY w procedurze okna hwnd_child usuwam używane przez tą kontrolkę bitmapy i struktury. tak to powinno wyglądać? Bo teraz już sam nie wiem :(

I jeszcze jedno, mógłby mi ktoś opisać co dają zwracane wartości przez procedurę okna na tym przykładzie??

 
LRESULT CALLBACK Proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
    switch (message)                  /* handle the messages */
    {
        case WM_DESTROY:{
            return 0;
        }
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd_parent, message, wParam, lParam);
    }

    return 0;
}

Czy dobrze myślę? Jak zwrócę 0 w obsłudze WM_DESTROY to do okna - rodzica nie trafi żaden komunikat a funkcją DefWindowProc (hwnd_parent, message, wParam, lParam); przekazuje komunikat po prostu do ona rodzica ?

0

Chcesz aby kontrolka była w całości obsługiwana przez formatkę?
Nie rozumiem pomysłu obsługi zdarzeń kontrolki poprzez kontrolkę nadrzędną.

0

Nie musisz dodawać tej flagi.

If an application processes this message, it should return zero.

Czyli jak się zajmujesz danym komunikatem to zwracasz zero bez zastanawiania.

DefWindowProc (hwnd_parent, message, wParam, lParam); przekazuje komunikat po prostu do ona rodzica

DefWindowProc nie przekazuje do rodzica, to po prostu standardowa procedura okna.
Standardowa obsługa WM_DESTROY nie robi nic, więc jeśli chcesz robić samo case WM_DESTROY: return 0; to możesz to całkiem wyciąć.

Komunikat WM_DESTROY to notyfikacja przed zamknięciem okna pozwalająca na zwolnienie zasobów. Sam w sobie okna nie zamyka - jest generowany przez DestroyWindow.

0

Juz wszystko rozumiem ! :) Czyli flaga faktycznie jest zbędna... Wystarczy zwolnić zasoby i zwrócić 0 :)

0

Nie! Zwolnić zasoby i wywołać obsługę domyślną okienka, bo może ono (to standardowe okienko) ma jakieś zasoby do zwolnienia.

0

Ale stop...
Czyli wywołuje się WM_DESTROY okna potomnego. Zwalniam zasoby i przekazuję komunikat do okna nadrzędnego. Tam też mam komunikat WM_DESTROY : / Jak sam utworzyłem kontrolkę, zapisałem w niej strukturę zawierającą wszystkie bitmapy, wskaźniki itp. to chyba okienko nadrzędne nic nie powinno mieć do okna - dziecka tak? Jeżeli kontroluję to co zwalniam i nie zostawiam po sobie syfu to nic nie powinno złego się stać. A jeżeli mogłoby, to wytłumaczcie mi na chłopski rozum, dlaczego zamyka mi się program :(

W sumie to idiota ze mnie, bo źle wszystko opisałem:
okno główne (hwnd)
GetParent(hListaOdtwarzania) -> hwnd

I w tej liście odtwarzania tworzę kontrolki (przyciski symbolizujące utwór), które klawiszem delete mogę w każdej chwili usunąć z listy jak na odtwarzacz przystało. Uchwyty do wszystkich okien-utworów trzymam w std::vector<hwnd*>. Każdy utwór jest oknem-dzieckiem hListaOdtwarzania.

Procedura WM_DESTROY uchwytu hwnd:

 
case WM_DESTROY:{
            BASS_Free();
            DeleteObject(hBmpTlo);
            DeleteObject(hPedzelekStatic1);
            ReleaseDC(hwnd, hDCTlo);
            PostQuitMessage (0);
            break;
        }

Procedura WM_DESTROY uchwytu hListaOdtwarzania:

 
case WM_DESTROY:{
            for(int n=0; n<(int)hListaElementy.size(); n++)
             DestroyWindow(*hListaElementy[n]);
            break;
        }

Procedura WM_DESTROY każdego uchwytu hUtwor przesiadującego w wektorze:

 
case WM_DESTROY:{
            struct sListElement *wsk = (struct sListElement *)GetWindowLong(hwnd, 0);
            ReleaseDC(hwnd, wsk->hDC);
            DeleteObject(wsk->hBmp1);
            DeleteObject(wsk->hBmp2);
            DeleteObject(wsk->hBmp3);
            DeleteObject(wsk->hBmp4);
            DeleteObject(wsk->hBmp5);
            delete wsk;
            struct sListTrackInfo *wsk2 = (struct sListTrackInfo *)GetWindowLong(hwnd, 4);
            delete wsk2->dlugosc;
            delete wsk2->nazwa;
            delete wsk2->sciezka;
            delete wsk2;
            return 0;
        }

Tu wszystko wygląda poprawnie według mnie.
Co w ogóle daje oddanie komunikatu do kontrolki funkcją CallWindowProc? W kursach było napisane, że zawsze trzeba zwracać komunikat procedurze kontrolki nadrzędnej, a ja w procedurze hUtwor zwracam do procedury okna hwnd. Są 3 opcje procedury okna hUtwor i zachowanie programu:

  1. CallWindowProc(WindowProcedure, ...);
    REAKCJA: Przy usuwaniu jakiegos elementu program znika po prostu jakbym kliknął na krzyżyk.
 
case WM_DESTROY:{
            struct sListElement *wsk = (struct sListElement *)GetWindowLong(hwnd, 0);
            ReleaseDC(hwnd, wsk->hDC);
            DeleteObject(wsk->hBmp1);
            DeleteObject(wsk->hBmp2);
            DeleteObject(wsk->hBmp3);
            DeleteObject(wsk->hBmp4);
            DeleteObject(wsk->hBmp5);
            delete wsk;
            struct sListTrackInfo *wsk2 = (struct sListTrackInfo *)GetWindowLong(hwnd, 4);
            delete wsk2->dlugosc;
            delete wsk2->nazwa;
            delete wsk2->sciezka;
            delete wsk2;
            break;
        }
        case WM_DROPFILES:{
            fDrop_ReadFirst(wParam, &hwnd);
            SetWindowText(hInfo, "");
            break;
        }
    }
    return CallWindowProc( WindowProcedure, hwnd, mesg, wParam, lParam );
  1. CallWindowProc(ListProc, ...);
    REAKCJA: Przy usuwaniu jakiegos elementu program sie wiesza jak przy while(true){}
 
case WM_DESTROY:{
            struct sListElement *wsk = (struct sListElement *)GetWindowLong(hwnd, 0);
            ReleaseDC(hwnd, wsk->hDC);
            DeleteObject(wsk->hBmp1);
            DeleteObject(wsk->hBmp2);
            DeleteObject(wsk->hBmp3);
            DeleteObject(wsk->hBmp4);
            DeleteObject(wsk->hBmp5);
            delete wsk;
            struct sListTrackInfo *wsk2 = (struct sListTrackInfo *)GetWindowLong(hwnd, 4);
            delete wsk2->dlugosc;
            delete wsk2->nazwa;
            delete wsk2->sciezka;
            delete wsk2;
            break;
        }
        case WM_DROPFILES:{
            fDrop_ReadFirst(wParam, &hwnd);
            SetWindowText(hInfo, "");
            break;
        }
    }
    return CallWindowProc( ListProc, hwnd, mesg, wParam, lParam );
  1. Obojętnie czy jest WindowProcedure, czy ListProc, ale wewnątrz WM_DESTROY zamiast break; daję return 0;
    REAKCJA: Wszystko działa
 
case WM_DESTROY:{
            struct sListElement *wsk = (struct sListElement *)GetWindowLong(hwnd, 0);
            ReleaseDC(hwnd, wsk->hDC);
            DeleteObject(wsk->hBmp1);
            DeleteObject(wsk->hBmp2);
            DeleteObject(wsk->hBmp3);
            DeleteObject(wsk->hBmp4);
            DeleteObject(wsk->hBmp5);
            delete wsk;
            struct sListTrackInfo *wsk2 = (struct sListTrackInfo *)GetWindowLong(hwnd, 4);
            delete wsk2->dlugosc;
            delete wsk2->nazwa;
            delete wsk2->sciezka;
            delete wsk2;
            return 0;
        }
        case WM_DROPFILES:{
            fDrop_ReadFirst(wParam, &hwnd);
            SetWindowText(hInfo, "");
            break;
        }
    }
    return CallWindowProc( ListProc, hwnd, mesg, wParam, lParam );

Jeżeli jestem skończonym cymbałem i kretynem i macie zamiar mnie zwyzywać to wiedzcie, że nie stać mnie na książki i uczę się WinAPI tylko z kursów z internetu, a teraz próbuję wszystko sobie utrwalić pisząc program zawierający wszystko po trochu.

W załączniku przesłałem cały program. Sam uważam, że jest to jeden wielki syf kodzisty i powinienem to poukładać, ale wszystko robiłem spontanicznie. Jeżeli się ktoś baaaardzo nudzi może uda się znaleźć błąd. Jak nie potraficie sie w tym syfie odnaleźć piszcie jaki fragment podać, to go wkleję.

1

Którego słowa nie zrozumiałeś:

_13th_Dragon napisał(a):

Nie! Zwolnić zasoby i wywołać obsługę domyślną okienka ...
?

2

for(int n=0; n<(int)hListaElementy.size(); n++)
DestroyWindow(*hListaElementy[n]);

To jest zbędne. Wystarczy że okna z tablicy hListaElementy będą potomne i miały hListaOdtwarzania jako parenta.

PS. a trzymanie wskaźników na HWND to już zupełna przesada, bo samo HWND jest wskaźnikiem i można go sobie kopiować.

0

Poprawiłem! Śmiga wszystko i jest poprawne. Jak zwykle źle rozumowałem. Poprawiłem też dużżżżżżżżo podstawowych błędów które były wytykane w moich starszych postach (tak btw, dlaczego niewskazane jest używać okna pulpitu jako parenta okna głównego programu ? Ktoś mi tego zabronił w starszych postach i wskazał wstawiać NULL).

1

dlaczego niewskazane jest używać okna pulpitu jako parenta okna głównego programu

Bo główne okno z definicji ma nie mieć parenta. Gdy podasz tam pulpit, to po pierwsze nie jest to już okno główne tylko okno potomne pulpitu, po drugie jest to okno potomne zupełnie innego procesu. Jedno i drugie może mieć dziwne konsekwencje w postaci kaszaniącego się interfejsu czy nienormalnego działania okna.
Nawet jeśli nie dzisiaj i nie u ciebie, to być może w innej wersji systemu i u kogo innego.
Po prostu tak nie rób. Podawaj NULL.

0

Przetwarzasz komunikaty przeznaczone nie dla tego okna i tyle.
Pewnie za bardzo się starałeś...

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