上周的工作需要在代码中读写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;
}