使用类成员作为WNDPROC / DLGPROC,有或没有全局

时间:2012-09-25 11:59:12

标签: c++ winapi callback wrapper wndproc

我将继续对此进行总结,如何使用作为类成员的对话程序?我正在创建一个窗口包装类,但是CreateDialogParam需要一个全局对话框程序,所以我尝试了这个解决方法:

我已经对这个话题进行了一些搜索。我正在创建一个Dialog类,我将其子类化为CMainWnd,然后实例化它。在Dialog类中,我有一个定义为INT_PTR CALLBACK Dialog::cb_proc(HWND,UINT,WPARAM,LPARAM)的成员函数。现在,我知道windows必须具有全局函数作为回调过程。

所以我创建了一个std::map<HWND,Dialog*> DlgProcs映射来将对话框窗口句柄与其Dialog类指针相关联。

INT_PTR CALLBACK DlgMainProc(HWND,UINT,WPARAM,LPARAM)我可以将其传递给CreateDialogParam()。在DlgMainProc(...)正文中,我搜索地图以使用hWnd参数查找Dialog*并返回其cb_proc(..)成员。

我的问题是没有处理任何消息,这是因为我的Dialog类中的成员过程永远不会被调用。即使当我在MessageBox()语句中放置DlgMainProc时,也会一遍又一遍地显示消息框,直到我不得不从Visual Studio 2008中止该程序。这告诉我它正在我的地图中找到if (DlgProcs.find(hWnd) != DlgProcs.end()) {。奇怪的是,如果我把它放在hWnd语句之后也会这样做,这反过来告诉我它没有在地图中找到else

如果我在hWnd成员函数中放置了一个消息框,则根本不会显示它。但在此期间,我从未得到任何编译器,链接器或运行时错误。当我从中删除消息框(因为不必中止程序,它只是为了调试目的)程序运行但没有消息得到处理,X按钮不关闭程序,按钮点击什么都不做。


以下是PasteBin代码:http://pastebin.com/GsGUBpZU 顺便说一句,我没有问题继承这个,我的窗口创建得很好,只是没有处理任何消息,cb_proc永远不会被调用。

编辑:以下是代码的相关部分

cb_proc

有人知道为什么它永远不会被召唤?或者只是引导我使用成员函数作为DLGPROC的另一种方式?

3 个答案:

答案 0 :(得分:3)

标准解决方案是将您的this指针作为最后一个参数传递给Create,DialogParam,将其存储在DWLP_USER处理程序的WM_INITDIALOG中,并从{{{{}}中检索它之后1}}。基本上你使用DWLP_USER作为地图。

答案 1 :(得分:2)

我尝试了你的代码并且它有效:cb_proc被调用。您将错过在WM_INITDIALOG返回之前发送的所有邮件(例如CreateDialogParam)。

您可以通过在g_MainDlgProc中将窗口句柄和对象添加到地图来解决后一个问题。如果您收到未知窗口的消息,则表示它属于您正在创建的窗口;将对象放在全局中,您可以将句柄/对象添加到地图中。

答案 2 :(得分:0)

我只是在这里添加它,以防有人发现它有用;使用C ++ 11 lambda和模板的魔力,你可以有一个简单的包装模板,这意味着你不必不断重写样板代码,以便在窗口和对话框程序中保存和加载用户数据。

以下是DialogBoxParam函数的示例,但同样的技术也适用于CreateDialogParamCreateWindowEx

template <typename T, INT_PTR (T::*P)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)>
INT_PTR DialogBoxThis(T* pThis, HINSTANCE hInstance, LPCWSTR lpTemplateName, HWND hWndParent)
{
    return ::DialogBoxParam(hInstance, lpTemplateName, hWndParent, [](HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -> INT_PTR {
        if (uMsg == WM_INITDIALOG) SetWindowLongPtr(hWnd, DWLP_USER, lParam);
        T* pThis = reinterpret_cast<T*>(GetWindowLongPtr(hWnd, DWLP_USER));
        return pThis ? (pThis->*P)(hWnd, uMsg, wParam, lParam) : FALSE;
    }, reinterpret_cast<LPARAM>(pThis));
}

您可以这样使用它:

class MyClass
{
    INT_PTR MyDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};

// from inside MyClass, we can show a dialog that uses member function MyDlgProc as the dialog procedure
// note it is NOT a static function

DialogBoxThis<MyClass, &MyClass::MyDlgProc>(this, hInstance,
    MAKEINTRESOURCE(IDD_MYDIALOG), hWndParent);