如何获取活动的Excel实例?

时间:2009-04-16 16:32:31

标签: c# excel

我在C#中有一个应用程序,这个应用程序粘贴信息以满足用户需求,背后的逻辑是这样的,如果没有运行excel实例,它会创建一个并粘贴到该实例。

如果只有一个实例在运行,它会尝试获取该实例并使用它。这是我用来执行此操作的代码:

Guid _guid;
CLSIDFromProgID("Excel.Application", out _guid);
if (_guid == Guid.Empty) {...}
IntPtr _ptr = new IntPtr();
GetActiveObject(ref _guid, _ptr, out objApp);

到目前为止everythig工作正常,但我遇到的问题是当有多个excel实例运行时,我想获得Excel的活动实例,但是目前我只能得到第一个实例打开,这是根据我读到的内容在运行对象表中注册的第一个实例。

如果excel实例是活动实例并因此使用它,是否有办法“询问”它?或者我如何获得活动实例?

2 个答案:

答案 0 :(得分:4)

有关掌握或启动Excel的所有可能性,请参阅Andrew Whitechapel撰写的这篇博客文章:

  

Launching Office Apps Programmatically

如果您可以获得“活动”Excel实例的窗口句柄,您可能需要尝试使用AccessibleObjectFromWindow来访问OM。

答案 1 :(得分:-1)

我创建了一个类,可以遍历所有正在运行的Excel实例,并通过Hwnd,ProcessID或Process对象进行查找。它还有一个属性来返回" Active"实例(根据Marshal类),双击Excel文件图标的实例将打开,以及最顶层的实例,即具有最顶层窗口的实例。

代码如下,但请查看此链接以获取进一步说明。

http://www.codeproject.com/Tips/1080611/Get-a-Collection-of-All-Running-Excel-Instances

尚未在所有版本的Excel或Windows上测试过。

代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;

//Don't add the entire interop namespace, it will introduce some naming conflicts.
using xlApp = Microsoft.Office.Interop.Excel.Application;
using xlWin = Microsoft.Office.Interop.Excel.Window;

namespace ExcelExtensions {

    /// <summary>
    /// Collection of currently running Excel instances.
    /// </summary>
    public class ExcelAppCollection : IEnumerable<xlApp>  {

        #region Constructors

        /// <summary>Initializes a new instance of the 
        /// <see cref="ExcelAppCollection"/> class.</summary>
        /// <param name="sessionID">Windows sessionID to filter instances by.
        /// If not assigned, uses current session.</param>
        public ExcelAppCollection (Int32? sessionID = null) {
            if (sessionID.HasValue && sessionID.Value < -1)
                throw new ArgumentOutOfRangeException("sessionID");

            this.SessionID = sessionID
                ?? Process.GetCurrentProcess().SessionId;
        }

        #endregion

        #region Properties

        /// <summary>Gets the Windows sessionID used to filter instances.
        /// If -1, uses instances from all sessions.</summary>
        /// <value>The sessionID.</value>
        public Int32 SessionID { get; private set; }

        #endregion

        #region Accessors

        /// <summary>Gets the Application associated with a given process.</summary>
        /// <param name="process">The process.</param>
        /// <returns>Application associated with process.</returns>
        /// <exception cref="System.ArgumentNullException">process</exception>
        public xlApp FromProcess(Process process) {
            if (process == null)
                throw new ArgumentNullException("process");
            return InnerFromProcess(process);
        }

        /// <summary>Gets the Application associated with a given processID.</summary>
        /// <param name="processID">The process identifier.</param>
        /// <returns>Application associated with processID.</returns>
        public xlApp FromProcessID(Int32 processID) {
            try {
                return FromProcess(Process.GetProcessById(processID));
            }
            catch (ArgumentException) {
                return null;
            }
        }

        /// <summary>Get the Application associated with a given window handle.</summary>
        /// <param name="mainHandle">The window handle.</param>
        /// <returns>Application associated with window handle.</returns>
        public xlApp FromMainWindowHandle(Int32 mainHandle) {
            return InnerFromHandle(ChildHandleFromMainHandle(mainHandle));
        }

        /// <summary>Gets the main instance. </summary>
        /// <remarks>This is the oldest running instance.
        /// It will be used if an Excel file is double-clicked in Explorer, etc.</remarks>
        public xlApp PrimaryInstance {
            get {
                try {
                    return Marshal.GetActiveObject(MarshalName) as xlApp;
                }
                catch (COMException) {
                    return null;
                }
            }
        }

