基于这篇文章,我试图创建一个简单的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...
}