【问题标题】:Why isn't my COM class a Singleton?为什么我的 COM 类不是单例?
【发布时间】:2014-08-10 06:28:50
【问题描述】:

由于某种原因,当它们应该是单例时,正在创建 2 个对象。

我有一个类 Bridge,其目的是从一个应用程序到另一个应用程序进行通信。第一个应用 App1 通过 COM 创建网桥并立即调用网桥的初始化方法:

bool IBridge.Initialize(ref App1 theApp)
{
       if (theApp != null)
       {
            this.refToApp = theApp;
            log("Got bridge from App1");
            //spin up App2
            Process.Start([path to App2]);
       }
       else
       {
           log("theApp was null");
       }
       return true;
}

Bridge 类使用单例模式,但有一个公共默认构造函数,以便 COM 可以正常使用它,但此类的用户必须通过仅使用实例属性访问它来尊重它是单例的事实。

[ComVisibleAttribute(true)]
[ProgId("[id that App1 uses to instantiate class]")]
public class Bridge : IBridge
{
    private static readonly _instance;

    public static COMBridge Instance
    {
        get
        {
            if(_instance == null){
                _instance = new Bridge();
            }
            return _instance
        }
    }

  public Bridge()
  {
       log("Called default constructor");
       if (_instance == null)
       {
            _instance = this;
       }
  }

 ...

但是,当 App2 启动时,它会调用 Instance 的 getter 并再次调用构造函数。这很麻烦,因为桥接器是一个通信组件,我需要这两个应用程序使用桥接器相互通信。

有什么建议吗?

【问题讨论】:

  • 假设两个线程/进程同时执行if(_instance == null),会发生什么?
  • com 对象是否作为程序集 (.dll) 实现?如果是这样,是什么让您认为这两个进程都在寻找 com 对象的同一个实例?
  • @L.B 我认为这不是线程问题,因为调用相距甚远。就像我记录对构造函数的调用并且它们彼此分开一秒钟被调用,所以我不认为这是这里的问题(我确实认识到这是糟糕的代码,但我只需要它开始工作!)
  • @user957902 我认为这是我的问题。奇怪的是,以前,App2 是用 VB 编写的,它会调用一个返回相同对象的CreateObject(progId) 方法。现在我正在用 C# 编写 App2,它的工作方式似乎有所不同
  • 一旦你使用公共构造函数创建你的类 [ComVisible(true)] 然后游戏就开始了,客户端代码总是可以创建一个新对象。如果 _instance 不为空,您只能通过在构造函数中抛出异常来强制执行合同。这不太可能使客户端程序员的螺旋桨旋转。一个更有用的方案是让你的类[ComVisible],只有接口。并提供 another [ComVisible] 类,该类具有返回唯一接口引用的工厂方法。您需要考虑一生。

标签: c# com ipc unmanaged


【解决方案1】:

假设 com 对象被配置为进程外 com 对象(我假设这是因为它看起来以前在 VB 中以这种方式工作),那么您必须跳过一些障碍才能将其激活为一个进程外的对象。默认情况下,.Net 会将对象作为 In Process com 对象加载,这意味着每个进程都将拥有自己的对象副本。根据文章here

如果您现在尝试使用您的 COM 对象,您可能会发现它仍然加载到客户端进程中。原因是你必须告诉 COM 你对进程外激活感兴趣。如果您使用 C/C++,请将 CLSCTX_LOCAL_SERVER 作为 CoCreateInstance 函数的 dwClsContext 参数传递。如果您使用的是 C#/VB.NET,则必须为此 P/Invoke 到 CoCreateInstance。

【讨论】:

  • 所以我认为COM对象可以用来做IPC?也就是说,App1 在自己的进程中,创建了 COM 对象桥。 App2 在一个单独的进程中,需要与同一个 Bridge 和进程 1 通信。
  • 是的,它可以,但它必须是一个进程外的 COM 对象才能做到这一点。在这种情况下,COM 对象实际上存在于单独的第三个进程中。该进程甚至不必在同一台计算机上。
猜你喜欢
  • 2011-02-27
  • 1970-01-01
  • 2019-07-07
  • 1970-01-01
  • 1970-01-01
  • 2020-08-05
  • 2018-01-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多