VC定制个性化的MessageBox解决方法

 更新时间:2020年4月25日 17:42  点击:2072

相信学过VC的人都知道MessageBox()函数的用法:

int MessageBox(
 HWND hWnd,     // handle to owner window
 LPCTSTR lpText,   // text in message box
 LPCTSTR lpCaption, // message box title
 UINT uType     // message box style
);

虽然在参数uType中可以指定一些样式,但你在程序中能够对MessageBox的外观所做的定义却不多。原因是当调用MessageBox()函数后,它在内部有自己的消息循环(所有的模式对话框都有自己的消息循环),返回时MessageBox对话框窗口已经被Destroy,所以你没有办法得到MessageBox对话框的窗口句柄。但你可以根据自己的不同需求用下面的方法中去定制你的MessageBox:

如果你只是想用自己的icon去代替系统MessageBox提供的那几种有限的icon,用MessageBoxIndirect()函数就可以了:

int MessageBoxIndirect(
 CONST LPMSGBOXPARAMS lpMsgBoxParams // message box parameters
);

typedef struct { 
 UINT   cbSize; 
 HWND   hwndOwner; 
 HINSTANCE hInstance; 
 LPCTSTR  lpszText; 
 LPCTSTR  lpszCaption; 
 DWORD   dwStyle; 
 LPCTSTR  lpszIcon; 
 DWORD_PTR dwContextHelpId; 
 MSGBOXCALLBACK lpfnMsgBoxCallback; 
 DWORD   dwLanguageId; 
} MSGBOXPARAMS, *PMSGBOXPARAMS;

看到MSGBOXPARAMS结构中的lpszIcon吧,在使用过程中你应当准备一个合适的MSGBOXPARAMS结构,如果你要用自己的icon,你一定要用MB_USERICON这个flag。

上面我们也讲到不能定制MessageBox对话框的原因是没有办法得到它的窗口句柄,但我们真的没有办法了吗?当然有办法,那就是使用HOOK(钩子)机制。在windows系统中有多种HOOK,但在这里我们只用到HK_CBT类型的钩子。HK_CBT钩子过程在WM_MOVE、WM_SIZE、WM_ACTIVE、WM_CREATE、WM_DESTROY时被系统调用,所以HK_CBT钩子可以在这里用。下面让我们看如何实现MessageBox的定制过程。

1.安装HK_CBT钩子;
2.调用MessageBox()函数;
3.移除HK_CBT钩子。

整个过程很简单吧?我们在这里介绍第一步和第三步。

安装HK_CBT钩子:

HHOOK hMsgBoxHook = SetWindowsHookEx(
 WH_CBT,        // Type of hook 
 CBTProc,        // Hook procedure (see below)
 NULL,         // Module handle. Must be NULL (see docs)
 GetCurrentThreadId()  // Only install for THIS thread!!!
);

重要的是SetWindowHookEx()函数的后边两个参数,用它可以区别安装是一个全局钩子还是一个线程钩子,在这里我们只要安装一个线程钩子。所以我们将Module handle设置为NULL,同时将thread ID设为本线程的ID

在SetWindowHookEx()函数中有一个hook procedure,这是window调用的一个回调函数,在windows系统中有一个HOOK链,我们在编写hook procedure时要注意保证此链的完整,所以我们的hook procedure要调用CallNextHookEx()函数。下面就是我们的hook procedure:

LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
  HWND hwnd;
  if(nCode < 0)
    return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam);
  switch(nCode)
  {
  case HCBT_ACTIVATE:
    // 现在wParam中就是message box的句柄
    hwnd = (HWND)wParam;
    // 我们已经有了message box的句柄,在这里我们就可以定制message box了!
    return 0;
  }
  // Call the next hook, if there is one
  return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam);
}

移除HK_CBT钩子:

只要调用UnhookWindowsHookEx()函数就可以了

好了,我们将在上面的三步写成一个函数,如下:

int MsgBoxEx(HWND hwnd, TCHAR *szText, TCHAR *szCaption, UINT uType)
{  
  int ret;
  // Install a thread hook, so we can customize it
  hMsgBoxHook = SetWindowsHookEx(
    WH_CBT, 
    CBTProc, 
    NULL, 
    GetCurrentThreadId()
    );
  // Display a standard message box
  ret = MessageBox(hwnd, szText, szCaption, uType);
  // remove the window hook
  UnhookWindowsHookEx(hMsgBoxHook);
  return ret;
}

其实你也可以钩住WM_CREATE消息,不过那样处理要复杂一些。在早期的windows platform SDK中就有这样一个例子。

你可能说,定制一个MessageBox有什么用处,我想有下面的用途:

1.你可以用CreateWindowEx()给MessageBox添加一个check box控件,并子类化MessageBox来处理check box的消息

2.通过子类化改变messagebox、button或icon,以便和你整个程序的界面风格相一致

