目前我的代码使用
SurferApp = Marshal.GetActiveObject("Surfer.Application") as Surfer.Application
为了获取一个名为surfer的软件的运行实例,为了简单起见,我们可以将Surfer替换为大家都知道的Word。 现在假设我有 2 个 MS Word 应用程序正在运行,并且我想使用
Marshal.GetActiveObject()
来获取它们,如何获取两个正在运行的实例并将每个实例与单独的对象关联?
Marshal.GetActiveObject 返回它在 ROT(运行对象表)上找到的第一个实例。如果您有多个实例以相同的名称/ID 运行,您必须直接从 ROT 获取它。
一些开始链接:
接受的答案仅包含链接。我已经从引用的材料中提取了最短的答案。
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
var currentApplications = EnumerateActiveObjects("Surfer.Application");
Console.WriteLine($"Found Surfer.Applications: {currentApplications.Count()}");
return 0;
static IEnumerable<object> EnumerateActiveObjects(string programId)
{
var rotResult = NativeMethods.GetRunningObjectTable(0, out var rot);
if (rotResult != 0)
yield break;
IEnumMoniker? monikerEnumerator = null;
try
{
rot.EnumRunning(out monikerEnumerator);
var monikers = new IMoniker[1];
while (monikerEnumerator.Next(1, monikers, IntPtr.Zero) == 0)
{
var moniker = monikers[0];
var displayName = GetDisplayName(moniker);
if (!displayName.Contains(programId))
{
Marshal.ReleaseComObject(moniker);
continue;
}
rot.GetObject(moniker, out var comObject);
Marshal.ReleaseComObject(moniker);
yield return comObject;
}
}
finally
{
if (monikerEnumerator != null) Marshal.ReleaseComObject(monikerEnumerator);
if (rot != null) Marshal.ReleaseComObject(rot);
}
}
static string GetDisplayName(IMoniker moniker)
{
IBindCtx? bindCtx = null;
try
{
if (NativeMethods.CreateBindCtx(0, out bindCtx) != 0)
return string.Empty;
moniker.GetDisplayName(bindCtx, null, out var displayName);
return displayName;
}
finally
{
if (bindCtx != null) Marshal.ReleaseComObject(bindCtx);
}
}
public static class NativeMethods
{
[DllImport("ole32.dll")]
public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable pprot);
[DllImport("ole32.dll")]
public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);
}
注意:旧的
Marshal.GetActiveObject
在 dotnetcore (net5+) 中不存在
我给你一个
MarshalGetActiveObject
功能,其工作方式与旧的 Marshal.GetActiveObject
相同。
[DllImport("oleaut32.dll", PreserveSig = false)]
private static void GetActiveObject(ref Guid rclsid, IntPtr pvReserved, [MarshalAs(UnmanagedType.IUnknown)] out object ppunk)
[DllImport("ole32.dll")]
private static int CLSIDFromProgID([MarshalAs(UnmanagedType.LPWStr)] string lpszProgID, out Guid pclsid)
public static object MarshalGetActiveObject(string progId)
{
Guid clsid;
object obj = null;
if (CLSIDFromProgID(progId, out clsid) == 0)
GetActiveObject(ref clsid, IntPtr.Zero, out obj);
return obj;
}