EEAddIn 示例:调试表达式计算器外接程序
更新:2007 年 11 月
EEAddin 示例演示了如何使用“表达式计算器外接程序 API”来扩展本机调试器表达式计算器。
安全说明: |
---|
提供该示例代码是为了阐释一个概念,并不代表着最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,Microsoft 不承担任何责任。 |
获取示例和安装示例的说明:
在 Visual Studio 的“帮助”菜单上,单击“示例”。
有关更多信息,请参见定位示例文件。
示例的最新版本和完整列表可以从 Visual Studio 2008 Samples page(Visual Studio 2008 示例页面)联机获取。
还可以在计算机的硬盘上查找示例。默认情况下,示例和自述文件将复制到 \Program Files\Visual Studio 9.0\Samples\ 下的文件夹中。对于 Visual Studio 速成版,所有示例都位于联机位置。
EE 外接程序 API
表达式计算器是调试器的一部分,它解释(计算)表达式。在调试器窗口中键入表达式或在表达式上设置断点时,表达式计算器即对输入进行解释。有关详细信息,请参见调试器中的表达式。使用“表达式计算器外接程序 API”,可以扩展表达式计算器以处理新类型。
若要为新类型扩展表达式计算器,需要在 Win32 DLL(与 autoexp.dat 在同一目录中)中编写一个函数,然后按名称将其导出。还需要向 autoexp.dat 文件添加一行。可以通过从 DLL 导出多个函数来为多种类型扩展表达式计算器。
生成并运行示例
生成并运行此示例所需的步骤分为三部分。
生成并运行此示例
生成表达式计算器外接程序 DLL (eeaddin.dll)。
编辑 autoexp.dat 以使用表达式计算器外接程序 DLL。
通过创建一个项目来测试外接程序,该项目使用由 autoexp.dat 计算的自定义数据类型。
以下过程对这些步骤进行了详细介绍。
生成表达式计算器外接程序 DLL
在 Visual Studio 中,打开解决方案 eeaddin.sln。
从“生成”菜单中,单击“生成”。
将生成的 eeaddin.dll 复制到 common7\ide 目录(包含 devenv.exe 的同一目录)。
从**“文件”**菜单中,单击“关闭解决方案”。
编辑 autoexp.dat
从**“文件”菜单中,指向“打开”,然后单击“文件”**。
在“打开文件”对话框中,找到文件 autoexp.dat(在 common7\packages\debugger 目录中),然后单击**“打开”**。
编辑 autoexp.dat 以添加下面的行:
_SYSTEMTIME=$ADDIN(eeaddin.dll,AddIn_SystemTime@28) _FILETIME=$ADDIN(eeaddin.dll,AddIn_FileTime@28)
保存 autoexp.dat。
创建使用自定义数据类型的项目
从**“文件”菜单中,指向New,然后单击“项目”**。
在“新建项目”对话框中,突出显示“Visual C++ 项目”,单击“MFC 应用程序”,输入项目的名称,然后单击“确定”。
在**“MFC 应用程序向导”中,单击“完成”**。项目必须是 MFC 应用程序,这是因为在下一步骤中,将要添加 MFC 函数。
在 MFC 应用程序中,添加一个 SYSTEMTIME 或 FILETIME 对象。
SYSTEMTIME *s = new SYSTEMTIME(); FILETIME *f = new FILETIME(); GetSystemTime(s); SystemTimeToFileTime(s,f);
从“生成”菜单中,单击“生成”。
开始调试,并在监视窗口中检查 SYSTEMTIME 对象或 FILETIME 对象。
示例的工作机制
若要为自定义数据类型扩展表达式计算器,请在表达式计算器外接程序 DLL 中编写自定义查看器函数。该函数使用一个指针,该指针指向正在调试的程序的内存空间(而非要扩展的表达式计算器的内存空间)中的一个对象。不能对该指针应用普通强制转换。必须使用回调函数读取它和它所指向的数据。DEBUGHELPER* 类型的回调指针指向具有多个方法的对象。
语法如下所示:
HRESULT WINAPI CustomViewer(
DWORD dwAddress, // low 32-bits of address
DEBUGHELPER *pHelper, // callback pointer to access helper functions
int nBase, // decimal or hex
BOOL bIgnore, // not used
char *pResult, // where the result needs to go
size_t max, // how large the above buffer is
DWORD dwReserved // always pass zero
)
该示例有这一类型的函数的两个实现:timeaddin.cpp 中的 AddIn_SystemTime 和 AddIn_FileTime。DEBUGHELPER 结构(在 custview.h 中定义)包含可用来编写扩展的函数指针。该指针传递给 CustomViewer 函数,您可以使用它来调用 Helper 函数。
可以使用 pHelper->GetProcessorType 来获取处理器类型。有两种读取内存的方法:pHelper->ReadDebuggeeMemory 和 pHelper->ReadDebuggeeMemoryEx。ReadDebuggeeMemoryEx 处理 64 位地址且受 Visual Studio .NET 调试器支持。ReadDebuggeeMemory 不处理 64 位地址,Visual Studio .NET 和 Visual C++ 6.0 调试器都支持这种方法。如果您的外接程序只能用于 Visual Studio .NET 调试器,则可以使用 ReadDebuggeeMemoryEx。如果您的外接程序也需要与 Visual C++ 6.0 一起使用,则必须检查 dwVersion 字段,并对 Visual C++ 6.0 避免调用 ReadDebuggeeMemoryEx。
下面的代码可以与两种调试器一起使用,并从正在调试的程序中读取 localobject(其类型为 MyType)的内容:
DWORDLONG qwRealAddress;
DWORD dwGot;
MyType localobject;
if (pHelper->dwVersion<0x20000)
{
// Visual C++ 6.0 version
qwRealAddress = dwAddress;
pHelper->ReadDebuggeeMemory( pHelper, dwAddress,
sizeof(localobject), &localobject, &dwGot );
}
else
{
qwRealAddress = pHelper->GetRealAddress(pHelper);
pHelper->ReadDebuggeeMemoryEx( pHelper, qwRealAddress,
sizeof(localobject), &localobject, &dwGot );
}
// TODO: display localobject here
编辑 autoexp.dat
在 autoexp.dat 的 [AutoExpand] 节中,将添加的行具有以下语法:
type=$ADDIN(dllname.dll,exportname)
例如:
_SYSTEMTIME=$ADDIN(eeaddin.dll,AddIn_SystemTime)
或:
_FILETIME=$ADDIN(eeaddin.dll,AddIn_FileTime)
如果 DLL 不在包含 devenv.exe 的目录中或 PATH 上,则必须使用 DLL 的完整路径名称。exportname 参数区分大小写,必须与在 DLL 上运行 dumpbin ¨Cexports 时所获得的导出名称完全匹配。
若要使用新外接程序测试调试器,请首先停止调试在安装新 DLL 时正在调试的所有程序,然后启动新的调试器会话。
注意 外接程序在调试器内运行,因此如果您代码出现故障,IDE 将崩溃。