2012-07-18 9 views
21

Cosa è necessario per scrivere una DLL di visualizzazione nativa personalizzata in C++ per Visual Studio 2012 debugger? Voglio visualizzare un valore che può essere calcolato solo da una classe/struct on-demand, quindi è necessario un visualizzatore nativo DLL. Visual Studio 2012 utilizza un nuovo metodo per l'implementazione di visualizzatori nativi chiamato Natvis. A partire da questo momento, ci sono pochissime informazioni corrette su Natvis e soprattutto sull'utilizzo di Natvis per chiamare un visualizzatore DLL. La DLL calcolerà una stringa di visualizzazione in base ai valori dei membri classe/struttura.Come scrivere una DLL di visualizzazione nativa personalizzata per Visual Studio 2012 debugger?

+0

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

+0

Questo è un grande post natvis, che ho anche detto di seguito, ma non ha una parola di scrittura una dll nativa per visualizzatori nativi. Sarò generoso e dirò che è troppo presto per Microsoft per coprire l'intero argomento. – BSalita

risposta

38

Ecco il codice C++ che comprende la DLL AddIn. Ho chiamato il file NatvisAddIn.cpp e il progetto ha creato 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; 
} 

Ecco il file .natvis utilizzato dal debugger di Visual Studio 2012 per visualizzare il valore. Inseriscilo in un file .natvis. L'ho chiamato NatvisAddIn.natvis. Il file indica al debugger di VS 2012 di chiamare NatvisAddIn.dll. La DLL contiene due chiamate al metodo di visualizzazione; MyClassFormatter per formattare MyClass e MyStructFormatter per formattare MyStruct. Il debugger mostrerà il valore formattato del metodo nel display Auto, Watch o tooltip per ogni istanza del tipo specificato (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> 

Posizionare sia il file NatvisAddIn.dll compilato ei file NatvisAddIn.natvis in una delle seguenti tre posizioni:

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

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

VS extension folders 

Sarà necessario assicurarsi che la seguente chiave del Registro di sistema esiste e il valore è 1:

[HKEY_CURRENT_USER \ Software \ Microsoft \ VisualStudio \ 11.0_Config \ Debugger]

"EnableNatvisDiagnostics" = dword: 00000001

Se tutto va bene, si vedrà natvis messaggi vengono visualizzati nella finestra del debugger di output di Visual Studio. I messaggi mostreranno se Natvis è stato in grado di analizzare i file .natvis. I risultati dell'analisi di ogni file .natvis sono mostrati nella finestra di output. Se qualcosa non funziona, utilizzare il comando "dumpbin/exports" per verificare che i nomi dei metodi DLL corrispondano esattamente al tipo = del file .navis. Assicurati inoltre che i file .dll e .natvis correnti siano stati copiati nella directory appropriata.

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. 

programma di test:

#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; 
} 

risorse Informazioni:

\ Xml \ schemas \ 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

perchè è stato downvoted? –

+1

Grazie per avermelo chiesto. C'erano un paio di downvotes forse perché non avevo compilato tutti gli stub. Stavo aggiungendo in tempo reale. Ho imparato che dovrei completare il post sul post iniziale, se possibile. Il post è ora completo, quindi dovrebbero esserci molti uptotes che si accumulano. – BSalita

+1

Innanzitutto grazie per averlo pubblicato, ma non penso che questo funzionerebbe per le app a 64 bit. (DWORD viene utilizzato per l'indirizzo, ad esempio, e altre cose). Inoltre, come si potrebbe fare un plugin che in qualche modo si occupa del codice a 32 bit/64 bit sull'altro lato? – malkia

1

per 64 bit versione di debug, righe seguenti devono essere utilizzati:

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

Per esempio precedente, la versione a 64 bit potrebbe sembrare questo:

#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; 
}