Lister fichiers excels ouverts instances différentes

Guigui

XLDnaute Occasionnel
Bonjour à tous,

Je cherche un moyen de lister (dans un listbox) tous les fichiers excels ouverts.
Pas de souci avec ce code :

Code:
For i = 1 To Workbooks.Count
ListBox1.AddItem Workbooks(i).Name
Next i

Mon problème est le suivant :
Il arrive que plusieurs instances d'Excel soient ouvertes sur mon poste de travail.
Dans ce cas les fichiers ouverts dans les autres instances ne sont pas listés.

Avez vous une solution ?

La finalité est ensuite de cliquer le fichier attendu et de récupérer des valeurs dedans (en copier/coller) vers le fichier maitre.

Merci par avance

Guillaume
 

Pièces jointes

  • exemple.xls
    34.5 KB · Affichages: 41
  • exemple.xls
    34.5 KB · Affichages: 41
  • exemple.xls
    34.5 KB · Affichages: 42

Staple1600

XLDnaute Barbatruc
Re : Lister fichiers excels ouverts instances différentes

Bonsoir à tous

Guigui
Adapté à partir d'un code utilisant des API. [NB: test OK avec XL2013 même si ... ;) ]
Voir si cela peut te dépanner ou t'inspirer ;)
(A mettre dans le code de l'userform)
Code:
Option Explicit
Private Declare Function FindWindowEx Lib "User32" Alias "FindWindowExA" _
        (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, _
         ByVal lpsz2 As String) As Long
Private Declare Function IIDFromString Lib "ole32" _
        (ByVal lpsz As Long, ByRef lpiid As GUID) As Long
Private Declare Function AccessibleObjectFromWindow Lib "oleacc" _
        (ByVal hWnd As Long, ByVal dwId As Long, ByRef riid As GUID, _
         ByRef ppvObject As Object) As Long
         
Private Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(7) As Byte
End Type

Private Const S_OK As Long = &H0
Private Const IID_IDispatch As String = "{00020400-0000-0000-C000-000000000046}"
Private Const OBJID_NATIVEOM As Long = &HFFFFFFF0
Code:
Private Sub UserForm_Initialize()
Dim i&, hWinXL&
Dim xlApp As Object
Dim wb As Object
With ListBox1
    .Clear
    .ColumnCount = 2
    .ColumnWidths = "55;95"
        hWinXL = FindWindowEx(0&, 0&, "XLMAIN", vbNullString)
        While hWinXL > 0
            i = i + 1
            If GetXLapp(hWinXL, xlApp) Then
                For Each wb In xlApp.Workbooks
                .AddItem "Instance " & i
                .Column(1, .ListCount - 1) = wb.Name
                Next
            End If
            hWinXL = FindWindowEx(0, hWinXL, "XLMAIN", vbNullString)
        Wend
End With
End Sub
Code:
Function GetXLapp(hWinXL As Long, xlApp As Object) As Boolean
Dim hWinDesk&, hWin7&, obj As Object
Dim iid As GUID
    Call IIDFromString(StrPtr(IID_IDispatch), iid)
    hWinDesk = FindWindowEx(hWinXL, 0&, "XLDESK", vbNullString)
    hWin7 = FindWindowEx(hWinDesk, 0&, "EXCEL7", vbNullString)
    If AccessibleObjectFromWindow(hWin7, OBJID_NATIVEOM, iid, obj) = S_OK Then
        Set xlApp = obj.Application
        GetXLapp = True
    End If
End Function
 

Guigui

XLDnaute Occasionnel
Re : Lister fichiers excels ouverts instances différentes

Bonjour à tous, Stapple1600
Merci c'est parfait !

Pour la suite, comment recuperer la valeur du "xlApp.Workbooks" (j'imagine ?) pour pouvoir récupérer des données dans le fichier sélectionné ?

En rajoutant un commandbutton dans le USF, je prevois ce code :
Code:
Workbooks(ListBox1.List(ListBox1.ListIndex, 1)).ActiveSheet.Range("A1:B10").Copy _
     Destination:=ActiveWorkbook.ActiveSheet.Range("A2")

En clair copier une zone dans le fichier sélectionné et la coller dans le fichier actif.
Il me manque l'instance d'excel a rajouter avant nom du fichier ..(je pense !?)

Merci par avance
Guillaume
 

Staple1600

XLDnaute Barbatruc
Re : Lister fichiers excels ouverts instances différentes

Bonjour à tous


Vois ce que ceci peut t'inspirer
Code:
Private Sub ListBox1_Click()
Dim CHOIX_CLASSEUR$
With ListBox1
    CHOIX_CLASSEUR = .Column(1, .ListCount - 1)
End With
Workbooks(CHOIX_CLASSEUR).Activate: Me.Hide
End Sub
 

Guigui

XLDnaute Occasionnel
Re : Lister fichiers excels ouverts instances différentes

Staple1600,

Workbooks(CHOIX_CLASSEUR).Activate renvoie une erreur (l'indice ne correspond pas à la selection) ... Une idée ?

A a quoi correspond les : aprés "activate" ? :)
 

Staple1600

XLDnaute Barbatruc
Re : Lister fichiers excels ouverts instances différentes

Re

Chez moi cela fonctionne
j'ai ouvert plusieurs fichiers Excel
Dans un classeeur, j'ai un userform avec une ListBox1 et le code VBA que je t'ai soumis.
Quand je charge l'userform, la Listbox se remplie
Si je clique sur un nom de classeur affiché dans la ListBox, celui-lui devient le classeur actif et est affiché au premier plan.

PS: J'avais testé mon code avant de le poster... ;) et il fonctionne sur mon PC. ;)
Si cela ne fonctionne pas chez toi, c'est que tu fais ce qui doit pas être fait ou que tu as modifié le code de manière à générer une erreur.
 

Guigui

XLDnaute Occasionnel
Re : Lister fichiers excels ouverts instances différentes

Bonjour à tous, Staple1600,

Désolé pour la réponse tardive,

J'ai bien essayé de nouveau et pas d'erreur de "recopiage". ca ne fonctionne pas (2 pc différents)
On est d'accord on parle de jongler entre 2 instances Excel différentes ?

si j'ouvre 2 fichiers Excel dans la même instance, aucun problème je peux passer de l'un vers l'autre. mais entre 2 instances différentes ca coince...

J'ai l'impression qu'il manque l'information de l'instance à utiliser pour "activer" le "workbooks"

Merci par avance
 

Staple1600

XLDnaute Barbatruc
Re : Lister fichiers excels ouverts instances différentes

Bonsoir à tous

Tu m'as mis le doute.
J'ai donc cherché un autre moyen de compter les instances ouvertes
Code:
Sub InstanceCount()'code de Tom Urtis
Dim objList As Object, objType As Object, strObj$
strObj = "Excel.exe"
Set objType = GetObject("winmgmts:").ExecQuery("select * from win32_process where name='" & strObj & "'")
If objType.Count > 1 Then
MsgBox objType.Count & " Excel instances are running on your system.", , "More than one instance"
Else
MsgBox "Only this instance is running on your system.", , "One and done"
End If
End Sub
Et j'avais qu'une seule instance d'ouverte.
D'ailleurs comment tu fais pour ouvrir plusieurs instances ?
Car avec Excel 2013 , j'ai fait ceci:
Démarrer/Excel deux fois de suite -> une seule instance
puis
Démarrer Excel et ensuite double-clic sur un fichier Excel sur le bureau -> toujours une seule instance.
 

Guigui

XLDnaute Occasionnel
Re : Lister fichiers excels ouverts instances différentes

2 voir 3 écrans au travail. j'ai modifié les clés (ou je ne sais plus quoi) pour pouvoir ouvrir différente "fenetre" si besoin ...

J'ai tester ton code, il me compte bien 2 instances si j'en ouvre 2. la question reste entière :) comment "activer" le fichier x de l'instance x, copier une zone et la coller dans le fichier qui contient le code ...

(sans passer par l'activation ca serais le must ! :)
 

david84

XLDnaute Barbatruc
Re : Lister fichiers excels ouverts instances différentes

Bonjour Guigui, JM,
la question reste entière comment "activer" le fichier x de l'instance x, copier une zone et la coller dans le fichier qui contient le code ...

(sans passer par l'activation ca serais le must !
Si tu te poses cette question c'est peut-être que tu n'as pas compris l'intérêt d'utiliser l'API AccessibleObjectFromWindow qui te permet justement d'accéder à un objet VBA à partir du Handle (au sens identifiant) de sa fenêtre, et par là même aux propriétés de l'objet que tu pourras ensuite manipuler.

Tu peux par exemple regarder ici une possibilité qui te permettra de comprendre la manière de procéder.

En aménageant cet exemple tu peux par exemple récupérer le contenu de la 1ère cellule renseignée de chaque feuille de chaque classeur ouvert :
Code:
Option Explicit
#If Win64 Then
  Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
  (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
  Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" _
  (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
  Declare PtrSafe Function IIDFromString Lib "ole32" (ByVal lpsz As LongPtr, ByRef lpiid As UUID) As Long
  Declare PtrSafe Function AccessibleObjectFromWindow Lib "oleacc" _
  (ByVal hwnd As Long, ByVal dwId As Long, ByRef riid As UUID, ByRef ppvObject As Object) As Long
#Else
  Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
  (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
  Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
  (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
  Declare Function IIDFromString Lib "ole32" (ByVal lpsz As Long, ByRef lpiid As UUID) As Long
  Declare Function AccessibleObjectFromWindow Lib "oleacc" _
  (ByVal hwnd As Long, ByVal dwId As Long, ByRef riid As UUID, ByRef ppvObject As Object) As Long
#End If

Type UUID 'GUID
  Data1 As Long
  Data2 As Integer
  Data3 As Integer
  Data4(7) As Byte
End Type

Const IID_IDispatch As String = "{00020400-0000-0000-C000-000000000046}"
Const OBJID_NATIVEOM As Long = &HFFFFFFF0

Sub GetAllWorkbookWindowNames()
On Error GoTo MyErrorHandler
Dim hWndMain As Long

hWndMain = FindWindowEx(0&, 0&, "XLMAIN", vbNullString)

Do While hWndMain <> 0
  GetWbkWindows hWndMain
  hWndMain = FindWindowEx(0&, hWndMain, "XLMAIN", vbNullString)
Loop
Exit Sub

MyErrorHandler:
  MsgBox "GetAllWorkbookWindowNames" & vbCrLf & vbCrLf & "Err = " & Err.Number & vbCrLf & "Description: " & Err.Description
End Sub

Private Sub GetWbkWindows(ByVal hWndMain As Long)
  On Error GoTo MyErrorHandler

  Dim hWndDesk As Long
  hWndDesk = FindWindowEx(hWndMain, 0&, "XLDESK", vbNullString)

  If hWndDesk <> 0 Then
    Dim hwnd As Long
    hwnd = FindWindowEx(hWndDesk, 0, vbNullString, vbNullString)

    Dim strText As String
    Dim lngRet As Long
    
    Do While hwnd <> 0
      strText = String$(100, Chr$(0))
      lngRet = GetClassName(hwnd, strText, 100)

      If Left$(strText, lngRet) = "EXCEL7" Then
        GetExcelObjectFromHwnd hwnd
        Exit Sub
      End If

      hwnd = FindWindowEx(hWndDesk, hwnd, vbNullString, vbNullString)
    Loop

    On Error Resume Next
  End If

  Exit Sub

MyErrorHandler:
  MsgBox "GetWbkWindows" & vbCrLf & vbCrLf & "Err = " & Err.Number & vbCrLf & "Description: " & Err.Description
End Sub

Public Function GetExcelObjectFromHwnd(ByVal hwnd As Long) As Boolean
  On Error GoTo MyErrorHandler

  Dim fOk As Boolean
  fOk = False

  Dim iid As UUID
  Call IIDFromString(StrPtr(IID_IDispatch), iid)

  Dim obj As Object
  'Dim myWorkbook As Workbook
  Dim i As Byte
  Dim myWorksheet As Worksheet
  If AccessibleObjectFromWindow(hwnd, OBJID_NATIVEOM, iid, obj) = 0 Then 'S_OK
    Dim objApp As Excel.Application
    Set objApp = obj.Application
    For i = 1 To objApp.Workbooks.Count
      'Set myWorkbook = objApp.Workbooks(i)
      Debug.Print objApp.Workbooks(i).Name
      For Each myWorksheet In objApp.Workbooks(i).Worksheets
        Debug.Print "     " & myWorksheet.Name
        On Error Resume Next
        Debug.Print "     " & myWorksheet.UsedRange.Value2(1, 1)
        If Err.Number > 0 Then
          Debug.Print "     " & myWorksheet.UsedRange.Value2
          'Debug.Print "     celulle vide"
          Err.Clear
        End If
        DoEvents
      Next
    Next i
    fOk = True
  End If

  GetExcelObjectFromHwnd = fOk

  Exit Function

MyErrorHandler:
  MsgBox "GetExcelObjectFromHwnd" & vbCrLf & vbCrLf & "Err = " & Err.Number & vbCrLf & "Description: " & Err.Description
End Function

Mais tu peux également modifier des données, activer des classeurs, etc.
Je pense que tu as intérêt à étudier cette API de plus près et tu verras tout l'intérêt que tu peux en retirer.
A+
 

Guigui

XLDnaute Occasionnel
Re : Lister fichiers excels ouverts instances différentes

Bonjour à tous, David84,

Merci pour cette approche.

j'ai modifier la fonction comme ceci (après les '@@@@) ... c'est surement "sale" .. mais cela fonctionne :)

Code:
Public Function GetExcelObjectFromHwnd(ByVal hwnd As Long) As Boolean
 extraction = 0
   On Error GoTo MyErrorHandler
   Dim fOk As Boolean
   fOk = False

   Dim iid As UUID
   Call IIDFromString(StrPtr(IID_IDispatch), iid)

   Dim obj As Object

    Dim i As Byte
   Dim myWorksheet As Worksheet
   If AccessibleObjectFromWindow(hwnd, OBJID_NATIVEOM, iid, obj) = 0 Then 'S_OK
     Dim objApp As Excel.Application
     Set objApp = obj.Application
     For i = 1 To objApp.Workbooks.Count
'@@@@@@@@@@@@@@@@@
'       Debug.Print objApp.Workbooks(i).Name

       For Each myWorksheet In objApp.Workbooks(i).Worksheets
'       Debug.Print myWorksheet
    On Error Resume Next
'on copie que si le fichier est le bon fichier du personnel
        If objApp.Workbooks(i).Name Like "*csv_liste_personnel*" And extraction_dde = "csv_liste_personnel" Then
        Workbooks(ActiveWorkbook.Name).Sheets.Add
        Workbooks(ActiveWorkbook.Name).ActiveSheet.Name = "IMPORT"
'on copie depuis le bon fichier
        myWorksheet.Range("B1:BB4000").Copy
'et on le colle dans la feuille import
        Workbooks(ActiveWorkbook.Name).Sheets("IMPORT").Range("A1").PasteSpecial xlAll
        extraction = 1
        Application.DisplayAlerts = False
        objApp.Workbooks(i).Close
        Application.DisplayAlerts = True
        Exit Function
         End If

'on copie que si le fichier est le bon ABSENCE
        If objApp.Workbooks(i).Name Like "*liste_absence*" And extraction_dde = "liste_absence" Then

'on copie depuis le bon fichier
        myWorksheet.Range("D2:N4000").Copy
'et on le colle dans la feuille import
        Workbooks(ActiveWorkbook.Name).Sheets("CHECK DES ABS").Range("M2").PasteSpecial xlAll
        extraction = 1
        Application.DisplayAlerts = False
        objApp.Workbooks(i).Close
        Application.DisplayAlerts = True
        Exit Function
         End If

'Workbooks(i).ActiveSheet.Range("D2:N4000").Copy _
'     Destination:=ActiveWorkbook.ActiveSheet.Range("M2")



         If Err.Number > 0 Then

           Err.Clear
         End If
         DoEvents
       Next
     Next i
     fOk = True
   End If

   GetExcelObjectFromHwnd = fOk

   Exit Function

MyErrorHandler:
   MsgBox "GetExcelObjectFromHwnd" & vbCrLf & vbCrLf & "Err = " & Err.Number & vbCrLf & "Description: " & Err.Description
 End Function

Merci à tous.
 

Discussions similaires

Réponses
19
Affichages
2 K

Statistiques des forums

Discussions
312 084
Messages
2 085 194
Membres
102 811
dernier inscrit
caroline29260