Autor Wątek: WinAPI Minimize / Restore Window  (Przeczytany 3629 razy)

Offline MrKaktus

  • Użytkownik

# Grudzień 29, 2013, 18:42:44
Ok, całkiem głupia sytuacja ale siedzę nad nią już kilka godzin i nie mam pomysłu.
Do tej pory zawsze tworzyłem Aplikację w fullscreen mode, ewentualnie w oknie podczas debugu.
Teraz postanowiłem że w sumie fajnie byłoby dodać obsługę systemowych eventów jak minimalizacja okna do paska i spowrotem.

Po wciśnięciu guzika "Minimize" okna moja procedura WndProc otrzymuje msg :
WM_SIZE
wParam == SIZE_MINIMIZED
Obsługuje ten event w aplikacji pauzując wykonanie gry.
Robie klasyczny "return 0" po obsłużeniu eventu i wychodzę z WndProc.

I tutaj powstaje kłopot.
Kontrola nigdy nie powraca do aplikacji, nie ma powrotu z wywołania:
DispatchMessage(&InputContext.msg); // Call WndProc to process incoming events

Nie mam pomysłu czemu kontrola nigdy nie wraca do aplikacji. W końcu okno nie jest jej równoważne szczególnie że aplikacja by default jest CmdLine app a nie WindowApp i okno tworzy sobie później.
Ktoś się może spotkał już z czymś takim? Znacie jakieś rozwiązania?

Proces odpalam na Windows 7 i widzę miniaturkę okna aplikacji ale po najechaniu na nią i kliknięciu okno nie powraca na pulpit (co jest swoją drogą oczywiste skoro nie nastąpił powrót z DispatchMessage() hmmm ).

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Grudzień 29, 2013, 20:11:01
Cytuj
I tutaj powstaje kłopot.
Kontrola nigdy nie powraca do aplikacji, nie ma powrotu z wywołania:
DispatchMessage(&InputContext.msg); // Call WndProc to process incoming events
Jaki konkretnie message i do którego okna jest powodem zawieszenia? Jak wygląda call stack wątku wiszącego na DispatchMessage?

Offline MrKaktus

  • Użytkownik

# Grudzień 29, 2013, 20:49:11
Ostatni message jaki zostaje przekazany do WindowProc to wspomniany WM_SIZE z wParam == SIZE_MINIMIZED. Po wyjściu z WindowProc z return 0, kod wraca do user32.dll skąd WindowProc było wywołane pośrednio po wywołaniu w aplikacji DispatchMessage.
Aplikacja nie jest zwieszona, tylko nie zostaje do niej zwrócona kontrola.

Pauzowanie debugu w dowolnym momencie powoduje zatrzymanie w systemowym callstacku:

>   ntdll.dll!770100fd()    
    [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]   
    ntdll.dll!770100fd()    
    KernelBase.dll!74f10962()    
    kernel32.dll!74dd162d()    
    user32.dll!759903da()    
    user32.dll!7599066e()    
    nvoglv32.dll!68ead8a7()    
    kernel32.dll!74dd3677()    
    ntdll.dll!77029d72()    
    ntdll.dll!77029d45()    


Offline Xion

  • Redaktor
    • xion.log

# Grudzień 29, 2013, 20:53:54
Próbowałeś wysyłać message dalej do DefWindowProc zamiast zwracać 0?

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Grudzień 29, 2013, 21:05:29
Cytuj
>   ntdll.dll!770100fd()   
    [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]   
    ntdll.dll!770100fd()   
    KernelBase.dll!74f10962()   
    kernel32.dll!74dd162d()   
    user32.dll!759903da()   
    user32.dll!7599066e()   
    nvoglv32.dll!68ead8a7()   
    kernel32.dll!74dd3677()   
    ntdll.dll!77029d72()   
    ntdll.dll!77029d45()   
A można prosić jeszcze raz, tyle że ze ściągniętymi symbolami z serwera MS? :)

Offline MrKaktus

  • Użytkownik

# Grudzień 29, 2013, 21:06:13
Ok, wyczyscilem switcha(msg) z wszystkiego poza :

       case WM_DESTROY:
            PostQuitMessage(WM_QUIT);
            break;

       default:
            return DefWindowProc(hWnd, msg, wParam, lParam);

