【问题标题】:Bind Dialog Procedure as method to custom class [duplicate]将对话框过程作为方法绑定到自定义类[重复]
【发布时间】:2015-07-19 18:46:48
【问题描述】:

我正在尝试使用 WINAPI 来实现作为自定义类成员的无模式对话框窗口的过程。我不确定这是否可能,但我希望有人知道一种方法。目标是拥有一个可以访问自定义类的成员变量的过程

我知道使用普通窗口是可能的。 示例

//MyClass.h
class MyClass
{
    public:
    bool init( ... )
    static LRESULT CALLBACK    redirect(HWND hWnd, UINT msg,
                                          LPARAM lParam, WPARAM wParam);
    LRESULT myWndProc(HWND hWnd, UINT msg,
                      LPARAM lParam, WPARAM wParam);

    private:
    HWND m_MainHwnd;
}

通过定义一个将指针重定向到非静态实际过程处理的静态成员函数,该过程可以是一个成员函数:

//MyClass.cpp
MyClass::init( ... )
{
    //Create the window class for the main Window//
    m_windowed = windowed;
    WNDCLASSEX wc;  //Create a new extended windows class

    wc.cbSize = sizeof(WNDCLASSEX); //Size of our windows class
    wc.style = CS_HREDRAW | CS_VREDRAW; //class styles
    wc.lpfnWndProc = MyClass::redirect; //Default windows procedure function
    wc.cbClsExtra = NULL;   //Extra bytes after our wc structure
    wc.cbWndExtra = NULL;   //Extra bytes after our windows instance
    wc.hInstance = hInstance;   //Instance to current application
    wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); //Title bar Icon
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);   //Default mouse Icon
    wc.hbrBackground = CreateSolidBrush(0xFFFFFF);  //Window bg color
    wc.lpszMenuName = NULL; //Name of the menu attached to our window
    wc.lpszClassName = m_windowName;    //Name of our windows class
    wc.hIconSm = LoadIcon(NULL, IDI_WINLOGO); //Icon in your taskbar

    if (!RegisterClassEx(&wc))  //Register our windows class
    {
        //if registration failed, display error
        MessageBox(NULL, "Error registering Main Window class",
            "Error", MB_OK | MB_ICONERROR);
        return false;
    }

    m_MainHwnd = CreateWindowEx(    //Create our Extended Window
        NULL,   //Extended style
        m_windowName,   //Name of our windows class
        m_windowName,   //Name in the title bar of our window
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,   //style of our window | Make it              visible on showWindow cmd
        30, 30, //Top left corner of window
        width,  //Width of our window
        height, //Height of our window
        NULL,   //Handle to parent window
        NULL,   //Handle to a Menu
        hInstance,  //Specifies instance of current program
        this    //used for an MDI client window
    );
}

查看 WNDCLASSEX 中设置中的行:wc.lpfnWndProc = MyClass::redirect;?这是有效的,因为重定向静态函数的实现如下:

MyClass::redirect(HWND hwnd, UINT msg, LPARAM lParam, WPARAM wParam)
{
    if (msg == WM_CREATE)  SetWindowLongPtr(hwnd, GWL_USERDATA, (LONG_PTR)((CREATESTRUCT FAR *)lParam)->lpCreateParams);
    MyClass * pObject = (MyClass*)((LONG_PTR)GetWindowLongPtr(hwnd, GWL_USERDATA));
    if (pObject) return pObject->MyWndProc(hwnd, msg, wParam, lParam);

    //return the message for windows to handle it
    return DefWindowProc(hwnd,
        msg,
        wParam,
        lParam);
};

这使您可以像任何其他成员方法一样实现 MyWndProc ( ... )。

现在!我真的希望能够对我的无模式对话框做同样的事情——因为它知道“MyClass”的成员变量是相当重要的。另外 - 我喜欢我可以设计它并按照我的喜好重新设计它(如果我必须使用普通窗口 - 用代码设计它会很乏味。)

有可能吗?

提前谢谢你!

【问题讨论】:

    标签: c++ winapi


    【解决方案1】:

    是的,可以在对话框中使用此方法,方式大致相同。

    您使用WM_INITDIALOG 而不是使用WM_CREATE 来存储this 指针。请注意,用户数据在lParam 本身中传递给WM_INITDIALOG - 没有像WM_CREATE 那样需要取消引用的结构。

    您可以将指针存储在DWLP_USER 中,这是对话框所有者可以使用的指针大小的窗口数据槽。

    最后的区别是如果尚未分配数据指针,则只需返回 FALSE - 您不会从对话过程中调用 DefWindowProc

    class MyClass
    {
    public:
            static INT_PTR CALLBACK dlgRedirect(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
            LRESULT myDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    }
    
    //...
    HWND hwndDlg = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MYDIALOG), hwndParent,
        MyClass::dlgRedirect, reinterpret_cast<LPARAM>(this));
    
    //...
    INT_PTR CALLBACK MyClass::dlgRedirect(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        if (uMsg == WM_INITDIALOG) SetWindowLongPtr(hWnd, DWLP_USER, lParam);
        MyClass* pThis = reinterpret_class<MyClass*>(GetWindowLongPtr(hWnd, DWLP_USER));
        if (pThis) return pThis->myDlgProc(hWnd, uMsg, wParam, lParam);
        return FALSE;
    }
    
    INT_PTR MyClass::myDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        // real dialog procedure here
    }
    

    【讨论】:

    • 非常感谢……这正是我要找的模组!请问您是否已经知道这一点,或者您有消息来源吗?只是出于好奇。
    • 你不知道我有多开心!我几乎放弃了!谢谢!
    • @Silverback 我认为这是一项众所周知的技术,我已经使用了多年。不记得我第一次在哪里捡到它。
    • 此技术在 SO 的其他部分得到了演示,例如 herehere
    • 好的 - 当然。谢谢你。我以前从未见过对话框的修复 - 但感谢您的帮助! @Raymon Chen - 谢谢陈先生 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-25
    • 2017-11-25
    • 1970-01-01
    • 2012-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多