只要有了MessageBox对话框的句柄,你能做的很多,很多...

另外,如果你对模式对话框的机理很了解,你可以自己写出一个"MessageBox"来代替系统MessageBox用在你的程序中。你可以参考Jeffrey Richter的《Windows 95程式设计指南》,在书中给出了模式对话框的伪码。这本书的繁体电子版可以在候捷的个人网站上下载。这种方法也比较简单(添加一个消息循环,Enable/Disable Owner窗口),示例代码这里就不实现了。读者可以参考相关资料加以完善。

[!--infotagslink--]

相关文章

  • MessageBox的Buttons和三级联动效果

    这篇文章主要介绍了MessageBox的Buttons和三级联动的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • C#实现延时并自动关闭MessageBox的方法

    这篇文章主要介绍了C#实现延时并自动关闭MessageBox的方法,非常实用的功能,需要的朋友可以参考下...2020-06-25
  • SpringMVC文件上传原理及实现过程解析

    这篇文章主要介绍了SpringMVC文件上传原理及实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-07-15
  • C# MVC模式中应该怎样区分应用程序逻辑(Controller层)和业务逻辑(Model层)?

    这篇文章主要介绍了C# MVC模式中应该怎样区分应用程序逻辑(Controller层)和业务逻辑(Model层)?,这也小编做.NET项目时经常思考和让人混乱的一个问题,这篇文章写的挺好,一下清晰了许多,需要的朋友可以参考下...2020-06-25
  • 使用Maven 搭建 Spring MVC 本地部署Tomcat的详细教程

    这篇文章主要介绍了使用Maven 搭建 Spring MVC 本地部署Tomcat,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-08-16
  • SpringMvc自动装箱及GET请求参数原理解析

    这篇文章主要介绍了SpringMvc自动装箱及GET请求参数原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-19
  • SpringMvc获取请求头请求体消息过程解析

    这篇文章主要介绍了SpringMvc获取请求头请求体消息过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-17
  • vc提示unexpected end of file found的原因分析

    这篇文章主要介绍了vc提示unexpected end of file found的原因分析,给出了几点常见错误原因的分析,需要的朋友可以参考下...2020-04-25
  • Springmvc ResponseBody响应json数据实现过程

    这篇文章主要介绍了Springmvc ResponseBody响应json数据实现过程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-10-26
  • 基于C#后台调用跨域MVC服务及带Cookie验证的实现

    本篇文章介绍了,基于C#后台调用跨域MVC服务及带Cookie验证的实现。需要的朋友参考下...2020-06-25
  • 详解CocosCreator MVC架构

    这篇文章主要介绍了CocosCreator MVC架构,同学们在制作游戏过程中,尽量使用一些架构,会避免很多问题...2021-04-16
  • Spring MVC 处理一个请求的流程

    Spring MVC是Spring系列框架中使用频率最高的部分。不管是Spring Boot还是传统的Spring项目,只要是Web项目都会使用到Spring MVC部分。因此程序员一定要熟练掌握MVC部分。本篇博客简要分析Spring MVC处理一个请求的流程。...2021-02-06
  • 理解javascript中的MVC模式

    这篇文章主要为大家介绍了javascript中的MVC模式,MVC是一种软件架构模式,一般把软件模式分为三部分,本文就针对MVC模式的三部分进行讲解,感兴趣的小伙伴们可以参考一下...2016-02-01
  • 仅30行代码实现Javascript中的MVC

    这篇文章主要介绍了仅30行代码实现Javascript中的MVC的方法,MVC的基础是观察者模式,这是实现model和view同步的关键,想要深入了解的朋友可以参考本文...2016-02-18
  • 使用jQuery.form.js/springmvc框架实现文件上传功能

    这篇文章主要介绍了使用jQuery.form.jsspringmvc框架实现文件上传功能,非常具有参考借鉴价值,感兴趣的朋友一起学习吧...2016-05-14
  • SpringMVC和rabbitmq集成的使用案例

    这篇文章主要介绍了SpringMVC和rabbitmq集成的使用案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-20
  • AngularJS教程之MVC体系结构详解

    本文主要讲解AngularJS MVC体系结构,这里提供详细的教程供大家学习参考,有需要的小伙伴可以参考下...2016-08-24
  • web面试MVC与MVVM区别及Vue为什么不完全遵守MVVM解答

    这篇文章主要介绍了web面试中常问问题,MVC与MVVM区别以及Vue为什么不完全遵守MVVM的难点解答,有需要的朋友可以借鉴参考下,希望能够有所帮助...2021-09-24
  • ASP.NET MVC API 接口验证的示例代码

    本篇文章主要介绍了ASP.NET MVC API 接口验证的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2021-09-22
  • SpringMVC中的handlerMappings对象用法

    这篇文章主要介绍了SpringMVC中的handlerMappings对象用法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-26