0

This is a continuation from this question.

I have the following assignment:

WNDCLASSEX wndClass =
{
    sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0, 0,
    GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
    "D3D Tutorial", NULL
};
wc = wndClass;

Which gives me the following error:

1>e:\rat_engine\rat_engine\rat_engine\rat_rendererdx9.cpp(19): error C2440: 'initializing' : cannot convert from 'overloaded-function' to 'WNDPROC'

1>None of the functions with this name in scope match the target type

With MsgProc underlined as the cause, it should reference the following function:

LRESULT WINAPI RAT_RendererDX9::MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
        case WM_DESTROY:
            CleanUp();
            PostQuitMessage( 0 );
            return 0;

        case WM_PAINT:
            Render();
            ValidateRect( hWnd, NULL );
            return 0;
    }

    return DefWindowProc( hWnd, msg, wParam, lParam );
}

In the tutorial it works like this and I have copied it almost exactly. So where does the error come from and how can I fix it?

edit:

The declaration of MsgProc is:

private:
    LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
Community
  • 1
  • 1
Friso
  • 2,328
  • 9
  • 36
  • 72

2 Answers2

3

From your declaration of MsgProc it seems that it's a regular member function, which means it takes a "hidden" this pointer. That makes it incompatible with WNDPROC and that's why the compiler complains.

Trying marking it as static. Of course, this means that you cannot access non-static members of the class easily - you will need to stash a copy of the this pointer of the instance you want somewhere to do that.

You may also need CALLBACK instead of WINAPI but I don't have easy access to a compiler to verify this at this time.

Nik Bougalis
  • 10,495
  • 1
  • 21
  • 37
  • It seems to me that I need a class to use my `CleanUp()` and `Render()` functions, but to use them in `MsgProc()` I'll need to make them static as well. Is there a way around this? – Friso Feb 06 '13 at 23:27
  • If you can "stash" a copy of the `this` pointer somewhere (perhaps in a map mapping an `HWND` to a `RAT_RendererDX9 *`?) then you can retrieve it and use it to call `CleanUp()` and `Render()` using the regular function-call syntax (i.e. `ptr->CleanUp()`) – Nik Bougalis Feb 06 '13 at 23:29
  • I can't seem to envision this. Could you give me a code example? – Friso Feb 06 '13 at 23:43
  • Without knowing more about your particular implementation, I cannot easily give you one. But the idea is to make it so your static window procedure can retrieve the `RAT_RendererDX9` with which a particular message is associated, then it can simply call the member functions on that instance. Do you foresee having multiple `RAT_RendererDX9` instances active at any one time? If not, then you could use a singleton (or make everything static... ick!). If yes, you'll need a more advanced technique. – Nik Bougalis Feb 06 '13 at 23:50
  • For now I'll probably only use one implementation of the Renderer, so I'll go with the singleton for now. – Friso Feb 06 '13 at 23:55
0

To me, it seems most elegant if you bind the instance/object of your class to the HWND. To set and retrieve the pointer to your instance, you can use SetWindowLongPtr/GetWindowLongPtr.

So after creating your window, you call

SetWindowLongPtr(hWnd, GWLP_USERDATA, static_cast<LONG_PTR>(this));

And in your WindowProcedure, you call

YourClass* instance = static_cast<YourClass*> (GetWindowLongPtr(hWnd, GWLP_USERDATA));

Be careful in the WindowProcedure: It already gets called when you create the window but obviously, you can only call SetWindowLongPtr afterwards. So, when your WindowProcedure gets called first, GetWindowLongPtr will fail. Make sure, that the function even works in these cases.

Binabik
  • 1,013
  • 11
  • 24