-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathopen_windows.go
More file actions
91 lines (80 loc) · 2.1 KB
/
Copy pathopen_windows.go
File metadata and controls
91 lines (80 loc) · 2.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
//go:build windows
package browser
import (
"context"
"fmt"
"sync"
"syscall"
"unsafe"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
loadLibraryExW = kernel32.NewProc("LoadLibraryExW")
shellExecuteOnce sync.Once
shellExecuteW *syscall.Proc
shellExecuteLoadErr error
)
func openDefault(ctx context.Context, rawURL string) error {
if err := ctx.Err(); err != nil {
return err
}
return shellExecuteURL(rawURL)
}
var shellExecuteURL = func(rawURL string) error {
proc, err := loadShellExecuteW()
if err != nil {
return err
}
operation, err := syscall.UTF16PtrFromString("open")
if err != nil {
return err
}
target, err := syscall.UTF16PtrFromString(rawURL)
if err != nil {
return err
}
// ShellExecuteW returns a value greater than 32 on success. It uses the
// user's registered URL handler directly, avoiding cmd.exe and PowerShell
// quoting and availability issues.
result, _, _ := proc.Call(
0,
uintptr(unsafe.Pointer(operation)),
uintptr(unsafe.Pointer(target)),
0,
0,
1, // SW_SHOWNORMAL
)
if result > 32 {
return nil
}
return fmt.Errorf("ShellExecuteW failed (%d)", result)
}
func loadShellExecuteW() (*syscall.Proc, error) {
shellExecuteOnce.Do(func() {
name, err := syscall.UTF16PtrFromString("shell32.dll")
if err != nil {
shellExecuteLoadErr = err
return
}
// Do not use syscall.NewLazyDLL("shell32.dll") here. Unlike kernel32,
// shell32 is not on the standard library's internal system-DLL
// allowlist. LOAD_LIBRARY_SEARCH_SYSTEM32 prevents DLL preloading from
// the application or working directory without adding a dependency.
const loadLibrarySearchSystem32 = 0x00000800
handle, _, callErr := loadLibraryExW.Call(
uintptr(unsafe.Pointer(name)),
0,
loadLibrarySearchSystem32,
)
if handle == 0 {
shellExecuteLoadErr = fmt.Errorf("LoadLibraryExW shell32.dll: %w", callErr)
return
}
shell32 := &syscall.DLL{
Name: "shell32.dll",
Handle: syscall.Handle(handle),
}
shellExecuteW, shellExecuteLoadErr = shell32.FindProc("ShellExecuteW")
})
return shellExecuteW, shellExecuteLoadErr
}