winapi-windowprocedure w klasie

0

Bawię się z klasą okna. Korzystam z winapi. Kiedy windowproc jest poza klasą to działa, jednak jak mam wektor klas okna i każda komórka powinna mieć własną funkcję do tego a nie tę samą, bo używam windowproc do sprawdzenia, czy dane okno jest aktywne czy nie.

0

Statyczna metoda lub std::bind

0

nie za bardzo rozumiem jak to ma pomóc... chcę włożyć funkcję windowproc do klasy, kiedy mam ją poza klasą to jest dobrze, jak wkładam ją do klasy to wywala mi błąd konwersji typów:

cannot convert 'Window::WindowProc' 
from type:
'LRESULT (Window::)(HWND, UINT, WPARAM, LPARAM) {aka long int (Window::)(HWND__*, unsigned int, unsigned int, long int)}'
to type:
'WNDPROC {aka long int (__attribute__((__stdcall__)) *)(HWND__*, unsigned int, unsigned int, long int)}' 
0

Musisz znać różnicę między funkcją, statyczną metodą(ergo funkcją) i metodą
Zwykła metoda musi być wywołana na rzecz jakiegoś obiektu

0

z tego co wiem metody statyczne działają dla wszystkich zadeklarowanych zmiennych typu tej klasy... a ja chcę, żeby moja klasa miała funkcję windowproc która będzie zmieniać zmienną active w tej jednej zadeklarowanej a nie we wszystkich tego typu

2

To się da zrobić na kilka sposobów. Podam jeden, ale bez gotowego przykładu, bo mi się nie chce szukać :-P

WndProc podane do CreateWindow[Ex] musi, absolutnie musi być static. Żeby ze statycznej metody wywołać metodę niestatyczną, potrzebny ci jest obiekt klasy, bo metody statyczne nie znają this.

LRESULT _stdcall Window::WndProcStatic(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   Window *that;

   /*** tutaj czarna magia ***/

   return that->WndProc(hWnd, uMsg, wParam, lParam);
}

tak powinna wyglądać procedura okna. tylko skąd teraz wziąć obiekt that, odpowiadający danemu oknu?

Można trzymać globalną mapę std::map<HWND, Window*> i dodawać i usuwać elementy w miarę tworzenia i niszczenia okien.
Ale to taki trochę hack. Właściwszym sposobem byłoby przechowywanie wskaźnika na Window jakoś w samym HWND.

Do tego można wykorzystać ostatni parametr funkcji CreateWindow. Tam możesz przekazać this typu Window*. Potem powyższa „czarna magia” będzie wyglądać mniej więcej tak (piszę z głowy, bez kompilowania):

LRESULT _stdcall Window::WndProcStatic(bla bla)
{
   if (uMsg == WM_NCCREATE)
   {
      SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams);
   }

   Window *that = (Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);

   if (that)
      return that->WndProc(hWnd, uMsg, wParam, lParam);
   else
      return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
0

Dobra ten błąd rozwiązany ale nie wiem czy działa dobrze bo zmieniłem trochę struktury i klasy w programie i mam 46 błędów z tego powodu i jeszcze nie udało mi się tego ogarnąć

0

no to wywaliłem cały stos błędów z gry i... nie działa dalej... crash i "process terminated with status 255"

0

a więc mam takie coś:

class Window
{
public:
    jakieś zmienne
    bool active;
    static LRESULT CALLBACK Windowproc(argumenty funkcji obsługi komunikatów okna);
    jakieś funkcje
}


