From 6bf304573c094b941bcc0011ed0959c3ab387f32 Mon Sep 17 00:00:00 2001 From: nathaninline Date: Fri, 7 Aug 2026 22:09:43 +0200 Subject: [PATCH] Correctif : l'application ne demarrait plus du tout au double-clic ShowWindow etait cherchee dans kernel32 alors qu'elle vit dans user32. LazyProc.Call PANIQUE quand la procedure est introuvable, et setupConsole s'execute avant tout le reste : le programme mourait sur le champ, sans rien installer et sans rien afficher. Seul le chemin du double-clic etait touche (console creee pour nous), d'ou une CI verte et des tests CLI qui passaient. Tous les appels Win32 de ce fichier passent desormais par un helper qui verifie la presence de la procedure au lieu de paniquer : aucun reglage de confort ne justifie d'empecher le programme de demarrer. Verifie de bout en bout cette fois : lancement facon double-clic -> arborescence creee, bin/ajean.exe installe, aucune panique, processus vivant ; et les chemins CLI (ordre d'affichage, redirection, tube, aide sans argument) inchanges. --- internal/ajean/sys_console_windows.go | 52 +++++++++++++++++---------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/internal/ajean/sys_console_windows.go b/internal/ajean/sys_console_windows.go index 3222fee..8921f7f 100644 --- a/internal/ajean/sys_console_windows.go +++ b/internal/ajean/sys_console_windows.go @@ -25,6 +25,24 @@ import ( "unsafe" ) +// win appelle une procédure Win32 et renvoie (résultat, trouvée). +// +// LazyProc.Call PANIQUE quand la procédure est introuvable. Or tout ce fichier +// s'exécute AVANT le reste du programme : une panique ici et il ne reste rien à +// l'écran pour la comprendre, l'application ne démarre tout simplement plus. +// C'est exactement ce qui est arrivé en cherchant ShowWindow dans kernel32 +// alors qu'elle vit dans user32. Aucun réglage de confort ne mérite ça. +func win(dll *syscall.LazyDLL, name string, a ...uintptr) (uintptr, bool) { + p := dll.NewProc(name) + if err := p.Find(); err != nil { + return 0, false + } + r, _, _ := p.Call(a...) + return r, true +} + +var kernel32 = syscall.NewLazyDLL("kernel32.dll") + // setupConsole décide dans quel monde on tourne et renvoie true en usage CLI. // // Le signal est le nombre de processus rattachés à notre console : si nous @@ -32,27 +50,21 @@ import ( // ne nous a lancés. On la fait disparaître et on bascule en mode application. // Un shell rattaché (cmd, PowerShell, Windows Terminal) en fait au moins deux. func setupConsole() bool { - k := syscall.NewLazyDLL("kernel32.dll") - - // Combien de processus partagent notre console ? Nous seul (1) = personne ne - // nous a lancés depuis un terminal, Windows a créé cette console pour nous : - // c'est un double-clic. Un shell rattaché en fait au moins deux. - // // Le compte vaut 0 quand il n'y a aucune console (parent détaché). On répond // alors « CLI », le cas contraire étant couvert autrement : les relances // internes passent « app » explicitement (voir launch, sys_firstrun_windows.go). // Mieux vaut afficher une aide inutile que démarrer un serveur en silence. var pids [8]uint32 - n, _, _ := k.NewProc("GetConsoleProcessList").Call( + n, ok := win(kernel32, "GetConsoleProcessList", uintptr(unsafe.Pointer(&pids[0])), uintptr(len(pids))) - if n == 1 { - if hwnd, _, _ := k.NewProc("GetConsoleWindow").Call(); hwnd != 0 { - // Masquer AVANT de libérer : sinon la fenêtre reste peinte le temps - // que Windows la détruise. + if ok && n == 1 { + // Masquer AVANT de libérer : sinon la fenêtre reste peinte le temps que + // Windows la détruise. ShowWindow est dans user32, pas kernel32. + if hwnd, ok := win(kernel32, "GetConsoleWindow"); ok && hwnd != 0 { const swHide = 0 - _, _, _ = k.NewProc("ShowWindow").Call(hwnd, swHide) + win(u32s, "ShowWindow", hwnd, swHide) } - _, _, _ = k.NewProc("FreeConsole").Call() + win(kernel32, "FreeConsole") return false } @@ -71,13 +83,15 @@ func configureConsole() { enableVirtualTerminalProcessing = 0x0004 stdOutputHandle = ^uintptr(10) // -11 ) - k := syscall.NewLazyDLL("kernel32.dll") - _, _, _ = k.NewProc("SetConsoleOutputCP").Call(uintptr(cpUTF8)) - _, _, _ = k.NewProc("SetConsoleCP").Call(uintptr(cpUTF8)) - h, _, _ := k.NewProc("GetStdHandle").Call(stdOutputHandle) + win(kernel32, "SetConsoleOutputCP", uintptr(cpUTF8)) + win(kernel32, "SetConsoleCP", uintptr(cpUTF8)) + h, ok := win(kernel32, "GetStdHandle", stdOutputHandle) + if !ok { + return + } var mode uint32 - if r, _, _ := k.NewProc("GetConsoleMode").Call(h, uintptr(unsafe.Pointer(&mode))); r != 0 { - _, _, _ = k.NewProc("SetConsoleMode").Call(h, uintptr(mode|enableVirtualTerminalProcessing)) + if r, ok := win(kernel32, "GetConsoleMode", h, uintptr(unsafe.Pointer(&mode))); ok && r != 0 { + win(kernel32, "SetConsoleMode", h, uintptr(mode|enableVirtualTerminalProcessing)) } }