1. 错误处理 -> Windows核心编程【第五版】

新博客地址: vonsdite.cn

新博客地址: vonsdite.cn

文章目录

  • 新博客地址: vonsdite.cn
  • 新博客地址: vonsdite.cn
    • 1. 常见的Windows函数返回值数据类型
    • 2. 使用watch监视
    • 3. GetLastError函数
    • 4. FormatMessage函数
    • 5. 定义自己的错误代码
    • 6. ErrorShow 示例程序##
          • 如下主要介绍FormatMessage怎么使用

1. 常见的Windows函数返回值数据类型

  • 调用Windows函数时, 它会先验证传给它的参数,然后再开始执行任务

  • 如果传入的参数无效, 或者由于其他原因导致操作无法执行,则函数的返回值将指出函数因为某些原因失败了

  • 常见的Windows函数返回值数据类型
    1. 错误处理 -> Windows核心编程【第五版】_第1张图片

PS: 通常情况下, 如果Windows函数能返回错误代码时,它会使用线程本地存储区(thread-local storage)的机制,将相应的错误代码和主调函数关联到一起。这种机制使不同的线程能独立运行,不会出现相互干扰对方的错误代码的情况(线程本地存储区 后续再介绍

2. 使用watch监视

  • 调试程序时,使用监视相当有用

  • 监视可以显示线程的上一个错误代码错误的文本描述

  • 具体操作是在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);
}

1. 错误处理 -> Windows核心编程【第五版】_第2张图片

3. GetLastError函数

  • DWORD GetLastError();

  • 返回由上一个函数调用设置的线程的32位错误代码

  • 该函数在WinError.h头文件中

  • 一部分错误代码列表
    1. 错误处理 -> Windows核心编程【第五版】_第3张图片

  • 每个错误都有三种表示:

    1. 一个消息ID(一个可在源代码中使用的宏,用于与GetLastError的返回值比较)
    2. 消息文本(描述错误的英文文本)
    3. 一个编号
  • 注: Windows函数失败之后,应马上调用GetLastError,因为假如又调用了另一个WIndows函数,则此值很有可能被改写。

  • 成功调用Windows函数,返回值为ERROR_SUCCESS

4. FormatMessage函数

  • 该函数可将错误代码转换为相应的文本描述
 DWORD FormatMessage(
	 DWORD dwFlags,
	 LPCVOID pSource,
	 DWORD dwLanguageId,
	 PTSTR pszBuffer,
	 DWORD nSIze,
	 Va_list *Arguments
 ) ;
  • 支持多种语言(汉语、英语等)

5. 定义自己的错误代码

1. 错误处理 -> Windows核心编程【第五版】_第4张图片

6. ErrorShow 示例程序##

1. 错误处理 -> Windows核心编程【第五版】_第5张图片

  • 这个应用程序展示了调试器Watch窗口Error Lookup程序是如何工作的
  • 可以在该程序的编辑控件中输入任何错误代码, 单击Look up按钮即可查看相应的错误文本描述
如下主要介绍FormatMessage怎么使用

1. 错误处理 -> Windows核心编程【第五版】_第6张图片
1. 错误处理 -> Windows核心编程【第五版】_第7张图片
1. 错误处理 -> Windows核心编程【第五版】_第8张图片

  • 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 /

你可能感兴趣的:(windows核心编程)