我需要开发一个专门的CLR探查器。CLR 探查器必须实现为实现 ICorProfilerCallback
的 COM 服务器或当前到 5 的较新版本。探查器初始化发生在回调方法Initialize(IUnknown* pICorProfilerInfoUnk)
中。这使人们有机会对提供的IUnknown
对象执行QueryInterface
并获取指向ICorProfilerInfo
接口的指针。从.NET 4.5开始,有ICorProfilerInfo
、ICorProfilerInfo2
、ICorProfilerInfo3
和ICorProfilerInfo4
,每个新版本都提供了额外的功能。理想情况下,我想获得指向最新可用版本的指针,并让 vtables 弄清楚真正的对象是什么。
if (FAILED(pICorProfilerInfoUnk->QueryInterface(IID_ICorProfilerInfo4, (LPVOID*)&m_pICorProfilerInfo)))
{
if (FAILED(pICorProfilerInfoUnk->QueryInterface(IID_ICorProfilerInfo3, (LPVOID*)&m_pICorProfilerInfo)))
{
if (FAILED(pICorProfilerInfoUnk->QueryInterface(IID_ICorProfilerInfo2, (LPVOID*)&m_pICorProfilerInfo)))
{
if (FAILED(pICorProfilerInfoUnk->QueryInterface(IID_ICorProfilerInfo, (LPVOID*)&m_pICorProfilerInfo)))
{
AtlTrace(TEXT("[Initialize] Failed to retrieve any ICorProfilerInfo~ interface."));
return S_FALSE;
}
}
}
}
请注意,在所有情况下,指向返回接口的指针都是同一个变量 m_pICorProfilerInfo
,其类型为 CComQIPtr<ICorProfilerInfo>
。然后,我调用它的方法,而不考虑实现该方法的对象的实际类型。
这让我想到两个问题:
- 在 COM/ATL 上下文中,检索派生接口,将它们存储在父接口中(如上所示),然后从中调用函数是否安全?
- 父接口显然不了解派生接口中的函数。如何检查指针是否是派生接口(例如
ICorProfilerInfo2
)并将其转换为派生接口?
在到目前为止的测试中,#1 通常看起来还可以。但我更喜欢确认或建议。我对#2点更加不确定。例如,ICorProfilerInfo
具有SetEnterLeaveFunctionHooks
函数,而ICorProfilerInfo2
具有SetEnterLeaveFunctionHooks2
函数。我想做一些类似于以下伪代码的事情:
if (m_pICorProfilerInfo IS ICorProfilerInfo2)
{
((ICorProfilerInfo2) m_pICorProfilerInfo)->SetEnterLeaveFunctionHooks2(...)
}
else
{
m_pICorProfilerInfo->SetEnterLeaveFunctionHooks(...)
}
关于如何做到这一点的任何建议将不胜感激。
1) 对于这些接口类型是可以的,它们被精心设计为始终继承以前的版本。 因此,ICorProfilerInfo4 的向量表包括了 3 个先前版本的所有方法。 对于COM接口来说,这当然不一定总是如此,但在这里有效。 这是危险的,当您获得ICorProfilerInfo3接口时调用ICorProfilerInfo4方法会使程序崩溃。 你不会从编译器那里得到任何帮助来让你远离麻烦。
2)C++中没有IS运算符,您可以通过再次调用QueryInterface()在COM中执行此操作。 或者,您可以设置一个变量来指示您获得的接口版本。 使用 QI 可以避免在版本检查错误时崩溃,并允许编译器帮助您正确获取代码。
我建议您首先对实际需要的分析器功能进行编目。 你面临着增加太多灵活性的危险,这种灵活性会让你编写你永远不会使用的代码,并发布一个未经充分测试的程序。 FunctionEnter2 和 FunctionEnter3 之间的差异并不微妙,但是两者都可以正常工作,您不太可能注意到优化。