0

我试图找到 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。

4

1 回答 1

2

在努力让它工作之后,结果证明用这种通用方法是不可能的,因为一些组件在运行对象表(ROT) 上注册了具有相同键的不同实例。IRunningObjectTable.GetObject在这种情况下返回第一个注册的实例。例如 Word 用它的ApplicationClass.

解决方案:

似乎没有干净和通用的解决方案,但对我有用。DocumentWord 还会在 ROT 中注册 的实例。所以我们可以很容易地得到这些文件,然后我们就可以得到应用程序。

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

好吧,这有点可疑。这种方法的一个令人讨厌的问题是无法找到没有文档的实例。

于 2018-12-08T06:30:40.367 回答