Window class procedure pointer?

SephirothSephiroth Fayetteville, NC, USA
Alright, I have all of my newer programs running in classes using C++, with the exception of the main loop and all the functions for my windows. However, I am now developing my own window class that will be VERY easy to use with both plain old Windows and OpenGL. My problem however, is that I am not sure how to point the window-class to the procedure within the class. Some code may explain this more clearly.
[code]
//The window procedure for the "Window" class
LRESULT CALLBACK Window::HandleMessage(HWND hwndWindow, UINT uiMessage, WPARAM wpCode, LPARAM lpCode)
{
return DefWindowProc(hwndWindow, uiMessage, wpCode, lpCode);
}

//The method that registers the class
bool Window::RegisterSelf()
{
WNDCLASSEX wcStyle;

if(this->pClassName[0] == '')
return false;

memset(&wcStyle, 0, sizeof(WNDCLASSEX));
wcStyle.cbSize = sizeof(WNDCLASSEX);
wcStyle.style = CS_HREDRAW | CS_VREDRAW;
wcStyle.lpfnWndProc = (WNDPROC)&Window::HandleMessage;
wcStyle.cbClsExtra = 0;
wcStyle.cbWndExtra = 0;
wcStyle.hInstance = this->hInstance;
wcStyle.hIcon = LoadIcon(NULL, IDI_INFORMATION);
wcStyle.hCursor = LoadCursor(NULL, IDC_ARROW);
wcStyle.hbrBackground = (HBRUSH)(COLOR_WINDOW);
wcStyle.lpszMenuName = NULL;
wcStyle.lpszClassName = pClassName;
wcStyle.hIconSm = LoadIcon(NULL, IDI_INFORMATION);

//Attempt to register the class
if(RegisterClassEx(&wcStyle) == 0)
{
UnregisterClass(pClassName, this->hInstance);
return false;
}

return true;
}
[/code]
The line that reads "wcStyle.lpfnWndProc = (WNDPROC)&Window::HandleMessage;" is failing to compile. I have tried other methods as well, such as "Window::HandleMessage", "this->HandleMessage", and more, but none seem to work. How would I reference the procedure in each instance of the window in a unique manner? For instance, if I have five windows, I would wants each window to use the procedure within itself, not one of the other windows.

-[italic][b][red]S[/red][purple]e[/purple][blue]p[/blue][green]h[/green][red]i[/red][purple]r[/purple][blue]o[/blue][green]t[/green][red]h[/red][/b][/italic]

