vendor/github.com/inconshreveable/mousetrap/trap_windows.go
changeset 242 2a9ec03fe5a1
child 265 05c40b36d3b2
equal deleted inserted replaced
241:e77dad242f4c 242:2a9ec03fe5a1
       
     1 // +build windows
       
     2 // +build !go1.4
       
     3 
       
     4 package mousetrap
       
     5 
       
     6 import (
       
     7 	"fmt"
       
     8 	"os"
       
     9 	"syscall"
       
    10 	"unsafe"
       
    11 )
       
    12 
       
    13 const (
       
    14 	// defined by the Win32 API
       
    15 	th32cs_snapprocess uintptr = 0x2
       
    16 )
       
    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 	}
       
    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 
       
    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 }
       
    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
       
    85 func 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 }