簡體   English   中英

如何為Visual Studio 2012調試器編寫自定義本機可視化DLL?

[英]How to write a custom native visualizer DLL for Visual Studio 2012 debugger?

在C ++中為Visual Studio 2012調試器編寫自定義本機可視化DLL需要什么? 我想顯示一個只能根據需要從類/結構計算的值,因此需要一個本機可視化DLL。 Visual Studio 2012使用一種新方法來實現名為Natvis的本機可視化工具。 截至目前,關於Natvis的信息非常少,尤其是使用Natvis調用可視化DLL。 DLL將根據類/結構成員值計算顯示字符串。

這是包含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或工具提示顯示中為指定類型的每個實例(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的調試器輸出窗口中。 這些消息將顯示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-c​​an-i-do-with-them.aspx

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

對於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;
}

我需要一個與查找加載上述“NatvisAddIn.dll”的搜索路徑相關的澄清。 讓我試着通過擴展上面的例子來解釋

為了可視化我的自定義C ++類對象(比如說MyCustomeType),我需要在“DisplayString”的“Export”屬性中提到的函數(比如MyClassFormatter)的實現中調用一些額外的API(以計算MyCustomeType的顯示字符串)。 XML。

調用這些額外的API會在上面提到的“NatvisAddIn.dll”上創建一個庫/ dll依賴項。 如果這個額外的依賴只是一個或兩個庫,我可以將這些庫放在NatvisAddIn.dll所在的相同位置。 但是,在我的情況下,依賴包含一長串庫。

有人可以建議我一些優雅的方法來解決依賴關系而不將完整的庫鏈拉入%USERPROFILE%\\ My Documents \\ Visual Studio 2012 \\ Visualizers文件夾?

為了演示我的用例,讓我們考慮下面的依賴樹:NatvisAddIn.dll a.dll
a1.dll a2.dll a3.dll

我在一個NatvisAddIn.dll的相同位置復制了a.dll。 它依賴的dll(a1,a2和a3)出現在添加到PATH變量的位置。 當我嘗試在visual studio調試器中可視化MyCustomeType對象時,natvis diagonostic在輸出窗口中給出以下錯誤

Natvis:C:\\ Users \\ myUser \\ Documents \\ Visual Studio 2017 \\ Visualizers \\ mydata.natvis(9,6):錯誤:無法從C:\\ Users \\ myuser \\ Documents \\ Visual Studio 2017 \\ Visualizers \\ NatvisAddIn加載插件。類型為MyCustomeType的dll ::找不到指定的模塊。

我理解上面的錯誤,visual studio調試器無法解析a.dll(a1,a2和a3)的依賴關系,因此無法加載NatvisAddIn.dll

當我嘗試在我的testApplication中使用a.dll並為MyCustomeType計算DisplayString時,依賴項得到解析,加載了a.dll並且我得到了預期的out字符串而沒有復制a1.dll,a2.dll和a3.dll。 依賴的dll從窗口PATH變量中解析/拾取。 但是,在visual studio調試器的情況下,依賴DLL不會從PATH變量解析

正如依賴工具所確定的那樣,調試器無法解析的一些dll是:

api-ms-win-core-errorhandling-l1-1-0.dll api-ms-win-crt-time-l1-1-0.dll api-ms-win-crt-heap-l1-1-0。 DLL

其中一些dll存在visual studio安裝,其他存在於c:\\ windows \\ WinSxS中

我在visual studio 2012和visual studio 2017上嘗試了我的用例。我在視覺工作室中遇到了同樣的問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM