XLDOTNET : QUITTER EXCEL SANS LAISSER D'INSTANCE EN RAM

Afyn Messages postés 608 Date d'inscription samedi 3 août 2002 Statut Membre Dernière intervention 22 décembre 2016 - 13 nov. 2004 à 19:11
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018 - 22 févr. 2007 à 08:20
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/27541-xldotnet-quitter-excel-sans-laisser-d-instance-en-ram

cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
22 févr. 2007 à 08:20
CreateObject permet de faire de la liaison tardive : le code source peut être compilé même si Excel n'est pas installé, et il suffit de trapper l'erreur dans ce cas. Alors qu'utiliser Excel.Application nécessite que Excel soit installé, et à la bonne version qui plus est. Et l'exe ne tournera qu'avec cette version, alors qu'en liaison tardive, la compatibilité ascendante et descendante est assurée (toutes les versions sup. et inf. d'Excel sont supportées, du moment que tu n'appelles pas de fonctionnalité spécifique). L'inconvénient est l'absence de vérification de type à la compilation (mais ça tu peux le faire dans un autre projet de test éventuellement, ou avec des constantes conditionnelles, mais ce n'est certes pas très pratique).
bertatoa Messages postés 3 Date d'inscription vendredi 17 février 2006 Statut Membre Dernière intervention 21 février 2007
21 févr. 2007 à 17:07
tu as raison, j'avais pas compris le code, la seule petite différence, c'est la non utilisation de CreateObject, relicat de vb6, je crois?
Je ferais plus attention la prochaine fois, désolé. :0(
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
21 févr. 2007 à 16:52
Je voulais dire que c'est la meme chose qu'XlDotNet : pas d'API non plus.
bertatoa Messages postés 3 Date d'inscription vendredi 17 février 2006 Statut Membre Dernière intervention 21 février 2007
21 févr. 2007 à 16:46
:o) tout à fait, juste que personnellement j'aime pas trop utiliser les API.
(par rapport au code de Eldim)
ce qui n'engage que moi...
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
21 févr. 2007 à 16:30
C'est strictement la même chose du point de vue fonctionnel.
bertatoa Messages postés 3 Date d'inscription vendredi 17 février 2006 Statut Membre Dernière intervention 21 février 2007
21 févr. 2007 à 14:10
bonjour,
en cherchant le moyen de tuer le process que je lance, sans tuer les autres instances de ce même process (par ex. Excel) j'ai trouvé une solution ingénieuse sur un autre site.
Le principe est de récupérer l'ID du Process et de le tuer par celui-ci. Tout ceci sans utiliser d'API ;o)):

dans une class:

Private appXls As Excel.Application
Private myWorkBooks As Excel.Workbooks
Private myWorkBook As Excel.Workbook
Private xlProcessID As Integer

Public sub exemple()

'création d'une instance d'Excel et récupération de son ID de process
xlProcessID = GetMyProcessID("Excel")

'Ajouter un nouveau classeur
appXls.Workbooks.Add()

myWorkBook = appXls.ActiveWorkbook

