c++ - 作为类的成员函数的对话框窗口过程
问题描述
基于这篇文章,我正在尝试创建一个简单的 Win32 应用程序,其中对话框窗口的窗口过程/回调函数是类的成员函数。我的代码如下所示:
H 文件:
class MyClass
{
public:
HINSTANCE hInstance;
HWND hWnd;
int APIENTRY WinMainProc(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
static LRESULT CALLBACK WinProcWraper(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK WinProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
ATOM MyClassRegisterClass(HINSTANCE hInstance);
};
CPP 文件:
LRESULT CALLBACK MyClass::WinProcWraper(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
if (WM_NCCREATE == message)
{
SetWindowLong (hWnd, GWL_USERDATA, (long)((CREATESTRUCT*) lParam)->lpCreateParams);
return TRUE;
}
return ((MyClass*) GetWindowLong (hWnd, GWL_USERDATA))->WinProc (hWnd, message, wParam, lParam);
}
int APIENTRY MyClass::WinMainProc(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
MyClass.hInstance=hInstance;
MyClass.MyClassRegisterClass(hInstance);
//MY PROBLEM IS HERE: cannot convert parameter 4 to int
HWND hWnd = CreateDialog(hInstance,MAKEINTRESOURCE(IDD_MAIN_DIALOG), 0, (DLGPROC)MyClass::WinProc);
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsWindow(hWnd) || !IsDialogMessage(hWnd,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK MyClass::WinProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
(...)
}
调用时CreateDialog()
,我收到以下错误:
cannot convert from 'long (__stdcall MyClass::*)(struct HWND__ *,unsigned int,unsigned int,long)'
to 'long (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long)'
在这种情况下如何进行正确的类型转换?
解决方案
让我们从错误消息开始。您正在尝试使用非静态类方法WinProc()
, 作为您的CreateDialog()
回调。那不管用。您遇到了实现static
类方法的麻烦,该方法WinProcWraper()
调用WinProc()
,但您实际上并没有使用它。您需要将WinProcWraper()
其用作CreateDialog()
.
此外,如果它的签名以正确的开头(你的签名不是),则WinProcWraper
在将其传递给时无需进行类型转换。CreateDialog()
修复后,您还有其他问题:
您正在建模的其他代码是为 的窗口过程设计的
CreateWindow/Ex()
,但您正在使用CreateDialog()
它,它有不同的要求。由于您使用的是
CreateDialog()
代替CreateWindow/Ex()
,WinProcWraper()
并且WinProc()
需要返回 aBOOL
而不是LRESULT
。如果需要将实际LRESULT
值返回给系统,WinProc()
则需要SetWindowLong(DWL_MSGRESULT)
用于该目的。WinProcWraper()
期望收到一条WM_NCCREATE
消息,向其传递一个MyClass*
指针,然后将其分配给HWND
. 但是,由于您使用的是CreateDialog()
,WinProcWraper()
不会收到任何WM_(NC)CREATE
消息,而是会收到一条WM_INITDIALOG
消息。即使这样,CreateDialog()
也不允许您将任何用户定义的值传递给窗口过程,因此您无法传入需要的MyClass*
指针WinProcWraper()
。你需要使用CreateDialogParam()
它。WM_INITDIALOG
可能不是窗口接收到的第一条消息,只是可以让您访问MyClass*
传递给的指针的第一条消息CreateDialogParam()
。 需要处理它在接收到对指针WinProcWraper()
的访问之前可以接收消息的可能性。MyClass*
您正在使用
SetWindowLong()
. 如果您的代码曾经编译为 64 位,您的代码将无法工作。改为使用SetWindowLongPtr()
,即使是 32 位代码。
话虽如此,试试这个:
class MyClass
{
public:
HINSTANCE hInstance;
HWND hWnd;
int APIENTRY WinMainProc(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
BOOL CALLBACK WinProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
ATOM MyClassRegisterClass(HINSTANCE hInstance);
private:
static BOOL CALLBACK WinProcWraper(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};
BOOL CALLBACK MyClass::WinProcWraper(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
MyClass *cls;
if (WM_INITDIALOG == uMsg)
{
cls = reinterpret_cast<MyClass*>(lParam);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(cls));
}
else
cls = reinterpret_cast<MyClass*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
if (cls)
return cls->WinProc(uMsg, wParam, lParam);
return FALSE;
}
int APIENTRY MyClass::WinMainProc(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
MyClass.hInstance = hInstance;
MyClass.MyClassRegisterClass(hInstance);
HWND hWnd = CreateDialogParam(hInstance, MAKEINTRESOURCE(IDD_MAIN_DIALOG), NULL, MyClass::WinProcWraper, reinterpret_cast<LPARAM>(this));
if (!hWnd)
return -1;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsWindow(hWnd) || !IsDialogMessage(hWnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return static_cast<int>(msg.wParam);
}
BOOL CALLBACK MyClass::WinProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
...
if (needed)
SetWindowLongPtr(hWnd, DWLP_MSGRESULT, ...);
return ...; // TRUE or FALSE as needed...
}
推荐阅读
- sql - SQL - 从错误的名字/姓氏中清除数据库
- python - 如何根据熊猫的时差为用户设置会话
- oracle - 如何将 Grails 与 oracle db 连接起来?
- kotlinx.coroutines - kotlin 协程 - 什么是默认范围?
- r - 从多个 txt 文件创建语料库
- node.js - node.js 11.1.0 上的 sqlite3 无法打开数据库
- python - 在python中使用正则表达式提取日期
- c++ - 如何将文件中的数据输入到C++中的矩阵中?
- javascript - 你将如何计算这个函数的空间复杂度?
- svg - VS Code 扩展中的 SVG 工具栏图标