【问题标题】:C++/Win32 dialog generated from resource not behaving normally从资源行为不正常生成的 C++/Win32 对话框
【发布时间】:2014-08-23 19:30:42
【问题描述】:

我为一个(无模式)对话框编写了一个资源脚本,该对话框应该包含一个编辑控件(用于显示非编辑日志报告):

IDD_LOG DIALOGEX 10, 10, 300, 200, 0
STYLE WS_VISIBLE | WS_POPUP | WS_CAPTION | WS_BORDER | WS_SYSMENU | DS_CENTER
CAPTION "Last Log Report"
{
    EDITTEXT 301, 0, 0, 250, 180, WS_VISIBLE | WS_CHILD | WS_VSCROLL | ES_MULTILINE | ES_READONLY
}   

当我通过菜单调用对话框时

hwndLogDlg = CreateDialog(NULL, MAKEINTRESOURCE(IDD_LOG), hwnd, (DLGPROC)LogDlgProc)

以下几点是不对的:

  1. 对话框窗口包含一个编辑控件,但上面还有另一个大小相同的编辑控件。该编辑控件似乎是一个非子窗口。 此外,当我在调用 SetDlgItemText(hwndLogDlg, IDDE_LOGTXT, "<Could not load log data>"); 的编辑控件中设置文本时,它们都已设置。
    我怀疑资源编译器将脚本中的编辑控件视为对话框的子项和第二次作为单独的窗口,尽管设置了 WS_CHILD。
  2. 创建对话框时主窗口被阻止,尽管对话框是无模式的。
  3. 即使我在 WM_QUIT 和 WM_DESTROY 上调用DestroyWindow(hwndDlg);,单击对话框窗口的关闭按钮也不会导致它关闭。加上主窗口被阻塞的问题,我关闭一切的唯一方法是从任务栏或任务管理器关闭窗口。

消息循环:

while(GetMessage(&Msg, NULL, 0, 0) > 0) {
    if (!IsDialogMessage(hwndDlg, &Msg)){
        TranslateMessage(&Msg); 
        DispatchMessage(&Msg);
    }
}

对话框窗口过程:

INT_PTR CALLBACK LogDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam){
switch (message){
    case WM_INITDIALOG:{
        hwndLogTxt = GetDlgItem(hwndDlg, IDDE_LOGTXT);

        fileHandler fH;
        if (!fH.init("report.log")){
            SetDlgItemText(hwndLogTxt, IDDE_LOGTXT, "<Could not load log data>");
            err(ERR_CUSTOM,"Failed to extract log file!","Extraction Error!");
        }
        else SetDlgItemText(hwndLogTxt, IDDE_LOGTXT, fH.getStr());
        break;
    }
    case WM_DESTROY:{
        DestroyWindow(hwndDlg);
        break;
    }
}
return true;
}

所以我最终想要的是一个包含(只读)编辑控件(占据对话框窗口的所有客户区域)的无模式对话框。 这个问题是关于我的资源语法还是关于我调用它的方式?我什至可能错过了 WM_INITDIALOG 上的必要步骤吗?

【问题讨论】:

  • 您的代码行为不正确。因此,您已经发布了对话框模板定义。
  • 是的,因为对话框模板几乎是我拥有的关于对话框的所有代码。它也可能是消息循环,但这应该是正确的,因为我确实喜欢msdn.microsoft.com/en-us/library/windows/desktop/… 的其他示例。现在将其添加到问题中。
  • 不知道您的幻像编辑控件(显示您的代码)但您对SetDlgItemText 的调用是错误的 - 它需要 parent(对话框) 句柄,而不是控制句柄。
  • 我在匆忙复制到这个问题时不小心更改了 SetDlgItemText() 参数,感谢您的提示。我现在添加了对话框窗口过程。

标签: c++ winapi dialog resources


【解决方案1】:

一些cmets:

a) 我想您在调用CreateDialog() 时实际上使用了LogDlgProcCreateDialog() 后面还有ShowWindow(hwndDlg, SW_SHOW); 吗?

