上周的工作需要在代码中读写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返回给调用者,这个也是宏定义本身的局限。当调用者需要对出错情况进行处理,需要编写这样的代码。
BOOL retval;
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;
}