我需要绑定到一个正在运行的 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 服务器仅将活动对象注册为弱引用时。我对此没有影响,我不是服务器端的作者......我需要绑定到正在运行的对象,而不会有对象可以从运行对象表中撤销的风险。