0

This question is basically regarding to loop all workbooks in all excel instances!

  • Create an array and store workbook to it as you open each one? Or even key it with dictionary for faster retrieval later instead of looping? – findwindow Mar 28 '16 at 15:53
  • Maybe this'll help? http://www.ozgrid.com/forum/showthread.php?t=182853 – Visual Vincent Mar 28 '16 at 15:58
  • 1
    You are only ever going to get one... You are looping `Excel` processes, but ***not*** doing anything with them once found. You create a new object of `ExcelApplication` and by default it's **1** workbook. This is why you only ever see one book... – Trevor Mar 28 '16 at 16:06
  • Even the Windows API? Might be hard to find what you're looking for _if_ there isn't any simple solution. – Visual Vincent Mar 28 '16 at 16:07
  • @Markowitz Can you use API? – Trevor Mar 28 '16 at 16:23

1 Answers1

1

Your main issue you are facing is you are not using any of the process's you come across. Therefore, you will not get anything that way. Inside of the loop for the process's you then create a new instance of ExcelApplication and then try to loop through the Workbooks. By default when you do this there is only 1 at that time, hence why you get only 1 Workbook and also why you will only ever see 1 Workbook.

Solution (Tried & Tested)

You need to look into Windows API calls to get what you need. A few of them are:

  1. GetDesktopWindow()
  2. EnumChildWindows()
  3. GetClassName()
  4. EnumWindowsProc()
  5. AccessibleObjectFromWindow()

    Imports Microsoft.Office.Interop
    Imports System.Runtime.InteropServices
    
    Public Class Form1
    
    Private Declare Function GetDesktopWindow Lib "user32" () As Integer
    Private Declare Function EnumChildWindows Lib "user32.dll" (ByVal WindowHandle As IntPtr, ByVal Callback As EnumWindowsProc, ByVal lParam As IntPtr) As Boolean
    Private Declare Function GetClassName Lib "user32.dll" Alias "GetClassNameA" (ByVal hWnd As IntPtr, ByVal lpClassName As String, ByVal nMaxCount As Integer) As Integer
    Private Delegate Function EnumWindowsProc(ByVal hwnd As IntPtr, ByVal lParam As Int32) As Boolean
    Private Declare Function AccessibleObjectFromWindow Lib "oleacc" (ByVal Hwnd As Int32, ByVal dwId As Int32, ByRef riid As Guid, <MarshalAs(UnmanagedType.IUnknown)> ByRef ppvObject As Object) As Int32
    
    Private Const OBJID_NATIVE = &HFFFFFFF0
    
    'Required to show the workbooks. Used in function to add to.
    Private lstWorkBooks As New List(Of String)
    
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        lstWorkBooks.Clear()
        GetExcelOpenWorkBooks()
    End Sub
    
    
    Private Sub GetExcelOpenWorkBooks()
        Try
            'Get handle to desktop
            Dim WindowHandle As IntPtr = GetDesktopWindow()
    
            'Enumerate through the windows (objects) that are open
            EnumChildWindows(WindowHandle, AddressOf GetExcelWindows, 0)
    
            'List the workbooks out if we have something
            If lstWorkBooks.Count > 0 Then MsgBox(String.Join(Environment.NewLine, lstWorkBooks))
    
        Catch ex As Exception
        End Try
    
    End Sub
    
    Public Function GetExcelWindows(ByVal hwnd As IntPtr, ByVal lParam As Int32) As Boolean
    
        Dim Ret As Integer = 0
        Dim className As String = Space(255) 'Return the string with some padding...
    
        Ret = GetClassName(hwnd, className, 255)
        className = className.Substring(0, Ret)
    
        If className = "EXCEL7" Then
            Dim ExcelApplication As Excel.Application
            Dim ExcelObject As Object = Nothing
            Dim IDispatch As Guid
    
            AccessibleObjectFromWindow(hwnd, OBJID_NATIVE, IDispatch, ExcelObject)
    
            'Did we get anything?
            If ExcelObject IsNot Nothing Then
                ExcelApplication = ExcelObject.Application
                'Make sure we have the instance...
                If ExcelApplication IsNot Nothing Then
                    'Go through the workbooks...
                    For Each wrk As Excel.Workbook In ExcelApplication.Workbooks
                        'If workbook ins't in the list then add it...
                        If Not lstWorkBooks.Contains(wrk.Name) Then
                            lstWorkBooks.Add(wrk.Name)
                        End If
                    Next
                End If
    
            End If
        End If
    
        Return True
    
    End Function
    
    End Class
    
Trevor
  • 7,777
  • 6
  • 31
  • 50
  • 1
    Seriously, `I prefer vb.net code without API. But if this is not possible I accept API solution`. What is the problem? This ***answer's your issue and more***. `I prefer simple code` I wish it was that easy, if you think that's the case you have a long way to the top :) – Trevor Mar 28 '16 at 18:56
  • 1
    @Codexer You should have deleted the answer since he appears ungrateful that you solved his issue. – Sorceri Mar 28 '16 at 19:02
  • @Markowitz Thank you, accepting answer's is how it works here. If it's helped, it is important to vote and accept answer. This helps other coming along that may have the same issue. Also without using API it's probably impossible to loop through active windows and getting that object, the only way I know of is what I posted – Trevor Mar 28 '16 at 19:49