1 // +build windows |
|
2 // +build !go1.4 |
|
3 |
|
4 package mousetrap |
1 package mousetrap |
5 |
2 |
6 import ( |
3 import ( |
7 "fmt" |
|
8 "os" |
|
9 "syscall" |
4 "syscall" |
10 "unsafe" |
5 "unsafe" |
11 ) |
6 ) |
12 |
7 |
13 const ( |
8 func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { |
14 // defined by the Win32 API |
9 snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) |
15 th32cs_snapprocess uintptr = 0x2 |
10 if err != nil { |
16 ) |
11 return nil, err |
17 |
|
18 var ( |
|
19 kernel = syscall.MustLoadDLL("kernel32.dll") |
|
20 CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot") |
|
21 Process32First = kernel.MustFindProc("Process32FirstW") |
|
22 Process32Next = kernel.MustFindProc("Process32NextW") |
|
23 ) |
|
24 |
|
25 // ProcessEntry32 structure defined by the Win32 API |
|
26 type processEntry32 struct { |
|
27 dwSize uint32 |
|
28 cntUsage uint32 |
|
29 th32ProcessID uint32 |
|
30 th32DefaultHeapID int |
|
31 th32ModuleID uint32 |
|
32 cntThreads uint32 |
|
33 th32ParentProcessID uint32 |
|
34 pcPriClassBase int32 |
|
35 dwFlags uint32 |
|
36 szExeFile [syscall.MAX_PATH]uint16 |
|
37 } |
|
38 |
|
39 func getProcessEntry(pid int) (pe *processEntry32, err error) { |
|
40 snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0)) |
|
41 if snapshot == uintptr(syscall.InvalidHandle) { |
|
42 err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1) |
|
43 return |
|
44 } |
12 } |
45 defer syscall.CloseHandle(syscall.Handle(snapshot)) |
13 defer syscall.CloseHandle(snapshot) |
46 |
14 var procEntry syscall.ProcessEntry32 |
47 var processEntry processEntry32 |
15 procEntry.Size = uint32(unsafe.Sizeof(procEntry)) |
48 processEntry.dwSize = uint32(unsafe.Sizeof(processEntry)) |
16 if err = syscall.Process32First(snapshot, &procEntry); err != nil { |
49 ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) |
17 return nil, err |
50 if ok == 0 { |
|
51 err = fmt.Errorf("Process32First: %v", e1) |
|
52 return |
|
53 } |
18 } |
54 |
|
55 for { |
19 for { |
56 if processEntry.th32ProcessID == uint32(pid) { |
20 if procEntry.ProcessID == uint32(pid) { |
57 pe = &processEntry |
21 return &procEntry, nil |
58 return |
|
59 } |
22 } |
60 |
23 err = syscall.Process32Next(snapshot, &procEntry) |
61 ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) |
24 if err != nil { |
62 if ok == 0 { |
25 return nil, err |
63 err = fmt.Errorf("Process32Next: %v", e1) |
|
64 return |
|
65 } |
26 } |
66 } |
27 } |
67 } |
|
68 |
|
69 func getppid() (pid int, err error) { |
|
70 pe, err := getProcessEntry(os.Getpid()) |
|
71 if err != nil { |
|
72 return |
|
73 } |
|
74 |
|
75 pid = int(pe.th32ParentProcessID) |
|
76 return |
|
77 } |
28 } |
78 |
29 |
79 // StartedByExplorer returns true if the program was invoked by the user double-clicking |
30 // StartedByExplorer returns true if the program was invoked by the user double-clicking |
80 // on the executable from explorer.exe |
31 // on the executable from explorer.exe |
81 // |
32 // |
82 // It is conservative and returns false if any of the internal calls fail. |
33 // It is conservative and returns false if any of the internal calls fail. |
83 // It does not guarantee that the program was run from a terminal. It only can tell you |
34 // It does not guarantee that the program was run from a terminal. It only can tell you |
84 // whether it was launched from explorer.exe |
35 // whether it was launched from explorer.exe |
85 func StartedByExplorer() bool { |
36 func StartedByExplorer() bool { |
86 ppid, err := getppid() |
37 pe, err := getProcessEntry(syscall.Getppid()) |
87 if err != nil { |
38 if err != nil { |
88 return false |
39 return false |
89 } |
40 } |
90 |
41 return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) |
91 pe, err := getProcessEntry(ppid) |
|
92 if err != nil { |
|
93 return false |
|
94 } |
|
95 |
|
96 name := syscall.UTF16ToString(pe.szExeFile[:]) |
|
97 return name == "explorer.exe" |
|
98 } |
42 } |