Get active excel application

I’ve created a class that can iterate through all running Excel instances, and lookup by Hwnd, ProcessID, or a Process object. It also has a property to return the «Active» instance (according to the Marshal class) which is the instance that double-clicked Excel file icons will open in, as well as the top-most instance, which is the instance with the top-most window.

The code is below, but check this link for further description.

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

This has not been tested on all versions of Excel or Windows.


Code:

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

  • Remove From My Forums
  • Question

  • I develop an UDF in C#:  
    public string GetActiveSheetName()
            {
                string Caller = null;
                Excel.Application oExcel = Marshal.GetActiveObject("Excel.Application") as Excel.Application;
                Caller = oExcel.ActiveSheet.Name;
                return Caller;
            }
    

    This works fine if there is only one Excel process running. But if I have two or more instances of Excel are running, it still return first excel application’s
    active sheet name.

Answers

  • I’ve been working this problem since your previous posting.  After a few days of trying I finally got all the code to work.  I had to use a number of Winn32 API to get it to work.  Here are the steps I used.  I not sure if there is an
    easier way to do this.

    1) You need to find all the Excel.exe processes.  This was pretty easy to do.  I used the Net Library function Process.GetProcessesByName(@»excel») which returns an array of Processes

    2) I then checked that the Excel.exe window was the active window using Win32 API user32.dll function IsWindowVisible.

    3) I then had to write another function EnumChildWindows(ExcelWin, cb, ref hwndChild) which uses the Win32 API User32.dll function GetClassName().   I needed the child window to be able to extract the excel application from the window.

    4) Next I used the Win32 API Oleacc.dll function AccessibleObjectFromWindow  to get the excel object from the window.

    5) Finally I overload the window object to an excel object and get the sheet name.

    //using System.Runtime.InteropServices;
            //using System.Diagnostics;
    
            public delegate bool EnumChildCallback(int hwnd, ref int lParam);
    
            [System.Runtime.InteropServices.DllImport("User32.dll")]
            public static extern bool EnumChildWindows(IntPtr hWndParent, EnumChildCallback lpEnumFunc, ref IntPtr lParam);
    
            private static EnumChildCallback cb;
    
    
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool IsWindowVisible(IntPtr hWnd);
      
    
            [DllImport("Oleacc.dll")]
            private static extern int AccessibleObjectFromWindow(
                IntPtr hwnd, uint dwObjectID, byte[] riid, [MarshalAs(UnmanagedType.IUnknown)]ref object winobj);
    
            [DllImport("User32.dll")]
            public static extern int GetClassName(
                int hWnd, StringBuilder lpClassName, int nMaxCount);
    
            
            public static bool EnumChildProc(int hwndChild, ref int lParam)
            {
                StringBuilder buf = new StringBuilder(128);
    
                GetClassName(hwndChild, buf, 128);
                if (buf.ToString() == "EXCEL7")
                {
                    lParam = hwndChild;
                    return false;
                }
                return true;
            }
    
            public static string GetActiveSheetName()
            {
                
                string activesheetname = null;
                IntPtr activeAppWindow = IntPtr.Zero; 
                IntPtr ExcelWin;
                
    
                Process[] ExcelProcesses = Process.GetProcessesByName(@"excel");
               
                foreach(Process MyProcess in ExcelProcesses)
                {
                    ExcelWin = MyProcess.MainWindowHandle;
                    IntPtr hwndChild = (IntPtr)0;
     
    
                    cb = new EnumChildCallback(EnumChildProc);
                    EnumChildWindows(ExcelWin, cb, ref hwndChild);
    
                
                        if (IsWindowVisible(ExcelWin))
                        {
                       
                        
                           const uint OBJID_NATIVEOM  = 0xFFFFFFF0;
                           Guid IID_IDispatch = new Guid("{00020400-0000-0000-C000-000000000046}");
                           object winptr = null;
                        
                       
                            int As = AccessibleObjectFromWindow(
                                hwndChild, OBJID_NATIVEOM, IID_IDispatch.ToByteArray(), ref winptr);
                            Excel.Window excelwin = (Excel.Window)winptr;
                            Excel.Application XlApp = excelwin.Application;
    
                            Excel.Worksheet sht = (Excel.Worksheet)XlApp.ActiveSheet;
                            activesheetname = sht.Name;
    
    
                            break;
    
                    }
                   
                }
                return activesheetname;
            }    
    
    • Edited by

      Friday, December 30, 2011 4:37 AM

    • Marked as answer by
      Calvin_Gao
      Monday, January 9, 2012 5:38 AM

We have created add in for office application by using VSTO in c# language.In this add in providing save as ribbon where user can save document on server location.

When user click on save as ribbon -> showing custom save as dialog box.   here i want to show file name in text box as window shows.

