簡體   English   中英

獲取多個相同類型的運行COM對象

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM