PC SOFT

FOROS PROFESIONALES
WINDEVWEBDEV y WINDEV Mobile

Inicio → WINDEV 2025 → ObjetActif avec Excel
ObjetActif avec Excel
Iniciado por TheCout, 30,abr. 2020 10:01 - 4 respuestas
Miembro registrado
104 mensajes
Publicado el 30,abril 2020 - 10:01
Bonjour,

Je suis confronté à un problème parfaitement reproductible.

Je veux manipuler un fichier Excel avec Automation et que l'utilisateur voit le résultat.

Donc j'ai fait dans un premier temps:
v_obj_xls est un objet automation "Excel.Application"
v_obj_xls>>Visible = Vrai
//diverses manipulations

Le problème avec çà est que Excel reste derrière la fenêtre de mon application. Il faut que l'utilisateur l'active.

Du coup, j'ai fait plutôt ceci:

LanceAppli(....excel.exe)
//....Excel se lance en avant-plan : très bien
v_obj_xls est un objet automation dynamique

//attente 30 secondes maxi jusqu'à ce que Excel "réagisse"
ChronoDébut()
BOUCLE
v_obj_xls = ObjetActif("Excel.Application")
SI v_obj_xls <> Null
SORTIR
SINON
v_dur = ChronoValeur()
SI v_dur..EnSecondes > 30
Erreur("Excel inaccessible")
RETOUR
FIN
FIN
FIN

//je continue mon traitement avec Excel...


Le problème, c'est que ObjetActif renvoie toujours null. Il faut que je remette mon appli avant-plan, quitte ensuite à remettre Excel en avant plan à nouveau et là ObjetActif fonctionne.

Est-ce que certains ont déjà rencontré ce problème ? Avec Word, on n'a pas ce problème.
Miembro registrado
948 mensajes
Publicado el 01,mayo 2020 - 20:19
Bonjour
J'ai trouvé cette méthode mais c'est un petit lourd...Il y a surement mieux

WindowsFound est un booléen
WinPID est un entier système
ExcelFileName, CompleteExcelFileName, ListeDesFenetres, sLigne est une chaîne
xl est un objet automation dynamique

ExcelFileName = "tests.xlsx"
CompleteExcelFileName = ComplèteRep(fRepExe()) + ExcelFileName
IF NOT fFichierExiste(ExcelFileName) THEN
Erreur("Fichier Excel inconnu !")
RETOUR
END

xl = allouer un objet automation "Excel.Application"
IF xl = Null THEN
Erreur("Erreur 'Excel.application' n'est pas installé sur ce poste !")
RETOUR
END
xl>>Visible = True
xl>>WorkBooks>>Open(CompleteExcelFileName)
Multitâche(0)
ListeDesFenetres = EnumWindows()
IF ListeDesFenetres = "" THEN
Erreur("Impossible de lister les fenêtres !")
xl>>ActiveWorkbook>>Close()
xl>>Quit()
RETOUR
END

WindowsFound = False
FOR ALL STRING sLigne OF ListeDesFenetres SEPARATED by CRLF
IF ChaîneOccurrence(sLigne, ExcelFileName) > 0 THEN WindowsFound = True; SORTIR
END

IF NOT WindowsFound THEN
Erreur("Fenêtre non trouvée !")
xl>>ActiveWorkbook>>Close()
xl>>Quit()
RETOUR
END
WinPID = Val(ExtraitChaîne(sLigne, 1), 16)

IF EnModeTest() THEN Trace(ObjetActif("Excel.Application") <> Null ? "Actif" ELSE "Inactif")
API("User32.dll", "ShowWindow", WinPID, 3)
IF EnModeTest() THEN Trace(ObjetActif("Excel.Application") <> Null ? "Actif" ELSE "Inactif")

// test d'écriture...
xl>>Range("A6")>>Value = "1"
xl>>Range("A7")>>Value = "2"
xl>>Range("A8")>>Value = "3"



FUNCTION EnumWindows(pHndParent est un entier système = -1):chaîne
resDLL est un booléen
MyHandle, nbChar, Pid est un entier système
Patern, Liste, Temp, WindowsListe est une chaîne

WindowsListe = ""

Patern = Répète("Z", 8) + Caract(0x0d) // 9 octets
Liste = Répète(Patern, 1000) //(9 * 1000)+1 pour le 0x00 terminal soit len=9001 pour lpClassName et lpLibellé
lpClassName, lpLibellé est une chaîne ASCIIZ sur 9001