It works by using

 Microsoft.Office.Interop.Excel.Application loExcelApp;

loExcelApp = (Excel.Application)Marshal.GetActiveObject(«Excel.Application»);

 txtFileName.Text = loExcelApp.ActiveWorkbook.Name;

but it fails when i start multiple excel application,it shows first application workbook name in second document while click on save as ribbon.

1.how to get name of current file name

2.Does it possible to get handle of parent window when i show save as dialog box.

kindly refer below screens.

Screen one showing proper working but in screen 2 document name is book 2 and showing name as book1 in text box.

Both are separate excel application running simultaneously.

kindly help me anyone

JohnH


  • #2

Check first that Excel is running with Process.GetProcessesByName(«excel»).
Get the Application object with Marshal.GetActiveObject(«Excel.Application») and then get ActiveWorkbook.

  • #3

I can’t seem to get the activeworkbook or the sheet or much of anything else.
Can someone please point me to some books or tutorials that will help me understand this better?

Skydiver


  • #4

Are you looking to understand? Or looking to copy-and-paste some code? Post #2 explains the steps needed to accomplish the task that you asked about, assuming that you have the rudimentary understanding of C# and Office InterOp.

  • #5

Both actually, I’d like to understand how to use the object browser to find the objects that I need. I would also like some form of documentation (Ideally with examples) or using the excel interop. I understand the basics of c#.

I need to get whatever workbooks happen to be open into a combobox and then each workbooks worksheets into another combobox. Finally I want the program to detect which column of which worsheet the user is in and to transfer information from my c# portion into that active column at specific rows.

This is all I have so far:

public Microsoft.Office.Interop.Excel.Workbook ActiveWorkbook { get; }
        private void button1_Click(object sender, EventArgs e)
        {
            Process.GetProcessesByName("excel");

            Marshal.GetActiveObject("Excel.Application");
            comboBox1.Items.Add(ActiveWorkbook);
        }

The code gets to the last line then throws an exception.

Skydiver


  • #6

The Process.GetProcessesByName() lets you check to see if Excel is already running. You need to check the returned value to see if Excel is found. If it is running, then you need to call Marshal.GetActiveObject() to get the main Excel COM server instance’s interface as an Application. From that Application object, you can get the ActiveWorkbook object/interface.

As a quick aside, it’s not really a good idea to add an object directly into a WinForms UI element. You’ll likely want to get the string representation of the active workbook. Perhaps it’s name?

  • #7

Thank you for your input. I’ve been on another project for a bit and am now back to this issue. I will try to implement what you have said. I realize my wording must have been misleading, but yes, I realize that I’m trying to add a string expression of the object.

JohnH


  • #8

Process.GetProcessesByName(«excel»); Marshal.GetActiveObject(«Excel.Application»);

These are methods that return a value, and it’s that value you have to work with.

using System.Diagnostics;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;

if (Process.GetProcessesByName("excel").Length > 0)
{
    var app = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
    var book = app.ActiveWorkbook;
    
}

Skydiver


  • #9

@Frans : How is what you posted different from what has previously been described and shown on this thread?

  • #10

needs to write data to an already open excel workbook.

You’re going to struggle; excel locks its files upon opening to the extent that other apps can’t even read them so you won’t be able to do it by editing the file itself

Probably easiest to just start a timer and then tell the user then have 10 seconds to switch to make Excel the active app, then SendKeys the data you want. That can include keys like Ctrl+Home and Right Right Right to move to cell D1 etc

JohnH


  • #11

You’re going to struggle; excel locks its files upon opening to the extent that other apps can’t even read them so you won’t be able to do it by editing the file itself

Probably easiest to just start a timer and then tell the user then have 10 seconds to switch to make Excel the active app, then SendKeys the data you want. That can include keys like Ctrl+Home and Right Right Right to move to cell D1 etc

Office automation is no problem, granted that it is ok with the interactive user. You can do whatever you want with the ‘book’ reference shown in post 8.

SendKeys is last resort for automation.

JohnH


  • #12

The code in post 8 works just fine. No need for dynamic late-binding.

Skydiver


  • #13

Posts #2 says «and then get the ActiveWorkbook». It answers the question.

My response in post #4 asking about understanding vs just copying and pasting is relevant because this site meant to be a learning site — not a question and answer site. And further in post #4, I redirected the user back to post #2 which is all the user actually needs to know if they are just seeking to understand (vs. just copy and paste code).

And then in post #6, I elaborated on what post #2 was describing in broad term. It also answers the question, since post #2 answered the question. Post #6 just goes into more details without giving the OP code that they can copy and paste. My second paragraph in post #6 was not about not using WinForms. It was about not putting the active workbook object directly into the WinForms combobox.

