调用Windows函数时, 它会先验证传给它的参数,然后再开始执行任务。
如果传入的参数无效, 或者由于其他原因导致操作无法执行,则函数的返回值将指出函数因为某些原因失败了
PS: 通常情况下, 如果Windows函数能返回错误代码时,它会使用
线程本地存储区(thread-local storage)
的机制,将相应的错误代码和主调函数
关联到一起。这种机制使不同的线程能独立运行,不会出现相互干扰对方的错误代码的情况(线程本地存储区 后续再介绍)
调试程序时,使用监视相当有用
监视可以显示线程的上一个错误代码和错误的文本描述
具体操作是在Watch(监视)
窗口选择一行,然后输入$err,hr
, 可参考以下例子:
CreateFile
函数后,该函数的返回值是INVALID_HANDLE_VALUE(-1)
的一个HANDLE,表明函数调用失败了,该函数无法打开它指定的文件。Watch
窗口上,既指出了上一个错误代码为0x00000002,同时又指出了错误代码的文本描述系统找不到指定的文件(hr限定符的作用
)#include
#include
#include
int WINAPI _tWinMain(HINSTANCE hInstanceEex, HINSTANCE b, PTSTR pszCmd, int a)
{
HANDLE hFile = CreateFile(TEXT("c://Sdite"), 0, 0, NULL, OPEN_EXISTING, 0, NULL);
return(0);
}
DWORD GetLastError();
返回由上一个函数调用设置的线程的32位错误代码
该函数在WinError.h
头文件中
每个错误都有三种表示:
GetLastError
的返回值比较)注: Windows函数失败之后,应马上调用GetLastError
,因为假如又调用了另一个WIndows函数,则此值很有可能被改写。
成功调用Windows函数,返回值为ERROR_SUCCESS
DWORD FormatMessage(
DWORD dwFlags,
LPCVOID pSource,
DWORD dwLanguageId,
PTSTR pszBuffer,
DWORD nSIze,
Va_list *Arguments
) ;
ErrorShow.cpp
/******************************************************************************
Module: ErrorShow.cpp
Notices: Copyright (c) 2008 Jeffrey Richter & Christophe Nasarre
******************************************************************************/
#include "..\CommonFiles\CmnHdr.h" /* See Appendix A. */
#include
#include
#include "Resource.h"
///
#define ESM_POKECODEANDLOOKUP (WM_USER + 100)
const TCHAR g_szAppName[] = TEXT("Error Show");
///
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) {
chSETDLGICONS(hwnd, IDI_ERRORSHOW);
// Don't accept error codes more than 5 digits long
Edit_LimitText(GetDlgItem(hwnd, IDC_ERRORCODE), 5);
// Look up the command-line passed error number
SendMessage(hwnd, ESM_POKECODEANDLOOKUP, lParam, 0);
return(TRUE);
}
///
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) {
switch (id) {
case IDCANCEL:
EndDialog(hwnd, id);
break;
case IDC_ALWAYSONTOP:
SetWindowPos(hwnd, IsDlgButtonChecked(hwnd, IDC_ALWAYSONTOP)
? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
break;
case IDC_ERRORCODE:
EnableWindow(GetDlgItem(hwnd, IDOK), Edit_GetTextLength(hwndCtl) > 0);
break;
case IDOK:
// Get the error code
DWORD dwError = GetDlgItemInt(hwnd, IDC_ERRORCODE, NULL, FALSE);
HLOCAL hlocal = NULL; // Buffer that gets the error message string
// Use the default system locale since we look for Windows messages.
// Note: this MAKELANGID combination has 0 as value
DWORD systemLocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
// Get the error code's textual description
BOOL fOk = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, dwError, systemLocale,
(PTSTR) &hlocal, 0, NULL);
if (!fOk) {
// Is it a network-related error?
HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL,
DONT_RESOLVE_DLL_REFERENCES);
if (hDll != NULL) {
fOk = FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
hDll, dwError, systemLocale,
(PTSTR) &hlocal, 0, NULL);
FreeLibrary(hDll);
}
}
if (fOk && (hlocal != NULL)) {
SetDlgItemText(hwnd, IDC_ERRORTEXT, (PCTSTR) LocalLock(hlocal));
LocalFree(hlocal);
} else {
SetDlgItemText(hwnd, IDC_ERRORTEXT,
TEXT("No text found for this error number."));
}
break;
}
}
///
INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
case ESM_POKECODEANDLOOKUP:
SetDlgItemInt(hwnd, IDC_ERRORCODE, (UINT) wParam, FALSE);
FORWARD_WM_COMMAND(hwnd, IDOK, GetDlgItem(hwnd, IDOK), BN_CLICKED,
PostMessage);
SetForegroundWindow(hwnd);
break;
}
return(FALSE);
}
///
int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) {
HWND hwnd = FindWindow(TEXT("#32770"), TEXT("Error Show"));
if (IsWindow(hwnd)) {
// An instance is already running, activate it and send it the new #
SendMessage(hwnd, ESM_POKECODEANDLOOKUP, _ttoi(pszCmdLine), 0);
} else {
DialogBoxParam(hinstExe, MAKEINTRESOURCE(IDD_ERRORSHOW),
NULL, Dlg_Proc, _ttoi(pszCmdLine));
}
return(0);
}
End of File //
Resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by ErrorShow.rc
//
#define IDD_ERRORSHOW 101
#define IDI_ERRORSHOW 102
#define IDC_ERRORCODE 1000
#define IDC_ERRORTEXT 1001
#define IDC_ALWAYSONTOP 1002
#define IDC_STATIC (-1) // all static controls
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 104
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1005
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
CmnHdr.h
/******************************************************************************
Module: CmnHdr.h
Notices: Copyright (c) 2008 Jeffrey Richter & Christophe Nasarre
Purpose: Common header file containing handy macros and definitions
used throughout all the applications in the book.
See Appendix A.
******************************************************************************/
#pragma once // Include this header file once per compilation unit
Windows Version Build Option /
// = 0x0600 for VISTA level from sdkddkver.h
#define _WIN32_WINNT _WIN32_WINNT_LONGHORN
#define WINVER _WIN32_WINNT_LONGHORN
Unicode Build Option /
// Always compiler using Unicode.
#ifndef UNICODE
#define UNICODE
#endif
// When using Unicode Windows functions, use Unicode C-Runtime functions too.
#ifdef UNICODE
#ifndef _UNICODE
#define _UNICODE
#endif
#endif
/ Include Windows Definitions /
#pragma warning(push, 3)
#include
#pragma warning(pop)
#pragma warning(push, 4)
#include
#include // For _beginthreadex
/ Verify that the proper header files are being used //
#ifndef FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
#pragma message("You are not using the latest Platform SDK header/library ")
#pragma message("files. This may prevent the project from building correctly.")
#endif
// Allow code to compile cleanly at warning level 4 ///
/* nonstandard extension 'single line comment' was used */
#pragma warning(disable:4001)
// unreferenced formal parameter
#pragma warning(disable:4100)
// Note: Creating precompiled header
#pragma warning(disable:4699)
// function not inlined
#pragma warning(disable:4710)
// unreferenced inline function has been removed
#pragma warning(disable:4514)
// assignment operator could not be generated
#pragma warning(disable:4512)
// conversion from 'LONGLONG' to 'ULONGLONG', signed/unsigned mismatch
#pragma warning(disable:4245)
// 'type cast' : conversion from 'LONG' to 'HINSTANCE' of greater size
#pragma warning(disable:4312)
// 'argument' : conversion from 'LPARAM' to 'LONG', possible loss of data
#pragma warning(disable:4244)
// 'wsprintf': name was marked as #pragma deprecated
#pragma warning(disable:4995)
// unary minus operator applied to unsigned type, result still unsigned
#pragma warning(disable:4146)
// 'argument' : conversion from 'size_t' to 'int', possible loss of data
#pragma warning(disable:4267)
// nonstandard extension used : nameless struct/union
#pragma warning(disable:4201)
/ Pragma message helper macro /
/*
When the compiler sees a line like this:
#pragma chMSG(Fix this later)
it outputs a line like this:
c:\CD\CmnHdr.h(82):Fix this later
You can easily jump directly to this line and examine the surrounding code.
*/
#define chSTR2(x) #x
#define chSTR(x) chSTR2(x)
#define chMSG(desc) message(__FILE__ "(" chSTR(__LINE__) "):" #desc)
// chINRANGE Macro
// This macro returns TRUE if a number is between two others
#define chINRANGE(low, Num, High) (((low) <= (Num)) && ((Num) <= (High)))
/ chSIZEOFSTRING Macro
// This macro evaluates to the number of bytes needed by a string.
#define chSIZEOFSTRING(psz) ((lstrlen(psz) + 1) * sizeof(TCHAR))
/// chROUNDDOWN & chROUNDUP inline functions //
// This inline function rounds a value down to the nearest multiple
template
inline TV chROUNDDOWN(TV Value, TM Multiple) {
return((Value / Multiple) * Multiple);
}
// This inline function rounds a value down to the nearest multiple
template
inline TV chROUNDUP(TV Value, TM Multiple) {
return(chROUNDDOWN(Value, Multiple) +
(((Value % Multiple) > 0) ? Multiple : 0));
}
/ chBEGINTHREADEX Macro ///
// This macro function calls the C runtime's _beginthreadex function.
// The C runtime library doesn't want to have any reliance on Windows' data
// types such as HANDLE. This means that a Windows programmer needs to cast
// values when using _beginthreadex. Since this is terribly inconvenient,
// I created this macro to perform the casting.
typedef unsigned (__stdcall *PTHREAD_START) (void *);
#define chBEGINTHREADEX(psa, cbStackSize, pfnStartAddr, \
pvParam, dwCreateFlags, pdwThreadId) \
((HANDLE)_beginthreadex( \
(void *) (psa), \
(unsigned) (cbStackSize), \
(PTHREAD_START) (pfnStartAddr), \
(void *) (pvParam), \
(unsigned) (dwCreateFlags), \
(unsigned *) (pdwThreadId)))
// DebugBreak Improvement for x86 platforms ///
#ifdef _X86_
#define DebugBreak() _asm { int 3 }
#endif
/// Software Exception Macro //
// Useful macro for creating your own software exception codes
#define MAKESOFTWAREEXCEPTION(Severity, Facility, Exception) \
((DWORD) ( \
/* Severity code */ (Severity ) | \
/* MS(0) or Cust(1) */ (1 << 29) | \
/* Reserved(0) */ (0 << 28) | \
/* Facility code */ (Facility << 16) | \
/* Exception code */ (Exception << 0)))
/// Quick MessageBox Macro
inline void chMB(PCSTR szMsg) {
char szTitle[MAX_PATH];
GetModuleFileNameA(NULL, szTitle, _countof(szTitle));
MessageBoxA(GetActiveWindow(), szMsg, szTitle, MB_OK);
}
Assert/Verify Macros /
inline void chFAIL(PSTR szMsg) {
chMB(szMsg);
DebugBreak();
}
// Put up an assertion failure message box.
inline void chASSERTFAIL(LPCSTR file, int line, PCSTR expr) {
char sz[2*MAX_PATH];
wsprintfA(sz, "File %s, line %d : %s", file, line, expr);
chFAIL(sz);
}
// Put up a message box if an assertion fails in a debug build.
#ifdef _DEBUG
#define chASSERT(x) if (!(x)) chASSERTFAIL(__FILE__, __LINE__, #x)
#else
#define chASSERT(x)
#endif
// Assert in debug builds, but don't remove the code in retail builds.
#ifdef _DEBUG
#define chVERIFY(x) chASSERT(x)
#else
#define chVERIFY(x) (x)
#endif
/// chHANDLE_DLGMSG Macro /
// The normal HANDLE_MSG macro in WindowsX.h does not work properly for dialog
// boxes because DlgProc returns 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))))
Dialog Box Icon Setting Macro
// Sets the dialog box icons
inline void chSETDLGICONS(HWND hWnd, int idi) {
SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)
LoadIcon((HINSTANCE) GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
MAKEINTRESOURCE(idi)));
SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)
LoadIcon((HINSTANCE) GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
MAKEINTRESOURCE(idi)));
}
/// Common Linker Settings
#pragma comment(linker, "/nodefaultlib:oldnames.lib")
// Needed for supporting XP/Vista styles.
#if defined(_M_IA64)
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='IA64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#if defined(_M_X64)
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.6000.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#if defined(M_IX86)
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
/ End of File /