1.函数返回值:
2.获得错误消息
从系统内部来讲,当一个 Windows函数检测到一个错误时,它会使用一个称为线程本地存储器(thread-local storage)的机制,将相应的错误代码号码与调用的线程关联起来。这将使线程能够互相独立地运行,而不会影响各自的错误代码。当函数返回时,它的返回值就能指明一个错误已经发生。使用GetlastError()获得错误代码(当Windows函数运行失败时,应该立即调用GetLastError函数。如果调用另一个Windows函数,它的值很可能被改写)。
WINBASEAPI _Check_return_ _Post_equals_last_error_ DWORD WINAPI GetLastError(
VOID);
对应的错误消息在WinError.h可以查看。每个错误都有3种表示法:一个消息ID(这是你可以在源代码中使用的一个宏,以便与GetLastError的返回值进行比较),消息文本(对错误的英文描述)和一个号码(应该避免使用这个号码,可使用消息ID)。如:
//
// MessageId: ERROR_PROFILING_NOT_STOPPED
//
// MessageText:
//
// Profiling not stopped.
//
#define ERROR_PROFILING_NOT_STOPPED 551L
//
// MessageId: ERROR_COULD_NOT_INTERPRET
//
// MessageText:
//
// The passed ACL did not contain the minimum required information.
//
#define ERROR_COULD_NOT_INTERPRET 552L
注意 GetLastError能返回线程产生的最后一个错误。如果该线程调用的 Windows函数运行成功,那么最后一个错误代码就不被改写,并且不指明运行成功。有少数Windows函数并不遵循这一规则,它会更改最后的错误代码;但是 Platform SDK文档通常指明,当函数运行成功时,该函数会更改最后的错误代码。
3.定义自己的错误代码
//设置线程错误代码
WINBASEAPI VOID WINAPI SetLastError(
_In_ DWORD dwErrCode); // 32位的错误代码
自定义错误代码29位必须设置为1.
3.1编写错误信息文本
自定义错误代码:点击打开链接
4.错误查看小工具:
vs查看错误:
通过选定 Watch窗口(快速监视窗口)中的一行,并键入“@ e r r, h r”,能显示线程的最后错误代码的号码和该错误的英文描述。
在vs目录下VSSystem\Common7\Tools\errlook.exe可以用来查看错误信息代码所代表的意思。
5.FormatMessage函数:
DWORD WINAPI FormatMessage (
DWORD dwFlags, // source and processing options
LPCVOID lpSource, // message source
DWORD dwMessageId, // message identifier
DWORD dwLanguageId, // language identifier
LPTSTR lpBuffer, // message buffer
DWORD nSize, // maximum size of message buffer
va_list *Arguments // array of message inserts
);
标志 | 标志说明 |
---|---|
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
函数会分配一个足够大的缓冲区保存格式化消息,并且通过lpBuffer指向该
地址。当不再使用lpBuffer数据时,需调用LocalFree释放内存。
|
FORMAT_MESSAGE_ARGUMENT_ARRAY
|
Arguments参数不是指向
va_list结构体,是一个指向保存参数的数组指针。
|
FORMAT_MESSAGE_FROM_HMODULE
|
指定lpSource参数是要去搜索的一个包含消息表的模块句柄。如果 lpSource 是NULL,会搜索当前进程的主模块,这个标志不能与
FORMAT_MESSAGE_FROM_STRING 同时使用。
|
FORMAT_MESSAGE_FROM_STRING
|
lpSource参数是一个指向以NULL结尾的字符串,字符串包含一个消息定义,
这个消息定义可以包含
插入序列。此标志不能与
FORMAT_MESSAGE_FROM_HMODULE 、
FORMAT_MESSAGE_FROM_SYSTEM同时使用
|
FORMAT_MESSAGE_FROM_SYSTEM
0x00001000
|
函数会从系统信息列表中搜索所请求的信息。如果使用
FORMAT_MESSAGE_FROM_HMODULE,函数会先在lpSource指定
的模块中搜索请求的消息,如果搜索不到再去搜索系统消息表资源。此
标志不能与
FORMAT_MESSAGE_FROM_STRING同时使用。
|
FORMAT_MESSAGE_IGNORE_INSERTS
|
指定消息定义中的插入序列将被忽略,并将其直接传递给输出缓冲区。 此标志对于获取稍后格式化的消息很有用。 如果设置了此标志,则忽略Arguments参数。
|
6.消息分流器:
对于系统带有的消息分流器HANDLE_MESSAGENAME,如HANDLE_WM_COMMAND、HANDLE_WM_HSCROLL等。本质上是使用函数指针实现。
#define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(LOWORD(wParam)), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L)
#define HANDLE_WM_HSCROLL(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L)
#define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L)
使用:
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
return HANDLE_WM_CREATE(hwnd, wParam, lParam, Cls_OnCreate); //Cls_OnCreate(HWND hwnd, LPCREATESTRUCT lParam)
case WM_PAINT:
return HANDLE_WM_PAINT(hwnd, wParam, lParam, Cls_OnPaint);
case WM_DESTROY:
return HANDLE_WM_DESTROY(hwnd, wParam, lParam, Cls_OnDestroy);
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
在《Windows核心编程》中作者使用如下宏
// The normal HANDLE_MSG macro in WindowsX.h does not work properly for dialog
// boxes because DlgProc return a BOOL instead of an LRESULT (like
// WndProcs). This chHANDLE_DLGMSG macro corrects the problem:
#define chHANDLE_DLGMSG(hwnd, message, fn) \
case (message): return (SetDlgMsgResult(hwnd, uMsg, \
HANDLE_##message((hwnd), (wParam), (lParam), (fn))))
而在<windowsx.h>中有宏HANDLE_MSG
#define HANDLE_MSG(hwnd, message, fn) \
case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))
在chHANDLE_DLGMSG中实际上是调用SetDlgMsgResult实现:
#define SetDlgMsgResult(hwnd, msg, result) (( \
(msg) == WM_CTLCOLORMSGBOX || \
(msg) == WM_CTLCOLOREDIT || \
(msg) == WM_CTLCOLORLISTBOX || \
(msg) == WM_CTLCOLORBTN || \
(msg) == WM_CTLCOLORDLG || \
(msg) == WM_CTLCOLORSCROLLBAR || \
(msg) == WM_CTLCOLORSTATIC || \
(msg) == WM_COMPAREITEM || \
(msg) == WM_VKEYTOITEM || \
(msg) == WM_CHARTOITEM || \
(msg) == WM_QUERYDRAGICON || \
(msg) == WM_INITDIALOG \
) ? (BOOL)(result) : (SetWindowLongPtr((hwnd), DWLP_MSGRESULT, (LPARAM)(LRESULT)(result)), TRUE))
对于SetWindowLongPtr在ASCII下:
#define SetWindowLongPtr SetWindowLongPtrA
#define SetWindowLongPtrA SetWindowLongA
WINUSERAPI LONG WINAPI SetWindowLongA(
_In_ HWND hWnd, //窗口句柄,间接给出窗口所属的类。
_In_ int nIndex, //指定将设定的大于等于0的偏移值。有效值的范围从0到额外类的存储空间的字节数减去一个整型的大小(-sizeof(int))。
要设置其他任何值,可以指定下面值之一:
_In_ LONG dwNewLong); //指定的替换值。
nlndex | 说明 |
---|---|
GWL_EXSTYLE |
设定一个新的扩展风格。更多信息,请见
CreateWindowEx。
|
GWL_STYLE | 设定一个新的窗口风格。 |
GWL_WNDPROC | 为窗口过程设置一个新的地址。 |
GWL_HINSTANCE | 设置一个新的应用程序实例句柄。 |
GWL_ID | 设置一个新的窗口标识符。 |
GWL_USERDATA |
设置与该窗口相关的用户数据。这些用户数据可以在程序创建该窗口时被使用。用户数据的初始值为0。
|
当hWnd参数标识了一个对话框时,也可使用下列值: | |
DWL_DLGPROC | 设置对话框过程的新地址。 |
DWL_MSGRESULT | 设置对话框中的消息处理程序的返回值。 |
DWL_USER | 设置的应用程序所私有的新的额外信息,例如句柄或指针。 |
DialogProc与WndProc的区别:
DialogProc與WndProc不同,前者要返回True或者False,後者成功時返回0。如果返回False,對話框管理器將處理消息。如果消息需要一個特定的返回值,必須在返回True之前調用SetWindowLong(hwndDlg, DWL_MSGRESULT, lResult)。
参考:点击打开链接