Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a win32 API and giving a callback to a class function

Tags:

c++

winapi

I'm trying to clean up some existing win32 UI code by putting it into a class. Previously I had an AppDlgProc function like this:

BOOL CALLBACK AppDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { ... }

Which I used like so:

DialogBoxParam(hInstance, (LPCTSTR)IDD_SETTINGS, 0, AppDlgProc, 0);

Now I'm putting all this in a SettingsWindow object, and I call settingsWindow->show() which kicks off this:

void SettingsWindow::show(HINSTANCE hInstance) {
     DialogBoxParam(hInstance, (LPCTSTR)IDD_SETTINGS, 0, &SettingsWindow::AppDlgProc, 0);
}

I'm pretty sure I'm giving the callback method incorrectly here. Visual Studio tells me "Intellisense: Argument of type ... is incompatible with parameter of type DLGPROC". Googling seems to tell me seems to tell me I need another argument - is there no other way?

For reference, my AppDlgProc function now looks like this:

BOOL CALLBACK SettingsWindow::AppDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {  ... }
like image 890
Malcolm Crum Avatar asked Sep 05 '14 05:09

Malcolm Crum


1 Answers

Window and dialog procedures (and other Win32 callback functions) need to be static or global functions - they can't be non-static class functions. Win32 is fundamentally a C-based API and it has no concept of the hidden this pointer that class functions require.

The normal way to do this is to declare the function as static and store a pointer to the class instance in a window property. For example,

struct SettingsWindow
{
    // static wrapper that manages the "this" pointer
    static INT_PTR CALLBACK AppDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        if (uMsg == WM_INITDIALOG)
            SetProp(hWnd, L"my_class_data", (HANDLE)lParam);
        else
        if (uMsg == WM_NCDESTROY)
            RemoveProp(hWnd, L"my_class_data");

        SettingsWindow* pThis = (SettingsWindow*)GetProp(hWnd, L"my_class_data");
        return pThis ? pThis->AppDlgFunc(hWnd, uMsg, wParam, lParam) : FALSE;
    }

    INT_PTR AppDlgFunc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        // the real dialog procedure goes in here
    }
};


// to show the dialog - pass "this" as the dialog parameter
DialogBoxParam(hInstance, (LPCTSTR)IDD_SETTINGS, 0, SettingsWindow::AppDlgProc,
    (LPARAM)this);
like image 146
Jonathan Potter Avatar answered Nov 13 '22 19:11

Jonathan Potter