''''votre code

'sauver et tuer le process Excel
call SaveWorkBook(myWorkBook)

End sub

Public Function GetMyProcessID() As Integer

' Note: Imports System.Diagnostics
Dim priorSum As Integer = 0
Dim newSum As Integer = 0
Dim xlProcID As Integer = 0

' (1) Save the Sum of the Existing "Excel" Processes:
For Each proc As Process In Process.GetProcessesByName("Excel")
priorSum += proc.Id
Next proc

' (2) Create the New "Excel" Process:
appXls = New Excel.Application

' (3) Determine the 'newSum' of the Existing "Excel" Processs:
For Each proc As Process In Process.GetProcessesByName("Excel")
newSum += proc.Id
Next

' (4) Subtract the difference to detarmine the 'xlProcID'
xlProcID = newSum - priorSum

Return xlProcID

End Function

Public Sub SaveWorkBook(ByVal myWorkBook As Excel.Workbook)

'Enregistrer et quitter excel

myWorkBook.Save()
myWorkBook.Close()
myWorkBook = Nothing
appXls.Quit()

'tuer le process si toujours présent
Try
Dim proc As Process = Process.GetProcessById(xlProcessID)
proc.Kill()
Catch ' On error do nothing.
End Try

appXls = Nothing

End Sub

voila en gros (code pas optimisé) et vite fait, j'espère que cela pourra aider.
alex
cs_eldim Messages postés 956 Date d'inscription lundi 30 mai 2005 Statut Membre Dernière intervention 21 août 2014 1
17 nov. 2005 à 16:31
lol
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
17 nov. 2005 à 13:57
J'ai peut être répondu un peu vite cette fois :-)

Faudra que je teste GetWindowThreadProcessId : effectivement cela pourrait convenir dans tous les cas (si le Hwnd est disponible pour Excel 2000, ce qui est le cas je crois)
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
17 nov. 2005 à 13:02
Rappel de ce que j'ai mis dans ma doc : cela ne marchera pas avec Excel 2000 :

La seule solution pour éviter de traîner une instance en RAM est de la tuer purement et simplement. Pour la tuer il suffit de noter son Id de processus. Or, si l'on peut effectivement retrouver cet Id via le handle d'instance, accessible pour Excel XP et 2003, cette technique ne fonctionne pas pour Excel 2000 (le handle d'instance n'est pas accessible dans ce cas, et le handle de fenêtre ne permet pas de retrouver l'Id processus). Et de plus, ce problème concerne tous les logiciels Office.
cs_eldim Messages postés 956 Date d'inscription lundi 30 mai 2005 Statut Membre Dernière intervention 21 août 2014 1
17 nov. 2005 à 12:00
lol

tiens voila ma recup de process :

Dim H As Integer = ExcelApplication.Hwnd
If fnAjoutPossible(ExcelHWnd, H) Then
ExcelHWnd.Add(H)
End If
Dim Id As Integer = fnRecupProcessId(H)
If fnAjoutPossible(ExcelPID, Id) Then
ExcelPID.Add(Id)
End If

Avec :
Public Function fnAjoutPossible(ByVal C As Collection, ByVal S As Integer) As Boolean
Dim B As Boolean = True
Try
Dim i As Integer
For i = 1 To C.Count
If C.Item(i) = S Then
B = False
Exit For
End If
Next
fnAjoutPossible = B
Catch ex As Exception
End Try
End Function

Et aussi :
Friend ExcelPID As Collection = New Collection
Friend WithEvents ExcelApplication As Excel.Application

Et :
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Integer, _
ByRef lpdwProcessId As Integer) As Integer
Public Function fnRecupProcessId(ByVal hWnd As Integer) As Integer
Try
Dim R As Integer
Dim RetVal = GetWindowThreadProcessId(hWnd, R)
fnRecupProcessId = R
Catch ex As Exception
gRes.sbMsgCr(ex.Message, "modPremierPlan.fnRecupProcessId")
fnRecupProcessId = -1
End Try
End Function
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
17 nov. 2005 à 11:22
Ca veut dire quoi RDP ?

Je reconnais que si tu t'amuses à lancer une kyrielle d'Excel depuis un serveur, je suis bien content de savoir que ca ne marche plus ! (pour info Office12 va fonctionner en mode serveur)

Si tu parviens à récupérer l'IdProcess exact que tu as créé, ca m'intéresse.

Pour en revenir, à mon test, il compte bien le nombre de process : Process1.Length() est juste.

En conclusion, j'ajouterai que mon code XLDotNet est dédié au poste de travail, et pas à un serveur (jusqu'à preuve du contraire)
cs_eldim Messages postés 956 Date d'inscription lundi 30 mai 2005 Statut Membre Dernière intervention 21 août 2014 1
17 nov. 2005 à 10:51
de toute façon c'est pas une usine à gaz quand on récupère directement le process que l'on crée plutôt qu'une liste qui peut être inexacte en cas de simultanéité d'action...
cs_eldim Messages postés 956 Date d'inscription lundi 30 mai 2005 Statut Membre Dernière intervention 21 août 2014 1
17 nov. 2005 à 10:50
si si t'inquéquète

moi c sur un WinServ2003 en RDP et ça fonctionne pas
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
17 nov. 2005 à 10:32
Pourtant je viens de faire ceci pour un "Utilisateur avec accès restreint" et cela fonctionne :

Dim Process1() As Process
Try
Process1 = Process.GetProcesses()
MsgBox("GetProcesses : Ok")
Catch ex As Exception
MsgBox("GetProcesses : Bug")
End Try

Peut-être que tu n'as pas réessayé avec le dernier Framework 1.1 ?
cs_eldim Messages postés 956 Date d'inscription lundi 30 mai 2005 Statut Membre Dernière intervention 21 août 2014 1
17 nov. 2005 à 09:30
Salut Patrice99 !

La liste des process via la class VB.NET nécessite des droits d'administration sinon l'application tourne dans le vide. Je le sais puisque ça m'est arrivé même avec des utilisateur avec pouvoir

Pour le reste c'est + politique que développement...

"Aller bonne journée quand même.." (<On en plaisante pas...>)
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
17 nov. 2005 à 09:24
> ça ne peut fonctionner que si on est administrateur du pc donc pas utilisable en entreprise...

Faux ! ce code fonctionne aussi parfaitement pour un "Utilisateur avec accès restreint" ("Groupe des utilisateurs" qui est justement plus restreint que "Utilisateur standard" : "Groupe des utilisateurs avec pouvoir")

> Plutôt que de lister les process récupère ton process excel uniquement ça évitera les plantages...

Ca peut sans doute faire gagner quelques chouilla-secondes, mais ça ne plante pas chez moi.

Sur le fond, ce que l'on trouve dans une entreprise, c'est un magma de versions différentes d'Office : en pratique on ne peut pas forcer la version d'Office d'un client pour lequel on créé un logiciel, et à mon avis les outils VSTO ne sont pertinents que pour des développements internes à une entreprise, ou alors spécifiques à un seul client, pour lesquels (à la rigueur) on peut forcer la version d'Office.
cs_eldim Messages postés 956 Date d'inscription lundi 30 mai 2005 Statut Membre Dernière intervention 21 août 2014 1
16 nov. 2005 à 16:56
Salut tout le monde !

Je m'incruste un peu...

Dsl de vous déranger dans votre euphorie mais ça ne peut fonctionner que si on est administrateur du pc donc pas utilisable en entreprise...

Plutôt que de lister les process récupère ton process excel uniquement ça évitera les plantages...

A+
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
13 oct. 2005 à 08:34
DotNet2 : on peut maintenant cibler aussi Office 2000 et 97 !!!, mais toujours pas simultanément :-(
http://morpheus.developpez.com/vsto2/
Nesmontou Messages postés 5 Date d'inscription mardi 14 juin 2005 Statut Membre Dernière intervention 2 septembre 2005
2 sept. 2005 à 16:50
Excellent, exactement ce que je cherchais
Bravo
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
15 juil. 2005 à 08:35
Voir aussi :
SafeCOMWrapper - Managed Disposable Strongly Typed safe wrapper to late bound COM
www.codeproject.com/csharp/SafeCOMWrapper.asp
L'auteur se propose de résoudre tous ces problèmes !
cs_Benouille Messages postés 215 Date d'inscription jeudi 24 octobre 2002 Statut Membre Dernière intervention 7 septembre 2007
7 juin 2005 à 10:47
hé mais c'est pas con ça :)
c'est un peu dommage dans l'idée mais pas con du tout!
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
7 juin 2005 à 09:12
Il y a une alternative : Depuis dotnet, lancer un programme VB6 qui lance Excel : dans ce cas, il ne reste pas d'instance en RAM non plus.
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
12 févr. 2005 à 10:24
J'ai enfin trouvé pourquoi ma contribution était illisible : c'était la ligne très longue de == qui faisait boguer toute la page...
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
18 janv. 2005 à 13:03
Si le ProcId de clsExcelHost reste à 0, c'est que cela ne marche pas !
skowee59 Messages postés 78 Date d'inscription vendredi 17 janvier 2003 Statut Membre Dernière intervention 29 juin 2006
18 janv. 2005 à 11:58
C bon j'ai trouvé.
En fait, avant j'utilisais la référence Excel avec notamment la propriété Cells. Mais comme là tu utilises la propriété Range et qu'il y a une petite différence de syntaxe. J'avais pas fait gaffe ...
Par contre, l'ID qui est retourné pour Excel est toujours 0. Excel se ferme quand même mais pas tout le temps !
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
18 janv. 2005 à 09:02
Tu as recompilé les sources ? c'est nécessaire car l'exe que j'ai mis a été compilé avec le framework 1.1 qui n'est pas compatible avec le 1.0
skowee59 Messages postés 78 Date d'inscription vendredi 17 janvier 2003 Statut Membre Dernière intervention 29 juin 2006
18 janv. 2005 à 08:26
Ton code m'intéresse fortement mais je l'ai testé et il me retourne l'erreur suivante : "Exception de HRESULT : 0x800A03EC"
As-tu une idée ?
Pour info, je suis avec le .NET framework 1.0
Merci
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
13 janv. 2005 à 09:19
Ce n'est pas tant le ramasse miette qui est déficient que la libération des objets de l'interopérabilité com-ActiveX de dotnet.

Pour résumer, tu as besoin de ce code si tu comptes utiliser aussi Excel 2000 ou Word 2000 avec ton appli dotnet, sinon tu vas te trimbaler une instance en RAM que tu ne pourras pas quitter tant que ton appli.net restera ouverte. Le simple fait d'avoir ouvert et manipuler Excel via automation pose le problème, si tu ne fait qu'ouvrir un document Excel via ProcessStartInfo, il n'y a pas de problème.
cs_Benouille Messages postés 215 Date d'inscription jeudi 24 octobre 2002 Statut Membre Dernière intervention 7 septembre 2007
12 janv. 2005 à 16:32
moi j'utilise excel pour exporter les données d'une grille (grid de vb.net), excel n'a pour but que d'apporter les fonctionalités d'excel: filtre tri etc ... pour mes utilisateurs expérimentés.

autrement dit en utilisation ça se passe comme ça:
ils ouvrent ma mini appli de reporting qui leur renvoie un gros tableaux avec pleins de soldes de banques, ils font l'export excel du tableau, puis travaille sur le doc excel qu'ils stockent, mettent en partage ou l'envoie a nos clients/fournisseurs si besoin.

en bref l'appli et le doc sont indépendants, de plus ils peuvent avoir leurs propres doc excels ouverts a coté, et je ne vois pas bien l'utilité d'avoir 5 ou 6 excel en parallèles parcequ'on a 5 ou 6 classeur d'ouverts (une instance d'excel gérant tous les classeurs).

j'ai aussi noté ce probleme et avait été réconforté quand tu m'en avais parlé, mais je ne vois pas bien comment mon appli peut avec ce bout de code suppléer le ramasse miette déficient.

vbnouille
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
10 janv. 2005 à 16:46
Non tu me déranges pas : en fait quand tu créé un Excel, tu obtiens à coup sur son ProcId et pas le procId d'un autre Excel qui serait déjà ouvert. Du coup, il n'y a absolument aucun risque de tuer le mauvais processus Excel. De plus, tu peux lancer plusieurs Excel, quand tu appelleras la fonction oXLH.Quitter() de chacun, tu les tueras dans le bon ordre, sans qu'il puisse y avoir de confusion entre eux, d'accord ?
DonCastor Messages postés 9 Date d'inscription lundi 17 novembre 2003 Statut Membre Dernière intervention 10 janvier 2005
10 janv. 2005 à 15:35
pas mal du tout ton truc, mais j'ai une question:
Comment tu fais si jamais ton utilisateur lance plusieurs fichiers excel dans ton appli?
Si je comprends bien ton code, tu peux en arreter un seul et de suite apres l'avoir lancé, mais si l'utilisateur en lance plusieurs comment tu fais pour retrouver lequel est le bon.
Je m'explique, imaginons que je crée une application qui se sert d'excel:
- je génère un premier classeur, je le quitte, j'en génère un deuxième, comment ton code va me le tuer et lequel?
- je génère un classeur, j'en génère un deuxième sans les fermer lequels des deux est-ce qu'il va tuer?
- si j'appelle ton code avec une instance d'excel qui tourne déjà, est-ce qu'il va la considerer comme étant un processus Excel ou est-ce qu'il va la tuer?
-sachant que quand je quitte mon application les processus sont tous tués sans problèmes, comment faire (pour ne pas tuer un classeur que je veux garder pour travailler dessus par exemple) sans le tuer.

Désolé de te déranger avec toutes ces questions, mais ton code a l'air bien mais je veux m'assurer de voir si je peux vraiment en avoir l'utilité ou si je dois en rajouter ou en core trouver carrement une autre méthode.

Merci.
DonCastor
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
4 déc. 2004 à 12:19
Voir aussi :
www.codeproject.com/dotnet/Office2000usingDotnet.asp
Afyn Messages postés 608 Date d'inscription samedi 3 août 2002 Statut Membre Dernière intervention 22 décembre 2016
13 nov. 2004 à 19:11
Bien vu ... Bravo

Afyn
Navedac
Rejoignez-nous