vendor/github.com/inconshreveable/mousetrap/trap_windows.go
changeset 265 05c40b36d3b2
parent 242 2a9ec03fe5a1
equal deleted inserted replaced
264:8f478162d991 265:05c40b36d3b2
     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 }