如何使用DialogBoxParam?

时间:2012-08-07 09:43:19

标签: c++ windows winapi dialog embedded-resource

我有一个预先制作的模板资源对话框,我想使用DialogBoxParam来显示它,但我在互联网上找不到任何好的例子。该对话框是一个简单的登录对话框,有人可以解释如何构建我的lpDialogFunc以及放入dwInitParam的内容吗?

3 个答案:

答案 0 :(得分:5)

您已将此问题标记为C ++,但未指定任何特定框架(例如ATL或MFC)。

所以,本着为问题提供c ++ / OOP答案的精神,不使用框架,首先要做的是创建一个包装对话框的类,并为对话框提供一种方法可靠地检索指向类的指针。 Windows API是一个C API,不能直接调用类成员,因此有必要创建静态方法,然后可以从某处检索类this指针。

class MyDialog {
  HWND _dlg;
public:
  int RunModal(HINSTANCE resModule, UINT resId,HWND parent){
    return DialogBoxParam(resModule,MAKEINTRESOURCE(resId),parent,&StaticDialogProc,(LPARAM)this);
  }
protected:
  static INT_PTR CALLBACK StaticDialogProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam){
    MyDialog* self;
    if(uMsg == WM_INITDIALOG){
      self = (MyDialog*)lParam;
      self->_dlg = hwndDlg;
      SetWindowLongPtr(hwndDlg,DWLP_USER,lParam);
    }
    else
      self = (MyDialog*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);

    if(self)
      return self->DialogProc(uMsg,wParam,lParam);

    return FALSE;
  }

  virtual UINT_PTR DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam){
    switch(uMsg){
    case WM_INITDIALOG:
      OnInitDialog();
      break;
    case WM_COMMAND:
      OnCommand(LOWORD(wParam),HIWORD(wParam),(HWND)lParam);
      break;
    default:
      return FALSE;
    }
    return TRUE;
  }

  virtual void OnInitDialog(){
  }
  virtual void OnCommand(int id, USHORT notifyCode,HWND control){
    EndDialog(_hdlg,id);
  }
};

现在,Windows可以向对话框发送数百个窗口消息。将每条消息的处理程序添加到DialogProc并调用特定的虚函数,以便派生类可以通过覆盖虚拟来以不同方式处理消息。

要处理的关键消息通常是WM_INITDIALOG,它会在创建对话框后立即发送,因此是初始化对话框上任何控件的理想时间 - 填充下拉控件或{{1}使用默认值启动文本框。 和WM_COMMAND,由按钮等控件发送,点击它们,传入它们的id,这就是你可以处理OK和CANCEL按钮的地方。

一旦DialogBoxParam返回,对话框及其所有子控件都已被销毁,因此您通常会在调用SetWindowText之前提取OnCommand处理程序中的所有输入字段并将它们存储在类成员中。

答案 1 :(得分:1)

问题第二部分的另一个用例:“dwInitParam中的内容”?

如果您更喜欢OO编程而不想使用对话框的全局范围,则可以将this传递给形式参数dwInitParam

获取指向来电者的指针

template< typename CallerT >
inline CallerT *GetDialogCaller(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {

    if (WM_INITDIALOG != uMsg) {
        // Retrieves information about the specified window.
        // 1. A handle to the window and, indirectly, the class to which the window belongs.
        // 2. Retrieves the user data associated with the window.
        return reinterpret_cast< CallerT * >(GetWindowLongPtr(hwndDlg, GWLP_USERDATA));
    }

    CallerT * const caller = reinterpret_cast< CallerT * >(lParam);

    // Changes an attribute of the specified window.
    // 1. A handle to the window and, indirectly, the class to which the window belongs.
    // 2. Sets the user data associated with the window.
    // 3. The replacement value.
    SetWindowLongPtr(hwndDlg, GWLP_USERDATA, reinterpret_cast< LONG_PTR >(caller));

    return caller;
}

将消息委派给来电者

class Widget {

public:

    static INT_PTR CALLBACK DialogProcDelegate(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {

        // Retrieve a pointer to the instance of Widget
        // that called DialogBoxParam.
        Widget * const widget = GetDialogCaller< Widget>(hwndDlg, uMsg, wParam, lParam);

        // Delegate the message handling.
        return widget->DialogProc(hwndDlg, uMsg, wParam, lParam);
    }

    INT_PTR Show() const {
        return DialogBoxParam(nullptr, MAKEINTRESOURCE(IDD_WIDGET_SETTINGS), nullptr, DialogProcDelegate, reinterpret_cast< LPARAM >(this));
    }

private:

    INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {

        // Note that this method is not affected by our approach,
        // i.e. this method will still receive a WM_INITDIALOG.
        switch (uMsg) {
            ...
        }

        return FALSE;
    }
};

替代方案将调用者置于全局范围内,并且仅限于所有对话框的单个调用者。

答案 2 :(得分:0)

你可以做这样的事。 dwInitParam指定要传递给WM_INITDIALOG消息的lParam参数中的对话框的值。您可以传递任何值或只是传递NULL

INT_PTR CALLBACK editDlg(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) {

        switch (msg) {
            case WM_INITDIALOG:                  
                return 1;
            break;
        }
        return 0;
    }

if(DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_EDIT),hwndMain,editDlg,NULL)==IDOK) 
{
}