I have been trying to access the COM objects of all the instances of Excel 2010 registered in ROT in Visual C# Express 2010. I found a code on http://adndevblog.typepad.com/autocad/2013/12/accessing-com-applications-from-the-running-object-table.html, which I modified a little in order to return all the possible Excel.Application
objects registered in Running Object Table. The code :-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
namespace APPROT
{
[ComVisible(true)]
class COMApp
{
[DllImport("Ole32.dll")]
public static extern int CreateBindCtx(
uint reserved,
out IBindCtx ppbc);
[DllImport("Ole32.dll")]
public static extern int GetRunningObjectTable(
int reserved,
out IRunningObjectTable prot);
[STAThread]
public static List<Excel.Application> GetRunningInstances()
{
string[] progIds = new string[] { "Excel.Application"};
List<string> clsIds = new List<string>();
// get the app clsid
foreach (string progId in progIds)
{
Type type = Type.GetTypeFromProgID(progId);
if (type != null)
clsIds.Add(type.GUID.ToString().ToUpper());
}
// 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<Excel.Application> instances = new List<Excel.Application>();
IntPtr pNumFetched = new IntPtr();
IMoniker[] monikers = new IMoniker[1];
// go through all entries and identifies app instances
while (monikerEnumerator.Next(1, monikers, pNumFetched) == 0)
{
object ComObject;
Rot.GetObject(monikers[0], out ComObject);
if (ComObject == null)
continue;
try
{
instances.Add((Excel.Application)ComObject);
}
catch {}
}
return instances;
}
}
}
But this only returns the Excel.Application
object of the first instance of excel.
I also tried to access the object using the filename with the code mentioned on http://dotnet-snippets.de/snippet/laufende-com-objekte-abfragen/526 (site in german) i.e. with GetRunningCOMObjectByName(string objectDisplayname)
, but after getting the COM object with that, when I try to cast it as Excel.Application
, I get the following error :-
Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.Office.Interop.Excel.Application'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{000208D5-0000-0000-C000-000000000046}' failed due to the following error: Cette interface n’est pas prise en charge (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
I have tried checking for faulty dlls, checking the registry if the CLSID has a conflict due to existance of different "Versions" in TypeLib
under HKEY_CLASSES_ROOT
, tried repairing Ms Office 2010, uninstalled old versions of Office (2003) etc. to get around this error. But nothing works. I have also tried using the Microsoft.VisualBasic
reference and then using Interaction.GetObject
, but this gives the same error as well.
Any ideas?
I have also tried the late-binding method mentioned on https://stackoverflow.com/a/779710/2960814. But this also gives access to the first instance of Excel in ROT.