Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Encapsulating WndProc message processing callback in a class

Posted on 2006-11-22
3
Medium Priority
?
801 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
[X]
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
3 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 240 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 260 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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
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…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
Suggested Courses

705 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