DirectX11--HR宏關於dxerr庫的替代方案

DirectX11 With Windows SDK完整目錄html

歡迎加入QQ羣: 727623616 能夠一塊兒探討DX11,以及有什麼問題也能夠在這裏彙報。git

綜述

參考文章:https://blogs.msdn.microsoft.com/chuckw/2012/04/24/wheres-dxerr-lib/github

在龍書11中所使用的HR宏和dxerr庫是一個比較實用的錯誤緣由追蹤工具。D3D中的某些函數擁有返回值HRESULT,經過dxerr庫,能夠將錯誤碼轉換成錯誤詳細信息的字符串。windows

在DirectX SDK中,包含了頭文件dxerr.h和庫文件dxerr.lib,在以往的作法包含了DX SDK後,就能夠直接使用dxerr了。但若是是要編寫基於Windows SDK的Direct3D程序,在Windows SDK 8.0以上已經沒有了dxerr庫。函數

此時此刻,你仍然有兩種選擇來脫離對DirectX SDK的依賴:工具

  1. 尋找較新的dxerr.hdxerr.cpp源碼來編譯出dxerr.lib,或者直接加入你的項目當中;
  2. 直接拋棄dxerr

新的dxerr源碼

微軟已經將dxerr庫開源了,下面的連接能夠下載,若是不放心的話,你也能夠到上面的參考文章去下載。測試

dxerr_nov2015.zip下載地址.net

在我以往的DirectX11項目中,則是從DXUT中拉過來的dxerr調試

DXUT Github/Corecode

但要注意的是,因爲新的dxerr.h僅提供了DXTrace的Unicode字符集版本,須要將原來的__FILE__替換爲__FILEW__,並在項目屬性頁中將字符集設置爲Unicode

拋棄dxerr庫

自Windows SDK 8.0起,HRESULT值關於DirectX圖形API的錯誤消息字符串映射已經加入到FormatMessage函數中。咱們能夠直接脫離對dxerr的依賴,並使用該函數來直接獲取錯誤消息字符串。所以,dxerr庫也就沒有必要在Windows SDK 8.0以上版本保留了。

FormatMessageW函數--獲取格式化消息字符串

鑑於咱們只是要獲取錯誤碼對應的字符串信息,這裏就簡單說起一下該函數的部分用法:

DWORD FormatMessageW(
  DWORD   dwFlags,          // [In]FORMAT_MESSAGE系列宏
  LPCVOID lpSource,         // [In]直接填NULL
  DWORD   dwMessageId,      // [In]傳入函數異常時返回的HRESULT
  DWORD   dwLanguageId,     // [In]語言ID
  LPTSTR  lpBuffer,         // [In]用於輸出消息字符串的緩衝區
  DWORD   nSize,            // [In]WCHAR緩衝區可容納元素個數
  va_list *Arguments        // [In]直接填NULL
);

DXTraceW函數

這裏我將dxerrDXTraceW函數的實現進行了修改,因爲如今錯誤碼信息爲中文,爲此也順便把錯誤窗口和輸出也漢化了。只須要包含Windows.hsal.h就可使用。
函數原型:

// ------------------------------
// DXTraceW函數
// ------------------------------
// 在調試輸出窗口中輸出格式化錯誤信息,可選的錯誤窗口彈出(已漢化)
// [In]strFile          當前文件名,一般傳遞宏__FILEW__
// [In]hlslFileName     當前行號,一般傳遞宏__LINE__
// [In]hr               函數執行出現問題時返回的HRESULT值
// [In]strMsg           用於幫助調試定位的字符串,一般傳遞L#x(可能爲NULL)
// [In]bPopMsgBox       若是爲TRUE,則彈出一個消息彈窗告知錯誤信息
// 返回值: 形參hr
HRESULT WINAPI DXTraceW(_In_z_ const WCHAR* strFile, _In_ DWORD dwLine, _In_ HRESULT hr, _In_opt_ const WCHAR* strMsg, _In_ bool bPopMsgBox);

函數實現:

HRESULT WINAPI DXTraceW(_In_z_ const WCHAR* strFile, _In_ DWORD dwLine, _In_ HRESULT hr,
    _In_opt_ const WCHAR* strMsg, _In_ bool bPopMsgBox)
{
    WCHAR strBufferFile[MAX_PATH];
    WCHAR strBufferLine[128];
    WCHAR strBufferError[300];
    WCHAR strBufferMsg[1024];
    WCHAR strBufferHR[40];
    WCHAR strBuffer[3000];

    swprintf_s(strBufferLine, 128, L"%lu", dwLine);
    if (strFile)
    {
        swprintf_s(strBuffer, 3000, L"%ls(%ls): ", strFile, strBufferLine);
        OutputDebugStringW(strBuffer);
    }

    size_t nMsgLen = (strMsg) ? wcsnlen_s(strMsg, 1024) : 0;
    if (nMsgLen > 0)
    {
        OutputDebugStringW(strMsg);
        OutputDebugStringW(L" ");
    }
    // Windows SDK 8.0起DirectX的錯誤信息已經集成進錯誤碼中,能夠經過FormatMessageW獲取錯誤信息字符串
    // 不須要分配字符串內存
    FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        nullptr, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        strBufferError, 256, nullptr);

    WCHAR* errorStr = wcsrchr(strBufferError, L'\r');   
    if (errorStr)
    {
        errorStr[0] = L'\0';    // 擦除FormatMessageW帶來的換行符(把\r\n的\r置換爲\0便可)
    }

    swprintf_s(strBufferHR, 40, L" (0x%0.8x)", hr);
    wcscat_s(strBufferError, strBufferHR);
    swprintf_s(strBuffer, 3000, L"錯誤碼含義:%ls", strBufferError);
    OutputDebugStringW(strBuffer);

    OutputDebugStringW(L"\n");

    if (bPopMsgBox)
    {
        wcscpy_s(strBufferFile, MAX_PATH, L"");
        if (strFile)
            wcscpy_s(strBufferFile, MAX_PATH, strFile);

        wcscpy_s(strBufferMsg, 1024, L"");
        if (nMsgLen > 0)
            swprintf_s(strBufferMsg, 1024, L"當前調用:%ls\n", strMsg);

        swprintf_s(strBuffer, 3000, L"文件名:%ls\n行號:%ls\n錯誤碼含義:%ls\n%ls您須要調試當前應用程序嗎?",
            strBufferFile, strBufferLine, strBufferError, strBufferMsg);

        int nResult = MessageBoxW(GetForegroundWindow(), strBuffer, L"錯誤", MB_YESNO | MB_ICONERROR);
        if (nResult == IDYES)
            DebugBreak();
    }

    return hr;
}

HR宏

如今的HR宏變成了這樣:

// ------------------------------
// HR宏
// ------------------------------
// Debug模式下的錯誤提醒與追蹤
#if defined(DEBUG) | defined(_DEBUG)
    #ifndef HR
    #define HR(x)                                               \
    {                                                           \
        HRESULT hr = (x);                                       \
        if(FAILED(hr))                                          \
        {                                                       \
            DXTraceW(__FILEW__, (DWORD)__LINE__, hr, L#x, true);\
        }                                                       \
    }
    #endif
#else
    #ifndef HR
    #define HR(x) (x)
    #endif 
#endif

測試效果以下:

在調試輸出窗口也能夠看到:

DirectX11 With Windows SDK完整目錄

歡迎加入QQ羣: 727623616 能夠一塊兒探討DX11,以及有什麼問題也能夠在這裏彙報。

相關文章
相關標籤/搜索