最近在看侯捷翻译的《Win32多线程程序设计》。我去,这本书可真够老了(1997年),不过总要学多线程啊,不然感觉自己还是门外汉。
书是老了些,但是讲的真的很系统也很基础,挺适合我的。
刚看了几个程序示例,里面都有一个宏MTVERIFY,貌似是用来记录并解释GetLastError()函数的结果,方便调试出错信息的。
本来不想理这个东东,后来发现在书里用的很频繁,就索性深入的看看吧。
首先制造一个会出错的程序:
#include "stdafx.h"
#include
#include "MtVerify.h"
#define THREAD_NUM 2
DWORD WINAPI MyFun(LPVOID p);
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hThread[THREAD_NUM];
DWORD ThreadID[THREAD_NUM];
DWORD ExitWord[THREAD_NUM];
int i = 0;
for (i=0; i
应该看的出,出错位置在GetExitCodeThread函数的调用。原因是在调用该函数之前,已经结束句柄。
下面是定义宏MTVERIFY的头文件MtVerify.h:
/**
* MtVerify.h
*
* Error handling for applications in
* "Multitheading Applications in Win32"
*
* 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. For the examples in this book, this works fine.
* 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.
*/
#pragma comment( lib, "USER32" )
#include
#include
#define MTASSERT(a) _ASSERTE(a)
// 宏定义 __FILE__ 与__LINE__都是预处理符号提供错误信息的描述
// 如果a返回FALSE就执行PrintError函数
#define MTVERIFY(a) if (!(a)) PrintError(#a,__FILE__,__LINE__,GetLastError())
__inline void PrintError(LPSTR linedesc, LPSTR filename, int lineno, DWORD errnum)
{
LPSTR lpBuffer;
char errbuf[256];
#ifdef _WINDOWS
char modulename[MAX_PATH];
#else // _WINDOWS
DWORD numread;
#endif // _WINDOWS
// 把从GetLastError()返回的错误码转化为错误信息
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errnum,
LANG_NEUTRAL,
(LPTSTR)&lpBuffer,
0,
NULL );
wsprintfA(errbuf, "\nThe following call failed at line %d in %s:\n\n"
" %s\n\nReason: %s\n", lineno, filename, linedesc, lpBuffer);
// 如果是console程序就输出信息到控制台上
#ifndef _WINDOWS
WriteFile(GetStdHandle(STD_ERROR_HANDLE), errbuf, strlen(errbuf), &numread, FALSE );
等待3秒钟是为了使用者看到出错信息
//Sleep(3000);
system("Pause");//按任意键继续
// 如果是窗口程序就一弹出对话框的形式输出错误信息
#else
// 当前exe文件的全路径
GetModuleFileName(NULL, modulename, MAX_PATH);
// 置弹出窗口在最上层以免被忽略
MessageBox(NULL, errbuf, modulename, MB_ICONWARNING|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);
#endif
// 把结束代码EXIT_FAILURE 交给操作系统
exit(EXIT_FAILURE);
}
现在就可以编译运行了。虽然确实能正确地显示出错的位置,但是出错的原因会有乱码,也不知道咋弄,就先这样吧。