• Advertisement
Sign in to follow this  

Pointer to member function

This topic is 3026 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Urgh! Im writing a general window class which goal is to hide the WIN32/WINAPI and at the same time offer OpenGL support for the window. So instead of creating a application full of WNDCLASSEX, HWND, HDC, HGLRC stuff, I made a cake and baked those things inside it. But as you know, all window handles need a window class, and this window class need a window procedure! Say that I want this procedure to be a member of my window class, like this (and alot more of course):
class Window
{
    private:

        ...
        static WNDCLASSEX m_wc;
        ...

    public:

        ...
        bool create(int, int);
        LRESULT CALLBACK wndProcedure(HWND, UINT, WPARAM, LPARAM);
        ...
};
Now in the 'Window::create' method, we specifies the WNDCLASSEX member:
        ...
        m_wc.lpfnWndProc = &Window::wndProcedure;
        ...
But this will produce the following error: window.cpp:13: error: cannot convert `LRESULT (Window::*)(HWND__*, UINT, WP ARAM, LPARAM)' to `LRESULT (*)(HWND__*, UINT, WPARAM, LPARAM)' in assignment How should I do to solve this???

Share this post


Link to post
Share on other sites
Advertisement
You can get around this by using a static member function, but then of course you are limited by only being able to create one object of that type.

Either that or come up with a mechanism for forwarding events to the right object.

It kind of seems like you'd only need one of those guys ever though if it contains your wndproc.

anyhow, make it static and it'll work (:

the reason why is because member functions secretly have a "this" parameter as the first parameter passed to the function.

That's why function pointers can't point at them so easily.

Static member functions don't take the "this" pointer though so work just fine.

Share this post


Link to post
Share on other sites
Actually, the situation becomes more complex when you say so. I do not want to have it static, this because of the following point:

If I do so, the WndProc will have no idea which Window we are operating on, so why would this be necessary? Well the Window class also have a pollEvents method, this takes care of user input, from mouse and keyboard. It gets all that information from the message queue of the HWND. But one message that does not get into that queue is WM_SIZE, but it does get into the WndProc.

Well we could solve it like this (from inside our static WndProc), we send a message with this information to the message queue:

...
case WM_SIZE:
PostMessage(hwnd, msg, wparam, lparam);
break;
...

Great! The only error is that our message queue gets totally screwed up, we need to directly examine the queue after sending this message, that is done by the pollEvents method, but wait we do not know about the Window because the WndProc is STATIC!!!!

Share this post


Link to post
Share on other sites
rip-off's second link shows you how to hook up a static WndProc to the member version WndProc.