Comments

  • Is [b]Window::HandleMessage[/b] declared [b]static[/b]?
    If not, thats probably the problem.
    [hr][size=1][leftbr].:EvolutionEngine[rightbr][leftbr].:MicroOS Operating System[rightbr][leftbr][link=http://www.mt2002.sitesled.com]Website[rightbr][/link][/size]
  • SephirothSephiroth Fayetteville, NC, USA
    : Is [b]Window::HandleMessage[/b] declared [b]static[/b]?
    : If not, thats probably the problem.
    Just tried that suggestion, and it isn't the problem. For some reason I get the following error since I am referencing a method within a class instead of a function in a plain old C file.
    [code]
    1>.Class-Window.cpp(52) : error C2440: 'type cast' : cannot convert from 'LRESULT (__stdcall Window::* )(HWND,UINT,WPARAM,LPARAM)' to 'WNDPROC'
    1> There is no context in which this conversion is possible
    [/code]
    This is the ONLY warning/error my library generates, and if I comment this method and the line in the WNDCLASSEX setup, it compiles with no warnings or errors, which means it is something with making the compiler recognize that this is the same function I have used, only now it is a method inside the class.

    *UPDATE*

    I had to do a clean, wait several minutes (Windows was building before the OS deleted the old object files when I used the rebuild option), and the static declaration worked. The library compiled with no errors or warnings. However, I then created a simple file with a WinMain() to test my new class and I get an unresolved external for the window procedure.
    [code]
    1>Linking...
    1>shared.lib(Class-Window.obj) : error LNK2019: unresolved external symbol "protected: static long __stdcall Window::HandleMessage(struct HWND__ *,unsigned int,unsigned int,long)" ([email protected]@@[email protected]@[email protected]) referenced in function "public: bool __thiscall Window::Register(struct tagWNDCLASSEXA *)" ([email protected]@@Z)
    [/code]
    Any ideas why it's throwing this error after the library compiled properly but an app attempts to link with the library?
    -[italic][b][red]S[/red][purple]e[/purple][blue]p[/blue][green]h[/green][red]i[/red][purple]r[/purple][blue]o[/blue][green]t[/green][red]h[/red][/b][/italic]
  • [code]
    : LRESULT CALLBACK Window::HandleMessage(HWND hwndWindow, UINT uiMessage, WPARAM wpCode, LPARAM lpCode)
    : {
    : return DefWindowProc(hwndWindow, uiMessage, wpCode, lpCode);
    : }
    :
    : //The method that registers the class
    : bool Window::RegisterSelf()
    : {
    : wcStyle.lpfnWndProc = (WNDPROC)&Window::HandleMessage;
    : }
    : [/code]:

    The problem is clear: you cannot cast a member function (Window::HandleMessage) to an ordinary WNDPROC (::HandleMessage) !

    This is because, when you set a pointer to a function, all information is there, as a function is unique. When you set a pointer to a method, you also need to supply the class whose method is to be called.

    Below is the somewhat difficult syntax.

    [code]
    #include

    struct Test
    {
    int A() const { return 1; }
    int B() const { return 2; }
    };

    int main()
    {
    typedef int (Test::* TestMemFun)();
    Test t;

    TestMemFun myFun = &Test::A;
    assert((t.*myFun)() == 1);
    myFun = &Test::B;
    assert((t.*myFun)() == 2);
    }
    [/code]

    Good luck creating a workaround!
    See ya,



    bilderbikkel
  • [color=Blue]
    Here is how it may be done (method I use in my C++ class library):

    1. You need just one procedure for ALL generic windows in the system and this procedure is not a class method, but normal Win32 function (like daddy Petzold describes in his books :-) )
    [/color]

    [code]
    LRESULT CALLBACK MyGenericWndProc (HWND h, UINT msg, WPARAM wp, LPARAM lp)
    {
    // ... see below ...
    }
    [/code]

    [color=Blue]
    2. Your library must have a base class for all windows. And this base class must have some virtual functions defined. For example:
    [/color]

    [code]
    LRESULT YourBaseClass::MsgMap (UINT msg, WPARAM wp, LPARAM lp)
    {
    }

    PTCHAR YourBaseClass::MyClassName ()
    {
    return _T ("... unique name for each class...");
    }

    VOID YourBaseClass::FillRegistration (WNDCLASS& wc)
    {
    // Fill up all the members of the structure
    //
    wc. = ;
    wc. = ;
    wc. = ;

    //...
    }

    BOOL YourBaseClass::WmCreate (HWND h)
    {
    return TRUE;
    }
    [/code]

    [color=Blue]
    Now: how to connect every created HWND with the pointer of the class, which created it? Simply pass it as a last parameter to CreateWindowEx(). The call to create a window should be done in a method of the base class, so all derived classes can create themselves just by calling it:
    [/color]

    [code]
    BOOL YourBaseClass::CreateEx (...put some values here for CreateWindowEx()...)
    {
    // Find out if this class has been registered already
    //
    WNDCLASS wc;

    if (! GetClassInfo (hInstance, [b]MyClassName ()[/b], &wc))
    {
    // Not registered yet. Fill up the WNDCLASS structure and
    // ask Windows to register that class name
    //
    [b]FillRegistration (wc)[/b];
    RegisterClass (&wc);
    }

    // At this point the class name is ready for creation of HWND!
    //
    HWND hWnd = CreateWindowEx (... [b]MyClassName ()[/b], ...
    hInstance, [italic]this[/italic]);

    return (hWnd != NULL);

    // Notice the methods in BOLD - they are virtual, which provides
    // for the different behaviour of the same code. Also, notice how
    // 'this' is passed as the last parameter. That pointer will be
    // passed to you by Windows through WM_CREATE message - read MSDN
    // for this.
    }
    [/code]

    [color=Blue]I wish I had some more time to write more. I gotta run to work. Send me something at [email protected] - I will send back the working example of a base window class for C++ library.[/color]
  • I hope this website may help you solve the problem you are having right now.
    This is where i learnt win32 Object Oriented Programming.It can be a very good start for you.
    Please make sure you read line per line if you wish to understand all up
    till the end.
    http://www.relisoft.com/win32/index.htm
  • SephirothSephiroth Fayetteville, NC, USA
    Thanks for the replies, but I created my own solution at around 3AM today. It's the way Windows deals with those functions that was the problem, but I got around it by using two procedures per class. One is a "dummy" procedure that stores the object data using "SetWindowLong()" and then when a message is passed to the window it is actually relayed t the real procedure after getting the object data using "GetWindowLong()". Compiles and works fine now, with no warnings or errors, and is VERY simple to use.

    -[italic][b][red]S[/red][purple]e[/purple][blue]p[/blue][green]h[/green][red]i[/red][purple]r[/purple][blue]o[/blue][green]t[/green][red]h[/red][/b][/italic]
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories