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

 更新时间:2014年07月16日 14:54:43   投稿:shichen2014  
这篇文章主要介绍了VC定制个性化的MessageBox解决方法,有助于进一步的了解windows应用程序的消息机制及运行原理,需要的朋友可以参考下

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

相关文章

  • iOS锁屏音频播放控制及音频信息设置

    iOS锁屏音频播放控制及音频信息设置

    这篇文章主要为大家详细介绍了iOS锁屏音频播放控制及音频信息设置,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12
  • C中实现矩阵乘法的一种高效的方法

    C中实现矩阵乘法的一种高效的方法

    本篇文章介绍了,在C中实现矩阵乘法的一种高效的方法。需要的朋友参考下
    2013-05-05
  • C语言图文并茂讲解分支语句用法

    C语言图文并茂讲解分支语句用法

    分支结构的执行是依据一定的条件选择执行路径,而不是严格按照语句出现的物理顺序。分支结构的程序设计方法的关键在于构造合适的分支条件和分析程序流程,根据不同的程序流程选择适当的分支语句
    2022-04-04
  • 在C/C++项目中合理使用宏详解

    在C/C++项目中合理使用宏详解

    这篇文章主要介绍了在C/C++项目中合理使用宏详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • C++之BOOST字符串查找示例

    C++之BOOST字符串查找示例

    这篇文章主要介绍了C++之BOOST字符串查找的方法,实例演示了boost针对字符串的查找、判定及替换等操作,具有一定的实用价值,需要的朋友可以参考下
    2014-10-10
  • C++封装IATHOOK类实例

    C++封装IATHOOK类实例

    这篇文章主要介绍了C++封装IATHOOK类的实现方法,对IAT的HOOK实例进行了封装,非常具有实用价值,需要的朋友可以参考下
    2014-10-10
  • C语言带你学会位段相关知识

    C语言带你学会位段相关知识

    这篇文章主要介绍了什么是位段,位段的声明和结构是类似的,位段的成员必须是 int、unsigned int 或signed int;位段的成员名后边有一个冒号和一个数字,本文有详细的代码案例,感兴趣的同学可以参考阅读
    2023-04-04
  • C++高精度计时的几种方法总结(测试函数运行时间)

    C++高精度计时的几种方法总结(测试函数运行时间)

    本文介绍了C++中常用的几种程序计时方法,包括clock()函数、GetTickCount()、QueryPerformanceCounter()以及C++11中的chrono库函数,这篇文章主要介绍了C++高精度计时的几种方法,需要的朋友可以参考下
    2024-09-09
  • C++缺省参数的具体使用

    C++缺省参数的具体使用

    缺省参数是声明或定义函数时为函数的参数指定一个默认值。本文就详细的介绍了一下C++缺省参数的具体使用,具有一定的参考价值,感兴趣的可以了解一下
    2022-01-01
  • C语言中将日期和时间以字符串格式输出的方法

    C语言中将日期和时间以字符串格式输出的方法

    这篇文章主要介绍了C语言中将日期和时间以字符串格式输出的方法,分别是ctime()函数和asctime()函数,注意参数区别,需要的朋友可以参考下
    2015-08-08

最新评论