我正在开发一个使用第三方 COM 服务器 API 的项目。COM 服务器是我无法控制的本地服务器(进程外 exe)。
我正在尝试从 runnin 对象表访问 COM 对象,以在从应用程序的每个实例开始的几个 COM 对象实例之间进行选择:
private static List<object> GetRunningInstances(string progId) {
// get Running Object Table ...
IRunningObjectTable Rot = null;
GetRunningObjectTable(0, out Rot);
if (Rot == null)
return null;
// get enumerator for ROT entries
IEnumMoniker monikerEnumerator = null;
Rot.EnumRunning(out monikerEnumerator);
if (monikerEnumerator == null) return null;
monikerEnumerator.Reset();
List<object> instances = new List<object>();
IntPtr pNumFetched = new IntPtr();
IMoniker[] monikers = new IMoniker[1];
while (monikerEnumerator.Next(1, monikers, pNumFetched) == 0) {
IBindCtx bindCtx;
CreateBindCtx(0, out bindCtx);
if (bindCtx == null) continue;
Guid clsid = Type.GetTypeFromProgID(progId).GUID;
string displayName;
Guid monikerClsid;
Guid riid = Marshal.GenerateGuidForType(typeof(IApplication));
object obj;
monikers[0].GetDisplayName(bindCtx, null, out displayName);
monikers[0].GetClassID(out monikerClsid);
if (displayName.IndexOf(clsid.ToString(), StringComparison.OrdinalIgnoreCase) > 0) {
//monikers[0].BindToObject(bindCtx, null, ref unkid, out obj);
Rot.GetObject(monikers[0], out obj);
instances.Add((IApplication)obj);
}
}
}
如果我启动目标应用程序的两个实例,ROT 转储会显示相应 COM 对象(此处命名为 IApplication)的两个实例,因为 GetDisplayName 显示在注册表中注册的接口 IApplication 的正确 clsid。
问题是我从 Rot.GetObject 获得的对象被描述为 System.__ComObject 并且不能强制转换为 IApplication(InvalidCastException,因为 QueryInterface 因 E_NOINTERFACE 失败),即使它们的绰号描述了正确的 clsid ...
我尝试将它以编程方式投射到我的项目中的每个可用类型,只是为了看看,但唯一的成功是将它投射到 System.__ComObject...
我也尝试使用 IMoniker.BindToObject 而不是 Rot.GetObject 但这次,当我提供相应的接口 GUID 时,我得到了 FileNotFound 异常。当我为 IUnknown 提供 riid 时,BindToObject 有效,但它给了我一个 System.__ComObject 我无法转换(回到第一方!)。
有关信息,在 ROT 转储中,我还可以显示与目标应用程序中打开的项目相对应的文件名字对象,但我也无法从中创建 COM 对象。
任何人都知道如何从 ROT 中正确检索对象?
感谢和问候。
编辑 :
几天后,对这个问题有了新的认识,我发现名字对象显示名称中的 CLSID 与我想要的不完全相同,但有两个数字(indexof 测试结果是错误的)。
仔细阅读 clsid 后发现,名字对象的显示名称中的 clsid 是 IApplication 的 coclass 的 clsid,而不是 IApplication 的 clsid。
我尝试将对象转换为“ApplicationClass”(前面提到的 coclass),但这给了我一个例外。我得到的附加信息(法语)可以翻译如下:不可能将 __ComObject 包装器实例转换为另一个类,但只要底层 com 组件支持接口 IID 的 QueryInterface 调用,就可以将这些实例转换为接口。
关于如何从这里开始的任何想法?