forked from TrueCloudLab/restic
Add mousetrap library for Windows
This commit is contained in:
parent
565d72ef36
commit
02f7bb0d4c
6 changed files with 201 additions and 0 deletions
6
vendor/manifest
vendored
6
vendor/manifest
vendored
|
@ -13,6 +13,12 @@
|
||||||
"revision": "cbb1ebac08e2ca5495a43f4ef5555e61a7ec7677",
|
"revision": "cbb1ebac08e2ca5495a43f4ef5555e61a7ec7677",
|
||||||
"branch": "master"
|
"branch": "master"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"importpath": "github.com/inconshreveable/mousetrap",
|
||||||
|
"repository": "https://github.com/inconshreveable/mousetrap",
|
||||||
|
"revision": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75",
|
||||||
|
"branch": "master"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"importpath": "github.com/kr/fs",
|
"importpath": "github.com/kr/fs",
|
||||||
"repository": "https://github.com/kr/fs",
|
"repository": "https://github.com/kr/fs",
|
||||||
|
|
13
vendor/src/github.com/inconshreveable/mousetrap/LICENSE
vendored
Normal file
13
vendor/src/github.com/inconshreveable/mousetrap/LICENSE
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Copyright 2014 Alan Shreve
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
23
vendor/src/github.com/inconshreveable/mousetrap/README.md
vendored
Normal file
23
vendor/src/github.com/inconshreveable/mousetrap/README.md
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# mousetrap
|
||||||
|
|
||||||
|
mousetrap is a tiny library that answers a single question.
|
||||||
|
|
||||||
|
On a Windows machine, was the process invoked by someone double clicking on
|
||||||
|
the executable file while browsing in explorer?
|
||||||
|
|
||||||
|
### Motivation
|
||||||
|
|
||||||
|
Windows developers unfamiliar with command line tools will often "double-click"
|
||||||
|
the executable for a tool. Because most CLI tools print the help and then exit
|
||||||
|
when invoked without arguments, this is often very frustrating for those users.
|
||||||
|
|
||||||
|
mousetrap provides a way to detect these invocations so that you can provide
|
||||||
|
more helpful behavior and instructions on how to run the CLI tool. To see what
|
||||||
|
this looks like, both from an organizational and a technical perspective, see
|
||||||
|
https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/
|
||||||
|
|
||||||
|
### The interface
|
||||||
|
|
||||||
|
The library exposes a single interface:
|
||||||
|
|
||||||
|
func StartedByExplorer() (bool)
|
15
vendor/src/github.com/inconshreveable/mousetrap/trap_others.go
vendored
Normal file
15
vendor/src/github.com/inconshreveable/mousetrap/trap_others.go
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package mousetrap
|
||||||
|
|
||||||
|
// StartedByExplorer returns true if the program was invoked by the user
|
||||||
|
// double-clicking on the executable from explorer.exe
|
||||||
|
//
|
||||||
|
// It is conservative and returns false if any of the internal calls fail.
|
||||||
|
// It does not guarantee that the program was run from a terminal. It only can tell you
|
||||||
|
// whether it was launched from explorer.exe
|
||||||
|
//
|
||||||
|
// On non-Windows platforms, it always returns false.
|
||||||
|
func StartedByExplorer() bool {
|
||||||
|
return false
|
||||||
|
}
|
98
vendor/src/github.com/inconshreveable/mousetrap/trap_windows.go
vendored
Normal file
98
vendor/src/github.com/inconshreveable/mousetrap/trap_windows.go
vendored
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
// +build windows
|
||||||
|
// +build !go1.4
|
||||||
|
|
||||||
|
package mousetrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// defined by the Win32 API
|
||||||
|
th32cs_snapprocess uintptr = 0x2
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernel = syscall.MustLoadDLL("kernel32.dll")
|
||||||
|
CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot")
|
||||||
|
Process32First = kernel.MustFindProc("Process32FirstW")
|
||||||
|
Process32Next = kernel.MustFindProc("Process32NextW")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessEntry32 structure defined by the Win32 API
|
||||||
|
type processEntry32 struct {
|
||||||
|
dwSize uint32
|
||||||
|
cntUsage uint32
|
||||||
|
th32ProcessID uint32
|
||||||
|
th32DefaultHeapID int
|
||||||
|
th32ModuleID uint32
|
||||||
|
cntThreads uint32
|
||||||
|
th32ParentProcessID uint32
|
||||||
|
pcPriClassBase int32
|
||||||
|
dwFlags uint32
|
||||||
|
szExeFile [syscall.MAX_PATH]uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProcessEntry(pid int) (pe *processEntry32, err error) {
|
||||||
|
snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0))
|
||||||
|
if snapshot == uintptr(syscall.InvalidHandle) {
|
||||||
|
err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer syscall.CloseHandle(syscall.Handle(snapshot))
|
||||||
|
|
||||||
|
var processEntry processEntry32
|
||||||
|
processEntry.dwSize = uint32(unsafe.Sizeof(processEntry))
|
||||||
|
ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry)))
|
||||||
|
if ok == 0 {
|
||||||
|
err = fmt.Errorf("Process32First: %v", e1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
if processEntry.th32ProcessID == uint32(pid) {
|
||||||
|
pe = &processEntry
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry)))
|
||||||
|
if ok == 0 {
|
||||||
|
err = fmt.Errorf("Process32Next: %v", e1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getppid() (pid int, err error) {
|
||||||
|
pe, err := getProcessEntry(os.Getpid())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = int(pe.th32ParentProcessID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartedByExplorer returns true if the program was invoked by the user double-clicking
|
||||||
|
// on the executable from explorer.exe
|
||||||
|
//
|
||||||
|
// It is conservative and returns false if any of the internal calls fail.
|
||||||
|
// It does not guarantee that the program was run from a terminal. It only can tell you
|
||||||
|
// whether it was launched from explorer.exe
|
||||||
|
func StartedByExplorer() bool {
|
||||||
|
ppid, err := getppid()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
pe, err := getProcessEntry(ppid)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
name := syscall.UTF16ToString(pe.szExeFile[:])
|
||||||
|
return name == "explorer.exe"
|
||||||
|
}
|
46
vendor/src/github.com/inconshreveable/mousetrap/trap_windows_1.4.go
vendored
Normal file
46
vendor/src/github.com/inconshreveable/mousetrap/trap_windows_1.4.go
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// +build windows
|
||||||
|
// +build go1.4
|
||||||
|
|
||||||
|
package mousetrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) {
|
||||||
|
snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer syscall.CloseHandle(snapshot)
|
||||||
|
var procEntry syscall.ProcessEntry32
|
||||||
|
procEntry.Size = uint32(unsafe.Sizeof(procEntry))
|
||||||
|
if err = syscall.Process32First(snapshot, &procEntry); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
if procEntry.ProcessID == uint32(pid) {
|
||||||
|
return &procEntry, nil
|
||||||
|
}
|
||||||
|
err = syscall.Process32Next(snapshot, &procEntry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartedByExplorer returns true if the program was invoked by the user double-clicking
|
||||||
|
// on the executable from explorer.exe
|
||||||
|
//
|
||||||
|
// It is conservative and returns false if any of the internal calls fail.
|
||||||
|
// It does not guarantee that the program was run from a terminal. It only can tell you
|
||||||
|
// whether it was launched from explorer.exe
|
||||||
|
func StartedByExplorer() bool {
|
||||||
|
pe, err := getProcessEntry(os.Getppid())
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:])
|
||||||
|
}
|
Loading…
Reference in a new issue