Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Encapsulating WndProc message processing callback in a class

Posted on 2006-11-22
3
771 Views
Last Modified: 2008-02-01
Currently, i'm writing a class wrapper for the basic Win32 API functions that create windows, a menu, and a few controls. I know I could use MFC, but i'm learning much more doing it this way.

I'd like to include the standard message processing callback as a method in my window class, but haven't been able to get it to compile. A cut down version of what i'm talking about is here:

// class descriptor
class WindowsGui {
public:
    WindowsGui(HINSTANCE hInstance, int iCmdShow, const char* cClassName);
    virtual ~WindowsGui();

private:
    WNDCLASS _WndClass;
    LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
};

// Constructor
WindowsGui::WindowsGui(HINSTANCE hInstance, int iCmdShow, const char* cClassName)
{
    _WndClass.lpfnWndProc = WndProc;
}

// Callback method
LRESULT CALLBACK WindowsGui::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    return 0;
}

I've cut out all non-relevant parts. When I try to compile I get an error stating that the assignment to lpfnWndProc cannot complete as a type mismatch has occured between (LRESULT)(WindowsGui::*) and (LRESULT)(*). I've tried many different ways around this including different casts and using the 'this' operator, but I think my basic understanding of whats going on here is a little lacking.

Can anyone offer advice on what cast or fix can be applied either in the assignment of lpfnWndProc, or how I encapsulate the WndProc function into a method in my class?

Thanks for any advice
salukibob
0
Comment
Question by:salukibob
3 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 60 total points
ID: 17997450
The problem is that you can't use a non-static member function for a callback, since they're passed an invisible 'this' parameter so that the signatures won't match. The possible solutions are:

- use a static member
- use an adapter, see e.g. http://www.codeproject.com/win32/callback_adapter.asp ("Use member functions for C-style callbacks and threads - a general solution")
0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 65 total points
ID: 17997787
>>>> The problem is that you can't use a non-static member function for a callback  

jkr is right. Add the keyword static to the declaration of the member function

   static LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);

to get it compiled.

However, as the callback function now is a static function you need to retrieve somehow the instance of class WindowsGui, the hWnd was associated to. Normally, you would do such a thing by implementing a global map where hwnd is the key and the pointer to WindowsGui is the data. You also could do that by a little 'Manager' class:

class GuiManager
{
     std::map<HWND, WindowsGui*> hwndMap;
public:
     void register(HWND hwnd, WindowsGui* pWnd) { hwndMap[hwnd] = pWnd; }
     void unregister(HWND hwnd) { hwndMap.erase(hwnd); }
     WindowsGui* lookup(HWND hwnd)
     {
          map<HWND, WindowsGui*>::iterator it = hwndMap.find(hwnd);
          if (it != hwndMap.end())
                return it->second;
    }
    return NULL;
};

// the one and only GuiManager
extern  GuiManager theGuiManager;


// in windowsgui.cpp

#include "guimanager.h"

// the one and only GuiManager
GuiManager theGuiManager;      // needs to get defined in one cpp file (without extern keyword)

If doing so, you can retrieve the WindowsGui object in the callback function by

// Callback method
LRESULT CALLBACK WindowsGui::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    WindowsGui* pWnd = theGuiManager.lookup(hWnd);
   
    if (pWnd != NULL)
    {
           // we found the object!
           ...
    }
    return 0;
}


Regards, Alex
0
 

Author Comment

by:salukibob
ID: 17997998
Thanks for the advice. I see what you mean, and I can see now that I was missing the point that I will only want one message processing function, not one with each object created. Hence the static. Thanks also for the additional pointers.

Points split.

Regards
salukibob
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

829 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question