TL;DR —
Shelldémarre un programme et rend la main immédiatement, avant que ce programme n'ait rien fait. Il vous renvoie un identifiant de tâche (unDouble), pas un code de sortie, ni une sortie, ni un indicateur de réussite, et la ligne suivante de votre macro s'exécute pendant que le programme est encore en train de se lancer. Si vous devez l'attendre ou lire ce qu'il a produit,Shellest le mauvais outil — utilisezWScript.Shell(.Runavec attente, ou.Exec).
Sub ShellDemo()
Dim taskId As Double
taskId = Shell("notepad.exe", vbNormalFocus) ' renvoie un identifiant de tache, puis continue
Debug.Print taskId ' ex. 4180 - PAS un code de sortie
' la ligne ci-dessous s'execute MAINTENANT, alors que Notepad s'ouvre encore
End Sub
Shell est le seul mot de VBA qui sort d'Excel pour démarrer un autre programme Windows. L'ennui, c'est
qu'il ne se comporte en rien comme le reste de votre macro. Partout ailleurs, une ligne termine son travail
avant que la suivante ne s'exécute, et un échec lève une erreur bien visible. Shell rompt ces deux
habitudes : il lance le programme et rend la main aussitôt, et il ne vous dit presque rien sur le fait que
le programme ait fonctionné ou non. Une fois que vous le voyez comme « lancer et oublier »
(fire-and-forget), les bugs déroutants — « mon code a ouvert le fichier avant que le convertisseur n'ait
fini de l'écrire » — cessent d'être déroutants.
Ce que vous allez apprendre
- Le modèle mental —
Shelllance puis oublie : il démarre, puis rend la main immédiatement - Pourquoi la valeur de retour est un identifiant de tâche, pas un code de sortie ni la sortie du programme
- Pourquoi la ligne après
Shells'exécute trop tôt, et comment attendre réellement le programme - Comment mettre entre guillemets un chemin contenant des espaces, et pourquoi
Shellseul ne peut pas ouvrir un PDF ou une URL - Quand abandonner
ShellpourWScript.Shell.Run(attente + code de sortie) ou.Exec(capture de la sortie) - Les erreurs que
Shelllève quand le programme est introuvable, et comment s'en prémunir
Le modèle mental : Shell lance et oublie
L'idée unique qui explique toutes les surprises de Shell : Shell n'exécute pas un programme — il en
démarre un et s'en va. Il demande à Windows de lancer l'exécutable, récupère un numéro identifiant la
nouvelle tâche, et rend aussitôt la main à votre macro. Le programme tourne désormais en parallèle de
votre code, pas à l'intérieur.
Shell "calc.exe" ' Windows demarre la Calculatrice...
MsgBox "done" ' ...et ce MsgBox apparait instantanement, calc charge encore
Comparez cela à un appel de méthode normal comme Range("A1").Copy, terminé à l'instant où la ligne
suivante s'exécute. Shell est l'inverse : il est asynchrone. Votre macro et le programme lancé suivent
chacun leur route. Toutes les règles ci-dessous découlent de ce seul fait.
Le deuxième argument est le style de fenêtre — vbNormalFocus, vbMinimizedNoFocus, vbHide, etc. Il
contrôle la façon dont la nouvelle fenêtre apparaît ; il ne fait pas attendre Shell. Aucun style de
fenêtre ne rend Shell synchrone.
Shell renvoie un identifiant de tâche, pas un résultat
Shell renvoie un Double — l'identifiant de processus (de tâche) que Windows a attribué au nouveau
programme. Les gens saisissent ce nombre en s'attendant à un code de sortie ou à un indicateur « a-t-il
marché », et ce n'est ni l'un ni l'autre :
Dim result As Double
result = Shell("robocopy.exe C:\a C:\b", vbHide)
' result est un identifiant de tache comme 7820 - ne dit rien sur la reussite de robocopy
Comme l'appel rend la main avant que le programme n'ait fait son travail, il n'y a encore rien de
significatif à signaler. Shell ne peut pas vous donner le code de sortie du programme, ne peut pas
capturer sa sortie console, et ne vous dit pas si le programme a planté par la suite. L'identifiant de
tâche n'est utile que comme poignée — par exemple, à passer à une API Windows telle que
OpenProcess/WaitForSingleObject si vous décidez d'attendre. Si votre logique dépend de ce que le
programme a renvoyé, Shell est structurellement incapable de le fournir, et aucun code supplémentaire
autour de Shell n'y changera rien.
Pourquoi votre ligne suivante s'exécute trop tôt
C'est le bug vedette, et il découle directement du « lancer et oublier ». Vous lancez un outil qui produit un fichier, puis vous utilisez immédiatement ce fichier :
Shell "C:\Tools\convert.exe report.docx report.pdf"
Workbooks.Open "C:\Tools\report.pdf" ' ECHOUE - le PDF n'existe pas encore
convert.exe a besoin d'une seconde ou deux pour tourner, mais Workbooks.Open s'exécute maintenant,
alors que le convertisseur commence à peine. Le fichier est absent, et vous obtenez une erreur « fichier
introuvable » qui pointe vers la mauvaise ligne — la vraie cause est trois lignes plus haut, dans le
Shell qui n'a pas attendu.
Le correctif n'est pas un Application.Wait ou un Sleep fixé au jugé — attendez trop peu et ça
échoue quand même, attendez trop et vous gaspillez le temps de l'utilisateur, et de toute façon une machine
lente casse tout. Pour vraiment attendre que le programme se termine, il vous faut autre chose que
Shell. La réponse propre, c'est WScript.Shell.Run avec son indicateur d'attente (ci-dessous) ; la
réponse bas niveau, c'est l'API WaitForSingleObject sur l'identifiant de tâche. Ce que vous devez cesser
de faire, c'est parsemer votre code de Sleep 2000 en croisant les doigts.
Chemins avec espaces, et ouvrir un document au lieu d'un exe
Deux pièges pratiques attrapent presque tout le monde.
Espaces dans le chemin. Shell prend une seule chaîne de ligne de commande, et un espace sépare le
programme de ses arguments. Alors un chemin comme C:\Program Files\... se coupe au mauvais endroit :
Shell "C:\Program Files\App\app.exe" ' error 53 - Windows cherche "C:\Program"
Shell """C:\Program Files\App\app.exe""" ' correct - encadrez le chemin de l'exe avec des guillemets
À l'intérieur d'une chaîne VBA, chaque "" est un guillemet littéral, donc """...""" place de vrais
guillemets autour du chemin. Encadrez l'exécutable de guillemets dès que son dossier peut contenir un
espace (et la plupart en contiennent).
Ouvrir un document, pas un programme. Shell lance des exécutables — il ne sait pas qu'un .pdf
doit s'ouvrir dans votre lecteur PDF ou qu'un .xlsx doit s'ouvrir dans Excel. Le pointer vers un document
échoue :
Shell "C:\Reports\Q1.pdf" ' error 53 - pas un executable
Shell "cmd /c start """" ""C:\Reports\Q1.pdf""" ' fonctionne - laisse le shell resoudre l'app par defaut
La commande start (via cmd /c) demande à Windows d'ouvrir le fichier avec le programme qui lui est
associé — exactement ce que fait un double-clic. Le "" vide après start est le paramètre fictif du
titre de fenêtre, que start exige lorsque le chemin est entre guillemets. Pour ouvrir des documents et des
URL, cette approche est courante ; l'alternative plus propre est l'API ShellExecute ou WScript.Shell,
abordée juste après.
Quand il vous faut vraiment le résultat : WScript.Shell
Dès l'instant où vous devez attendre le programme, lire son code de sortie ou capturer sa
sortie, passez de Shell à l'objet WScript.Shell, créé avec
CreateObject :
Dim sh As Object
Set sh = CreateObject("WScript.Shell")
' .Run - le troisieme argument True signifie ATTENDRE la fin du programme ;
' la valeur de retour est alors le vrai code de sortie.
Dim exitCode As Long
exitCode = sh.Run("robocopy.exe C:\a C:\b", 0, True) ' 0 = fenetre masquee
If exitCode >= 8 Then MsgBox "robocopy failed: " & exitCode
' .Exec - execute et lit le texte stdout du programme
Dim p As Object, output As String
Set p = sh.Exec("cmd /c dir C:\")
output = p.StdOut.ReadAll
.Run(command, windowStyle, waitOnReturn) est le remplacement direct quand vous voulez attendre et obtenir
un code de sortie. .Exec va plus loin et vous donne un objet processus vivant dont vous pouvez lire le
StdOut — le seul moyen de ramener dans Excel le texte d'un programme console. Construisez les chemins de
la commande à partir d'Environ pour qu'ils marchent sur n'importe quelle machine,
et enveloppez le tout dans une gestion des erreurs pour qu'un programme manquant
soit signalé proprement au lieu de faire planter.
Le verdict honnête : Shell pour lancer-et-oublier, WScript.Shell pour le reste
Shell est un mot à un seul tour, et ce tour est étroit : démarrer un programme et l'oublier. Il est
authentique et utile pour exactement cela — lancer une visionneuse, ouvrir un dossier, démarrer un outil au
long cours que vous n'avez pas besoin de suivre. Les bugs viennent de ce qu'on lui demande des choses qu'il
n'a jamais promises. Quatre règles couvrent toute la surface :
- Il lance et oublie →
Shellrend la main immédiatement ; le programme tourne en parallèle. Aucun style de fenêtre ne le fait attendre. - La valeur de retour est un identifiant de tâche, pas un résultat → pas de code de sortie, pas de
sortie, pas d'indicateur de réussite. Si votre logique a besoin du résultat du programme,
Shellest le mauvais outil. - Mettez entre guillemets les chemins avec espaces ; les documents ne sont pas des exécutables →
encadrez l'exe de
""...""; ouvrez un document aveccmd /c startouShellExecute, pas directementShell. - Besoin d'attendre ou de lire la sortie ? Utilisez
WScript.Shell→.Run(..., True)attend et renvoie le code de sortie ;.Execcapture leStdOut. Saisissez-le dès l'instant où le silence deShellpose problème.
Adaptez l'outil à la tâche et la catégorie de bug « ça a ouvert le fichier avant que le programme ait fini » disparaît — vous utilisiez un lanceur « lancer et oublier » pour faire un travail « attendre et vérifier ».
Comment ExcelMaster aide
Les bugs de Shell qui coûtent vraiment du temps sont ceux de timing : une macro qui ouvre un fichier que
le programme lancé n'a pas encore écrit, un Sleep 2000 qui marche sur votre machine et échoue sur une plus
lente, un convertisseur dont l'échec est invisible parce que Shell n'a rien signalé. Chacun vient d'avoir
utilisé un mot « lancer et oublier » là où il fallait en réalité attendre et vérifier.
ExcelMaster écrit correctement la
logique de lancement-puis-attente. Décrivez la tâche — « exécute ce convertisseur, puis ouvre sa sortie »,
ou « appelle cet outil en ligne de commande et dis-moi s'il a échoué » — et il choisit le bon mécanisme :
Shell quand « lancer et oublier » convient vraiment, ou WScript.Shell.Run/.Exec quand vous devez
attendre la fin, lire un code de sortie, ou capturer une sortie. Vous décrivez le programme que vous voulez
exécuter ; il écrit le code qui l'exécute et qui sait quand c'est terminé.
Questions fréquentes
Comment faire attendre VBA Shell jusqu'à la fin du programme ?
Shell lui-même ne peut pas attendre — il rend toujours la main immédiatement. Pour attendre, utilisez
plutôt l'objet WScript.Shell : CreateObject("WScript.Shell").Run(command, windowStyle, True). Le
troisième argument True (waitOnReturn) le fait bloquer jusqu'à ce que le programme se termine, et la
valeur de retour est alors le vrai code de sortie du programme. L'autre approche est celle d'une API
Windows — passer l'identifiant de tâche renvoyé par Shell à WaitForSingleObject — mais
WScript.Shell.Run est bien plus simple pour un usage courant.
Que renvoie la fonction VBA Shell ?
Shell renvoie un Double — l'identifiant de tâche (de processus) que Windows a attribué au programme qui
vient de démarrer. Ce n'est pas un code de sortie, ni la sortie du programme, ni un indicateur de
réussite. Comme Shell rend la main avant que le programme n'ait fini, il n'y a encore aucun résultat à
signaler. L'identifiant de tâche n'est qu'une poignée que vous pourriez passer à une API Windows. Si vous
avez besoin du code de sortie du programme, utilisez plutôt WScript.Shell.Run(..., True).
Pourquoi VBA Shell donne-t-il l'erreur 53 (fichier introuvable) ?
Deux causes courantes. D'abord, le chemin contient un espace et n'est pas entre guillemets —
Shell "C:\Program Files\..." se coupe à l'espace, donc Windows cherche C:\Program ; encadrez le chemin
de l'exécutable de guillemets doublés : Shell """C:\Program Files\App\app.exe""". Ensuite, vous avez
pointé Shell vers un document (un .pdf, un .xlsx) plutôt que vers un exécutable — Shell lance des
programmes, pas des fichiers. Pour ouvrir un document avec son application par défaut, utilisez
Shell "cmd /c start """" ""C:\file.pdf""" ou l'API ShellExecute.
Comment exécuter un fichier batch ou une commande en ligne de commande depuis VBA ?
Pour un fichier .bat, Shell peut le lancer directement : Shell "C:\scripts\build.bat" (mettez le
chemin entre guillemets s'il contient des espaces). Pour une commande brute qui n'est pas un exécutable —
un dir, un copy, un pipe — passez-la par l'interpréteur de commandes : Shell "cmd /c copy a.txt b.txt". Si vous devez l'attendre et lire son code de sortie ou sa sortie, utilisez
CreateObject("WScript.Shell").Run("cmd /c ...", 0, True) ou .Exec au lieu de Shell.
Comment capturer la sortie d'un programme exécuté depuis VBA ?
Shell ne peut pas capturer la sortie du tout. Utilisez la méthode .Exec de l'objet WScript.Shell, qui
renvoie un objet processus doté d'un flux StdOut lisible : Set p = CreateObject("WScript.Shell").Exec("cmd /c dir C:\") : output = p.StdOut.ReadAll. C'est la façon standard de ramener dans VBA le texte d'un
programme console. Pour les programmes qui ne signalent leur réussite que par un code de sortie, utilisez
plutôt .Run(command, 0, True) et vérifiez sa valeur de retour.
Testé dans
Testé dans : Excel 365 (Windows 11), VBA 7.1 — vérifié le 30/08/2026.
Guides connexes : VBA CreateObject & GetObject · VBA Environ · VBA Wait & Sleep · VBA On Error · VBA FreeFile & Open
