《Windows核心编程》读书笔记零 构建环境

来源:互联网 发布:java cova spank bang 编辑:程序博客网 时间:2024/06/07 01:26

Solution配置

建立一个Solution将每个project加入此Solution

确保输出目录在同一个目录下



C/C++ ->Code Generation -> Runtime Library 选择多线程的版本



C/C++ 检测64位可移植性  (/Wp64)  在VS2013中此选项已经移除。想启用此选项需要自行增加命令行参数 WP64 在VS2013中32位应用已经不再支持此选项。


CmnHdr.h头文件


包含宏定义,链接参数等。


Microsoft Windows Version 构建选项

_WIN32_WINNT 和 WINVER   = 0x600 表示windows VISTA

// = 0x0600 for VISTA level from sdkddkver.h#define _WIN32_WINNT _WIN32_WINNT_LONGHORN #define WINVER       _WIN32_WINNT_LONGHORN 

因为在VISTA中 CreateMutexExW 需要windows版本在Vista以上才支持

#if (_WIN32_WINNT >= 0x0600)#pragma region Application Family#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)#define CREATE_MUTEX_INITIAL_OWNER  0x00000001WINBASEAPI_Ret_maybenull_HANDLEWINAPICreateMutexExA(    _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,    _In_opt_ LPCSTR lpName,    _In_ DWORD dwFlags,    _In_ DWORD dwDesiredAccess    );WINBASEAPI_Ret_maybenull_HANDLEWINAPICreateMutexExW(    _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,    _In_opt_ LPCWSTR lpName,    _In_ DWORD dwFlags,    _In_ DWORD dwDesiredAccess    );
如果不加入此定义则会可能导致编译错误。


Unicode构建选项


默认开启Unicode

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

Windows Definitions与编译警告级别4

常用代码使用最高警告级别。

因为微软设计的Windows.h使用了很多对标准C的扩展,设置警告级别为3。


///////////////////////// Include Windows Definitions /////////////////////////#pragma warning(push, 3)#include <Windows.h>#pragma warning(pop) #pragma warning(push, 4)#include <CommCtrl.h>#include <process.h>       // For _beginthreadex



pragma message 辅助宏

#pragma message("fix this later")

这样在编译时会提示一串文字,提醒我们在某个地方还有一些工作要做。

使用自定义宏 

#pragma chMsg(Fix this later)

编译器会提示

1>------ Build started: Project: ErrorShow, Configuration: Debug Win32 ------1>  ErrorShow.cpp1>  c:\users\admin\documents\visual studio 2013\windowsviacpp\errorshow\errorshow\errorshow.cpp(19):fix this later1>  ErrorShow.vcxproj -> C:\Users\admin\Documents\Visual Studio 2013\WindowsViaCPP\ErrorShow\Debug\ErrorShow.exe========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========


chlNRANGE 宏

用于判断一个值是否处于两个值之间

// This macro returns TRUE if a number is between two others#define chINRANGE(low, Num, High) (((low) <= (Num)) && ((Num) <= (High)))



chBEGINTHREADEX宏

本书采用Microsoft C/C++的运行库 _beginthreadex来开启线程而不是windows系统函数CreateThread。

因为此beginthread运行C++运行库来初始化一个新线程,并且在线程返回时,为每一个新线程所分配的C/C++运行库信息快都能得到销毁

_beginthreadex定义

_CRTIMP uintptr_t __cdecl _beginthreadex(     _In_opt_ void * _Security,     _In_ unsigned _StackSize,    _In_ unsigned (__stdcall * _StartAddress) (void *),     _In_opt_ void * _ArgList,    _In_ unsigned _InitFlag,     _Out_opt_ unsigned * _ThrdAddr);
CreateThread定义
HANDLEWINAPICreateThread(    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,    _In_ SIZE_T dwStackSize,    _In_ LPTHREAD_START_ROUTINE lpStartAddress,    _In_opt_ __drv_aliasesMem LPVOID lpParameter,    _In_ DWORD dwCreationFlags,    _Out_opt_ LPDWORD lpThreadId    );


因为C/C++开发团队不想对windows操作系统开发团队有任何依赖,而没有用大量的平台相关的数据类型。(作者赞同C++团队的决定,尽管这样_beginthreadex 用起来会更加困难)

但是某些参数类型会使得编译器发出警告。比如unsigned  和 DWORD

返回值 long 和handle

因此cmmhdr定义了宏  chBEGINTHREADEX来进行相关数据的转换操作,防止编译器警告。

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)))


适用于x86平台的对DebugBreak的改进

某些情况下,即便进程不是通过调试器来启动的,我也希望它能按照我们的意愿停留在某一个断点。在Windows平台上,可以在一个线程调用DebugBreak函数来实现这个功能。这个kernel32.dll中的函数可以让我们attach一个调试器到进程。一旦attach到进程,指令指针(IP)就会停在那条激发断点的cpu指令。因为这条就是kernell32.dll中的DebugBreak指令,所以为了继续运行我们不得不在调试器中单步调试跳出DebugBreak函数


在x86处理器上,其实可以通过执行一条“int 3”使得cpu产生一个断点。作者通过内嵌int 3中断重新定义了一个DebugBreak函数。但执行DebugBreak的时候,系统并没有执行Kernell32.dll里的代码。这样单每次程序执行到断点的时候,CS:IP执像的就是DebugBreak的下一条代码。


////////////////// DebugBreak Improvement for x86 platforms ///////////////////#ifdef _X86_   #define DebugBreak()    _asm { int 3 }#endif


创建软件异常码

使用MAKESOFTWAREEXCEPTION宏

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


chMB宏

弹出一个消息框,消息框的标题是调用进程对应可执行文件的完整路径的名称。

/////////////////////////// Quick MessageBox Macro ////////////////////////////inline void chMB(PCSTR szMsg) {   char szTitle[MAX_PATH];   GetModuleFileNameA(NULL, szTitle, _countof(szTitle));   MessageBoxA(GetActiveWindow(), szMsg, szTitle, MB_OK);}

chASSERT和chVERIFY宏

判断一个Assert断言。仅在Debug下有效

chVERIFY在debug和release下都有效。

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

Message Cracker, 不应该使用HANDLE_MSG 因为其不会返回TRUE 或 FALSE

使用chHANDLE_DLGMSG能对消息的返回值进行处理,适用在对话框过程中调用。

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


chSETDLGICONS宏

在对话框接收到WM_INITDIALOG消息的时候调用chSETDLGICONS来设置图标

//////////////////////// Dialog Box Icon Setting Macro ////////////////////////// Sets the dialog box iconsinline 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)));}


强制编译器寻找wWinMain入口函数

Solution设置控制台默认入口函数是 (w)main

而GUI程序默认入口函数是 _tWinMain

cmmhdr.h中使用了一条pragma强制寻找WinMain入口函数


通过pragma预处理指令来支持XP风格的用户界面主题

Microsoft提供了一个manifestdependency选项默认支持xp+ style的风格

原创粉丝点击