The code in post #8 works just fine without using dynamic

1669675201478.png

Your post #9 is still there. I don’t know why you think it’s been deleted.

Skip to content

Get Active Workbook or Worksheet Name Path FullName in Excel VBA

Home » Excel VBA » Get Active Workbook or Worksheet Name Path FullName in Excel VBA

  • Get an Active Workbook or Worksheet Name

Description:

When we are working with workbooks and worksheets, some times we may required to Get Active Workbook or Worksheet Name, Path of the workbook to know the directory, FullName(Complete path) of the workbook to know the location of the workbook, selected Range address in active sheet or selected Cell address in active sheet using Excel VBA.

Solution(s):

You can get Active Workbook Or Worksheet Name by using Name property of the workbook or worksheet.

Get Active Workbook or Worksheet Name – Example Cases:

  • Get an Active Workbook Name
  • Get an Active Workbook Path
  • Get an Active Workbook FullName
  • Get an Active Worksheet Name
  • Get an Active Range Address
  • Get an Active Cell Address
Get an Active Workbook Name

You can use ActiveWorkbook property to return the active workbook name. You can use the following code to get the name of the Active Workbook

Code:
Sub DisplayWorkbookName()

    MsgBox ActiveWorkbook.Name, vbInformation, "Workbook Name"

End Sub
Output:

Get Active Workbook-Worksheet Name

Instructions:
  1. Open an excel workbook
  2. Press Alt+F11 to open VBA Editor
  3. Insert a new module from Insert menu
  4. Copy the above code and Paste in the code window
  5. Press F5 to see the output
  6. You should see output as shown above
  7. Save the file as macro enabled workbook
Get an Active Workbook Path

You can use ActiveWorkbook property to return the active workbook Path.You can use the following code to Get Active Workbook Path to know the workbook directory.

Code:
Sub DisplayWorkbookPath()

    MsgBox ActiveWorkbook.Path, vbInformation, "Workbook Path"

End Sub
Output:

Get Active Workbook Path

Instructions:
  1. Open an excel workbook
  2. Press Alt+F11 to open VBA Editor
  3. Insert a new module from Insert menu
  4. Copy the above code and Paste in the code window
  5. Press F5 to see the output
  6. You should see output as shown above
  7. Save the file as macro enabled workbook
Get an Active Workbook FullName

You can use ActiveWorkbook property to return the active workbook FullName. You can use the following code to get Active Workbook FullName to know the location of workbook.

Code:
Sub DisplayWorkbookFullName()

    MsgBox ActiveWorkbook.FullName, vbInformation, "Workbook Complete Path"

End Sub
Output:

Get Active Workbook Full Path

Instructions:
  1. Open an excel workbook
  2. Press Alt+F11 to open VBA Editor
  3. Insert a new module from Insert menu
  4. Copy the above code and Paste in the code window
  5. Press F5 to see the output
  6. You should see output as shown above
  7. Save the file as macro enabled workbook
Get an Active Worksheet Name

You can use ActiveSheet property to return the ActiveSheet Name. You can use the following code to get Active Worksheet Name.

Code:
Sub DisplayWorkSheetName()

    MsgBox ActiveSheet.Name, vbInformation, "Active Sheet Name"

End Sub
Output:

Get Active Worksheet Name

Instructions:
  1. Open an excel workbook
  2. Press Alt+F11 to open VBA Editor
  3. Insert a new module from Insert menu
  4. Copy the above code and Paste in the code window
  5. Press F5 to see the output
  6. You should see output as shown above
  7. Save the file as macro enabled workbook
Get an Active(Selected) Range Address

You can use Address property of the selected range(Selection Method). You can use the following code to get the selected range address in active sheet.

Code:
Sub SelectedRangeAddress()
    
    'Variable Declaration
    Dim MyRange As String
    
    'Assign Selected Range Address to variable
    MyRange = Selection.Address
    
    'Display Output
    MsgBox MyRange, vbInformation, "Range Address"
    
    '-----------------------(OR)------------------
     
    MsgBox Selection.Address, vbInformation, "Range Address"

End Sub
Output:

Get Selected Range Address

Instructions:
  1. Open an excel workbook
  2. Press Alt+F11 to open VBA Editor
  3. Insert a new module from Insert menu
  4. Copy the above code and Paste in the code window
  5. Select a range from B2 to E11 in active sheet
  6. Goto code window and Press F5 to see the output
  7. You should see output as shown above
  8. Save the file as macro enabled workbook
Get an Active(Selected) Cell Address

You can use Address property of the selected cell(Selection Method). By using the following code you can get the selected cell address in active sheet.

Code:
Sub SelectedCellAddress()
    
    'Variable Declaration
    Dim MyCell As String
    
    'Assign Selected Range Address to variable
    MyCell = Selection.Address
    
    'Display Output
    MsgBox MyCell, vbInformation, "Cell Address"
    
    '-----------------------(OR)------------------
     
    MsgBox Selection.Address, vbInformation, "Cell Address"

End Sub
Output:

Get Selected Cell Address

Instructions:
  1. Open an excel workbook
  2. Press Alt+F11 to open VBA Editor
  3. Insert a new module from Insert menu
  4. Copy the above code and Paste in the code window
  5. Select a cell F5 in active sheet
  6. Goto code window and Press F5 to see the output
  7. You should see output as shown above
  8. Save the file as macro enabled workbook
Effortlessly Manage Your Projects and Resources
120+ Professional Project Management Templates!

A Powerful & Multi-purpose Templates for project management. Now seamlessly manage your projects, tasks, meetings, presentations, teams, customers, stakeholders and time. This page describes all the amazing new features and options that come with our premium templates.

Save Up to 85% LIMITED TIME OFFER
Excel VBA Project Management Templates
All-in-One Pack
120+ Project Management Templates
Essential Pack
50+ Project Management Templates

Excel Pack
50+ Excel PM Templates

PowerPoint Pack
50+ Excel PM Templates

MS Word Pack
25+ Word PM Templates

Ultimate Project Management Template

Ultimate Resource Management Template

Project Portfolio Management Templates

Related Posts

VBA Reference

Effortlessly
Manage Your Projects

120+ Project Management Templates

Seamlessly manage your projects with our powerful & multi-purpose templates for project management.

120+ PM Templates Includes:

One Comment

  1. Prabhaker
    July 5, 2017 at 4:10 PM — Reply

    thank you this is helpful

Effectively Manage Your
Projects and  Resources

With Our Professional and Premium Project Management Templates!

ANALYSISTABS.COM provides free and premium project management tools, templates and dashboards for effectively managing the projects and analyzing the data.

We’re a crew of professionals expertise in Excel VBA, Business Analysis, Project Management. We’re Sharing our map to Project success with innovative tools, templates, tutorials and tips.

Project Management
Excel VBA

Download Free Excel 2007, 2010, 2013 Add-in for Creating Innovative Dashboards, Tools for Data Mining, Analysis, Visualization. Learn VBA for MS Excel, Word, PowerPoint, Access, Outlook to develop applications for retail, insurance, banking, finance, telecom, healthcare domains.

Analysistabs Logo

Page load link

Go to Top

Return to VBA Code Examples

In this Article

  • ActiveSheet
    • Activate Worksheet (Setting the ActiveSheet)
    • ActiveSheet Name
  • Selected Sheets vs ActiveSheet
  • Select Worksheet
    • Select Worksheet by Tab Name
    • Select Worksheet by Index Number
    • Select Worksheet With VBA Code Name
    • Select Current Worksheet
  • More Activate / Select Sheet Examples
    • Set ActiveSheet to Variable
    • Change ActiveSheet Name
    • With ActiveSheet
    • Loop Through Selected Sheets
    • GoTo Next Sheet
  • VBA Coding Made Easy

This article will discuss the ActiveSheet object in VBA. It will also discuss how to activate, select, and go to Worksheets (& much more). Read our full VBA Worksheets Guide for more information about working with worksheets in VBA.

ActiveSheet

In VBA, ActiveSheet refers to the currently active Worksheet. Only one Sheet may be active at a time.

Activate Worksheet (Setting the ActiveSheet)

To set the ActiveSheet use Worksheet.Activate:

Worksheets("Input").Activate

The Activate Sheet command will actually “go to” the sheet, changing the visible Sheet.

vba activate sheet

The above example uses the Sheet (Tab) name.  Instead you can use the VBA code name for the worksheet:

Sheet1.Activate

vba activesheet

ActiveSheet Name

To get the ActiveSheet Name:

msgbox ActiveSheet.name

Selected Sheets vs ActiveSheet

At any point in time, only one Sheet can be the ActiveSheet. However, multiple Worksheets can be selected at once.

When multiple Worksheets are selected only the “top-most” Worksheet is considered active (the ActiveSheet).

vba selected sheets

Select Worksheet

If you would like to select a worksheet instead of activating it. Use .Select instead.

Select Worksheet by Tab Name

This selects a Worksheet based on it’s Sheet Tab Name

Sheets("Input").Select

vba select sheet

Select Worksheet by Index Number

This selects a Worksheet based on it’s position relative to other tabs

Worksheets(1).Select

vba select sheet index number

Select Worksheet With VBA Code Name

Sheet1.Select

Selecting worksheets by code name can prevent errors caused by worksheet name changes.

Select Current Worksheet

