如何使用DialogBoxParam

How to use DialogBoxParam?

本文关键字:DialogBoxParam 何使用      更新时间:2023-10-16

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

您已将此问题标记为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,它在对话框创建后立即发送,因此是初始化对话框上任何控件的理想时间-填充下拉控件,或者SetWindowText初始化具有默认值的文本框。和WM_COMMAND,它是由按钮等控件发送的,当它们被点击时,会传递它们的id,这就是处理OK和CANCEL按钮的地方。

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

问题第二部分的另一个用例:"在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;
    }
};

备选方案将调用方放在全局范围内,并限制为所有对话框的单个调用方。

您可以这样做。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) 
{
}