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

相信学过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窗口),示例代码这里就不实现了。读者可以参考相关资料加以完善。

(0)

相关推荐

  • 完美解决IIS 服务器无法加载应用程序 ‘/LM/W3SVC/1/ROOT’。错误是:没有注册类别

    现象:        浏览ASP页面提示   500内部错误 事件查看器中:        [1]:                服务器无法加载应用程序 '/LM/W3SVC/1/ROOT'.错误是 '没有注册类别'.                 有关此消息的详细信息,请访问 Microsoft 联机支持站点: http://www.microsoft.com/contentredirect.asp. 有关更多信息,请参阅在 http://go.microsoft.com/fwlink/e

  • VC外部符号错误_main,_WinMain@16,__beginthreadex解决方法

    本文实例讲述了VC外部符号错误_main,_WinMain@16,__beginthreadex解决方法.分享给大家供大家参考.具体如下: 在创建MFC项目时, 不使用MFC AppWizard向导, 如果没有设置好项目参数,就会在编译时产生很多连接错误, 如error LNK2001错误, 典型的错误提示有: libcmtd.lib(crt0.obj) : error LNK2001: unresolved external symbol _main LIBCD.lib(wincrt0.obj

  • VC++实现通过API来查看程序错误信息的方法

    本文实例介绍了VC++通过API查看错误信息的方法,可以在遇到错误的时候,将显示出错信息并退出处理,具体的实现代码如下: if((m_hBitMap=(HBITMAP)::LoadImage(NULL,filepath,IMAGE_BITMAP,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE))==NULL) { LPVOID lpMsgBuf; DWORD dw = ::GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOC

  • VC6.0常见链接错误与解决方法

    (1)error LNK2001: unresolved external symbol _main 编号:LNK2001 直译:未解决的外部符号:_main. 错误分析:缺少main函数.看看main的拼写或大小写是否正确. (2)error LNK2005: _main already defined in xxxx.obj 编号:LNK2005 直译:_main已经存在于xxxx.obj中了. 错误分析: 直接的原因是该程序中有多个(不止一个)main函数.这是初学C++的低年级同学在初次

  • VC6.0常见编译错误提示附解决方法

    (1)error C2001: newline in constant 编号:C2001直译:在常量中出现了换行.错误分析: 1.①字符串常量.字符常量中是否有换行.2.②在这句语句中,某个字符串常量的尾部是否漏掉了双引号.3.③在这语句中,某个字符创常量中是否出现了双引号字符""",但是没有使用转义符"\"".4.④在这句语句中,某个字符常量的尾部是否漏掉了单引号.5.⑤是否在某句语句的尾部,或语句的中间误输入了一个单引号或双引号. (2)er

  • vc提示unexpected end of file found的原因分析

    本文较为详细的分析了vc提示unexpected end of file found的原因.分享给大家供大家参考.具体分析如下: 预编译出错,检查#if与#endif是否个数一致 Error executing cl.exe 则检查你的程序是否已经运行,这说明编译可能已经通过,程序仍在内存中 可能是类后没有加分号,或上面的漏了个"{"号或"}"号. 1. 如果你的部分代码从某些网页拷贝,最好先拷到写字板,在从写字板粘贴到VC中. 2. 如果你VC++工程包括了一些C

  • ASP.NET中MVC使用AJAX调用JsonResult方法并返回自定义错误信息

    一.如何用AJAX调用JsonResult方法 比如FuckController中添加有个返回JsonResult类型的方法FuckJson(): 复制代码 代码如下: <span class="kwd">public<span class="pln"> <span class="typ">JsonResult<span class="pln"> <span class=&

  • 完美修复SVCHOST.EXE出现0x745f2780错误的方法

    1.检查WINDOWS UPDATE服务程序的设置 1)点击开始-运行,输入services.msc,回车. 2)找到Automatic Updates服务程序,双击打开,. 3)切换到"登录"选项卡,确保登录身份中的本地系统账户为选中状态,未选中"允许服务与桌面交互". 4)确保下面的硬件配置文件右边的服务状态为"已启用". 5)切换到"常规"选项卡, 确保此服务的启动类型为"自动",如果不是,请从下拉列

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

    相信学过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的外观所做的定义却不多.原因

  • Yii使用ajax验证显示错误messagebox的解决方法

    本文实例讲述了Yii使用ajax验证显示错误messagebox的解决方法.分享给大家供大家参考.具体方法如下: yii 自带了ajax 表单验证 这个可能有些朋友不知道了,但我今天在使用yii 自带的ajax 表单验证 时碰到一些问题,下面我来整理例子与大家参考一下. 在Yii中,可以利用ajax执行一个action,但是这个action有时候会有弹出错误讯息的需求,这时候的处理方式如下 基本思想 利用exception,比如: 复制代码 代码如下: throw new CHttpExcept

  • VC中LINK 2001 和 LINK 2009 的错误的解决方法

    最近将两个开源C++项目编译成windows版本的时候遇到很多问题,关键是两个项目经过同事的修改之后,一个项目引用了另一个项目,两个项目的头文件中都有一些跨平台的关于数据类型,以及一些通用函数的定义,所以导致有冲突,编译的时候总是报错,报的最多的是"无法解析的外部符号",经过近3天的折腾总算都通过了,这里是一些总结. 首先,关于VC中的lib,与linux下的静态库是不同的,在VC中编译动态库的时候会生成一个lib和一个对应的dll,使用者在使用的时候需要包含头文件以及连接到该lib,

  • 跨域请求的完美解决方法(JSONP, CORS)

    一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题.解决方法有JSONP,Flash等等. JSONP 我们发现,Web页面上调用js文件时不受是否跨域的影响,凡是拥有"src"这个属性的标签都拥有跨域的能力,比如<script>.<img>.<iframe>.那就是说如果要跨域访问数据,就服务端只能把数据放在js格式的文件里.恰巧我们知道JSON可以简洁的描述复杂数据,而且JSON还被js原生支持,所以在客户端几乎可以随心所欲的处

  • Java系统的高并发解决方法详解

    一个小型的网站,比如个人网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构.性能的要求都很简单,随着互联网业务的不断丰富,网站相关的技术经过这些年的发展,已经细分到很细的方方面面,尤其对于大型网站来说,所采用的技术更是涉及面非常广,从硬件到软件.编程语言.mysql" target="_blank" title="MySQL知识库">数据库.WebServer.防火墙等各个领域

  • ON_COMMAND_RANGE多个按钮响应一个函数的解决方法

    本文描述了ON_COMMAND_RANGE多个按钮响应一个函数的解决方法. 开发人员需要注意在自定义消息响应函数的声明过程中,一定要注意参数的形式,稍微一疏忽就会导致莫须有的错误,具体以ON_COMMAND_RANGE为例说下. 1.声明消息响应函数:在要添加的工程上添加函数afx_msg void OnButtonPort(); 2.消息映射: BEGIN_MESSAGE_MAP(CXXXDlg, CDialog) //{{AFX_MSG_MAP(CXXXDlg) ON_WM_SYSCOMMA

  • Bootstrap栅格系统使用方法及页面调整变形的解决方法

    如果你以前使用过Bootstrap2或者了解过响应式技术,那么肯定对Bootstrap栅格系统并不陌生,由于栅格系统的引入,使得Bootstrap的跨设备布局显示变得可能. 什么是栅格系统 栅格系统是指,将页面布局划分为等宽的列,然后通过列数的定义来模块化页面布局. Bootstrap的栅格系统采用了1-12列的模式,并且通过比例计算来设置你定义的列宽. 例如你这一行想要采用两列的布局模式,那么每列的宽度都为外容器的50%,不管你用什么设备浏览,它都会采用这样的比例进行展示. 不过如果当设备宽度

  • IIS 配置问题 一些iis常见问题的解决方法

    1.iis6.0和5.0都不能装在XP系统中 2.下载了后不知道怎么安装 3.安装过程中弹出文件无法复制的对话框和什么系统被修改,是否继续的对话框,很是郁闷 4.安装后internet信息服务器中没有默认网站 5.安装后在地址栏中输入http://localhost出现Server Application Error 错误即500 错误 6.安装后默认网站无法启动 再说说这些问题的解决方法 问题一:1 在你装IIS之前需要知道你的系统是什么样的,HOME版的好想不能装,可好象网上也有装的方法,我

  • C#实现Socket通信的解决方法

    本文以实例详述了C#实现Socket通信的解决方法,具体实现步骤如下: 1.首先打开VS新建两个控制台应用程序: ConsoleApplication_socketServer和ConsoleApplication_socketClient.   2.在ConsoleApplication_socketClient中输入以下代码: using System; using System.Collections.Generic; using System.Linq; using System.Tex

随机推荐