VCL/VXL ähnlicher Win32API Wrapper



  • Hi,

    ihr kennt doch sicherlich das Verfahren von Buttons in VCL. Buttons sind Instanzen, die ihre eigenen Nachrichten verarbeiten und nicht das Elternfenster.

    Soetwas möchte ich gerne auch machen 🙂

    Ich hatte mir das folgendermaßen gedacht: Eine Klasse namens "button" bekommt einen Funktionspointer auf eine Funktion die aufgerufen werden soll, wenn der Button gedrückt wird (Also WM_COMMAND an das Elternfenster gesendet wird).

    Ich habe mit Subclassing meinen Button meine WndProc aufgetragen und das läuft auch Prima, WM_PAINT kommt an usw. leider jedoch nicht WM_COMMAND. 😞

    Jetzt hab ich mir gedacht, wie ich das emulieren könnte: Alle möglichen Fensternachrichten abfangen und zusammenfügen, die dieses Ereignis auslösen könnten. Leider eine unzähmbare arbeit. 😞

    Also bin ich zu extrem radikalen mitteln gegangen und habe im Elternfenster folgendes gemacht:

    case WM_COMMAND:
            SendMessage ((HWND)lParam, WM_COMMAND, wParam, lParam);
            break;
    

    Klappt wunderbar, nur na ja: nicht das wahre und extrem radikal!

    Jetzt meine Frage daher (und nein, ich möchte nicht rumdiskutieren wieso ich es so wie die VCL haben möchte!) : Wie kann ich es erreichen, das mein Button den Funktionspointer aufruft, wenn ich auf ihn klicke und an das Elternfenster WM_COMMAND gesendet würde?

    Danke im voraus 🙂



  • Ach das Thema hast du doch schonmal hier reingestellt...



  • Hi,

    ich habe es jetzt mal wie folgt ausprobiert:

    #include <windows.h>
    
    typedef bool (*action)(void);
    
    static const unsigned long WM_COMMAND_BUTTON = WM_APP+1;
    
    class IButton
    {
    public:
        IButton (::HWND__* parent, HINSTANCE instance, unsigned long x, unsigned long y, action on_command) 
        {
            m_on_command = on_command;
    
            m_hwnd = ::CreateWindow ("button", "Test", WS_CHILD | WS_VISIBLE, x, y, 100, 100, parent, NULL, instance, 0);
    
            set_wndproc (m_hwnd);
        } 
    
    private:
    
    void set_wndproc(HWND hwndCombo)
    {
    	LONG OldComboProc;
    
    	OldComboProc = GetWindowLong(hwndCombo, GWL_WNDPROC);
    	SetWindowLong(hwndCombo, GWL_USERDATA, OldComboProc);
    
    	OldComboProc = SetWindowLong(hwndCombo, GWL_WNDPROC, (LONG)WndProc);
    }
    
    static LRESULT WINAPI WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {	
    	WNDPROC			OldComboProc = (WNDPROC)GetWindowLong(hwnd, GWL_USERDATA);
    
    	switch(msg)
    	{
        case WM_COMMAND_BUTTON:
            m_on_command ();
            break;
    	}
    
    	return CallWindowProc(OldComboProc, hwnd, msg, wParam, lParam);
    }
        action      m_on_command;
        HWND   m_hwnd;
    };
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        switch(uMsg)
        {
        case WM_COMMAND:
            SendMessage ((HWND)lParam, WM_COMMAND_BUTTON, 0, 0);
            break;
       case WM_DESTROY:
                 PostQuitMessage(0);
                 return(0);
            default: break;
        }
    
      return(DefWindowProc(hWnd, uMsg, wParam, lParam));
    }
    
    bool button1 (void)
    {
        MessageBox (NULL, "", "Button 1", MB_OK);
        return(true);
    }
    
    bool button2 (void)
    {
        MessageBox (NULL, "", "Button 2", MB_OK);
        return(true);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int nCmdShow)
    {
      WNDCLASSEX           wc;
      HWND                 hWnd;
      MSG                  msg;
    
        wc.cbSize        = sizeof(wc);
        wc.style         = 0;
        wc.lpfnWndProc   = WndProc;
        wc.cbClsExtra    = 0;
        wc.cbWndExtra    = 0;
        wc.hInstance     = hInstance;
        wc.hIcon         = (HICON)LoadIcon(NULL, IDI_APPLICATION);
        wc.hCursor       = (HCURSOR)LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
        wc.lpszMenuName  = NULL;
        wc.lpszClassName = TEXT("Buttontest");
        wc.hIconSm       = (HICON)LoadIcon(NULL, IDI_APPLICATION);
    
        if(!RegisterClassEx(&wc))
            return(0);
        if(NULL == (hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW | WS_EX_APPWINDOW, 
                              wc.lpszClassName, wc.lpszClassName, WS_OVERLAPPEDWINDOW, 
                              CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
                              NULL, NULL, hInstance, NULL)))
            return(0);
    
        IButton test_button1(hWnd, hInstance, 10, 10, button1);
        IButton test_button2(hWnd, hInstance, 210, 10, button2);
    
        ShowWindow (hWnd, nCmdShow);
    
        while(GetMessage(&msg, NULL, 0, 0))
        {
            if(!IsDialogMessage(hWnd, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage (&msg);
            }
        }
    
      return(msg.wParam);
    }
    

    Jedoch sagt er mir in der WndProc:
    button_test.cpp(40) : error C2597: illegal reference to non-static member 'IButton::m_on_command'

    Wie kann ich dieses problem beheben? Wenn ich es static mache, bekomme ich linkerfehler 😞



  • kannst de aber ruhig static machen... musst dann nur halt folgendes net vergessen:

    action IButton::m_on_command = 0;
    


  • return CallWindowProc(OldComboProc, hwnd, msg, wParam, lParam);
    }
        static action IButton::m_on_command = 0;
        HWND   m_hwnd;
    };
    

    error C2864: 'IButton::m_on_command' : only static const integral data members can be initialized within a class

    oder war das anders gemeint? 😮



  • ja war anders gemeint 😉

    Das ist sowas ähnliches wie nen konstruktor 😉

    Also:

    return CallWindowProc(OldComboProc, hwnd, msg, wParam, lParam);
    }
        static action m_on_command;
        HWND   m_hwnd;
    }; 
    
    static action IButton::m_on_command = 0;
    


  • genial, das geht! aber klicke ich auf button1 wird die falsche Funktion aufgerufen? 😮



  • *push*



  • Schau Dir das hier an:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-149120.html

    Und wie dort schon erwähnt: Schau Dir MFC/wxWidget oder sonstige "Frameworks" an, die genau das gemacht haben...

    PS: Und eine "static"-Variable zu definieren ist für eine "Framework" fast immer tödlich.



  • Jo... das ist klar 😃 War aber auch klar das die Frage von ihm kommt 🙂


Anmelden zum Antworten