As for your other problem, you should never need to call PeekMessage/GetMessage and pass in a hwnd filter (in fact, you should probably avoid filtering messages entirely because there are just too many special cases - any message that is sent to your window (as opposed to being posted) - WM_SIZE is one that you've already found, but there are many examples - will bypass your message queue and go straight to your WndProc).

As I mentioned, rip-off's second link shows you how to do what you want to do.

Share this post


Link to post
Share on other sites
Yep, thats what i was talking about too.

Why you need multiple windows btw?

Most applications have a single wndproc why is yours different?

Share this post


Link to post
Share on other sites
Yeah, I guess I will solve it with a static member that points to the created Window class and uses that one in the WndProc in order to run: "m_createdWindow -> pollEvents()"

Share this post


Link to post
Share on other sites
Quote:
Original post by rikardo
I solved it by using a reinterpret cast from hwnd to my Window class


That sounds suspiciously dangerous. Can you show us the code?

Share this post


Link to post
Share on other sites
I did like this, inside the window procedure, because the windows message queue does not get any WM_SIZE message specificly.

case WM_SIZE:
PostMessage(p_hwnd, p_msg, p_wparam, p_lparam);
reinterpret_cast< Window* > (&hwnd) -> pollEvents();
break;

And pollEvents then examines the message queue for the window handle that is inside my Window class.

Share this post


Link to post
Share on other sites
Remember what reinterpret_cast<SomeType *> means. It means "quiet compiler, I know what I'm doing here. Treat this block of bits like a pointer to SomeType".

My question is, do you know what you are doing here? The HWND passed to a WNDPROC is almost certainly not a pointer to a Window, let alone the address of that variable.

Share this post


Link to post
Share on other sites
Quote:
Original post by rikardo
I did like this, inside the window procedure, because the windows message queue does not get any WM_SIZE message specificly.

case WM_SIZE:
PostMessage(p_hwnd, p_msg, p_wparam, p_lparam);
reinterpret_cast< Window* > (&hwnd) -> pollEvents();
break;

And pollEvents then examines the message queue for the window handle that is inside my Window class.
That'll crash the first time you try to access a member variable of your Window class. After all, which instance of Window do you think that's casting to?

I don't think you've read rip-off's second like I said, so I'll link to it again: read this to understand how to make it work.

If there's something in that link that you don't understand, come back here with your question, but don't just keep trying random things until it compiles...

Share this post


Link to post
Share on other sites
Ok, so its of no help that HWND actually is a pointer? And the Windows class wraps around just that address?

Share this post


Link to post
Share on other sites
No. HWND is an opaque window handle. If it uses a pointer internally, that's not for you to know or use.

Really, if you're not using the GWL_USERDATA field of your window's associated data to hold your wrapper class instance, You're Doing It Wrong. Have you read that article yet? :)

Share this post


Link to post
Share on other sites
Yeah I have, but this is the single row of code I need exactly that this works. And yes the router is the correct solution.

Share this post


Link to post
Share on other sites
What makes you think reinterpret_casting a HWND to a Window * will work/is working? The value of the HWND is specified by Windows.

Share this post


Link to post
Share on other sites
I think so since my Window class wraps the HWND, I just thought that the compiler would somehow find the correct window class since they share memory.

Share this post


Link to post
Share on other sites
How does it wrap it? If you mean you have a HWND member in Window, that doesn't count.

For casting to work, you'd have to have a valid Window instance allocated in memory at whatever the value of the HWND is. This is basically impossible, since Windows is going to give you whatever value it feels like, whether a small integer, or a full 32-bit width one. Treating the value as a memory location isn't going to work.

Have you actually tried stepping over the reinterpret_cast< Window* > (&hwnd) -> pollEvents(); call in a debugger? What is the value of this in pollEvents? Is it the correct, valid Window instance?

Share this post


Link to post
Share on other sites
Yes it is a member of the class.

Maybe Im lucky then? Because what I do is first is sending a WM_SIZE message and the related information to the queue of the HWND. And after that I make the cast and call pollEvents.

Now, pollEvents examines the message queue of the hwnd and it updates other members in the Window class correctly...

Share this post


Link to post
Share on other sites
Unless I'm missing something, you would have to be extremely lucky :/

Are you sure this is valid in pollEvents? You could be 'setting members' into some invalid memory that's not really a Window *.

What is the value of the HWND in a debugger?

Share this post


Link to post
Share on other sites
I should examine it more closely and do some debugging so you can get further information about how wrong/right it really have went out for this code.

But if the this pointer would be invalid, how can it affect more then one member correctly that is related to it in that context?

Share this post


Link to post
Share on other sites
As luck would have it, there's a reasonable chance that this will work if the pollEvents function does not touch any member variables:
reinterpret_cast< Window* > (&hwnd) -> pollEvents();
The reason is that most compilers implement this as if it were syntactic sugar for the equivalent function prototype in C:
void pollEvents(Window *this);
It is very non-kosher though as compilers may do things differently, and it's not legal to do this according to the C++ standard.

The good news is that if your pollEvents function doesn't touch any member variables (which is highly likely since it would otherwise most likely crash) then all you need to do is declare it as a static method, which you can then call without an instance.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement