Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

find all open Excel workbooks

I'm trying to get a list of all currently open Excel workbooks, so that the user can select which one of them to get some data from.

I tried this:

List<string> excelList = new List<string>();
Process[] processList = Process.GetProcessesByName("excel");
foreach (Process p in processList)
{
 excelList.Add(p.MainWindowTitle);
 Console.WriteLine(p.MainWindowTitle);
}

But that only gets the first open instance of Excel and the most recently opened instance, so any workbooks that were opened between those two aren't in the list.

I also started exploring the solution described in the blog link in the answer to this SO question, and tried to get access to the Running Object Table with the code suggested in the blog entry:

IBindCtx bc;
IRunningObjectTable rot;
CreateBindCtx(0, out bc);
bc.GetRunningObjectTable(out rot);

Problem here is that CreateBindCtx actually accepts a UCOMIBindCTX instead of IBindCTX, but UCOMIBindCTX is obsolete per MSDN.

Is there a simpler way to do what I'm trying to do: get a list of Workbook objects corresponding to all the open Excel books?

like image 955
sigil Avatar asked Dec 10 '12 18:12

sigil


People also ask

How do I find previously opened Excel files?

Click the File tab. Click Recent. Select the check box to Quickly access this number of recent documents: and choose how many files you want to see. Links to those files will appear above Info in the navigation bar, regardless of where you are in the Backstage View.

How do I search all Excel workbooks?

Highlight each worksheet tab you want to search by holding down the Ctrl key and clicking each tab you would like to search. Once each worksheet you want to search is highlighted, perform a Find, and all highlighted worksheets will be searched.

How do I search multiple workbooks at once?

The best way to do this is to use the Windows Search approach (described at the beginning of this tip) to identify the workbooks in which the desired text resides. Move those workbooks to their own folder and then do the macro search on that folder.

How can you close all open workbooks at once?

The quickest way to close all open workbooks is to hold the Shift key while pressing the Close Window button. The Close Window button is the “x” in the top-right corner of the application window. If all of the open workbooks have been saved, then they will all be closed.


1 Answers

Ok, I found a way to do this. The blog that describes the solution appears to no longer be available, but there is a Google cached version.

I slightly adapted the code so that the constructor accepts a MainWindowHandle, since I'm iterating through the handles for all processes.

The class is as follows. I've left some of Andrew Whitechapel's comments in to explain what's happening, since this code is beyond my present knowledge of Windows OS management:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;

namespace DTEExcel
{
    class ExcelApplicationRetriever
    {
        [DllImport("Oleacc.dll")]
        public static extern int AccessibleObjectFromWindow(
              int hwnd, uint dwObjectID, byte[] riid,
              ref Microsoft.Office.Interop.Excel.Window ptr);

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

        [DllImport("User32.dll")]
        public static extern bool EnumChildWindows(
              int hWndParent, EnumChildCallback lpEnumFunc,
              ref int lParam);

        public delegate bool EnumChildCallback(int hwnd, ref int lParam);
        private EnumChildCallback cb;
        public Excel.Application xl;

        public ExcelApplicationRetriever(int winHandle)
        {
            // We need to enumerate the child windows to find one that
            // supports accessibility. To do this, instantiate the
            // delegate and wrap the callback method in it, then call
            // EnumChildWindows, passing the delegate as the 2nd arg.
            if (winHandle != 0)
            {
                int hwndChild = 0;
                cb = new EnumChildCallback(EnumChildProc);
                EnumChildWindows(winHandle, cb, ref hwndChild);

                // If we found an accessible child window, call
                // AccessibleObjectFromWindow, passing the constant
                // OBJID_NATIVEOM (defined in winuser.h) and
                // IID_IDispatch - we want an IDispatch pointer
                // into the native object model.
                if (hwndChild != 0)
                {
                    const uint OBJID_NATIVEOM = 0xFFFFFFF0;
                    Guid IID_IDispatch = new Guid(
                         "{00020400-0000-0000-C000-000000000046}");
                    Excel.Window ptr = null;

                    int hr = AccessibleObjectFromWindow(
                          hwndChild, OBJID_NATIVEOM,
                         IID_IDispatch.ToByteArray(), ref ptr);
                    if (hr >= 0)
                    {
                        // If we successfully got a native OM
                        // IDispatch pointer, we can QI this for
                        // an Excel Application (using the implicit
                        // cast operator supplied in the PIA).
                        xl = ptr.Application;
                    }
                }
            }
        }

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

    }
}
like image 185
sigil Avatar answered Sep 28 '22 01:09

sigil