I'm working a project that uses API from a third party COM Server. The COM Server is a local server (out of process exe) on which I have no control.
I'm trying to access COM objects from the runnin object table to choose between the several instances of COM objects started with each instance of the application :
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);
}
}
}
If I start two instances of the target application, the ROT dump shows two instances of the corresponding COM object (named IApplication here) as GetDisplayName shows the right clsid for the interface IApplication registered in the registry.
The problem is that the objects I get from Rot.GetObject are described as System.__ComObject and cannot be cast to IApplication (InvalidCastException because QueryInterface failed with E_NOINTERFACE) even if their moniker describe the right clsid...
I tried casting it progammatically to every available type in my project just to see but the only success is casting it to System.__ComObject...
I also tried using IMoniker.BindToObject instead of Rot.GetObject but this time, I get a FileNotFound Exception when I provide the corresponding interface GUID. BindToObject works when I provide the riid for IUnknown but it gives me a System.__ComObject I can't cast (back to square one !).
For information, in the ROT dump, I can also shows a file moniker corresponding to an open project in the target app but I cannot create a COM object from this either.
Anyone has an idea about how to correctly retrieve the objects from the ROT ?
Thanks, Regards.
EDIT :
After a few days out and a new eye on this problem, I discovered the CLSID in the moniker's display name is not the exact same one I want but has two digits off (the indexof test turns out to be wrong).
After carefully reading the clsid's it turns out that the clsid in the moniker's displayname is the clsid of the coclass of IApplication and not the clsid of IApplication.
I tried casting the object to "ApplicationClass" (the aforedmentionned coclass) but this gives me an exception. The additional info I get (in french) could translate as follows : Impossible to cast __ComObject wrapper instances to another class but it's possible to cast these instances to interfaces as long as the underlying com component supports QueryInterface calls for the interface IID.
Any idea on how to proceed from here ?