2012-07-18 75 views
21

在C++中爲Visual Studio 2012調試器編寫自定義本機可視化器DLL需要什麼?我想顯示一個只能從類/結構按需計算的值,因此需要本地可視化DLL。 Visual Studio 2012使用一種新方法來實現稱爲Natvis的本機可視化器。到目前爲止,Natvis上的正確信息很少,特別是在使用Natvis調用可視化DLL時。該DLL將根據類/結構成員值計算顯示字符串。如何爲Visual Studio 2012調試器編寫自定義本機可視化器DLL?

+0

http://code.msdn.microsoft.com/windowsdesktop/Writing-type-visualizers-2eae77a2 – 2012-07-18 18:18:31

+0

這是一個偉大的natvis後,這也是我下面提到的,但它沒有關於寫一個字一個自定義的本地可視化工具DLL。我會慷慨地說,現在在微軟的遊戲中,爲了覆蓋整個話題還爲時過早。 – BSalita 2012-07-18 18:38:47

回答

38

這裏是包含AddIn DLL的C++代碼。我將文件命名爲NatvisAddIn.cpp,並且項目創建了NatvisAddIn.dll。

#include "stdafx.h" 
#include <iostream> 
#include <windows.h> 

#define ADDIN_API __declspec(dllexport) 

typedef struct tagDEBUGHELPER 
{ 
    DWORD dwVersion; 
    HRESULT (WINAPI *ReadDebuggeeMemory)(struct tagDEBUGHELPER *pThis, DWORD dwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot); 
    // from here only when dwVersion >= 0x20000 
    DWORDLONG (WINAPI *GetRealAddress)(struct tagDEBUGHELPER *pThis); 
    HRESULT (WINAPI *ReadDebuggeeMemoryEx)(struct tagDEBUGHELPER *pThis, DWORDLONG qwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot); 
    int (WINAPI *GetProcessorType)(struct tagDEBUGHELPER *pThis); 
} DEBUGHELPER; 

typedef HRESULT (WINAPI *CUSTOMVIEWER)(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t max, DWORD reserved); 

extern "C" ADDIN_API HRESULT MyClassFormatter(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t max, DWORD reserved); 
extern "C" ADDIN_API HRESULT MyStructFormatter(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t max, DWORD reserved); 

class MyClass 
{ 
public: 
    int publicInt; 
}; 

struct MyStruct { int i; }; 

ADDIN_API HRESULT MyClassFormatter(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t max, DWORD reserved) 
{ 
    MyClass c; 
    DWORD nGot; 
    pHelper->ReadDebuggeeMemory(pHelper,dwAddress,sizeof(MyClass),&c,&nGot); 
    sprintf_s(pResult,max,"Dll MyClass: max=%d nGot=%d MyClass=%x publicInt=%d",max,nGot,dwAddress,c.publicInt); 
    return S_OK; 
} 

ADDIN_API HRESULT MyStructFormatter(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t max, DWORD reserved) 
{ 
    MyStruct s; 
    DWORD nGot; 
    pHelper->ReadDebuggeeMemory(pHelper,dwAddress,sizeof(MyStruct),&s,&nGot); 
    sprintf_s(pResult,max,"Dll MyStruct: max=%d nGot=%d MyStruct=%x i=%d",max,nGot,dwAddress,s.i); 
    return S_OK; 
} 

這是Visual Studio 2012調試器用來顯示值的.natvis文件。將它放在.natvis文件中。我將它命名爲NatvisAddIn.natvis。該文件指示VS 2012調試器調用NatvisAddIn.dll。該dll包含兩個可視化器方法調用; MyClassFormatter格式化MyClass和MyStructFormatter以格式化MyStruct。調試器將在Auto,Watch或tooltip顯示中爲每個指定類型的實例(MyClass,MyStruct)顯示方法的格式化值。

<?xml version="1.0" encoding="utf-8"?> 
    <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> 
    <Type Name="MyClass"> 
     <DisplayString LegacyAddin="NatvisAddIn.dll" Export="MyClassFormatter"></DisplayString> 
    </Type> 
    <Type Name="MyStruct"> 
     <DisplayString LegacyAddin="NatvisAddIn.dll" Export="MyStructFormatter"></DisplayString> 
    </Type> 
</AutoVisualizer> 

地方都編譯NatvisAddIn.dll文件和文件NatvisAddIn.natvis分爲以下三個位置之一:

%VSINSTALLDIR%\Common7\Packages\Debugger\Visualizers (requires admin access) 

%USERPROFILE%\My Documents\Visual Studio 2012\Visualizers\ 

VS extension folders 

您將需要確保以下注冊表項存在和價值1:

[HKEY_CURRENT_USER \軟件\微軟\ VisualStudio的\ 11.0_Config \調試]

「EnableNatvisDiagnostics」= dword:00000001

