1// +build windows 2// +build !go1.4 3 4package mousetrap 5 6import ( 7 "fmt" 8 "os" 9 "syscall" 10 "unsafe" 11) 12 13const ( 14 // defined by the Win32 API 15 th32cs_snapprocess uintptr = 0x2 16) 17 18var ( 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 26type 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 39func 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 } 45 defer syscall.CloseHandle(syscall.Handle(snapshot)) 46 47 var processEntry processEntry32 48 processEntry.dwSize = uint32(unsafe.Sizeof(processEntry)) 49 ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) 50 if ok == 0 { 51 err = fmt.Errorf("Process32First: %v", e1) 52 return 53 } 54 55 for { 56 if processEntry.th32ProcessID == uint32(pid) { 57 pe = &processEntry 58 return 59 } 60 61 ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) 62 if ok == 0 { 63 err = fmt.Errorf("Process32Next: %v", e1) 64 return 65 } 66 } 67} 68 69func 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} 78 79// StartedByExplorer returns true if the program was invoked by the user double-clicking 80// on the executable from explorer.exe 81// 82// 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 84// whether it was launched from explorer.exe 85func StartedByExplorer() bool { 86 ppid, err := getppid() 87 if err != nil { 88 return false 89 } 90 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} 99