feat(build, syncthing): dynamic console allocation for Windows#10335
feat(build, syncthing): dynamic console allocation for Windows#10335Shablone wants to merge 40 commits intosyncthing:mainfrom
Conversation
78cad68 to
c2552bf
Compare
|
Did you have success running it? |
cmd/syncthing/monitor.go
Outdated
| } | ||
|
|
||
| // Check if --no-console was passed or if we have no args (double-clicked) | ||
| noConsole := len(args) <= 1 // No args means launched from GUI |
There was a problem hiding this comment.
noConsole := slices.Contains(args, "--no-console")
cmd/syncthing/monitor.go
Outdated
| childArgs := args[1:] // Start with original args (excluding binary name) | ||
| if noConsole { | ||
| // Check if --no-console is already in the args | ||
| hasNoConsole := false |
There was a problem hiding this comment.
hasNoConsole := slices.Contains(childArgs, "--no-console")
cmd/syncthing/console_windows.go
Outdated
| procFreeConsole = kernel32.NewProc("FreeConsole") | ||
| procGetConsoleWindow = kernel32.NewProc("GetConsoleWindow") | ||
| procSetStdHandle = kernel32.NewProc("SetStdHandle") | ||
| procCreateFileW = kernel32.NewProc("CreateFileW") |
There was a problem hiding this comment.
CreateFile and SetStdHandle are in sys/x/windows
cmd/syncthing/console_windows.go
Outdated
| return nil // No command line arguments, don't allocate console | ||
| } | ||
|
|
||
| // Check if --no-console flag is present |
There was a problem hiding this comment.
if slices.Contains(os.Args[1:], "--no-console") {
return nil
}
There was a problem hiding this comment.
(Prefer if they actually used the arguments parser we have...)
|
One issue with this is if a user runs this GUI version from inside an SSH session, they won't see any output. The console window will appear on the desktop. |
There was a problem hiding this comment.
This is the approach that we didn't get to work previously. If it does work, i.e. behaves reasonably in a normal terminal etc, that's cool. I don't see why you're reinventing command line parsing multiple times instead of using the parsed command line though?
|
Thank you for the review :) I was reinventing the stuff because
I will also investigate the ssh session. Although it seems very niche to me, to ssh into a windows server. |
|
I think the SSH bit is indeed extremely niche, but probably follows the same scenario as just running the command in an existing cmd? At least the latter should work, imho. (by which I mean "show output in that terminal") |
|
This seems somewhat promising. I'll have comments on the actual code and stuff at some point, but just some behavioural notes;
|
8357fc0 to
79e5eb0
Compare
|
Hey |
|
I'm trying to test the PR right now, but for me, even when launched from Explorer, the console window just stays open. This is under Windows 10 x64, and the default shell is set to Command Prompt. |
cmd/syncthing/console_windows.go
Outdated
| } | ||
|
|
||
| // User explicitly disabled console -> don't allocate console | ||
| if slices.Contains(os.Args[1:], "--no-console") { |
There was a problem hiding this comment.
I see no reason to do this instead of using our command line parser? (If there is one it's fine, but requires explanation. If it's about having a console available for when --help gets called, I suspect there is a way around that using the binding callback on the --no-console option perhaps...)
cmd/syncthing/console_windows.go
Outdated
| return nil | ||
| } | ||
|
|
||
| // SSH sessions -> don't allocate console |
cmd/syncthing/console_windows.go
Outdated
| // Try to attach to parent consol | ||
| if ret, _, err := procAttachConsole.Call(uintptr(ATTACH_PARENT_PROCESS)); ret != 0 { | ||
| return redirectStdHandles() | ||
| } else if err != syscall.Errno(0) { |
There was a problem hiding this comment.
This should probably be !errors.Is(err, syscall.Errno(0)) and errors.As below instead of the direct case
cmd/syncthing/console_windows.go
Outdated
| if ret, _, err := procAllocConsole.Call(); ret != 0 { | ||
| consoleAllocated = true | ||
| return redirectStdHandles() | ||
| } else if err != syscall.Errno(0) { |
cmd/syncthing/console_windows.go
Outdated
|
|
||
| // FreeConsole releases the console | ||
| func FreeConsole() { | ||
| if consoleAllocated { |
There was a problem hiding this comment.
I'd rather see this as a return value from InitConsole, to avoid keeping the global around...
Signed-off-by: Elias <[email protected]>
Signed-off-by: Elias <[email protected]>
Signed-off-by: Elias <[email protected]>
Signed-off-by: Elias <[email protected]>
Signed-off-by: Elias <[email protected]>
Signed-off-by: Elias <[email protected]>
Signed-off-by: Elias <[email protected]>
|
Alright. Please have another look I now splitted the console initialization into attachment (Already on present) and allocation (a new one needed). I also tested the ssh stuff. With the current commit when I ssh from unix into windows and call synthing.exe, it will pipe the output to my ssh shell. No new console appears 👍 I also learned that FreeConsole() is not needed, as windows this stuff on its own on process termination. So I could delete the defering stuff I removed the old HideConsole and replaced it with the dynamic allowcation |
|
Please keep in mind, that for testing there should be no newer version online, which does not have this feature implemented. Or auto-upgrade should be disabled. |
cmd/syncthing/openurl_windows.go
Outdated
| // 2. cmd.exe /C start (fallback): Traditional approach that spawns a command | ||
| // shell. Less secure (potential command injection) but works on all Windows | ||
| // versions including very old ones. |
There was a problem hiding this comment.
I'm pretty sure we don't run on those Windows versions...
calmh
left a comment
There was a problem hiding this comment.
Thanks, sorry for taking some time on this, I do want to get it in. Can you sort out the various style/linter complaints please, and then I think this is ready given it passes some manual testing 🙏
cmd/syncthing/main.go
Outdated
| var consoleAttached = false | ||
| if err := osutil.AttachConsole(); err == nil { | ||
| consoleAttached = true | ||
| } |
There was a problem hiding this comment.
| var consoleAttached = false | |
| if err := osutil.AttachConsole(); err == nil { | |
| consoleAttached = true | |
| } | |
| consoleAttached := osutil.AttachConsole() == nil |
if we don't care about the error, I guess
Signed-off-by: Elias <[email protected]>
Signed-off-by: Elias <[email protected]>
Thank you. There is no hurry 🙂 |
Signed-off-by: Elias <[email protected]>
|
Actual Windows users who want this, can we have some testing? 🙏 |
Dynamic Console Allocation for Windows
Purpose
Windows GUI builds either always show a short console pupup on windows systemstart implementation or never show one (CLI users can't see output).
See PR10334 , PR926 and many more
Solution
Implement dynamic console allocation:
--no-consoleflag to explicitly disable consoleTesting
Opening from explorer won't show a console.
Implementation
AllocConsole/AttachConsole) to create console on demand--no-consoleto child processes when appropriateFixes console window appearing briefly when launched from Explorer while maintaining proper CLI functionality.
Authorship