如果一切順利,您將看到natvis消息出現在Visual Studio的調試器Output窗口中。這些消息將顯示Natvis是否能夠解析.natvis文件。在輸出窗口中顯示解析每個.natvis文件的結果。如果出現錯誤,請使用命令「dumpbin/exports」仔細檢查DLL方法的名稱是否與.navis文件的Type =完全匹配。還要確保當前的.dll和.natvis文件已被複制到相應的目錄中。

Natvis: Parsing natvis xml file: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\Visualizers\atlmfc.natvis. 
Natvis: Done parsing natvis xml file: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\Visualizers\atlmfc.natvis. 
Natvis: Parsing natvis xml file: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\Visualizers\concurrency.natvis. 
Natvis: Done parsing natvis xml file: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\Visualizers\concurrency.natvis. 
Natvis: Parsing natvis xml file: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\Visualizers\NatvisAddIn.natvis. 
Natvis: Done parsing natvis xml file: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\Visualizers\NatvisAddIn.natvis. 
Natvis: Parsing natvis xml file: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\Visualizers\stl.natvis. 
Natvis: Done parsing natvis xml file: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\Visualizers\stl.natvis. 
Natvis: Parsing natvis xml file: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\Visualizers\windows.natvis. 
Natvis: Done parsing natvis xml file: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\Visualizers\windows.natvis. 
Natvis: Parsing natvis xml file: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\Visualizers\winrt.natvis. 
Natvis: Done parsing natvis xml file: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Packages\Debugger\Visualizers\winrt.natvis. 

測試程序:

#include "stdafx.h" 
#include <iostream> 

class MyClass 
{ 
public: 
    int publicInt; 
}; 

struct MyStruct { int i; }; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    struct MyStruct s = {1234}; 
    std::cout << s.i << std::endl; 
    MyClass *c = new MyClass; 
    c->publicInt = 1234; 
    std::cout << c->publicInt << std::endl; 
    return 0; 
} 

信息資源:

\ XML \架構\ natvis。XSD

http://code.msdn.microsoft.com/windowsdesktop/Writing-type-visualizers-2eae77a2

http://blogs.msdn.com/b/mgoldin/archive/2012/06/06/visual-studio-2012-and-debugger-natvis-files-what-can-i-do-with-them.aspx

http://blogs.msdn.com/b/vcblog/archive/2012/07/12/10329460.aspx

+0

爲什麼這會得到downvoted? – 2012-07-18 17:00:25

+1

感謝您的詢問。有一些情況可能是因爲我沒有填寫所有的存根。我正在實時添加。我瞭解到,如果可能的話,我應該在最初的帖子上填寫帖子。該帖子現在已完成,因此應該有很多upvotes堆積英寸 – BSalita 2012-07-18 17:56:54

+1

首先感謝張貼它,但我不認爲這將適用於64位應用程序。 (DWORD用於地址和其他東西)。另外,如何讓一個插件以某種方式處理另一端的32位/ 64位代碼? – malkia 2013-02-15 18:36:30

1

對於64位版本的調試,應使用以下行:

auto realAddress = pHelper->GetRealAddress(pHelper); 
pHelper->ReadDebuggeeMemoryEx(pHelper, realAddress, sizeof(MyClass), &c, &nGot); 

對於前面的例子中,64位版本可能看起來像這個:

#include "stdafx.h" 
#include <iostream> 
#include <windows.h> 

#define ADDIN_API __declspec(dllexport) 

typedef struct tagDEBUGHELPER 
{ 
    DWORD dwVersion; 
    HRESULT (WINAPI *ReadDebuggeeMemory)(struct tagDEBUGHELPER *pThis, DWORD dwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot); 
    // from here only when dwVersion >= 0x20000 
    DWORDLONG (WINAPI *GetRealAddress)(struct tagDEBUGHELPER *pThis); 
    HRESULT (WINAPI *ReadDebuggeeMemoryEx)(struct tagDEBUGHELPER *pThis, DWORDLONG qwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot); 
    int (WINAPI *GetProcessorType)(struct tagDEBUGHELPER *pThis); 
} DEBUGHELPER; 

typedef HRESULT (WINAPI *CUSTOMVIEWER)(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t max, DWORD reserved); 

extern "C" ADDIN_API HRESULT MyClassFormatter(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t max, DWORD reserved); 

class MyClass 
{ 
public: 
    int publicInt; 
}; 

ADDIN_API HRESULT MyClassFormatter(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t max, DWORD reserved) 
{ 
    MyClass c; 
    DWORD nGot; 
    auto realAddress = pHelper->GetRealAddress(pHelper); 
    pHelper->ReadDebuggeeMemoryEx(pHelper, realAddress, sizeof(MyClass), &c, &nGot); 
    sprintf_s(pResult,max,"Dll MyClass: max=%d nGot=%d MyClass=%llx publicInt=%d",max, nGot, realAddress, c.publicInt); 
    return S_OK; 
} 
相關問題