From 5da36ee6c8f8f2246004405fdec4084f44515567 Mon Sep 17 00:00:00 2001 From: Romain Marcadier Date: Thu, 20 Feb 2025 18:47:35 +0100 Subject: [PATCH] fix: CmdlineSlice[WithContext] incorrect on Windows --- process/process.go | 5 +++++ process/process_windows.go | 23 +++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/process/process.go b/process/process.go index 70411c6..ce08e88 100644 --- a/process/process.go +++ b/process/process.go @@ -408,6 +408,11 @@ func (p *Process) Cmdline() (string, error) { // CmdlineSlice returns the command line arguments of the process as a slice with each // element being an argument. +// +// On Windows, this assumes the command line is encoded according to the convention accepted by +// [golang.org/x/sys/windows.CmdlineToArgv] (the most common convention). If this is not suitable, +// you should instead use [Process.Cmdline] and parse the command line according to your specific +// requirements. func (p *Process) CmdlineSlice() ([]string, error) { return p.CmdlineSliceWithContext(context.Background()) } diff --git a/process/process_windows.go b/process/process_windows.go index 00b2236..f71cd7e 100644 --- a/process/process_windows.go +++ b/process/process_windows.go @@ -12,7 +12,6 @@ import ( "os" "path/filepath" "reflect" - "strings" "syscall" "time" "unicode/utf16" @@ -381,7 +380,27 @@ func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) if err != nil { return nil, err } - return strings.Split(cmdline, " "), nil + return parseCmdline(cmdline) +} + +func parseCmdline(cmdline string) ([]string, error) { + cmdlineptr, err := windows.UTF16PtrFromString(cmdline) + if err != nil { + return nil, err + } + + var argc int32 + argvptr, err := windows.CommandLineToArgv(cmdlineptr, &argc) + if err != nil { + return nil, err + } + defer windows.LocalFree(windows.Handle(uintptr(unsafe.Pointer(argvptr)))) + + argv := make([]string, argc) + for i, v := range (*argvptr)[:argc] { + argv[i] = windows.UTF16ToString((*v)[:]) + } + return argv, nil } func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {