3

我需要开发一个专门的 CLR 分析器。CLR 探查器必须作为 COM 服务器实现ICorProfilerCallback或当前最高 5 的较新版本来实现。探查器初始化发生在回调方法Initialize(IUnknown* pICorProfilerInfoUnk)中。这使人们有机会对QueryInterface提供的IUnknown对象执行操作并获得指向ICorProfilerInfo接口的指针。从 .NET 4.5 开始,有ICorProfilerInfoICorProfilerInfo2ICorProfilerInfo3ICorProfilerInfo4,每个新版本都提供附加功能。理想情况下,我想获得一个指向最新可用版本的指针,并让 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>。然后我在它上面调用方法,而忽略了实现该方法的对象的实际类型。

这让我想到了两个问题:

  1. 在 COM / ATL 上下文中,检索派生接口,将它们存储在上述父接口中,然后从中调用函数是否安全?
  2. 父接口显然不知道派生接口中的功能。如何检查指针是否是派生接口(例如ICorProfilerInfo2)并将其转换为此类?

在到目前为止的测试中,#1 通常看起来还可以。但我更愿意确认或建议。我对第 2 点更加不确定。例如,ICorProfilerInfo有一个SetEnterLeaveFunctionHooks功能,而ICorProfilerInfo2有一个SetEnterLeaveFunctionHooks2功能。我想做类似下面的伪代码:

if (m_pICorProfilerInfo IS ICorProfilerInfo2)
{
    ((ICorProfilerInfo2) m_pICorProfilerInfo)->SetEnterLeaveFunctionHooks2(...)
}
else
{
    m_pICorProfilerInfo->SetEnterLeaveFunctionHooks(...)
}

任何关于如何实现这一点的建议将不胜感激。

4

1 回答 1

2

1) 对于这些接口类型是可以的,它们被设计为始终继承以前的版本。所以ICorProfilerInfo4的v-table包含了之前3个版本的所有方法。对于 COM 接口,这当然不一定总是如此,但在这里有效。很危险,在获取 ICorProfilerInfo3 接口时调用 ICorProfilerInfo4 方法会使程序崩溃。您无法从编译器那里得到帮助来避免麻烦。

2) C++ 中没有 IS 运算符,您可以在 COM 中通过再次调用 QueryInterface() 来实现。或者您可以设置一个变量来指示您获得的接口版本。使用 QI 可以避免在版本检查错误时发生崩溃,并且确实允许编译器帮助您正确编写代码。

我建议您首先对您实际需要的分析器功能进行分类。你有增加太多灵活性的危险,这种灵活性会让你编写你永远不会使用的代码,并发布一个没有经过全面测试的程序。FunctionEnter2 和 FunctionEnter3 之间的区别并不细微,但是两者都可以正常工作,而且您不太可能注意到优化。

于 2013-11-09T12:08:58.807 回答