Teraz kontrola wraca do aplikacji. Mimo to, okno nie chce wrócić na pulpit po wybraniu go z paska zadań.
A to oznacza że dotychczasowa obsługa któregoś z eventów była niewystarczająca. Hmmm.

Offline MrKaktus

  • Użytkownik

# Grudzień 29, 2013, 21:47:00
Ok, doszedłem do takiego etapu:

       case WM_SIZE:
            {
            //if (wParam == SIZE_RESTORED)
            //   {
            //   ShowWindow(hWnd, SW_RESTORE);

            //   // Call event handling function
            //   event.type = AppWindowActive;
            //   en::InputContext.events.callback(event);
            //   }
            if (wParam == SIZE_MINIMIZED)
               {
               // Call event handling function
               event.type = AppWindowHidden;
               //en::InputContext.events.callback(event);
               }
            return DefWindowProc(hWnd, msg, wParam, lParam);
            }

Odkomentowanie wywołania callback'a do aplikacji dla  SIZE_MINIMIZED powoduje wspomniany zwis po stronie OS'a. Jeżeli nie wywołuje wspomnianego callback'a wszystko jest ok. No i teraz mam zagwozdkę bo funkcja pod callbackiem ustawia sobie jednego bool'a na true/false i to wszystko.

Parametry które wchodzą do DefWindowProc w obu przypadkach są takie same. Wygląda więc jakby coś ze stosem się działo.

Offline Xion

  • Redaktor
    • xion.log

# Grudzień 29, 2013, 21:55:27
Cytuj
No i teraz mam zagwozdkę bo funkcja pod callbackiem ustawia sobie jednego bool'a na true/false i to wszystko.
A jest gdzieś jakiś wątek, proces czy inny event loop którego działanie zależy od tego boola? W szczególnosci taki, którzy może wpasć w nieskończoną pętlę :)

Offline MrKaktus

  • Użytkownik

# Grudzień 29, 2013, 21:59:29
No własnie na tym myk polega że nie. Task Pool mam obecnie wyłączony. Callback idzie do funkcji w stanie gry i ustawia paused na true. Po zakończeniu obsługi wszystkich eventów, kontrola powinna być zwrócona z powrotem do metody update aktualnego stanu gry która to zażyczyła sobie je przetworzyć.

Offline MrKaktus

  • Użytkownik

  • +2
# Grudzień 29, 2013, 22:14:53
ROZWIĄZANIE :

bad:
bool Game::update(Time dt)
{
if (paused)
   return false;

double moveSpeed = 7.0 * dt.seconds();
float turnSpeed = static_cast<float>(45.0 * dt.seconds());

Input.update();

good:
bool Game::update(Time dt)
{
double moveSpeed = 7.0 * dt.seconds();
float turnSpeed = static_cast<float>(45.0 * dt.seconds());

Input.update();

if (paused)
   return false;

Input.update() wywolujemy w grze gdy chcemy sprocesowac wszystkie eventy przychodzace do aplikacji.
W srodku przechodzimy po eventach wolamy DefWindowProc, ono wola WindowProc, ono wola ze okno zostalo zminimalizowane odpowiednim callbackiem. Callback ustawia paused na true...

Przetwarzanie eventow sie konczy, wychodzimy z Input.update() robimy reszte updejtu stanu gry.
W kolejnym wywolaniu nieszczescny paused robi quick return i gra staje sie glucha na eventy z systemu..

Dodatkowo nalozyl sie tutaj brak wywolania:
DefWindowProc(hWnd, msg, wParam, lParam);
dla WM_SIZE poniewaz okazuje sie ze dla tego konkretnego eventu systemowego, OS uruchamia pod-petle obslugi eventow niewidoczna do aplikacji i ukryta w jego bebechach. Wspomniana pod-petla dziala dopuki nie zakonczy sie event WM_SIZE ktory trwa w 2 wariantach:
1) Jezeli resizujemy okno, dopuki user nie pusci klawisza myszki i nie skonczy akcji resize.
2) Gdy okno jest minimalizowane/maksymalizowane/przywracane wystepuje jego animacja.

Kurde problem nietrywialny przez wystapienie tych 2 rzeczy na raz ale cale szczescie udalo sie rozwiazac. Xion dzieki za zwrocenie uwagi na bool'a :)

Offline Xion

  • Redaktor
    • xion.log

# Grudzień 29, 2013, 22:17:47
Ha, czyli jednak była jakaś pętla która od niego zależy! Cool :)