2012-07-18 14 views
21

¿Qué se necesita para escribir una DLL de visualizador nativa personalizada en C++ para Visual Studio 2012 depurador? Quiero mostrar un valor que solo se puede calcular a partir de una clase/estructura bajo demanda, por lo tanto, se requiere una DLL del visualizador nativo. Visual Studio 2012 usa un nuevo método para implementar visualizadores nativos llamado Natvis. A partir de este momento, hay muy poca información correcta sobre Natvis y especialmente sobre el uso de Natvis para llamar a un visualizador DLL. La DLL calculará una cadena de visualización basada en los valores de los miembros de clase/estructura.Cómo escribir una DLL de visualizador nativa personalizada para Visual Studio 2012 depurador?

+0

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

+0

Eso es un gran post natvis, que también he mencionado más adelante, pero no tiene una palabra acerca de la escritura un visualizador nativo personalizado dll. Seré generoso y diré que es muy temprano en el juego para que Microsoft cubra todo el tema. – BSalita

Respuesta

38

Aquí está el código de C++ que comprende AddIn DLL. Llamé al archivo NatvisAddIn.cpp y el proyecto creó 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; 
} 

Aquí está el archivo .natvis el que Visual Studio 2012 depurador utiliza para visualizar el valor. Colóquelo en un archivo .natvis. Lo llamé NatvisAddIn.natvis. El archivo indica al depurador de VS 2012 que llame a NatvisAddIn.dll. El dll contiene dos llamadas al método visualizador; MyClassFormatter para formatear MyClass y MyStructFormatter para formatear MyStruct. El depurador mostrará el valor formateado del método en la pantalla Auto, Watch o Tooltip para cada instancia del tipo especificado (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> 

Place tanto el archivo NatvisAddIn.dll compilado y los archivos NatvisAddIn.natvis en una de las tres ubicaciones siguientes:

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

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

VS extension folders 

Usted tendrá que asegurarse de que existe la siguiente clave del Registro y el valor es 1:

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

"EnableNatvisDiagnostics" = dword: 00000001

Si todo va bien, se pueden ver natvis mensajes aparecen en la ventana de salida del depurador de Visual Studio. Los mensajes mostrarán si Natvis fue capaz de analizar los archivos .natvis. Los resultados de analizar cada archivo .natvis se muestran en la ventana de resultados. Si algo está mal, use el comando "dumpbin/exports" para verificar que los nombres de los métodos DLL coincidan exactamente con el tipo de archivo .navis =. Asegúrese también de que los archivos .dll y .natvis actuales se hayan copiado en el directorio apropiado.

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. 

Programa de prueba:

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

recursos de información:

\ 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

¿por qué esto se revocó? –

+1

Gracias por preguntar Hubo un par de votos negativos posiblemente porque no había rellenado todos los talones. Estaba agregando en tiempo real. Aprendí que debería completar la publicación en la publicación inicial, si es posible. La publicación ahora está completa, por lo que debería haber un montón de upvotes acumulando. – BSalita

+1

Primero, gracias por publicarlo, pero no creo que esto funcione para las aplicaciones de 64 bits. (DWORD se usa para la dirección, por ejemplo, y otras cosas). Además, ¿cómo podría uno hacer un complemento que de alguna manera se ocupe del código de 32 bits/64 bits del otro lado? – malkia

1

Para la versión de 64 bits de depuración, líneas siguientes deben utilizarse:

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

Por ejemplo anterior, la versión de 64 bits podría parecer esto:

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