2009-04-16 79 views
3

我在C#中有一個應用程序,這個應用程序粘貼信息以滿足用戶需求,後面的邏輯是這樣的,如果沒有運行excel實例,它會創建一個並粘貼到該實例。如何獲得活動的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,但目前我只能得到我打開的第一個實例,這是根據我閱讀的內容在Running Object Table中註冊的第一個實例。

有沒有辦法「問」到Excel實例,如果它是活動實例,並因此使用它?或者我如何獲得活動實例?

+2

什麼是你的積極的定義是什麼?有重點嗎?如果另一個應用程序有焦點呢?您可能只需要詢問用戶使用哪個實例... – 2009-04-16 16:35:47

回答

4

對於所有可能性弄個或啓動Excel看到這篇博客文章由安德魯白教堂:

Launching Office Apps Programmatically

如果你能得到「有效」 Excel實例的窗口句柄你可能想嘗試AccessibleObjectFromWindow這將讓你訪問OM。

-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 
     } 
    } 
+0

歡迎。請將代碼發佈在您的答案中,因爲如果鏈接中斷,它仍然很有用。 – 2016-02-29 18:14:18