To select the current Worksheet, use the ActiveSheet object:

ActiveSheet.Select

More Activate / Select Sheet Examples

VBA Programming | Code Generator does work for you!

Set ActiveSheet to Variable

This will assign the ActiveSheet to a Worksheet Object Variable.

Dim ws As Worksheet

Set ws = ActiveSheet

Change ActiveSheet Name

This will change the ActiveSheet Name.

ActiveSheet.Name = "NewName"

With ActiveSheet

Using the With Statement allows you to streamline your code when working with objects (such as Sheets or ActiveSheet).

With ActiveSheet
    .Name = "StartFresh"
    .Cells.Clear
    .Range("A1").Value = .Name
End With

Notice how you don’t need to repeat “ActiveSheet” before each line of code. This can be a huge time saver when working with a long list of commands.

Loop Through Selected Sheets

The following macro will Loop through all selected sheets, displaying their names.

Sub GetSelectedSheetsName()
    Dim ws As Worksheet

    For Each ws In ActiveWindow.SelectedSheets
         MsgBox ws.Name
    Next ws

End Sub

GoTo Next Sheet

This code will go to the next Sheet. If the ActiveSheet is the last Sheet, then it will go to the first Sheet in the Workbook.

If ActiveSheet.Index = Worksheets.Count Then
    Worksheets(1).Activate
Else
    ActiveSheet.Next.Activate
End If

VBA Coding Made Easy

Stop searching for VBA code online. Learn more about AutoMacro – A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!

Select Activate Worksheet

Learn More!

<<Return to VBA Examples

Update

I’ve created a new article that describes how to do the same things as this article, but with a reusable assembly instead of everything in one class, and there is a demo proejct and walkthrough as well.  Check it out here.


Introduction

If you write a lot of .NET Excel automation, particularly for use on servers where there may be multiple instances of Excel running at a time, you may find yourself needing to access a specific instance of Excel, not just the «active» one.

I have spent a lot of time on forums and Q&A sites trying to find a way to iterate over all running instances, and select specific instances by Hwnd or ProcessID, but have not yet found a satisfactory article. After a while of piecing different answers together, I believe I have a class that can provide this functionality for anyone in a similar situation.

A lot of credit goes to the anonymous article at the link below, as well as some hints from various users of StackOverflow.

http://pastebin.com/F7gkrAST

Background

You will need an intermediate grasp of C# for this project, and some familiarity with Windows processes and window handles. There is also some usage of LINQ and lambda expressions, but only in a few places. You actually don’t need to know much about Excel automation, other than knowing what the Microsoft.Office.Interop.Excel.Application class is.

Several parts of the private implementation of the class involve extern calls to the Win32 API, which you don’t necessarily need to understand to use this class.  I am not very familiar with the Win32 API myself, but learned a good bit about it in putting this class together. 

Please let me know if the code violates any best practices for dealing with Win32.

IMPORTANT: This code has not been tested on all versions of Excel or Windows.  (Please help me test them all out.) I believe this code may be particularly prone to issues based on different Excel and Windows versions.

Tested environments:

  • Windows 7 64-bit with Excel 2016 32-bit
  • Windows 7 64-bit with parallel instances of Excel 2010 32-bit and Excel 2013 32-bit.

Using the Code

The class below can be used alongside the Microsoft primary interop assembly for Excel, to get a Microsoft.Office.Interop.Excel.Application object for any running instance of Excel.

I’ve split the class into two partial class files, to breakup what would otherwise be a 200-line file. The first part is the public interface, and the second is the private implementation.

Public Interface

The publicly visible interface is pretty simple, and has the following members:

  • Constructor — This takes a nullable Int32 as a parameter, which defaults to null.  The value is used to filter Excel instances by Windows sessionID.  If null, the class’s SessionID property will be set to the current sessionID.
  • SessionID — This property is used to filter Excel instances by Windows sessionID. This is very important when working with servers where multiple users may be using Excel at once.
    • If -1, the collection will give access to instances from all sessions.
    • If a valid sessionID, the collection will give access to all Excel instances running in that session.
    • If not a valid sessionID, the collection will always be empty. No exception is thrown.
  • Accessors
    • FromProcess — This method takes a reference to a Process and returns the Excel instance of that Process, or null if the Process is not an Excel instance.
    • FromProcessID — This method takes a processID and returns the Excel instance of the corresponding Process, or null if the ID is invalid or does not correspond to an Excel instance.
    • FromMainWindowHandle — This method takes the Hwnd value of the main window of an Excel instance, and returns the corresponding Excel instance, or null if the Hwnd is invalid or does not correspond to an Excel instance.
    • PrimaryInstance — This property returns the first-created Excel instance, or null if there are none.  If a user double-clicks an Excel file icon, this will be the instance the file opens in.
    • TopMostInstance — This property returns the Excel instance with the top-most visible window, or null if there are none. This will normally be the last instance selected by a user.
  • Methods
    • GetEnumerator — This method returns a collection of all Excel instances, filtering by SessionID (if SessionID is not -1).
    • GetProcesses — This method returns a collection of all Process objects of Excel instances, filtering by SessionID (if SessionID is not -1).
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;


