[经验总结]获取Windows程序出错原因的C++代码

本文介绍了一个改进后的错误处理宏MTVERIFY,通过引入内联函数Myverify来简化代码并提高生产力。改进后的宏不仅适用于调试阶段,还能在出错时提供详细的错误信息。

上周的工作需要在代码中读写INI文件,但写INI文件的程序总是过不去,后经同事提示是INI文件被设为只读。问其如何才能得知此错误,只见他打开一个小工具,输入从调试窗口得到的ErrorCode,点“确定”之后,小窗口上显示出错原因“文件访问出错”。这种方式实在是低效,我想在程序中自动做这些工作。于是上网搜得《win32 多线程程序设计》一书中的错误处理代码,对其稍作修改就能使用。对原书代码修改主要体现以下三个方面:
1 > 将字符串类型改为Unicode;
2 > 删去PrintError函数中exit( EXIT_FAILURE );
3 > 原书代码中MTVERIFY宏如下:

#define MTVERIFY(a) if (!(a)) PrintError(#a, __FILE__ , __LINE__ ,GetLastError())
将其修改为Unicode版本:
#define MTVERIFY(a) if (!(a)) PrintError(_T(#a), _T( __FILE__ ), __LINE__ , GetLastError())
这个宏能很好的工作,但有一个局限,不能将BOOL参数a返回给调用者,这个也是宏定义本身的局限。当调用者需要对出错情况进行处理,需要编写这样的代码。
BOOLretval;
MTVERIFY(retval = do_something)
;
if (retval) {
// 错误处理 ... ...
}
最近在学Perl,Perl程序员的核心价值观就是“懒惰 急躁 傲慢“,那么可以再改造MTVERIFY宏,以少写两行代码。首先添加一个内联函数:
__inline BOOL Myverify(BOOL what,LPTSTR lpszFunc)
{
#ifdef _DEBUG
if (!what)
PrintError(_T(
__FILE__ ), __LINE__ , lpszFunc,GetLastError());
#endif

return what;
}

然后重写MTVERIFY宏:
#define MTVERIFY(a) Myverify(a,_T(#a))
如此这般,上述错误处理代码可以写成:
if (MTVERIFY(a)) {
// 错误处理 ... ...
}
虽然这一番折腾只能省下两行代码,但考虑到MTVERIFY函数以后会经常用到,从长远来看,省下的代码是2*N行,总的生产力会得到提升。所以,写代码,就该让“懒惰 ”进行到底。



/*
* MtVerify.h
*
* The function PrintError() is marked as __inline so that it can be
* included from one or more C or C++ files without multiple definition
* errors.
* To use the PrintError() in an application, it should be taken out,
* placed in its own source file, and the "__inline" declaration removed
* so the function will be globally available.
* [Modified by thinkhy 10/01/04] ...
* [Modified by thinkhy 10/01/07] Added function Myverify.
*/

#pragma comment( lib, "USER32" )

#define MTASSERT(a) _ASSERTE(a)


#ifdef _DEBUG
#define MTVERIFY(a) Myverify(a,_T(#a))
#else
#define MTVERIFY(f)(( void )(f))
#endif

__inline
void PrintError(LPTSTR filename, int lineno, LPTSTR lpszFunc, DWORD errnum)
{
LPTSTR lpBuffer;
TCHAR errbuf[
256 ];
#ifdef _WINDOWS
TCHAR modulename[MAX_PATH];
#else // _WINDOWS
DWORD numread;
#endif // _WINDOWS

FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM,
NULL ,
errnum,
LANG_NEUTRAL,
(LPTSTR)&lpBuffer,
// 这个参数很变态! [Commented by thinkhy 10/01/04]
0 ,
NULL );

wsprintf(errbuf, _T(
"Failed at Line: %d in File: /" %s /"/r/n Function: %s /r/n Reason: %s " ),
lineno, filename, lpszFunc, lpBuffer);
#ifndef _WINDOWS
WriteFile(GetStdHandle(STD_ERROR_HANDLE), errbuf, strlen(errbuf), &numread, FALSE );
Sleep(
3000 );
#else
GetModuleFileName(
NULL , modulename, MAX_PATH);
MessageBox(
NULL , errbuf, modulename, MB_ICONWARNING|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);
#endif
// exit(EXIT_FAILURE);
return ;
}


__inline BOOL Myverify(BOOL what,LPTSTR lpszFunc)
{
#ifdef _DEBUG
if (!what)
PrintError(_T(
__FILE__ ), __LINE__ , lpszFunc,GetLastError());
#endif

return what;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值