【问题标题】:Is it safe to use C++ "operator new" rather than CoCreateinstance to create a COM object?使用 C++“operator new”而不是 CoCreateinstance 创建 COM 对象是否安全?
【发布时间】:2012-10-14 16:54:12
【问题描述】:

这可能是一个新手 COM 问题,但在谷歌上搜索会引发比提供答案更多的问题:

对本地 COM 实例使用“operator new”而不是 CoCreateInstance 是否安全?

我做了什么:

  1. 我实现了 IOperationsProgressDialog 接口 http://msdn.microsoft.com/en-us/library/windows/desktop/bb775368(v=vs.85).aspx 通过使用公共继承,从而还实现了 IUnknown 接口。

  2. 我通过“new RecyclerProgressCallback”创建了一个实例,并将其放入 COM-Ptr 中进行生命周期管理。 “RecyclerProgressCallback”是我的派生类的名称。

  3. 我在 IFileOperation::SetProgressDialog 中使用这个实例 http://msdn.microsoft.com/en-us/library/windows/desktop/bb775803(v=vs.85).aspx

总结:我的方法“似乎”有效,但我不相信它,关于 COM 对象创建的令人不安的信息太多,无法仅依赖于可观察的行为。

是否存在任何微妙的风险、谬误或其他问题?谢谢!

【问题讨论】:

    标签: c++ com


    【解决方案1】:

    我什至把它们放在了堆栈上。 Andrey 的回答(现已删除)错误地暗示它不安全,因为您绕过了 COM 引用计数。这是错误的推理。 COM 不计算引用;它将责任委托给您。在 COM 在其最后一个接口上调用您的 Release 方法之后,您必须调用 deletefree() 或任何您使用的语言。重要的词是之后。不是何时,因为您没有义务立即这样做。

    同样,CoCreateInstance 是一个很长的弯路,因为 COM 是语言中立的,并且不知道是否必须使用 mallocnew 创建对象。你这样做了,所以绕过整个 COM 逻辑。

    【讨论】:

    • > 只是绕过整个 COM 逻辑。这是我希望听到的!从长远来看,注册新的 COM 对象不仅在 Visual C++ Express 中很痛苦,而且还会破坏我的应用程序的“可移植性”。
    • 好吧,您仍然必须正确实现IUnknown,因为这是您承诺的IOperationsProgressDialog 接口的一部分。例如。你的IOperationsProgressDialog::QueryInterface(IID_IUnknown) 必须成功等等。
    • 是的,我做到了。好在 IUnknown 是一个抽象基类,所以我只在实现 IOperationsProgressDialog 后注意到编译器错误。所以,整个过程,只是普通的 C++ 虚函数实现……这比我对 COM 的预期要简单,这让我很怀疑。
    • @Zenju,COM 作为一个整体是极其复杂的,因为它试图解决所有世界上的问题。虽然它的核心非常简单,尤其是在 C++ 中。
    • @zett42:如问题中所述,一个示例是对话框的回调接口。关闭对话框,不再有回调。
    【解决方案2】:

    这取决于您具体实例化的内容。当你应该提供一个 COM 指针时,没有人会问你它是用 COM API 还是 new 实例化,或者它有时甚至可以是堆栈上的对象(前提是你设法确保在所有引用之前它不会在堆栈上销毁被释放)。

    所以答案是肯定的,你可以使用new 就可以了。但是,无论如何它应该是一个有效的 COM 接口,它应该像 COM 对象那样实现引用计数和QueryInterface

    【讨论】:

      【解决方案3】:

      CoCreateInstance API 将查看registry 找到匹配指定CLSID 的模块,加载它并通过一种机制(取决于您的代码是DLL 还是EXE)它会调用一些创建对象的函数。因此,为了使CoCreateInstance 工作,您应该编写一个类来实现COMIClassFactory 接口并将其注册到注册表中,然后调用CoCreateInstance 与您一起做一些额外的工作代码至少做你可爱的operator new,然后是的,当然它是安全的。一般来说,在您的代码中调用source 接口(仅声明用于回调的接口)的实现总是安全的,这也是首选方式。

      【讨论】:

        【解决方案4】:

        这会很好。这就是 COM 服务器通常在内部创建其对象的方式(至少一个用 C++ 编写的)。从您的角度来看,RecyclerProgressCallback 类只是一些 C++ 代码。您可以将其视为程序中的任何其他类。

        话虽如此,COM 是一个充满微妙陷阱的雷区。我不能保证你的课程不会遇到问题,但我可以向你保证,这些问题与你对 operator new 的使用无关。

        【讨论】:

          【解决方案5】:

          这通常是不安全的,不仅仅是因为引用计数,还因为编组:类可能有一个需要编组的线程模型。如果是这种情况,CoCreateInstance 将创建一个代理和存根,而 new 不会。

          【讨论】:

          • 这不是真的。您将公开接口和 COM 对象,它们将由 COM 以同样安全的方式封送。
          • 没有。如果该类需要编组,则从 CoCreateInstance 获得的是代理对象,而不是对象本身。 new 永远不会发生这种情况。
          • 你无缘无故地把事情弄得一团糟。如果调用者需要在不同的公寓上课,他会从另一个线程new 并让 COM 进行正常的编组。 100% 安全可行。如果调用者出于某种原因需要new 并且他负责线程,new 绝对安全可靠。
          • 好的,但是“他会从另一个线程new 并让 COM 进行正常编组”听起来比实际上要简单。除非您知道什么是编组(很多程序员可能不知道)以及它是如何工作的(甚至更少的程序员知道),否则您只会尝试使用 new'ed 指针作为对象并将其传递给所有对象,可能结果不好。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-04-24
          • 2016-04-21
          • 1970-01-01
          • 2018-12-23
          • 2011-08-22
          • 1970-01-01
          • 2016-08-17
          相关资源
          最近更新 更多