b) 你的EDITTEXT 控件在资源文件中声明为一个数字作为id,你的逻辑使用IDDE_TXT -- 将你的对话框资源更改为EDITTEXT IDDE_TXT...

c) 更改代码以将您的编辑控件设置为SetDlgItemText(hwndDlg, IDDE_TXT, ...);;确保 fH.getStr() 返回正确的字符串值

d) 如有必要,在读取fH 后关闭它(取决于fileHandler 的实现方式)

e) 为未处理的消息返回 FALSE

f) 在您致电 DestroyWindow 之前,您不会收到 WM_DESTROY,我认为处理 IDCANCEL 就足够了

你的对话过程应该是这样的

INT_PTR CALLBACK LogDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{   switch (message)
    {   case WM_INITDIALOG:
        {   fileHandler fH;
            if (fH.init("report.log"))
            {   SetDlgItemText(hwndDlg, IDDE_TXT, fH.getStr());
                // close fH
            }
            else
            {   SetDlgItemText(hwndDlg, IDDE_TXT, "<Could not load log data>");
                err(ERR_CUSTOM,"Failed to extract log file!","Extraction Error!");
            }
            return TRUE;
        }

        case WM_COMMAND: 
            if (LOWORD(wParam) == IDCANCEL) 
            {   DestroyWindow(hwndDlg);
                return TRUE;
            }
//EDIT start
            if (HIWORD(wParam) == EN_SETFOCUS && LOWORD(wParam) == IDDE_TXT)
            {   SendDlgItemMessage(hwndDlg, IDDE_TXT, EM_SETSEL, -1, -1);
                return TRUE;
            }
//EDIT end

    }
    return FALSE;
}

【讨论】:

  • 我现在修复了变量标识符,在发布问题并试图简化回答者的情况时,我让它们来回更改。 fileHandler 是我自己的一个类;我想如果我在析构函数 ~fileHandler() 中释放动态内存,内存泄漏就不会出现,还是应该显式地实现一个释放函数?谢谢你的回答。
  • 在析构函数中释放/关闭文件句柄应该没问题——你的对话框现在可以工作了吗?
  • 是的,对话框现在可以工作了。我现在想找到一种取消选择我的整个编辑控件内容的方法,因为它在被分配默认焦点后会自动选择。这就是我所知道的。当我最小化对话框时,它以某种方式隐藏在屏幕的左下角,但仍然存在,非常小。我已将对话框样式更改为 '(WS_OVERLAPPEDWINDOW ^ (WS_CAPTION | WS_THICKFRAME | WS_MAXIMIZEBOX)) | WS_VISIBLE | DS_CENTER'。
  • 添加取消选择编辑框内容的代码;我通常使用对话框样式WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
【解决方案2】:

一般情况下,从对话过程中返回FALSE 以获得默认处理。

然而,一些逻辑上返回值的消息是特殊情况。您可以使用&lt;windowsx.h&gt; 中的SetDlgMsgResult 宏来正确处理这些特殊情况。或者你可以暂时忽略它们。

另外,我怀疑你不应该打电话给DestroyWindow

【讨论】:

  • 我想你是说 WM_DESTROY 没有必要?在收到第一个答案后,我现在解决了这个问题。如果您确实是指 DestroyWindow(),请告诉我原因。
  • WM_DESTROY 通常会告诉您正在销毁窗口,这是之前对DestroyWindow 的调用的结果。对于该正常操作,调用DestroyWindow 作为响应是没有意义的。但是,您没有或没有显示您的所有代码,所以我进入了假设领域,通常情况是这样。
  • 哦,我明白了,感谢您指出这一点。我想我更希望我的资源脚本是错误的,所以我一开始不想用其他代码来混淆这个问题。
  • 谢谢,我知道这篇文章已经有 6 年多了,但是从处理函数返回 false 的提示刚刚解决了我 4 小时的问题
猜你喜欢
  • 1970-01-01
  • 2011-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-24
  • 2011-01-17
  • 2012-05-20
  • 2012-08-15
相关资源
最近更新 更多