拦截 CDialog 创建

Posted

技术标签:

【中文标题】拦截 CDialog 创建【英文标题】:Intercept CDialog creation 【发布时间】:2011-03-10 17:25:48 【问题描述】:

我有一个相当大的应用程序,它显示许多不同的 MFC CDialog 派生对话框窗口。所有的对话框都从一个与此类似的中心功能中显示出来:

void ShowDialog(CDialog& dlg)

  dlg.DoModal();

现在我需要在每个对话框的 OnInitDialog 方法中调用一个函数。它在技术上不需要在 OnInitDialog 中,但最好在对话框可见之前。

蛮力方法是遍历代码并找到每个最后一个对话框并将函数调用添加到 OnInitDialog 方法(如果有,如果没有,则添加一个)。不过好像一定有​​更优雅的方式……

请注意,dlg 实际上不是 CDialog,而是从它派生的东西。

有什么想法、技巧或技巧吗?我不是在修补消息映射,但希望找到更清洁/更安全的东西。

【问题讨论】:

【参考方案1】:

如果您的所有对话框都有一个共同的祖先,您似乎暗示您有,那么您可以简单地将代码放在您选择的合适位置的共同祖先中。例如OnInitDialog() 是虚拟的。

【讨论】:

CDialog 是唯一的共同祖先 :( @Doug 把一个共同的祖先放进去。 这与蛮力“查找所有 OnInitDialog”方法没有太大区别。我希望能够将 WM_INITDIALOG 重定向到一个单独的函数(挂钩)或其他一些技巧,这样我就不必更改所有其他代码。 @Doug 切换到一个共同的祖先是微不足道的。你从 CDialog 传下来的任何地方,都插入了你的共同祖先。我可以向你保证,这些好处将在很长一段时间内显现出来! 我同意大卫的观点。也许添加一个共同祖先(CMyDialog)的工作量类似于向每个对话框添加方法调用。但它会在未来给你带来很多好处。【参考方案2】:

事实证明这很容易做到:

HHOOK gPrevHook = SetWindowsHookEx(WH_CALLWNDPROCRET, HookProc, NULL, myGUIThreadID);


LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)

    if(NULL != wParam)
    
         CWPRETSTRUCT* pS = (CWPRETSTRUCT*)lParam;
         if(WM_INITDIALOG == pS->message)
             CallFuncOnWindow(pS->hwnd);
    

    return CallNextHookEx(gPrevHook, nCode, wParam, lParam);

对于高性能应用程序来说可能不是这样,但对于一个简单的 GUI 来说,它可以完美运行。无需更改其他代码。

【讨论】:

这方面的官方术语是“技术债务”。 这简直令人震惊。以正确的方式做会更快!您所要做的就是在 class.*CDialog 上使用正则表达式并用 CMyCommonAncestor 替换 CDialog。 1小时绝对巅峰。您将永远受益。 除非它不会处理所有未实现 OnInitDialog 的对话框。它不会处理已经有基类的对话框并在它们的 OnInitDialog 中调用 Base::OnInitDialog。任何遗漏的案例都是错误。这是 7 行代码,不会遗漏任何代码,不依赖人类记住从基类派生未来代码等。如果这是一个“拦截框架”,就会有关于它的文章 :) CDialog 引入了 OnInitDialog。不调用 base OnInitDialog 已经是一个错误。你所拥有的是非常糟糕的设计。复杂、不透明和不必要的。你为了保持复杂而放弃了 KISS。 OnInitDialog 是虚拟的,而不是纯虚拟的。如果它只调用基类什么都不做,那么调用它就没有必要也很愚蠢。我看不出 7 行代码比在现有类层次结构中引入一个新类更复杂,并且需要数百行更改,其中大部分是编译器无法验证的。

以上是关于拦截 CDialog 创建的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot支持interceptor(拦截器)

springboot成神之——拦截器

拦截器的使用

ActiveMq-拦截创建消息队列

Spring Boot实践——三种拦截器的创建

springboot之拦截器