1

我需要绑定到一个正在运行的 COM 实例(可能有很多我正在寻找的实例,所以我需要通过检查运行对象表来确定哪一个是正确的)使用 CoClassCreate 或new带有类的运算符是我没有选择。

我的代码几乎可以工作,只是它不是异常安全的。

如果像下面的代码中那样抛出异常,有没有办法避免在Revoke幕后发生的自动?一旦应用程序结束,COM 对象就会从 ROT 中删除,而注册它的应用程序仍在运行。我很确定 Release() 会被自动调用,因为它是最后一个引用 COM 的对象,所以 ROT 条目消失了。

我想以原子和异常安全的方式获得对 ROT 中对象的强引用。

我尝试将绰号与该方法结合使用的所有尝试BindToObject均未成功。.NET 4.0 中的实现有问题吗?第一次调用似乎有效,但后续调用都因 Argument 或 invalidCast 异常而失败,即使在使用 IUnknown 的 Guid 时也是如此。据我所知,这应该总是成功还是我忽略了什么?

这是迄今为止我能产生的最好的工作代码。我只是想念异常安全。该程序旨在自行运行并且是可中断的(可以随时抛出异常以中断胎面)。如果我不能彻底解决,留下这件未完成的事情肯定会给我带来一些麻烦。

    [DllImport("ole32.dll")]
    static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);

    // Returns the contents of the Running Object Table (ROT), where
    // open Microsoft applications and their documents are registered.
    private IEnumerable<T> GetRunningObjects<T>()
    {
        // Get the table.
        IBindCtx bc;
        if (CreateBindCtx(0, out bc) != 0 || bc == null)
            throw new ApplicationException("Can't create COM binding context in GetRunningObjects<T>");

        IRunningObjectTable runningObjectTable;
        bc.GetRunningObjectTable(out runningObjectTable);

        IEnumMoniker monikerEnumerator;
        runningObjectTable.EnumRunning(out monikerEnumerator);
        monikerEnumerator.Reset();

        // Enumerate and fill our nice dictionary.
        IMoniker[] monikers = new IMoniker[1];
        IntPtr numFetched = IntPtr.Zero;
        while (monikerEnumerator.Next(1, monikers, numFetched) == 0)
        {
            object o = null;
            if (runningObjectTable.GetObject(monikers[0], out o) == 0 && o != null)
            {
                if (o is T)
                {
                    // TODO: If an exception is thrown here, then COM object gets revoked from ROT...
                    throw new Exception("Test");

                    // monikers[0].BindToObject does not work...
                    // there seems to be a weakness here.

                    // if found, create a strong reference to avoid auto-revokation in the ROT
                    IntPtr ptr = Marshal.GetIUnknownForObject(o);
                    Marshal.AddRef(ptr);

                    yield return (T)o;
                }
            }
        }
        Marshal.ReleaseComObject(bc);
    }

附加说明:这可能发生在 OutProc 服务器仅将活动对象注册为弱引用时。我对此没有影响,我不是服务器端的作者......我需要绑定到正在运行的对象,而不会有对象可以从运行对象表中撤销的风险。

4

0 回答 0