【问题标题】:CLR profiler: COM-style casting and calling functions from derived interfacesCLR 探查器:COM 风格的转换和从派生接口调用函数
【发布时间】:2013-11-21 07:19:10
【问题描述】:

我需要开发一个专门的 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>。然后我在其上调用方法,而忽略了实现该方法的对象的实际类型。

这引出了两个问题:

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

到目前为止,在测试中,#1 通常看起来没问题。但我更喜欢确认或建议。我对第 2 点更加不确定。例如,ICorProfilerInfo 具有 SetEnterLeaveFunctionHooks 函数,而 ICorProfilerInfo2 具有 SetEnterLeaveFunctionHooks2 函数。我想做类似下面的伪代码:

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

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

【问题讨论】:

    标签: c++ com atl clr-profiling-api


    【解决方案1】:

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

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

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

    【讨论】:

    • 感谢您的回复。我决定使用 CComQIPtr 并检查 NULL 来实现 IS / AS。关于灵活性的观点。尽管这可能仍将作为协助开发和 QA 的内部工具,但风险较小(尽管仍然很重要)。
    猜你喜欢
    • 1970-01-01
    • 2010-09-16
    • 2015-10-24
    • 1970-01-01
    • 2011-10-15
    • 1970-01-01
    • 1970-01-01
    • 2013-11-12
    • 2015-07-26
    相关资源
    最近更新 更多