using xlApp = Microsoft.Office.Interop.Excel.Application;

namespace ExcelExtensions {

                public partial class ExcelAppCollection : IEnumerable<xlApp>  {

        #region Constructors

                                        public ExcelAppCollection (Int32? sessionID = null) {
            if (sessionID.HasValue && sessionID.Value < -1)
                throw new ArgumentOutOfRangeException("sessionID");

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

        #endregion

        #region Properties

                                public Int32 SessionID { get; private set; }

        #endregion

        #region Accessors

                                        public xlApp FromProcess(Process process) {
            if (process == null)
                throw new ArgumentNullException("process");
            return InnerFromProcess(process);
        }

                                public xlApp FromProcessID(Int32 processID) {
            try {
                return FromProcess(Process.GetProcessById(processID));
            }
            catch (ArgumentException) {
                return null;
            }
        }

                                public xlApp FromMainWindowHandle(Int32 mainHandle) {
            return InnerFromHandle(ChildHandleFromMainHandle(mainHandle));
        }

                                public xlApp PrimaryInstance {
            get {
                try {
                    return Marshal.GetActiveObject(MarshalName) as xlApp;
                }
                catch (COMException) {
                    return null;
                }
            }
        }

                        public xlApp TopMostInstance {
            get {
                var topMost = GetProcesses() 
                    .Select(p => p.MainWindowHandle) 
                    .Select(h => new { h = h, z = GetWindowZ(h) }) 
                    .Where(x => x.z > 0) 
                    .OrderBy(x => x.z) 
                    .First(); 

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

        #endregion

        #region Methods

                                                public IEnumerator<xlApp> GetEnumerator() {
            foreach (var p in GetProcesses())
                yield return FromProcess(p);
        }
        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

                        public IEnumerable<Process> GetProcesses() {

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

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

            return result;
        }

        #endregion
   }
}

Private Implementation

As mentioned in the introduction, I am not an expert on the Win32 API.  Parts of the private implementation are still a bit mysterious to me and may violate best practices for using it.  That being said, it has been reliable as far as I’ve used it.

  • Methods
    • InnerFromProcess — This method takes a reference to a Process and returns the corresponding Microsoft.Office.Interop.Excel.Application object.
    • ChildHandleFromMainHandle — This method takes the Hwnd of a Process or Application object and returns a child window’s Hwnd.
    • InnerFromHandle — This method takes the Hwnd of a child window of an Application object and returns the Application.
    • GetWindowZ — This method takes the Hwnd of a window and returns its z value.
    • EnumChildFunc — This method is used by the EnumChildWindows method to get child window Hwnds.
  • External Methods
    • AccessibleObjectFromWindow — This method takes the Hwnd of an Excel window, as well as some of the constants below, and returns (through its ref parameter) a reference to a Window object, which can then be used to get its parent Application object. 
      • It does not work if you pass it the value of a Application‘s Hwnd property; it must be a specific workbook’s window’s Hwnd.  This may only be the case on Excel 2013 or newer, where there is no main Excel window.
    • EnumChildWindows — This method takes the Hwnd of the main window of an Excel instance and an EnumChildCallback delegate as parameters, and returns (through its ref parameter) the Hwnd of a child window, which can be used by AccessibleObjectFromWindow.
    • GetClassName — This method is used by the EnumChildCallback delegate that is passed to EnumChildWindows.  I believe it gets the details of the Window class internally so that an Hwnd can be returned.
    • GetWindow — This method takes an Hwnd and a constant as parameters.  The constant used determines how to get other Hwnds based on the provided Hwnd.  Using GW_HWNDPREV returns the Hwnd of the window directly above (z position) the given Hwnd.  This is used to get the TopMostInstance.
  • Constants and Delegates
    • MarshalName — This constant is required to get the «active» instance (PrimaryInstance) from the System.Runtime.InteropServices.Marshal class.
    • ProcessName — This constant is required to get Excel processes by name from System.Diagnostics.Process.
    • ComClassName — This constant is required for EnumChildFunc method, which is used by the EnumChildWindow method from the Win32 API.
    • DW_OBJECTID — This constant is required for the AccessibleObjectFromWindow method from the Win32 API.
    • GW_HWNDPREV — This constant is required for getting window z (depth) values from the GetWindow method from the Win32 API.  I copied a bit of the Microsoft documentation into the code comments.
    • rrid — This pseudo-constant is required for the AccesibleObjectFromWindow from the Win32 API.
    • EnumChildCallback — This delegate is implemented by the EnumChildFunc method and is requied for the EnumChildWindow method from the Win32 API.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;


using xlApp = Microsoft.Office.Interop.Excel.Application;
using xlWin = Microsoft.Office.Interop.Excel.Window;

namespace ExcelExtensions {

   public partial class ExcelAppCollection {

        #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;
        
        
        
        
        

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

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

Points of Interest

Please let me know if you find this class helpful (or terrible).  I’m especially interested in issues with older version of Excel (pre-2013), multiple versions of Excel on one machine, or multiple users on one server.  If you have any further insight into how the Win32 API is working behind the scenes, I would also like to know more about that.  Any feedback is highly appreciated.

Further Developments

I have recently started working on a WPF application called ExcelBrowser that allows users to easily browse through multiple Excel instances, their workbooks, and sheets.  Part of the implementation of this application is directly decended from the class described in this article.  Check it out at github.com/JamesFaix/ExcelBrowser.  Also, note that the solution uses C#6/.NET 4.6.1.  As of writing this, I also need to catch up on some code comments, so bear with me.

The parts related to this article are in the ExcelBrowser.Interop project of the solution.  All extern methods are encapsulated in the NativeMethods class, the Session class represents a collection of all running Applications and all running Processes with the name «Excel». AppFactory provides methods for getting specific Application instances.  Some other parts of this class are also in the ApplicationExtensionMethods and ProcessExtensionMethods classes.

History

  • Added «Further Developments» section 11/20/16
  • Posted 2/23/2016

I am a professional developer, but I really create software because it’s fun. I’ve always been interested in deconstructing complex systems, and software engineering has proven to be an inexhaustable supersystem of such systems. In the past I’ve also spent time focusing on music composition, audio engineering, electronics, game design, history, and philosophy.

My strongest languages are English and C#, in fact I’m a Microsoft Certified Professional for «Programming in C#». I do not have any certifications for English, so please trust me there. I’ve spent a lot of time working on Windows desktop applications, particularly for interacting with SQL Server or automating Microsoft Office programs, using technologies such as C#, VB.NET, VBA, T-SQL, WinForms, WPF, ADO.NET, the MS Office PIA’s, ExcelDNA, EPPlus, and Crystal Reports. I’ve also done some web development using JavaScript, HTML, CSS, TypeScript, ASP.NET, WCF, jQuery, and requirejs. I am very interested in functional programming (F#, Haskell, Clojure), and try to use C# and JavaScript in a «functional» way at times, but I haven’t had the opportunity to use a functional language for a serious project yet.

4 ответа

Примерно через пол дня игры я наконец понял, как сделать эту работу, чтобы вы могли защелкнуться на открытой копии Excel. Мои пользователи очень жаловались на то, что слишком много экземпляров Excel открыты.

Вот фрагмент того, что я сделал, чтобы заставить его работать:

_Application excelApp;

try
{
  excelApp = (_Application)Marshal.GetActiveObject("Excel.Application");
}
catch(Exception)
{
  // this is important. If Excel is not running, GetActiveObject will throw
  // an exception
  excelApp = null;
}

if( excelApp == null )
{
  excelApp = new ApplicationClass();
}

Я некоторое время гонялся за этим, и, наконец, у меня было время уйти и понять это.

Jager
20 янв. 2010, в 00:29

Поделиться

Чтобы иметь возможность ссылаться на объектную модель Excel как «Excel», вы можете создать псевдоним с помощью оператора using в верхней части пространства имен (или документа) следующим образом:

using Excel = Microsoft.Office.Interop.Excel;

После этого вы можете ссылаться на Excel.Application вместо длинного Microsoft.Office.Interop.Excel.Application.

Что касается того, почему ваш вызов в Marshal.GetActiveObject не работает, я не могу сказать точно. Несколько мыслей:

(1) Вы уверены, что есть уже запущенный экземпляр Excel? Если нет, то создайте новое приложение Excel:

Excel.Application xlApp = new Excel.Application();

(2) Если определенная версия приложения Excel уже запущена, возможно, экземпляр Excel еще не добавлен в таблицу рабочих столов (ROT), если приложение Excel никогда не теряло фокус. См. Visual С#.NET Ошибка присоединения к запуску экземпляра приложения Office для получения дополнительной информации об этом. Я считаю, что метод Marshal.GetActiveObject должен генерировать исключение в этом случае — не тихо возвращать null — но это все еще кажется потенциально релевантным.

Надеюсь, это поможет…

Mike

Mike Rosenblum
27 авг. 2009, в 15:59

Поделиться

Я также работал над надстройками Excel, в пространствах имен использовать

using Excel=Microsoft.Interop.Office.Excel;

вместо Microsoft.Interop.Office.Excel используйте приведенную выше строку, для большего понимания посмотрите мой код:

using System.IO;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.Office.Interop.Excel;
using static MMCAPP2010.Profile;
using System.Runtime.InteropServices;

namespace MMCAPP2010
{
    public class ExcelTemplateLoad
    {
        public void DeserializeObject(string filename)
        {
            Excel.Application instance;
            Workbook wb = null;
            try
            {
                //getting the current running instance of an excel application
                instance = (Excel.Application)Marshal.GetActiveObject("Excel.Application");   
            }
            catch
            {
                instance = new Excel.Application();
            }

            //opening the template
            wb = instance.Workbooks.Open(@"C:UsersU1152927Downloadssample.xltx");

Hemanth Mannam
07 авг. 2018, в 11:08

Поделиться

Ещё вопросы

  • 1Закрывает ли файл открытие и выполнение операции над этим файлом в одной строке?
  • 0MySQL поиск значения в двух столбцах и сумма третьего столбца
  • 0Как настроить положение определенных элементов / элементов / контента на странице с помощью CSS
  • 1Какое официальное название для этого алгоритма?
  • 0Rails API использует Devise для аутентификации
  • 0Как изменить цвет индикатора прогресса
  • 0получение пространства следующего размера в памяти в C #
  • 0«Docker-compose up» в Windows завершился неудачно с ошибкой на шаге контейнера Mysql
  • 0Индексы для большой таблицы MYSQL
  • 1Выравнивание текста в java JPanel
  • 0css позиционируется как сетка
  • 0Я хочу строку, где максимальный идентификатор
  • 0полоса прокрутки slimscroll не видна
  • 0перенос слов в машинах MAC
  • 1Flash-сообщения Node.js не отображаются на странице
  • 1Публикация на Android Маркете: атрибут android: icon: атрибут не является строковым значением
  • 0JQuery Colorbox с JQuery Validation не работает
  • 0часовой пояс для конкретной страны php [дубликаты]
  • 0Вернуть несколько строк из подзапроса
  • 1Поворот серии Multiindex в DataFrame
  • 0JQuery Slideshow error. Картинки перечисляют вниз по странице, а не перетасовывают. Не могу найти ошибку
  • 1AmChart умножает значения даты
  • 1Заставьте dijit.form.currencytextbox принимать отрицательное значение с одной цифрой после десятичной
  • 1Должен ли я создать экземпляр класса внутри класса?
  • 1Загрузка текста richTextBox в массив
  • 1ASP.NET MVC Выберите значение списка с помощью ключа
  • 1Ошибка при загрузке log4net
  • 0Выйти из Facebook Чат через JavaScript
  • 0Jquery событие не работает во второй раз, когда я называю это
  • 0О сегментации в OPENCV
  • 0Отображать поля, когда пользователь выбирает конкретное значение из поля со списком — Проблема логики проверки
  • 1Как выполнить итерацию по карте со значением Map <String, Integer>, объявленной как Map <String, Map <String, Integer >>, с использованием языка выражений?
  • 1Android Google Plus SDK: индикатор прогресса (ProgressBar) никогда не останавливается после нажатия кнопки +1
  • 0JQuery, чтобы скрыть и показать div с помощью выпадающего
  • 1Как сделать прозрачную область неприкосновенной для ImageView в Android?
  • 1Сохранить результаты в файл CSV без открытого CSV с Python
  • 1Как разобрать XML дочерний узел
  • 1Как открыть проект из GitHub в Android-студии? Проблемы с Maven и Android поддержки библиотек.
  • 1ArrayList не добавляет объекты?
  • 1Pandas Series.rename не отражено в столбцах DataFrame
  • 0Как избежать конфликтов в рамках веб-приложения
  • 1Можно ли восстановить расширения-атрибуты из скрытых элементов управления asp.net?
  • 1Angular использует неправильный роутер-розетку
  • 0Перезагрузить iframe после закрытия галереи изображений
  • 1Цикл Python для создания словаря
  • 1Как получить суммирование в группе по запросу linq
  • 0мобильная версия сайта номер мобильного телефона всегда белого цвета
  • 1Имя токена «приложение» не определено. колба
  • 0Не могу понять, почему функция не будет работать
  • 1Как сканировать все диски, чтобы найти конкретное расширение файла в Java?

Понравилась статья? Поделить с друзьями:
  • Gillette sensor excel станок с подставкой
  • Get a word in sideways
  • Gillette sensor excel станок купить в минске
  • Get a word document back
  • Gillette sensor excel станок купить в краснодаре