如何使用 Marshal.getActiveObject() 获取打开了两个进程的正在运行的进程的 2 个实例

问题描述 投票:0回答:2

目前我的代码使用

SurferApp = Marshal.GetActiveObject("Surfer.Application") as Surfer.Application

为了获取一个名为surfer的软件的运行实例,为了简单起见,我们可以将Surfer替换为大家都知道的Word。 现在假设我有 2 个 MS Word 应用程序正在运行,并且我想使用

Marshal.GetActiveObject()
来获取它们,如何获取两个正在运行的实例并将每个实例与单独的对象关联?

c#
2个回答
14
投票

Marshal.GetActiveObject 返回它在 ROT(运行对象表)上找到的第一个实例。如果您有多个实例以相同的名称/ID 运行,您必须直接从 ROT 获取它。

一些开始链接:


-1
投票

接受的答案仅包含链接。我已经从引用的材料中提取了最短的答案。

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;
}
© www.soinside.com 2019 - 2024. All rights reserved.