PC SOFT

FOROS PROFESIONALES
WINDEVWEBDEV y WINDEV Mobile

Inicio → WINDEV 2025 → Gerer les differentes instance d'excel en Cexcel
Gerer les differentes instance d'excel en Cexcel
Iniciado por kevin, 07,may. 2019 18:02 - 16 respuestas
Miembro registrado
36 mensajes
Publicado el 07,mayo 2019 - 18:02
Bonjour bonjour,

Voilà... je travaille sur un logiciel... et à son lancement, je liste tous les classeurs ouverts.
Le problème c'est que certain utilisateur de la société utilise plusieurs instance d'excel.. et je vois que la première.

Comment puis-je voir.. les autres instances ? (et passé de l'une à l'autre ???)

Du coup comme je ne trouvais pas... je me suis dit que j'allais m'y prendre autrement... et je me suis dit.. je n'ai qu'a passer cette étape et travailler que sur le classeur Actif... mais... même problème.. mon logiciel ne voit que le classeur actif de la première instance...
Mon bout de code pour récupéré le nom et le chemin du classeur actif...
xl est un objet automation dynamique
xl = ObjetActif("Excel.Application")

SI xl = Null ALORS
Info("Aucun Document Excel détecté")
Ferme()
SINON
sName est une chaîne UNICODE = xl>>ActiveWorkbook>>Name
sChemin est une chaîne = xl>>ActiveWorkbook>>Path
TableAjouteLigne(TABLE_Excel_Ouvert,sName,sChemin+"\"+sName)
FIN


Voilà ça fait un moment que je cherche comment faire... et je bloque..
J'ai même chercher du coté VBA.... j'ai trouvé... mais... moi pas comprendre...

Help !!
Merci d'avance !
K.
Miembro registrado
6 mensajes
Publicado el 09,mayo 2019 - 16:34
qu'est-ce que tu as trouvé en VBA?
Miembro registrado
36 mensajes
Publicado el 10,mayo 2019 - 11:57
Bonjour Patrick,
Alors j'ai trouver plusieurs truc différent en VBA. celui qui me correspond le plus je pense est ici :

https://www.excel-downloads.com/threads/lister-fichiers-excels-ouverts-instances-differentes.219949/

et j'arrive pas a tout refaire en OLE .. :(
Merci de ton aide
K.
Miembro registrado
36 mensajes
Publicado el 29,octubre 2019 - 16:39
Bonjour bonjour,

C'est encore moi... je galère beaucoup pour toujours le même problème.. :/
Est-ce que quelqu'un à une idée ?

;(

Merciiiiiii

K.
Miembro registrado
512 mensajes
Publicado el 30,octubre 2019 - 10:17
Bonjour Kevin,

Je pourrais te donner un coup de main dans quelques jours.

La fonction API AccessibleObjectFromWindow m'intéresse. Elle permet de récupérer une référence OLE d'un objet associé à une fenêtre.
https://docs.microsoft.com/fr-fr/windows/win32/api/oleacc/nf-oleacc-accessibleobjectfromwindow

Cette API fait partie de l'implémentation d'une technologie baptisée "Microsoft Active Accessibility", qui permet de rendre "accessible" aux personnes handicapées les interfaces utilisateur d'applications développées pour Windows. Mais cela permet aussi de piloter ou de tester l'interface utilisateur d'une application.
https://docs.microsoft.com/en-us/windows/win32/winauto/how-active-accessibility-works

Dans le cas de ce fil de discussion, l'objet OLE que l'on veut retrouver est de type "Excel.Application".

Il y a aussi cette ressource qui est un prolongement du lien que tu as donné.
https://www.excel-downloads.com/threads/creation-dune-fonction-getobject-amelioree.20025438/page-2

A bientôt. :-)
Miembro registrado
36 mensajes
Publicado el 30,octubre 2019 - 12:31
Bonjour =JBO= !!

Merci de ton aide et de tous les liens.
Je vais étudier tout ça et voir ce que je peux en faire !
Merci !
Miembro registrado
512 mensajes
Publicado el 30,octubre 2019 - 13:55
Kevin,
Dans ton message, tu disais "galérer".

As-tu commencé à coder quelque chose ? Si oui, ton code est peut-être intéressant...

Ou bien alors as-tu trouvé ça vraiment trop compliqué et tu recherches simplement un développeur qui aurait déjà défriché le sujet ?

Comment vois-tu la fonctionnalité dont tu as besoin ? Faire évoluer la classe CExcel, ou bien coder une procédure développée indépendamment ?

Pour ma part, je pensais faire simple, à savoir, coder une procédure qui ajoute dans un tableau d'objets OLE, toutes les instances "Excel.Application" en cours d'exécution sur le bureau Windows.
Mensaje modificado, 30,octubre 2019 - 14:03
Miembro registrado
36 mensajes
Publicado el 30,octubre 2019 - 16:16
Hey !

Alors pour le moment j'ai juste ça :
xl est un objet automation dynamique
xl = ObjetActif("Excel.Application")
SI xl = Null ALORS
Info("Aucun Document Excel détecté")
FIN
SI xl <> Null ALORS

sName est une chaîne UNICODE

POUR i=1 _À_ xl>>Workbooks>>Count()
sName =xl>>Workbooks(i)>>Name
sChemin est une chaîne = xl>>Workbooks(i)>>Path
TableAjouteLigne(TABLE_Excel_Ouvert,sName,sChemin+"\"+sName)
FIN
TABLE_Excel_Ouvert..Visible = Vrai
TableSelectMoins(TABLE_Excel_Ouvert)

FIN


Qui fonctionne parfaitement pour la première instance d'excel.
(je t'épargne tout mes tests foireux... d'essayer avec le PID de faire changer de focus d'excel... )
Bon là j'avoue c'est fait à l'arrache ... car j'utilise pas ma classe excel.... là c'est juste un soft bidon pour mes tests...MAIS...
J'ai déjà fait évolué ma classe et je ne suis pas contre la faire évolué encore.

La procédure n'est pas une mauvaise idée non plus... (elle à même l'air bonne....)
J'ai entre temps envoyé un mail au support technique... au cas ou...
Miembro registrado
36 mensajes
Publicado el 04,noviembre 2019 - 14:20
Hey !!

Après quelques recherches... j'ai trouvé une solution... (enfin .. une demi pour le moment.)
J'arrive à avoir le nom des Excel d'ouvert (Actuellement à l'affichage) quelque soit l'instance.
mais :
1 - ) Je ne vois pas les autre doc des instance (seul celui qui est en cours )
2 - ) j'arrive pas a choper leur chemin du coup...

Alors donc pour ça... faut importer un Assemblage.NET
==> System.
Et voilà le code :
TabProcessus est un tableau de 0 "System.Diagnostics.process" dynamique
TabProcessus = "System.Diagnostics.process".GetProcesses()
POUR TOUT proc de TabProcessus
SI Contient(proc.MainWindowTitle,"xls",SansCasse) ALORS
sName = ChaîneSupprime(proc.MainWindowTitle,"Microsoft Excel - ")
TableAjouteLigne(TABLE_Excel_Ouvert,sName,sChemin+"\"+sName)
FIN
FIN


Je continue de creuser...
Miembro registrado
2.682 mensajes
Publicado el 04,noviembre 2019 - 15:02
Bonjour,

Pourquoi ne pas utiliser ExeListeProcessus(exePID,exeNomCourt,exeNomLong). Ce serait certainement plus simple

--
Cordialement,

Philippe SAINT-BERTIN
Miembro registrado
36 mensajes
Publicado el 04,noviembre 2019 - 16:00
Bonjour Philippe.

J'ai déjà testé.. sauf que ça me donne la liste des Executable... pas des documents..
Et même en récupérant le PID.. ensuite.. je ne sais pas quoi faire du coup de ce PID...:/

Merci:)
Miembro registrado
512 mensajes
Publicado el 04,noviembre 2019 - 19:50
Bonjour Kevin,

J'ai pu avancer mais moi aussi je suis bloqué sur un point technique. :(
Je n'arrive pas (encore) à récupérer une référence sur un objet OLE Automation à partir d'un objet COM qui est obtenu avec la fonction AccessibleObjectFromWindow de l'API Windows.

J'ai créé une collection de procédures pour bénéficier du traitement (Déclaration].

Code du traitement [Déclaration ] de la collection de procédures :
API_FindWindowEx est une Description d'API
AVEC API_FindWindowEx
..NomDLL = "USER32"
..NomFonction = "FindWindowExA" // utilise des chaînes ANSI
..TypeRetour = apiEntierSystème // HWND
..Paramètre[1]..Type = apiEntierSystème // HWND hWndParent
..Paramètre[2]..Type = apiEntierSystème // HWND hWndChildAfter
..Paramètre[3]..Type = apiEntierSystème // LPCSTR lpszClass
..Paramètre[4]..Type = apiEntierSystème // LPCSTR lpszWindow
FIN

API_AccessibleObjectFromWindow est une Description d'API
AVEC API_AccessibleObjectFromWindow
..NomDLL = "OLEACC"
..NomFonction = "AccessibleObjectFromWindow"
..TypeRetour = apiEntier_4 // HRESULT
..Paramètre[1]..Type = apiEntierSystème // HWND hwnd
..Paramètre[2]..Type = apiEntier_4 // DWORD dwId
..Paramètre[3]..Type = apiEntierSystème // REFIID riid (pointeur sur IID, GUID)
..Paramètre[4]..Type = apiEntierSystème // void **ppvObject
FIN

GUID est une structure
Data1 est un entier sur 4 octets // DWORD
Data2 est un entier sur 2 octets // WORD
Data3 est un entier sur 2 octets // WORD
Data4 est un Buffer sur 8 octets // BYTE[8]
FIN

// Pseudo-constantes
C_XLMAIN est une chaîne ANSI = "XLMAIN"
C_XLDESK est une chaîne ANSI = "XLDESK"
C_EXCEL7 est une chaîne ANSI = "EXCEL7"
S_OK est un entier sur 4 octets = 0
C_IID_IDispatch est une chaîne UNICODE = "{00020400-0000-0000-C000-000000000046}" // LPOLESTR
C_OBJID_NATIVEOM est un entier sur 4 octets = 0xFFFFFFF0 // DWORD

// Identifiant de l'interface IDispatch
IID_IDispatch est un GUID
nResultIID est un entier = API("OLE32","IIDFromString",&C_IID_IDispatch,&IID_IDispatch)


Code de la procédure ListerApplicationsExcel (c'est dans cette procédure que je suis bloqué) :
Procedure ListerApplicationsExcel(tabAppExcel_inout est un tableau d'objet automation dynamique) : entier

nCompteur est un entier
hWndMain,hWndDesk,hWndExcel est un entier système

// rechercher la fenêtre de 1er niveau de classe XLMAIN
hWndMain = API_FindWindowEx(0,0,&C_XLMAIN,0)

TANTQUE hWndMain <> 0
BOUCLE (1) // pseudo-bloc de code
// rechercher la fenêtre de classe XLDESK
hWndDesk = API_FindWindowEx(hWndMain,0,&C_XLDESK,0)

SI hWndDesk = 0 ALORS SORTIR // sortir du pseudo-bloc de code

// rechercher la fenêtre de classe EXCEL7
hWndExcel = API_FindWindowEx(hWndDesk,0,&C_EXCEL7,0)

SI hWndExcel = 0 ALORS SORTIR // sortir du pseudo-bloc de code

// récupérer une référence à l'objet OLE Excel.Application
nResult est un entier sur 4 octets
nAdresse est un entier système

nResult = API_AccessibleObjectFromWindow(hWndExcel,C_OBJID_NATIVEOM,&IID_IDispatch,&nAdresse)

SI nResult <> S_OK ALORS SORTIR

IOLE_ExcelApplication est un COMObjet
IOLE_ExcelApplication..Adresse = nAdresse

// >> BUG pour "transformer un objet COM en objet OLE Automation
autAppExcel est un objet automation dynamique
autAppExcel = IOLE_ExcelApplication

TableauAjoute(tabAppExcel_inout,autAppExcel)

nCompteur++

FIN // fin pseudo-bloc de code

// boucler sur la prochaine fenêtre de 1er niveau de classe XLMAIN
hWndMain = API_FindWindowEx(0,hWndMain,&C_XLMAIN,0)
FIN

RENVOYER nCompteur


Exemple d'utilisation (le jour où ça voudra bien fonctionner) :
tabAppExcel est un tableau d'objets automation dynamique
nCompteurApp est un entier

nCompteurApp = ListerApplicationsExcel(tabAppExcel)
Mensaje modificado, 04,noviembre 2019 - 19:59
Publicado el 05,noviembre 2019 - 09:35
Bonjour

Qu'entends-tu et comment fais-tu pour ouvrir 2 instances d'Excel?
Quelle version d'Excel utilises-tu?
Je suis sous Excel 2016 et, si je ne me trompe pas, par défaut celui-ci ouvre une nouvelle instance pour chaque document.
Chez moi avec ce code je liste tous les classeurs ouverts et toutes les feuilles de chaque classeur.
oExcel est un objet automation dynamique = ObjetActif("Excel.Application")

POUR i = 1 _À_ oExcel>>Workbooks>>Count
Trace(oExcel>>Workbooks(i)>>Name)
POUR j = 1 _À_ oExcel>>Workbooks(i)>>Sheets>>Count
Trace(oExcel>>Workbooks(i)>>Name + " - " + oExcel>>Workbooks(i)>>Sheets(j)>>Name)
FIN
FIN


Bon dev.

Laurent M.
Miembro registrado
36 mensajes
Publicado el 05,noviembre 2019 - 11:25
Salut Laurent,

Alors en fait avec Excel 2016, quand tu ouvres un nouveau document ça ouvre pas une nouvelle instance. en revanche il l'ouvre dans une fenêtre séparé...
Mais c'est la même instance. (un peu comme les panneaux dockable de Windev en gros)
Sous Excel 2010 il y a encore ce "problème" d'instance.
En revanche ce qui est très intéressant dans ton code c'est qu'en plus du document excel il liste également les différents onglets de chaque document.

@=JBO= je me plonge dans ton code voir...

Merci à tous !!
Miembro registrado
36 mensajes
Publicado el 05,noviembre 2019 - 11:41
=JBO= !!!

Bon j'ai juste rajouter object actif .. et ça à l'air de marcher...
autAppExcel est un objet automation dynamique
autAppExcel = ObjetActif(IOLE_ExcelApplication)

enfin le code passe... et j'ai bien le nombre d'instance d'excel.
Publicado el 06,noviembre 2019 - 09:02
Bonjour

Ok.
Petit complément, j'ai trouvé comment ouvrir une instance supplémentaire sous Office 2013 et 2016. Il faut maintenir la touche ALT enfoncée lors du démarrage d'Excel. Apparaît alors une fenêtre qui demande si l'on veut ouvrir une instance supplémentaire.

Bon dev.

Laurent M.
Miembro registrado
36 mensajes
Publicado el 07,noviembre 2019 - 14:43
Bonjour bonjour,

Alors... je suis reparti de zéro... parce que je me perdais dans toutes les méthodes proposés.
J'ai trouvé une solution qui fonctionne.

Procédure :
Procedure listedesdoc()
tabName est une tableau de chaînes
hWndChild est un entier
lengthTitle est un entier
bRet est un booléen=Faux
szBuff est une chaîne ASCIIZ sur 255
sTitleFound est une chaîne
hWndChild= API("user32.dll","FindWindowA",0,0)
i est un entier =1
//// on parcours les fenetres
TANTQUE hWndChild<>0
SI API("User32.dll","GetParent",hWndChild)=0 ALORS
// on recupere le titre
lengthTitle=API("user32.dll","GetWindowTextLengthA",hWndChild)
szBuff=Complete(szBuff,255,Caract(32))
API("user32.dll","GetWindowTextA",hWndChild,&szBuff,Taille(szBuff))
SI lengthTitle>0 ALORS
sTitleFound=szBuff
SI Contient(sTitleFound,"xls") ALORS
TableauAjoute(tabName,sTitleFound)
FIN
FIN
FIN
hWndChild=API("user32.dll","GetWindow",hWndChild,2)
FIN

RENVOYER tabName


Code d'appel :

tabName est un tableau de chaîne = COL_ProcéduresGlobales.listedesdoc()
sChemin est une chaîne
sName est un chaîne

POUR i = 1 À tabName..Occurrence
sName = tabName[i]
TableAjouteLigne(TABLE_Excel_Ouvert,sName,sChemin+"\"+sName)
FIN


du coup je vais paufiner pour avoir maintenant le lien complet des documents.

Dites moi ce que vous en pensez et si ça marche bien chez vous.

K.