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

1 つのインスタンスで 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

OK、これは少し怪しいです。このアプローチの厄介な問題は、ドキュメントを持たないインスタンスが見つからないことです。

于 2018-12-08T06:30:40.367 に答える