[英]Get multiple running COM objects of same Type
我正在嘗試查找Word的第一個可見實例。 我在這里找到了一些有用的代碼,並對其進行了適當的修改。
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using Microsoft.Office.Interop.Word;
namespace TestConsole
{
internal class Program
{
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(uint reserved, out IRunningObjectTable pprot);
private static void Main(string[] args)
{
Application word1 = new Application();
word1.Visible = false;
Application word2 = new Application();
word2.Visible = true;
Application word3 = new Application();
word3.Visible = false;
int index = 0;
while (true)
{
Application application = Program.GetRunningCOMObjectOfType<Application>(++index);
if (application != null)
{
Console.WriteLine($"{index}) IsVisible: {application.Visible}");
Debug.WriteLine($"{index}) IsVisible: {application.Visible}");
}
else
{
break;
}
}
Console.WriteLine("############# End of program #############");
Console.ReadLine();
}
public static T GetRunningCOMObjectOfType<T>(int index)
{
IRunningObjectTable runningObjectTable = null;
IEnumMoniker monikerList = null;
try
{
if (GetRunningObjectTable(0, out runningObjectTable) != 0 || runningObjectTable == null)
{
return default(T);
}
runningObjectTable.EnumRunning(out monikerList);
monikerList.Reset();
IMoniker[] monikerContainer = new IMoniker[1];
IntPtr pointerFetchedMonikers = IntPtr.Zero;
int counter = 0;
while (monikerList.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
{
runningObjectTable.GetObject(monikerContainer[0], out object comInstance);
if (comInstance is T castedInstance)
{
if (index == ++counter)
{
return castedInstance;
}
}
}
}
finally
{
if (runningObjectTable != null)
{
Marshal.ReleaseComObject(runningObjectTable);
}
if (monikerList != null)
{
Marshal.ReleaseComObject(monikerList);
}
}
return default(T);
}
}
}
該代碼的結果如下所示:
1) IsVisible: False
2) IsVisible: False
3) IsVisible: False
我希望某個實例的Visible應該返回true。 似乎總是返回第一個實例。 如果使word1可見,則為所有實例返回true。
嘗試使此工作正常進行之后,事實證明,使用這種通用方法是不可能的,因為某些組件在運行對象表 (ROT)上使用相同的鍵注冊了不同的實例。 在這種情況下, IRunningObjectTable.GetObject
返回第一個注冊的實例。 例如,Word通過其ApplicationClass
的實例來做到這一點。
解:
接縫不是干凈的通用解決方案,而是對我有用的東西。 Word還會在ROT中注冊Document
的實例。 因此,我們可以輕松獲取此文檔,然后從那里獲取應用程序。
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using Microsoft.Office.Interop.Word;
namespace ConsoleApp
{
internal class Program
{
#region public methods
private static void Main(string[] args)
{
Application word1 = new Application();
word1.Visible = false;
word1.Documents.Add();
Application word2 = new Application();
word2.Visible = true;
word2.Documents.Add();
word2.Documents.Add();
Application word3 = new Application();
word3.Visible = false;
word3.Documents.Add();
word3.Documents.Add();
word3.Documents.Add();
List<(IMoniker moniker, IBindCtx bindingContext, object instance)> x = Program.GetRunningComObjects();
foreach ( (IMoniker moniker, IBindCtx bindingContext, object instance) in x)
{
// get only the instances that
if (instance is Document doc && doc.Application.ActiveDocument == doc)
{
moniker.GetDisplayName(bindingContext, moniker, out string displayName);
Console.WriteLine($"{displayName}");
Application wordInstance = doc.Application;
Console.WriteLine($"\tVisible:\t{wordInstance.Visible}");
Console.WriteLine($"\tDocumentCount:\t{wordInstance.Documents.Count}");
}
}
word1.Quit(false);
word2.Quit(false);
word3.Quit(false);
Console.WriteLine();
Console.WriteLine("############## End of program ##############");
Console.WriteLine("############## press enter to continue ##############");
Console.ReadLine();
}
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(uint reserved, out IRunningObjectTable pprot);
private static List<(IMoniker moniker, IBindCtx bindingContext, object instance)> GetRunningComObjects()
{
List<(IMoniker, IBindCtx, object)> result = new List<(IMoniker, IBindCtx, object)>();
IRunningObjectTable runningObjectTable = null;
IEnumMoniker monikerList = null;
try
{
if (Program.GetRunningObjectTable(0, out runningObjectTable) != 0
|| runningObjectTable == null)
{
return result;
}
runningObjectTable.EnumRunning(out monikerList);
monikerList.Reset();
IMoniker[] monikerContainer = new IMoniker[1];
IntPtr pointerFetchedMonikers = IntPtr.Zero;
while (monikerList.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
{
Program.CreateBindCtx(0, out IBindCtx bindingContext);
runningObjectTable.GetObject(monikerContainer[0], out object comInstance);
result.Add((monikerContainer[0], bindingContext, comInstance));
}
}
finally
{
if (runningObjectTable != null)
{
Marshal.ReleaseComObject(runningObjectTable);
}
if (monikerList != null)
{
Marshal.ReleaseComObject(monikerList);
}
}
return result;
}
#endregion
}
}
此代碼產生以下結果:
Dokument1
Visible: False
DocumentCount: 1
Dokument3
Visible: True
DocumentCount: 2
Dokument6
Visible: False
DocumentCount: 3
好,這有點腥。 這種方法的一個棘手問題是找不到沒有文檔的實例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.