WinXP环境中模仿WinCE的ASSERT表现行为的解决方案
//=====================================================================
//TITLE:
// WinXP环境中模仿WinCE的ASSERT表现行为的解决方案
//AUTHOR:
// norains
//DATE:
// Tuesday 23- February-2010
//Environment:
// WINDOWS CE 5.0
// WINDOWS XP
//=====================================================================
如果你开发过WinCE的程序,那么想必你对ASSERT宏的用法不陌生。简单点来说,该宏是在DEBUG版本才生效,当其表达式为FALSE时,调试器会自动停在该代码段,并且会在Output窗口输出相应的信息:
如果你将ASSERT(FALSE)放到WinXP的MFC工程的话,习惯于WinCE断言的方式的你,可能就会带你进入地狱。随着"咚"的一声,映入你眼帘的是这么一个警告信息:
刚在WinXP下编写程序的你,说不定看到这对话框,还以为自己的代码有了致命的错误呢。虽然我们可以点击"忽略"继续进行调试,但这对话框如果多来几个,我相信没几个人能忍受。
如果你不使用MFC,而是直接上WIN32 API的话,结局则更为离谱,你连编译都无法通过,直接提示ASSER没有定义。
查一下文档,WIN32确实没有ASSERT这玩意,但却有相应的替代,则是在该宏前加下划线,为_ASSERT。但这加下划线的也和MFC的ASSERT表现一样,会让你心跳加快:
好了,好了,基本上我们可以确认_ASSERT和ASSERT是同一个玩意,可以不用折腾了。但如果我们想获得在WinCE下的表现方式,那是不是就没辙了呢?
在讨论这个问题之前,我们先看看WinCE下关于ASSERT的定义是如何的。
归根结底,WinCE下的ASSERT用到了两个函数:NKDbgPrintfW和DebugBreak。我们很容易知道,NKDbgPrintfW是输出信息到Output窗口的函数,而DebugBreak则是让调试器暂停。
因为NKDbgPrintfW是WinCE特有的函数,所以我们先不管它,先看看DebugBreak。很幸运,这个函数在WinXP中也有定义。那么,我们将其放入代码里,看看其是什么表现。
当代码执行到DebugBreak()时,调试器也会跳出个对话框:
在该对话框中,如果选择Break,则会进入汇编代码的调试;如果是continue,则调试器会进入到下一语句。
虽然没有WinCE的那种静默的方式,但至少比那个带红红的"X",并且还有"咚"一声巨响的ASSERT好多了吧?
调试器的暂停我们算是不完美的解决了,那输出到Output窗口的信息该怎么办呢?NKDbgPrintfW可是WinCE的特权,WinXP可没有这个优待。在WinCE下,我们还能用printf输出到Output窗口,可是同样的调用,printf在WinXP下可就在Output窗口难觅踪影了。
查找文档,发现在WinXP下如果想将字符串输入到Output窗口,我们可以调用OutputDebugString。看起来问题能得到解决了,但其实OutputDebugString有个很大的缺陷,因为它不支持字符串的格式化!
换句话来说,如果将代码printf("Param:%d/r/n",iVal)替换为OutputDebugString("Param:%d/r/n",iVal),那么你将无法编译通过,因为OutputDebugString只支持一个形参!
难道,我们就没有办法在WinXP下实现一个和WinCE类似的ASSERT宏么?
没辙了,既然没有相应的格式化输出函数,那么我们自己弄一个不就行了么?
初始一看,整个函数的难点有两个,一个是可变参数,另一个是字符串格式化。其实这两个难点在wvsprintf上都能迎刃而解。它可以根据将可变形参格式化为字符串,然后保存到特定缓冲去。而这缓冲区的大小,根据文档,则为1024。所以,我们可以写出输出到output窗口的函数:
输出函数有了,那么我们接下来的事情是不是就简单多了?
最后,属于我们自己的ASSERT宏终于横空出世了: