trap_windows.go 2.3 KB

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