作为类的成员函数的对话框窗口过程



基于这篇文章,我试图创建一个简单的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()的实际窗口过程。

此外,在将其传递给CreateDialog()时,如果其签名一开始是正确的(您的签名不是),则无需键入强制转换WinProcWraper

修复后,你仍然有其他问题:

  • 您正在建模的其他代码是为CreateWindow/Ex()的窗口过程设计的,但您使用的是CreateDialog(),这有不同的要求。

  • 由于使用的是CreateDialog()而不是CreateWindow/Ex(),因此WinProcWraper()WinProc()需要返回BOOL而不是LRESULT。如果需要向系统返回实际的LRESULT值,则WinProc()需要为此使用SetWindowLong(DWL_MSGRESULT)

  • WinProcWraper()期望接收WM_NCCREATE消息以向其传递MyClass*指针,然后将其分配给HWND。但是,由于您使用的是CreateDialog()WinProcWraper()将不会收到任何WM_(NC)CREATE消息,而是会收到一条WM_INITDIALOG消息。即便如此,CreateDialog()也不允许将任何用户定义的值传递给窗口过程,因此无法传递WinProcWraper()所需的MyClass*指针。为此,您需要使用CreateDialogParam()

  • WM_INITDIALOG可能不是窗口收到的第一条消息,只是第一条可以让您访问传递给CreateDialogParam()MyClass*指针的消息。CCD_ 37需要处理它在接收到对CCD_ 38指针的访问之前可以接收消息的可能性。

  • 您正在使用SetWindowLong()。如果您的代码是为64位编译的,那么它将无法工作。即使对于32位代码,也应使用SetWindowLongPtr()

话虽如此,试试这个:

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...
}

最新更新