IF pHndParent = -1 THEN
// Premier passage on traite le cas des parents : «EnumWindows»
//see : http://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx
resDLL = API(user32_dll, "EnumWindows", &EnumWindowsFunction, &Liste)
IF NOT resDLL THEN RENVOYER ""
ELSE
// second passage on traite les child : «EnumChildWindows»
// see : https://docs.microsoft.com/fr-fr/windows/win32/api/winuser/nf-winuser-enumchildwindows
resDLL = API(user32_dll, "EnumChildWindows", pHndParent, &EnumWindowsFunction, &Liste)

// Si c'est faux c'est qu'il n'y a pas d'enfant...
IF NOT resDLL THEN RENVOYER ""
END

//-----> la liste contient les handle ( attention --> en format hexadécimal)
Liste = Remplace(Liste, Patern, "") // suppression des pattern (ZZZZZZZZ0x0d) non utilisés
Liste = Liste[[1 A Taille(Liste)-1]] // et suppression du dernier Caract(0x0d) qui ne sert à rien

FOR ALL STRING Temp OF Liste SEPARATED by Caract(0x0d)

MyHandle = Val(Temp,"x") // handle en décimal

IF pHndParent = -1 THEN
xPidParent est un entier système = API(user32_dll, "GetWindowThreadProcessId", MyHandle, &Pid)
END

// On lit le nom de la classe (ne peut pas être vide)
//see : https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclassnamea
lpClassName = Répète(" ", 512)
nbChar = API(user32_dll, "GetClassNameA", MyHandle, &lpClassName, Taille(lpClassName))
lpClassName = (nbChar > 0 ? lpClassName[[1 sur nbChar]] ELSE "")

// On lit le libellé (il peut être vide)
//see : http://msdn.microsoft.com/en-us/library/windows/desktop/ms633520%28v=vs.85%29.aspx
lpLibellé = Répète(" ", 512)
nbChar = API(user32_dll, "GetWindowTextA", MyHandle, &lpLibellé, Taille(lpLibellé))
lpLibellé = (nbChar > 0 ? lpLibellé[[1 sur nbChar]] ELSE "")

//---> Handle tab ClasseName tab Libellé cr
IF WindowsListe <> "" THEN WindowsListe += CRLF
WindowsListe += NumériqueVersChaîne(MyHandle, "08X") + TAB + SansEspace(lpClassName) + TAB + SansEspace(lpLibellé)
END
RENVOYER WindowsListe


Testé sur pc Win10-1909 / Windev20-01F200066p/ Excel 2016-pro

--
« L'erreur ne devient pas vérité parce qu'elle se propage et se multiplie ; la vérité ne devient pas erreur parce que nul ne la voit. » Gandhi
Miembro registrado
962 mensajes
Publicado el 02,mayo 2020 - 00:09
hello,
en plus simple avec un classeur déjà ouvert par OLE (ne pas lancer excel par un LanceAppli) :
excel est un objet OLE dynamique = ObjetActif("Excel.Application")
SI excel <> Null ALORS AppelDLL32("User32.dll","SetForegroundWindow",excel>>hwnd)


--
Ami calmant, J.P
Miembro registrado
948 mensajes
Publicado el 02,mayo 2020 - 16:00
Bonjour
Je me doutais bien qu'il y avait plus simple...
Je ne connaissais pas le xl>>hwnd qui permet effectivement de simplifier énormément.
Du coup il y a deux méthodes :
API("User32.dll", "ShowWindow", xl>>hwnd, 3)
AppelDLL32("User32.dll","SetForegroundWindow", xl>>hwnd)
Bien-vu Jurassic Pork

--
« L'erreur ne devient pas vérité parce qu'elle se propage et se multiplie ; la vérité ne devient pas erreur parce que nul ne la voit. » Gandhi
Miembro registrado
104 mensajes
Publicado el 03,mayo 2020 - 14:06
Effectivement, c'est la méthode que j'avais retenue entre temps.

J'hésitais à le faire car je me souvenais qu'il y a maintenant des restrictions Windows pour forcer à passer une fenêtre au premier-plan : (illustré ici par exemple : https://gist.github.com/EBNull/1419093). Mais en fait, je pense que la restriction lorsque l'on veut passer "soi-même" au premier-plan.

Par contre, quand on veut passer une autre fenêtre, il y a maintenant une procédure similaire dans Windev, SysFenActive qui je suppose fait la même chose que SetForegroundWindow. Donc, cela donne le code ci-dessous. Ce qui n'empêche pas PC Soft de réfléchir pourquoi ObjetActif avec Excel ne fonctionne pas dans certains cas (alors que cela fonctionne très bien avec Word par exemple). Mais c'est une autre histoire...

v_obj_xls est un objet automation "Excel.Application"
v_obj_xls>>Visible = Vrai

ET enfin
SI v_obj_xl <> Null ALORS SysFenActive(v_obj_xls>>hWnd)