Returning values from a dialog procedure - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20031107-00/?p=41923
Raymond Chen 2003年11月7日
简要
这篇文章由Raymond Chen撰写,解释了对话框过程如何从Windows编程中返回值。他详细说明了对话框过程需要返回两个信息,并且如何通过使用窗口的长整型属性来实现这一点。此外,还讨论了“特殊消息”的例外情况以及它们存在的原因。
正文
出于某种原因,人们常常对对话框过程如何返回值感到困惑,所以我打算用不同的方式解释一下。
对话框过程的关键在于,它们实际上需要返回两个信息:
- 消息是否已被处理?
- 如果是,返回值应该是什么?
由于需要返回两个信息,但C函数只能有一个返回值,所以需要用其他方式返回第二个信息。
对话框过程的返回值是消息是否已被处理。第二条信息——应该是什么返回值——存储在DWLP_MSGRESULT
的窗口长整型属性中。
换句话说,DefDlgProc
的大致工作流程如下:
LRESULT CALLBACK DefDlgProc(
HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
DLGPROC dp = (DLGPROC)GetWindowLongPtr(hdlg, DWLP_DLGPROC);
SetWindowLongPtr(hdlg, DWLP_MSGRESULT, 0);
BOOL_PTR fResult = dp(hdlg, uMsg, wParam, lParam);
if (fResult) return GetWindowLongPtr(hdlg, DWLP_MSGRESULT);
else ... 执行默认行为 ...
}
如果返回除0以外的任何值,则通过 SetWindowLongPtr(hdlg, DWLP_MSGRESULT, value)
设置的值将被用作消息结果。
例如,许多WM_NOTIFY
通知允许通过返回TRUE来覆盖默认行为。要防止列表视图标签被编辑,您可以从LVN_BEGINLABELEDIT
通知返回TRUE。但如果您从对话框过程这样做,您必须分两步进行:
SetWindowLongPtr(hdlg, DWLP_MSGRESULT, TRUE);
return TRUE;
第二行设置了对话框过程的返回值,这告诉DefDlgProc
消息已被处理,应该抑制默认处理。第一行告诉DefDlgProc
返回给消息发送者(列表视图控件)的值是什么。如果您忘记了这两个步骤中的任何一个,期望的值就不会到达列表视图控件。
请注意,DefDlgProc
在发送消息之前将DWLP_MSGRESULT
设置为零。这样,如果对话框过程忘记显式设置消息结果,结果将为零。
这也突出了在从对话框过程返回之前立即调用SetWindowLongPtr
的重要性,而且不要更早。如果您在设置返回值和返回TRUE之间做任何操作,可能会触发向对话框过程发送消息,这将把消息结果重置为零。
注意:有一些“特殊消息”不遵循这个规则。这些例外情况在DialogProc
的文档中给出。为什么存在这些例外?
因为在最初设计对话框管理器时,确定对这些消息进行特殊处理将使对话框过程更容易编写,因为您不必经历设置DWLP_MSGRESULT
的额外步骤。幸运的是,时至今日,没有人添加任何新的例外。记住这些例外所增加的心理复杂性超过了不必编写一行代码的心理节省(“SetWindowLongPtr(hdlg, DWLP_MSGRESULT, desiredResult)”)。