C# 在C中运行对象表访问其他Excel实例的应用程序对象#
我一直在尝试访问在Visual C#Express 2010中ROT中注册的所有Excel 2010实例的COM对象。我在上找到了一个代码,我对其进行了一些修改,以便返回在运行对象表中注册的所有可能的C# 在C中运行对象表访问其他Excel实例的应用程序对象#,c#,.net,excel,C#,.net,Excel,我一直在尝试访问在Visual C#Express 2010中ROT中注册的所有Excel 2010实例的COM对象。我在上找到了一个代码,我对其进行了一些修改,以便返回在运行对象表中注册的所有可能的Excel.Application对象。守则如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices.C
Excel.Application
对象。守则如下:
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;
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Runtime.InteropServices.ComTypes;
使用System.Runtime.InteropServices;
使用Excel=Microsoft.Office.Interop.Excel;
名称空间批准
{
[ComVisible(true)]
类COMApp
{
[DllImport(“Ole32.dll”)]
公共静态外部int CreateBindCtx(
尤因保留,
out IBindCtx ppbc);
[DllImport(“Ole32.dll”)]
公共静态外部int GetRunningObjectTable(
保留整数,
out IrunningObject表保护);
[状态线程]
公共静态列表GetRunningInstances()
{
字符串[]progIds=新字符串[]{“Excel.Application”};
List clsIds=新列表();
//获取应用程序clsid
foreach(progIds中的字符串progId)
{
Type Type=Type.GetTypeFromProgID(progId);
if(type!=null)
添加(type.GUID.ToString().ToUpper());
}
//获取正在运行的对象表。。。
IRunningObjectTable Rot=null;
GetRunningObjectTable(0,out Rot);
if(Rot==null)
返回null;
//获取ROT项的枚举数
IEnumMoniker名字枚举器=null;
Rot.EnumRunning(超出监视器枚举器);
if(monikerEnumerator==null)
返回null;
monikerEnumerator.Reset();
列表实例=新列表();
IntPtr pNumFetched=新的IntPtr();
IMoniker[]名字=新IMoniker[1];
//检查所有条目并识别应用程序实例
while(monikerEnumerator.Next(1,名字对象,pNumFetched)==0)
{
对象与对象;
Rot.GetObject(名字对象[0],out-ComObject);
if(ComObject==null)
继续;
尝试
{
添加((Excel.Application)ComObject);
}
捕获{}
}
返回实例;
}
}
}
但这只返回Excel第一个实例的Excel.Application
对象。
我还尝试使用文件名和(德语站点)中提到的代码访问对象,即使用GetRunningCOMObjectByName(string objectDisplayname)
,但在使用该文件名获取COM对象后,当我尝试将其转换为Excel.Application
,我得到以下错误:-
无法将“System.\u ComObject”类型的COM对象强制转换为接口类型“Microsoft.Office.Interop.Excel.Application”。此操作失败,因为对IID为“{000208D5-0000-0000-C000-0000000000 46}”的接口的COM组件的QueryInterface调用由于以下错误而失败:Cette接口不收费(HRESULT的例外:0x80004002(E_NOINTERFACE))
我曾尝试检查有故障的DLL,检查注册表中的CLSID是否因HKEY_CLASSES_ROOT
下的TypeLib
中存在不同的“版本”而发生冲突,尝试修复Ms Office 2010,卸载Office(2003)的旧版本等以避免此错误。但什么都不管用。我也尝试过使用Microsoft.VisualBasic
引用,然后使用Interaction.GetObject
,但这也会产生同样的错误
有什么想法吗
我还尝试了上面提到的后期绑定方法。
但这也让我们可以访问ROT中的第一个Excel实例。我认为我们面临着同样的问题。我正在使用windows7和office2010,使用与您提到的相同的方法获取ROT表来处理所有打开的excel 您有GetRunningCOMObjectByName(string objectDisplayname)来获取com对象,并尝试转换为Excel.Application,但它不是那种类型。我已经尝试过了,如果您按全名获取对象,则得到的对象是Excel.Workbook的类型,因此可以将其转换为Workbook。它适合我 因此,您可以从ROT中看到,您在Excel中打开的每个文档都有一个与之相关的全名。您通过名称获得的comObj类型为工作簿 但是我仍然有一些关于ROT的问题。如果我们查看ROT表,它有两个名称为:!{00024505-0014-0000-C000-0000000000 46}和!{00024500-0000-0000-C000-0000000000 46},与Excel.Application类似的classId。如果您得到这两项的comObj,您可以转换为Excel.Application。就像Marshal.GetActiveObject(“Excel.Application”)那样。这两个项目是相等的参考 但当有多个EXCEL.EXE进程运行时,我想我可以在ROT中获得更多的应用程序项,但事实是
那么,如果ROT中只有一个应用程序,并且等于workbook1.Applicaton,那么workbook2.Application在哪里?为什么workbook2.Application未在ROT表中注册?请尝试以下C#4.0+代码片段:
Excel是一个单实例应用程序。如果你重新开始,它只会问第一个问题
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace ROT.TestConsole
{
/// <summary>
/// Gets MS Excel running workbook instances via ROT
/// </summary>
public class MSExcelWorkbookRunningInstances
{
[DllImport("ole32.dll")]
static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
[DllImport("ole32.dll")]
public static extern void GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
public static IEnumerable<dynamic> Enum()
{
// get Running Object Table ...
IRunningObjectTable Rot;
GetRunningObjectTable(0, out Rot);
// get enumerator for ROT entries
IEnumMoniker monikerEnumerator = null;
Rot.EnumRunning(out monikerEnumerator);
IntPtr pNumFetched = new IntPtr();
IMoniker[] monikers = new IMoniker[1];
IBindCtx bindCtx;
CreateBindCtx(0, out bindCtx);
while (monikerEnumerator.Next(1, monikers, pNumFetched) == 0)
{
string applicationName = "";
dynamic workBook = null;
try
{
Guid IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}");
monikers[0].BindToObject(bindCtx, null, ref IUnknown, out workBook);
applicationName = workBook.Application.Name;
}
catch { }
if (applicationName == "Microsoft Excel") yield return workBook;
}
}
}
}
using System;
namespace ROT.TestConsole
{
class Program
{
static void Main(string[] args)
{
try
{
int index = 1;
foreach (dynamic worbook in MSExcelWorkbookRunningInstances.Enum())
System.Console.WriteLine("{0}. '{1}' '{2}'", index++, worbook.Application.Name, worbook.FullName);
}
catch (Exception ex)
{
System.Console.WriteLine("Error = '{0}'", ex.Message);
}
}
}
}