LRESULT CALLBACK Window::Windowproc(to co powyżej)
{
    Window *that;
    if (uMsg==WM_CREATE)
    {
        SetWindowLongPtr(hwnd,GWLP_USERDATA,(LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams);
    }
    that=(Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
    switch (uMsg)
    {
    case WM_CLOSE:
        {
            PostQuitMessage(0);
        }
        break;
    case WM_DESTROY:
        {
            return 0;
        }
    case WM_KEYDOWN:
        {
            switch (wParam)
            {
            case VK_ESCAPE:
                PostQuitMessage(0);
            break;
            }
        }
        break;
    case WM_ACTIVATE:
        {
            if(LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE)
            {
                that->active = 1;
            }
            else
            {
                that->active = 0;
            }
        }
        break;
    default:
        {
            if (that)
            {
                return that->WindowProc(hwnd, uMsg, wParam, lParam);
            }
            else
            {
                return DefWindowProc(hwnd, uMsg, wParam, lParam);
            }
        }
        break;
    }
    return 0;
}

no i się kompiluje i na tym się kończy to ci robi mój program, jak ta funkcja była poza klasą to działało ale źle

0

Przenieś to całe switch (uMsg) do metody niestatycznej, a statyczna powinna wyglądać tak jak pokazałem bez dodatków.
Jaki jest sens bawienia się z metodą niestatyczną, skoro komunikaty i tak wpychasz do statycznej?

    case WM_CLOSE:
        {
            PostQuitMessage(0);
        }
        break;
    case WM_DESTROY:
        {
            return 0;
        }

Przenieś PostQuitMessage do WM_DESTROY, a WM_CLOSE wywal. WM_CLOSE służy do wyświetlania np. messageboksa "Czy chcesz zapisać zmiany?".

           case VK_ESCAPE:
                PostQuitMessage(0);

Okno zamykamy przez PostMessage(hwnd, WM_CLOSE, 0, 0);

Powyższe zmiany dadzą ci prawidłową sekwencję zamykania okna¹. Nie widzę w tym co podałeś jednak powodu, dla którego program się zamyka na starcie. Jest w programie chociaż pętla komunikatów? Bez niej okno się utworzy, owszem, po czym zaraz program się zakończy bo nic nie ma do roboty.

Przydałby ci się debugger, to byś wiedział gdzie się wywala.

¹) PostQuitMessage przerywa pętlę komunikatów (GetMessage zwróci 0) i służy do zakończenia programu. Komunikat WM_CLOSE jest wysyłany przez Alt+F4 albo przez kliknięcie na [X]. Standardowo (w DefWindowProc) powoduje wykonanie DestroyWindow. Własny handler może wyświetlić jakiś message "Czy na pewno?" i wykonać DestroyWindow albo nie. Komunikat WM_DESTROY jest wysyłany przez DestroyWindow. Losy okna w WM_DESTROY są już przesądzone, możemy jedynie zwolnić jakieś zasoby, albo zrobić PostQuitMessage żeby zasygnalizować że to koniec programu. Standardowy handler WM_DESTROY nie robi PostQuitMessage bo nie każde zamknięcie okna musi oznaczać zamknięcie programu.

0

Ok znalazłem błąd nie związany z tym... po prostu nie ma zabezpieczenia przed złą wartością that (null) thx Azarien za pomoc

0

jednak nie działa, zauważyłem to przed chwilą... jakieś inne opcje?

0

program się kompiluje ale funkcja nie działa jak powinna(nie pobiera odpowiedniego uchwytu) i przez to zmienna active cały czas wynosi 0

0

nadal nie wiem jak wywoływać funkcję obsługi okna, tak by ustawiała zmienną active w każdym obiekcie klasy window w którym zminna typu hwnd wskazuje na aktywne okno

0

Pokaż kod.

0

no właśnie nie mam za bardzo czego pokazać... klasa okno posiada uchwyt do okna typu hwnd, styl okna, bufor do rysowania po tym oknie i zmienną active która mówi, czy okno jest aktywne. Chcę zrobić funkcję windowprocedure która obsługuje komunikaty okna, i żeby ustawiały zmienną active na true lub false w obiektach klasy okna, tak by jeśli w danym obiekcie wskaźnik na okno wskazuje na aktywne okno to zmienna active w tym obiekcie była ustawiona na true.

0

A po co w ogóle Ci ta zmienna, przecież możesz użyć funkcji GetActiveWindow?

Coś w ten deseń:

class Window
{
private:
	HWND	m_hwnd;
	...
	
public:	
	...
	
	bool IsActive() const { return GetActiveWindow() == m_hwnd; } 
};
0

no nie chodzi mi tylko o tą jedną zmienną tylko o wiele zmiennych od różnych rzeczy, to z active jest takim przykładem i chodzi mi o okno aktywne w sensie, że jak coś naciskam to to idzie do mojego okna. Rozważałem jeszcze użycie vectora wskaźników do obiektów klasy window, tylko nie jestem pewien jak to zrobić żeby funkcja klasy window wrzucała do vectora wskaźników(na obiekty klasy window) wskaźnik do samej siebie.

0

Bez kodu ciężko coś powiedzieć. Pokaż, jak tworzysz klasę okna (RegisterClassEx) i jak tworzysz okno.

0

po paru godzinach udało mi się rozwiązać problem, zrobiłem sobie vector wskaźników na obiekty klasy window i podczas tworzenia okna dodaje je do kolejki a podczas niszczenia okna usuwam, podczas obsługi komunikatów okna sprawdzam który wskaźnik w kolejce wskazuje na uchwyt okna taki sam jak ten podany w parametrze i jeśli w kolejce jest taki obiekt to kopiuję sobie jego uchwyt i dalej obsługa działa prawie tak samo tylko zamiast this mam that :)

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