i'm creating the form class. the form us showed and the window procedure works. the problem is that some messages(like WM_CREATE) aren't working. so how can i connect, correctly the form to window procedure?

Recommended Answers

All 31 Replies

All messages are sent to the WinProc() procedure -- the first parameter to that function tells you which hWnd the message is for. In the case of wm_create the message is sent before the window becomes visible.

in these sample, i only have 1 form.
see the setParent():

form()
    {
        ++FormCount;
        strCaption=strCaption + to_string(FormCount);
        setParent(HWND_DESKTOP);
    }

void setParent(HWND parent=GetDesktopWindow())
    {

            WNDCLASSEX FormClass;
            char classname[]="form";
            HINSTANCE mod = (HINSTANCE)GetModuleHandle(NULL);

            FormClass.cbSize        = sizeof(WNDCLASSEX);
            FormClass.style         = 0;
            FormClass.lpfnWndProc   = WndProcForm;
            FormClass.cbClsExtra    = 0;
            FormClass.cbWndExtra    = 0;
            FormClass.hInstance     = mod;
            FormClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
            FormClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
            FormClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
            FormClass.lpszMenuName  = NULL;
            FormClass.lpszClassName = classname;
            FormClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

            // register the new window class"
            RegisterClassEx(&FormClass);
            SetProp(hwnd, formpropname, (HANDLE)FormClass.lpfnWndProc);

            hwnd = CreateWindowEx(0, classname, "The title of my window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, parent, NULL, mod, (LPVOID) this);

            if (hwnd == NULL)
                MessageBox(NULL, "Can't create the control", "error", MB_OK);
            SetProp(hwnd, formclassprop, (HANDLE)this);
            ShowWindow(hwnd, SW_NORMAL);
            UpdateWindow(hwnd);

            clrBackColor= GetBkColor(GetDC(parent));
            clrTextColor = GetTextColor(GetDC(parent));


        RECT a;
        GetClientRect(hwnd,&a);
        intTop=a.top;
        intLeft=a.left;
        intWidth=a.right-a.left;
        intHeight=a.bottom-a.top;
    }

until here seems fine... now see the window procedure:

static LRESULT CALLBACK WndProcForm(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        static POINT PreviousLocation, Location;
        static bool Tracking = false;
        static MouseButtons MBButtons;
        static bool blControl=false;
        static bool blShift=false;
        static bool blResize=false;
        static int xPos=0;
        static int yPos=0;
        static UINT_PTR timerid;
        static bool blnDrag=false;



        //Working with messages
        switch(msg)
        {
            case WM_CREATE:
            {
                RECT a;
                GetWindowRect(hwnd,&a);
                Create(a.left, a.top);
            }
            break;

the Create is a function lambda that only show us a message box. the WM_CREATE don't show me the message box... but, for test, i use it with WM_KEYUP and it's showed.
so some messages aren't call in these window procedure :(
what i'm doing wrong?

use your debugger and put a breakpoint on WM_CREATE. Since the window hasn't been created yet there can be no message box to show you.

commented: thanks +2

you have right. the problem was not the window procedure(i did new tests)... but the order of code ;)
i fix that in constructor and now my 'event' is activated on that message.
i continue with several problems :(
how can i get the instance of class for a pointer?

static LRESULT CALLBACK WndProcForm(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        static POINT PreviousLocation, Location;
        static bool Tracking = false;
        static MouseButtons MBButtons;
        static bool blControl=false;
        static bool blShift=false;
        static bool blResize=false;
        static int xPos=0;
        static int yPos=0;
        static UINT_PTR timerid;
        static bool blnDrag=false;

        if (WindowMain==NULL)
            WindowMain=hwnd;
        form *inst=(form*)lParam;

        //Working with messages
        switch(msg)
        {
            case WM_CREATE:
            {

                RECT a;
                GetWindowRect(hwnd,&a);
                inst->Create(a.left, a.top);
            }
            break;
//................

unless you are sending a private message (one that you make up yourself) you can't control the value of lparam parameter. The easiest way to get a ponter to a specic instance of a class is to save the hwnd value in the class instance when it is first create, create a vector (or array) of class instances so that you can search the array for hwnd inside WinProc function. That's pretty much how Microsoft implemented MFC classes.

theres another way.. i have done with another code, but don't works with these code :(
let me ask in other way: when we use CreateWindowEx() function with 'this' class pointer. how can i get these pointer inside of a CALLBACK function?

Bad code here?

SetProp(hwnd, formpropname, (HANDLE)FormClass.lpfnWndProc);

hwnd = CreateWindowEx(0, classname, "The title of my window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, parent, NULL, mod, (LPVOID) this);

HWND isn't assigned when you call SetProp. You probably want to create the window before calling SetProp.

The real way to implement what you're looking for is as follows:

#include <windows.h>


/** 
  BaseForm abstract class.
  All other forms/windows must inherit from this one.
**/
class BaseForm
{
    private:
        HWND m_Hwnd;

    public:
        BaseForm() : m_Hwnd(NULL) {}
        ~BaseForm() {m_Hwnd = NULL;}

        bool Create(const char *Title, POINT Location, unsigned short Width, unsigned short Height, HWND Parent);

    protected:
        virtual int Show();
        HWND GetHWND() const {return m_Hwnd;}
        static LRESULT __stdcall WindowProcedure(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam);
        virtual LRESULT WinProc(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) = 0;
};

int BaseForm::Show()
{
    MSG Messages = {0};
    ShowWindow(m_Hwnd, SW_SHOW);

    while(GetMessage(&Messages, nullptr, 0, 0))
    {
        TranslateMessage(&Messages);
        DispatchMessage(&Messages);
    }
    return Messages.wParam;
}

bool BaseForm::Create(const char *Title, POINT Location, unsigned short Width, unsigned short Height, HWND Parent)
{
    WNDCLASSEX FormClass;
    FormClass.cbSize        = sizeof(WNDCLASSEX);
    FormClass.style         = 0;
    FormClass.lpfnWndProc   = WindowProcedure;
    FormClass.cbClsExtra    = 0;
    FormClass.cbWndExtra    = 0;
    FormClass.hInstance     = GetModuleHandle(NULL);
    FormClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    FormClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
    FormClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    FormClass.lpszMenuName  = NULL;
    FormClass.lpszClassName = "BASE_FORM";
    FormClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    RegisterClassEx(&FormClass);
    m_Hwnd = CreateWindowEx(0, "BASE_FORM", Title, WS_OVERLAPPEDWINDOW, Location.x, Location.y, Width, Height, Parent, NULL, GetModuleHandle(NULL), this);
    return m_Hwnd != NULL;
}

LRESULT __stdcall BaseForm::WindowProcedure(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    BaseForm *frm = NULL;

    if (Msg == WM_NCCREATE)
    {
        CREATESTRUCT *p = (CREATESTRUCT *)lParam;
        frm = (BaseForm *)(p->lpCreateParams;
        SetWindowLongPtr(Hwnd, GWLP_USERDATA, (LONG_PTR)frm);
        frm->m_Hwnd = Hwnd;
    }
    else
    {
        frm = (BaseForm *)GetWindowLongPtr(Hwnd, GWLP_USERDATA);
    }

    if (frm) 
        return frm->WinProc(Hwnd, Msg, wParam, lParam);

    return DefWindowProc(Hwnd, Msg, wParam, lParam);
}





/** 
  Example usage:

  Form inherits from BaseForm.
  We override the "Show" function to make it public and to call the parent one.
  We call "Create" and we implement our own WndProc.
**/

class Form : public BaseForm
{
    public:
        Form(const char *Title, POINT Location, unsigned short Width, unsigned short Height, HWND Parent = NULL);
        LRESULT WinProc(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam);
        int Show() {return BaseForm::Show();}
};

Form::Form(const char *Title, POINT Location, unsigned short Width, unsigned short Height, HWND Parent)
{
    BaseForm::Create(Title, Location, Width, Height, Parent);
}

LRESULT Form::WinProc(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch(Msg)
    {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;

        default:
            return DefWindowProc(Hwnd, Msg, wParam, lParam);
    }
    return 0;
}




int main()
{
    return Form("Hello", {CW_USEDEFAULT, CW_USEDEFAULT}, 500, 500).Show();
}

You could also make "Form" abstract by not implementing the WndProc in the above. Then inherit from Form. The only thing you'd have to implement then would be WndProc.

Example:

/** Form is now abstract **/

class Form : public BaseForm
{
    public:
        Form(const char *Title, POINT Location, unsigned short Width, unsigned short Height, HWND Parent = NULL);
        int Show() {return BaseForm::Show();}
};

Form::Form(const char *Title, POINT Location, unsigned short Width, unsigned short Height, HWND Parent)
{
    BaseForm::Create(Title, Location, Width, Height, Parent);
}




/** Example Usage (Whenever you want to create a Window nice and quick): **/

class Window : public Form
{
    public:
        LRESULT WinProc(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam);
};

LRESULT Window::WinProc(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch(Msg)
    {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;

        default:
            return DefWindowProc(Hwnd, Msg, wParam, lParam);
    }
    return 0;
}

int main()
{
    return Window("Hello", {CW_USEDEFAULT, CW_USEDEFAULT}, 500, 500).Show();
}
commented: thanks +2

triumphost: thanks... seen your code, i did:

void setParent(HWND parent=GetDesktopWindow())
    {
            WNDCLASSEX FormClass;
            char classname[]="form";
            HINSTANCE mod = (HINSTANCE)GetModuleHandle(NULL);

            FormClass.cbSize        = sizeof(WNDCLASSEX);
            FormClass.style         = 0;
            FormClass.lpfnWndProc   = WndProcForm;
            FormClass.cbClsExtra    = 0;
            FormClass.cbWndExtra    = 0;
            FormClass.hInstance     = mod;
            FormClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
            FormClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
            FormClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
            FormClass.lpszMenuName  = NULL;
            FormClass.lpszClassName = classname;
            FormClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

            // register the new window class
            RegisterClassEx(&FormClass);

            hwnd = CreateWindowEx(WS_EX_TRANSPARENT , classname, strCaption.c_str(), WS_OVERLAPPEDWINDOW | WS_TABSTOP,
                        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, parent, NULL, mod, this);

            if (hwnd == NULL)
                MessageBox(NULL, "Can't create the control", "error", MB_OK);

            ShowWindow(hwnd, SW_NORMAL);
            UpdateWindow(hwnd);

            clrBackColor= GetBkColor(GetDC(parent));
            clrTextColor = GetTextColor(GetDC(parent));


        RECT a;
        GetClientRect(hwnd,&a);
        intTop=a.top;
        intLeft=a.left;
        intWidth=a.right-a.left;
        intHeight=a.bottom-a.top;
    }


    //window procedure:
     static LRESULT CALLBACK WndProcForm(HWND HandleWindow, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        static POINT PreviousLocation, Location;
        static bool Tracking = false;
        static MouseButtons MBButtons;
        static bool blControl=false;
        static bool blShift=false;
        static bool blResize=false;
        static int xPos=0;
        static int yPos=0;
        static UINT_PTR timerid;
        static bool blnDrag=false;
        form *inst=NULL;


         HBRUSH g_hbrBackground = NULL;

        //Working with messages
        switch(msg)
        {
            case WM_NCCREATE:
            {
                CREATESTRUCT *p = (CREATESTRUCT *)lParam;
                inst = (form *)p->lpCreateParams;
                SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)form);
                inst->hwnd = hwnd;
                if (inst==NULL)
                     inst = (form *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
            }
            break;
            //....

but i'm getting several errors :(
error: "invalid use of member 'form::hwnd' in static member function"

The code I gave you works out of the box. I cannot tell what your error is without line numbers and context.

That setParent is not a member function so how are you passing this as the last argument to CreateWindowEx?

As far as I can tell, the only thing you did use the NCCreate. If you don't explain exactly what those functions are above, and why they aren't member functions, there isn't much I can do.. The example I gave you was to use member functions. Otherwise you're going to have to explicitly pass the instance pointer to CreateWindowEx.

Also, that is a LOT of static variables.

heres my entire class: http://codepad.org/SrOIpP6t
my objective is trying get the form instance pointer in WndProcForm() callback function.
i use some static variables, because the WndProcForm() callback function is static(class member).

@Cambalinho..

Your errors were:

case WM_NCCREATE:
{
    CREATESTRUCT *p = (CREATESTRUCT *)lParam;
    inst = (form *)p->lpCreateParams;

    SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)form); //error.. hwnd should be: HandleWindow parameter.  (LONG_PTR)form should be: (LONG_PTR)inst..
    //The line above should be: SetWindowLongPtr(HandleWindow, GWLP_USERDATA, (LONG_PTR)inst);

    inst->hwnd = hwnd; //should be: inst->hwnd = HandleWindow;
    if (inst == NULL)
        inst = (form *)GetWindowLongPtr(hwnd, GWLP_USERDATA); //error.. hwnd should be: HandleWindow parameter.
        //The line above should be: (form *)GetWindowLongPtr(HandleWindow, GWLP_USERDATA);
}
break;

If you fix it, it should look like:

case WM_NCCREATE:
{
    CREATESTRUCT *p = (CREATESTRUCT *)lParam;
    inst = (form *)p->lpCreateParams;
    SetWindowLongPtr(HandleWindow, GWLP_USERDATA, (LONG_PTR)inst);
    inst->hwnd = HandleWindow;

    if (inst == NULL)
        inst = (form *)GetWindowLongPtr(HandleWindow, GWLP_USERDATA);
}
break;

Also, I'd like you to read here: http://www.daniweb.com/software-development/cpp/threads/423106/separate-headers-from-source

I also like coding your way before.. I switched to the proper way and got so used to it. Please read the above for proper coding ethics. It will help you improve too. It helped me.

commented: thanks +0

sorry... i don't get errors, on code, but when i execute, i can't see the form and after some time i see the output message:
"Process terminated with status -1073741819"
what you think?

Your code is wrong.. How can you NOT get errors? There is no way that code would have compiled without the above fixes.. And to fix your runtime errors you need to change the code to the following:

    static LRESULT CALLBACK WndProcForm(HWND HandleWindow, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        static POINT PreviousLocation, Location;
        static bool Tracking = false;
        static MouseButtons MBButtons;
        static bool blControl=false;
        static bool blShift=false;
        static bool blResize=false;
        static int xPos=0;
        static int yPos=0;
        static UINT_PTR timerid;
        static bool blnDrag=false;

        //you're missing the below line..
        form *inst = (form *)GetWindowLongPtr(HandleWindow, GWLP_USERDATA);


         HBRUSH g_hbrBackground = NULL;

        //Working with messages
        switch(msg)
        {
            case WM_NCCREATE:
            {
                CREATESTRUCT *p = (CREATESTRUCT *)lParam;
                inst = (form *)p->lpCreateParams;
                SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)form);
                inst->hwnd = hwnd;
            }
            break;

            case WM_CREATE:
            {
                if(WindowMain==NULL)
                    WindowMain=HandleWindow;

                if (inst->Create != NULL) //you're also missing this line!
                    inst->Create(inst->intLeft, inst->intTop);
            }
            break;

            //..
            //..
            //..
        }
    }

You are also missing the main part of WinAPI windows:

while(GetMessage(Hwnd, 0, 0, 0, 0) > 0) do
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

that main message loop is used in these way:

#include "cambalinho.h"
HWND WindowMain=NULL;//these is inside of cambalinho.h
//and it's value is added when the form is created

#define WinMain() WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE, LPSTR, int nCmdShow)
#define End() PostQuitMessage(0);

//Message Loop
WPARAM MessageLoop(HWND MainWindow)
{
    MSG messages;
    while(GetMessage(&messages,0,0,0)>0)
    {
        if(!IsDialogMessage(MainWindow,&messages))
        {
            TranslateMessage(&messages);
            DispatchMessage(&messages);
        }
    }
    return messages.wParam;
}



form a;
form b;
button v(WindowMain);
button c(b);

//creating the window
int WinMain()
{

    c.MouseClick=[]()
    {
        v.setText("g&ood bye");
        Sleep(1000);
        End();
    };

    v.MouseClick=[]()
    {
        v.setText("hi");
    };

    return MessageLoop(a);
}

and now see the image: https://onedrive.live.com/?cid=C3EF456E15C8DEB6&id=C3EF456E15C8DEB6!1254&v=3

Ok but did you try what I said in the previous post? That fixes your error.

i'm getting problems, with your code, for get the pointer :(
i don't understand.... what i'm doing wrong?
tell me something for learn more please

see these inside of window procedure:

 form *inst = (form *)GetWindowLongPtr(HandleWindow, GWLP_USERDATA);//give me NULL(because the message box is showed), but no errors
        if (inst==NULL) MessageBox(NULL,"error", "error",MB_OK);

if i take of these message, the error(that image) isn't showed:

 //Working with messages
        switch(msg)
        {
            /* case WM_NCCREATE:
            {
                CREATESTRUCT *p = (CREATESTRUCT *)lParam;
                inst = (form *)p->lpCreateParams;
                SetWindowLongPtr(HandleWindow, GWLP_USERDATA, (LONG_PTR)inst);
                inst->hwnd = HandleWindow;
            }
            break;*/
            case WM_CREATE:
            {
                if(WindowMain==NULL)
                    WindowMain=HandleWindow;

               // inst->Create(inst->intLeft, inst->intTop);
            }
            break;

so, i belive, the error is from WM_NCCREATE message or passing the 'this' with CreateWindowEx() function.
what you can tell me?

Hmm.. well you must be doing something different.. The code I ran actually works. I tested everything before posting it.

Here is the project I tested:

Project Link

It includes Listeners and stuff similar to Java's.

There is already an example in the above project-link.

If you don't want to use that code then you will have to post everything you have because there really isn't enough information for me to tell you what is wrong with the code you currently have.

triumphost: thanks you very much, but i continue confuse: what i did wrong with my code?
(i'm trying see the diference code)

@Cambalinho: What you did wrong was to not make the changes I told you to make earlier. Might have missed it by accident.

You needed to have: if (inst->Create != NULL).. You should be testing your function pointers for NULL before calling them. That was the reason for your access violation.

The next thing is that you didn't put the inst = (form* )GetWindowLongPtr(...); in the case statement.

Other than that, I didn't change anything else.

commented: thanks for all... really thanks +0

triumphost: sorry... but i was trying :(
thanks for correct me that ;)
i have more 1 question: these way can be used for child controls(for getting the pointer)?
i need 1 tip: when i create the variable, from form, button or other, the control is created and showed in moment.... but before i change the events (yah... inclued the create event). what you advice me?
put a variable static in window procedure for activate that event before others?(and not when the control is created)

I couldn't understand the question.

Yes you could use it for child controls. Store the HWND or ID of the child control as well as the pointer to it in a map. Whenever an event is triggered, look up the ID or HWND and return the pointer to the control with that ID or HWND.

For me, the easier option is actually subclassing the control. If you do this, each control has its own WindowProc. Whenever an event is triggered, it'd just trigger its event listener.

Other than that, I couldn't figure out what you were trying to ask.

i need show you something... but now i'm getting, again errors and i don't undertstand why :(
i just change the event create from static to normal variable and i delete these line...
see the entire code: http://pastie.org/9389129
sometimes i don't understand some errors :(
don't make sence to me :(
i just change the static Create event to normal event(delete the static).

Here: http://pastie.org/private/c1qqrhycdpa1dk6flgonw

Same code you have but working. Only 1 line changed. Your error was because WM_CREATE is called before the default statement. If you initialise inst before you enter the switch statement, it will work.

commented: thank you very much +2

now works fine... thanks for all ;)
i need 1 advice... just see these code:

#include "cambalinho.h"

form a;//these line creates and show the form

int WinMain()
{
    //here i change the create event... that is called from WM_CREATE message in window procedure
    a.Create=[](int x, int y)
    {
        a.setText("hello world");
    };

    a.MouseEnter=[]()
    {
        a.setText("enter");
    };

    a.MouseLeave=[]()
    {
        a.setText("exit");
    };

    return MessageLoop(a);
}

i need 1 advice, please :(
how can i, automatic, call the create event in a diferent way?(for be called, without use a construtor)
if these question is confused, please tell me

i did these way:

static LRESULT CALLBACK WndProcForm(HWND HandleWindow, UINT msg, WPARAM wParam, LPARAM lParam)
        {
            static POINT PreviousLocation, Location;
            static bool Tracking = false;
            static MouseButtons MBButtons;
            static bool blControl = false;
            static bool blShift = false;
            static bool blResize = false;
            static int xPos = 0;
            static int yPos = 0;
            static UINT_PTR timerid;
            static bool blnDrag = false;
            form *inst = (form *)GetWindowLongPtr(HandleWindow, GWLP_USERDATA);

            if(inst!=NULL && inst->Create!=NULL)
            {
                 inst->Create(inst->intLeft, inst->intTop);
                 inst->Create=NULL;
            }

            //..................

but what you can tell me?

Beware of my complicated suggestion below.. but it is a good way to do it in my opinion:

Create event listeners..

The way it works it that you can subscribe to an event and unsubscribe. For implementation, you can call "Notify" and it will call the right function for you.

An example for the MouseListener would be:

class MouseListener : public IEventListener
{
    public:
        MouseListener();
        virtual ~MouseListener() {}

        //When the mouse moves, this function is called.
        virtual void mouseMoved(Component *source, KEY_MODIFIERS modifier, MOUSE_BUTTON id, int X, int Y) {}

        //When the mouse is pressed, this function is called.
        virtual void mousePressed(Component *source, KEY_MODIFIERS modifier, MOUSE_BUTTON id, int X, int Y) {}

        //When the mouse is released, this function is called.
        virtual void mouseReleased(Component *source, KEY_MODIFIERS modifier, MOUSE_BUTTON id, int X, int Y) {}

        //When the mouse is clicked, this function is called.
        virtual void mouseClicked(Component *source, KEY_MODIFIERS modifier, MOUSE_BUTTON id, int X, int Y) {}

        //When the mouse enters a component, this function is called.
        virtual void mouseEntered(Component *source, KEY_MODIFIERS modifier, MOUSE_BUTTON id, int X, int Y) {}

        //When the mouse exits a component, this function is called.
        virtual void mouseExited(Component *source, KEY_MODIFIERS modifier, MOUSE_BUTTON id, int X, int Y) {}
};

And then in the form class I did:

LRESULT Form::WinProc(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch(Msg)
    {
        case WM_MOUSEMOVE:
        {
            GetKeyMouseInfo(wParam, mouse, key);

            for (MouseListener* listener : mouse_listeners)
            {
                listener->notify(MOUSE_EVENTS::MOVED, NULL, key, mouse, mouse_x, mouse_y);
            }

            if (!Tracking)
            {
                Tracking = true;
                TrackMouse(Hwnd, 150);
            }
        }
        break;

        case WM_MOUSEHOVER:
        {
            GetKeyMouseInfo(wParam, mouse, key);

            for (MouseListener* listener : mouse_listeners)
            {
                listener->notify(MOUSE_EVENTS::ENTERED, NULL, key, mouse, mouse_x, mouse_y);
            }
        }
        break;

        case WM_MOUSELEAVE:
        {
            Tracking = false;

            for (MouseListener* listener : mouse_listeners)
            {
                listener->notify(MOUSE_EVENTS::EXITED, NULL, KEY_MODIFIERS::NONE, MOUSE_BUTTON::NONE, 0, 0);
            }
        }
        break;

        case WM_LBUTTONDOWN:
        case WM_RBUTTONDOWN:
        case WM_MBUTTONDOWN:
        {
            GetKeyMouseInfo(wParam, mouse, key);

            for (MouseListener* listener : mouse_listeners)
            {
                listener->notify(MOUSE_EVENTS::PRESSED, NULL, key, mouse, mouse_x, mouse_y);
            }
        }
        break;

        case WM_LBUTTONUP:
        case WM_RBUTTONUP:
        case WM_MBUTTONUP:
        {
            GetKeyMouseInfo(wParam, mouse, key);

            for (MouseListener* listener : mouse_listeners)
            {
                listener->notify(MOUSE_EVENTS::RELEASED, NULL, key, mouse, mouse_x, mouse_y);
            }
        }
        break;
    }
}

void Form::GetKeyMouseInfo(WPARAM wParam, MOUSE_BUTTON &mouse_event, KEY_MODIFIERS &key_event)
{
    key_event = KEY_MODIFIERS::NONE;
    mouse_event = MOUSE_BUTTON::NONE;

    if (wParam & MK_CONTROL) key_event |= KEY_MODIFIERS::CONTROL;
    if (wParam & MK_SHIFT) key_event |= KEY_MODIFIERS::SHIFT;

    if (wParam & MK_LBUTTON) mouse_event |= MOUSE_BUTTON::LEFT;
    if (wParam & MK_RBUTTON) mouse_event |= MOUSE_BUTTON::RIGHT;
    if (wParam & MK_MBUTTON) mouse_event |= MOUSE_BUTTON::MIDDLE;
}

In the form class it has a vector like this:

std::vector<MouseListener*> mouse_listeners;

Whenever an event occurs in the WNDProc, you just iterate the listeners and call "Notify".

Whenever you want to override a listener you do:

class MyCustomListener : MouseListener
{
    public:
       virtual void mousePressed(.......)
       {
           MessageBox(NULL, "Mouse was pressed", "", 0);
       }

       virtual void mouseReleased(.......)
       {
           MessageBox(NULL, "Mouse was Released", "", 0);
       }

       //you don't have to override all.. Just override the ones you want..
};


int main()
{
    Form f;
    MyCustomListener m;
    f.AddListener(&m());

    return f.show();
}

true.. it's more complex, but i get the point ;)
i have several more errors on my class, but i can fix them easely(you fix the master error) ;)
i'm thinking, for more late, joing\combining the form with MDI and ChildMDI... why? because is more easy to use after that for MDI programs ;)
do you like the way i do the code? at least, using my code, it avoids hundreds of lines ;)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.