        /// <summary>Gets the top most instance.</summary>
        /// <value>The top most instance.</value>
        public xlApp TopMostInstance {
            get {
                var topMost = GetProcesses() //All Excel processes
                    .Select(p => p.MainWindowHandle) //All Excel main window handles
                    .Select(h => new { h = h, z = GetWindowZ(h) }) //Get (handle, z) pair per instance
                    .Where(x => x.z > 0) //Filter hidden instances
                    .OrderBy(x => x.z) //Sort by z value
                    .First(); //Lowest z value

                return FromMainWindowHandle(topMost.h.ToInt32());
            }
        }

        #endregion

        #region Methods

        /// <summary>Returns an enumerator that iterates through the collection.</summary>
        /// <returns>
        /// A <see cref="T:System.Collections.Generic.IEnumerator`1" /> 
        /// that can be used to iterate through the collection.
        /// </returns>
        public IEnumerator<xlApp> GetEnumerator() {
            foreach (var p in GetProcesses())
                yield return FromProcess(p);
        }
        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

        /// <summary>Gets all Excel processes in the current session.</summary>
        /// <returns>Collection of all Excel processing in the current session.</returns>
        public IEnumerable<Process> GetProcesses() {

            IEnumerable<Process> result = Process.GetProcessesByName(ProcessName);

            if (this.SessionID >= 0)
                result = result.Where(p => p.SessionId == SessionID);

            return result;
        }

        #endregion

    //--------Implementation

        #region Methods

            private static xlApp InnerFromProcess(Process p) {
                return InnerFromHandle(ChildHandleFromMainHandle(p.MainWindowHandle.ToInt32()));
            }

            private static Int32 ChildHandleFromMainHandle(Int32 mainHandle) {
                Int32 handle = 0;
                EnumChildWindows(mainHandle, EnumChildFunc, ref handle);
                return handle;
            }

            private static xlApp InnerFromHandle(Int32 handle) {
                xlWin win = null;
                Int32 hr = AccessibleObjectFromWindow(handle, DW_OBJECTID, rrid.ToByteArray(), ref win);
                return win.Application;
            }

            private static Int32 GetWindowZ(IntPtr handle) {
                var z = 0;
                for (IntPtr h = handle; h != IntPtr.Zero; h = GetWindow(h, GW_HWNDPREV))
                    z++;
                return z;
            }

            private static Boolean EnumChildFunc(Int32 hwndChild, ref Int32 lParam) { 
                var buf = new StringBuilder(128); 
                GetClassName(hwndChild, buf, 128); 
                if (buf.ToString() == ComClassName) { 
                    lParam = hwndChild; 
                    return false; 
                } 
                return true; 
            }

            #endregion

            #region Extern Methods

            [DllImport("Oleacc.dll")] 
            private static extern Int32 AccessibleObjectFromWindow(
                Int32 hwnd, UInt32 dwObjectID, Byte[] riid, ref xlWin ptr); 

            [DllImport("User32.dll")] 
            private static extern Boolean EnumChildWindows(
                Int32 hWndParent, EnumChildCallback lpEnumFunc, ref Int32 lParam); 

            [DllImport("User32.dll")] 
            private static extern Int32 GetClassName(
                Int32 hWnd, StringBuilder lpClassName, Int32 nMaxCount); 

            [DllImport("User32.dll")] 
            private static extern IntPtr GetWindow(IntPtr hWnd, UInt32 uCmd);

            #endregion

            #region Constants & delegates

            private const String MarshalName = "Excel.Application";

            private const String ProcessName = "EXCEL";

            private const String ComClassName = "EXCEL7";

            private const UInt32 DW_OBJECTID = 0xFFFFFFF0;

            private const UInt32 GW_HWNDPREV = 3;
            //3 = GW_HWNDPREV
            //The retrieved handle identifies the window above the specified window in the Z order.
            //If the specified window is a topmost window, the handle identifies a topmost window.
            //If the specified window is a top-level window, the handle identifies a top-level window.
            //If the specified window is a child window, the handle identifies a sibling window.

            private static Guid rrid = new Guid("{00020400-0000-0000-C000-000000000046}");

            private delegate Boolean EnumChildCallback(Int32 hwnd, ref Int32 lParam);
            #endregion
        }
    }