首页 > 解决方案 > 作为类的成员函数的对话框窗口过程

问题描述

基于这篇文章,我正在尝试创建一个简单的 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)'

在这种情况下如何进行正确的类型转换?

标签: c++windowswinapivisual-c++

解决方案


让我们从错误消息开始。您正在尝试使用非静态类方法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...
}

推荐阅读