Search code examples
c++winapi

Cannot compile when I pass a member function to winapi's callback


I have a Windows class as follows:

struct PlatformState
{
    HINSTANCE hInstance;
    HWND WindowHandle;
};

class Win32Platform
{
public:
    Win32Platform(const char* app_name, uint32 startX, uint32 startY, uint32 width, uint32 height);
    ~Win32Platform();
private:
    PlatformState* PlatState;
    const char* AppName;
    uint32 StartPosX;
    uint32 StartPosY;
    uint32 Width;
    uint32 Height;
    LRESULT CALLBACK Win32ProcessMessage(HWND window_handle, uint32 msg, WPARAM w_param, LPARAM l_param);    
};

When I am trying to create a constructor like this:

Win32Platform::Win32Platform(const char* app_name, uint32 startX, uint32 startY
    , uint32 width, uint32 height)

    : AppName(app_name), StartPosX(startX), StartPosY(startY), Width(width), Height(height)
{
    PlatState = nullptr;
    PlatState = (PlatformState *)malloc(sizeof(PlatformState));
    
    PlatState->hInstance = GetModuleHandleA(0);

    //Setup and Register Window Class
    HICON icon = LoadIcon(PlatState->hInstance, IDI_APPLICATION);
    WNDCLASSA WinClass;
    WinClass.style = CS_DBLCLKS;
    WinClass.lpfnWndProc = this->Win32ProcessMessage;    
}

The driver code is basically:

Win32Platform window{"New", 100, 200, 1280, 720};

The get the error message

a pointer to a bound function may only be used to call the function

I need the function Win32ProcessMessage as a member function because I need it to access certain class instance variables. I tried it with and without this.

How can I fix this?


Solution

  • You can't use a non-static class method as a Win32 WndProc callback, as the method has a hidden this parameter which the API can't pass anything into.

    To remove the this parameter, you need to instead use a static class method, or a standalone function.

    Then, you can use the lpParam parameter of CreateWindow/Ex() to pass your object's this pointer into your callback. You can handle the WM_(NC)CREATE message to receive the pointer, and then store it into the created HWND via SetWindowLongPtr() or SetProp(). In subsequent messages, you can then retrieve the pointer from the HWND to access the object as needed.

    For example:

    class Win32Platform
    {
        ...
    protected:
        ...
        LRESULT ProcessMessage(uint32 msg, WPARAM w_param, LPARAM l_param);    
        ...
    private:
        ...
        static LRESULT CALLBACK Win32ProcessMessage(HWND window_handle, uint32 msg, WPARAM w_param, LPARAM l_param);    
        ...
    };
    
    WinClass.lpfnWndProc = &Win32Platform::Win32ProcessMessage;    
    ...
    CreateWindowEx(..., WinClass.lpszClassName, ..., this);
    
    static LRESULT CALLBACK Win32Platform::Win32ProcessMessage(HWND window_handle, uint32 msg, WPARAM w_param, LPARAM l_param)
    {
        Win32Platform *plat;
        if (msg == WM_NCCREATE) {
            plat = (Win32Platform*) ((CREATESTRUCT*)l_Param)->lpCreateParams;
            SetWindowLongPtr(window_handle, GWL_USERDATA, plat);
        }
        else {
            plat = (Win32Platform*) GetWindowLongPtr(window_handle, GWL_USERDATA);
        }
    
        if (plat)
            return plat->ProcessMessage(msg, w_param, l_Param);
    
        return DefWindowProc(window_handle, msg, w_param, l_param);
    }
    
    LRESULT Win32Platform::ProcessMessage(uint32 msg, WPARAM w_param, LPARAM l_param)
    {
        ...
    }