Desktop integration (#2073)

* Open stash in system tray on Windows/MacOS
* Add desktop notifications
* MacOS Bundling
* Add binary icon

Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
kermieisinthehouse 2022-02-02 16:20:34 -08:00 committed by GitHub
parent e48b2ba3e8
commit 0e514183a7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
306 changed files with 29542 additions and 4792 deletions

View file

@ -13,7 +13,7 @@ concurrency:
cancel-in-progress: true
env:
COMPILER_IMAGE: stashapp/compiler:5
COMPILER_IMAGE: stashapp/compiler:6
jobs:
build:
@ -91,12 +91,11 @@ jobs:
- name: Compile for all supported platforms
run: |
docker exec -t build /bin/bash -c "make cross-compile-windows"
docker exec -t build /bin/bash -c "make cross-compile-osx-intel"
docker exec -t build /bin/bash -c "make cross-compile-osx-applesilicon"
docker exec -t build /bin/bash -c "make cross-compile-macos"
docker exec -t build /bin/bash -c "make cross-compile-linux"
docker exec -t build /bin/bash -c "make cross-compile-linux-arm64v8"
docker exec -t build /bin/bash -c "make cross-compile-linux-arm32v7"
docker exec -t build /bin/bash -c "make cross-compile-pi"
docker exec -t build /bin/bash -c "make cross-compile-linux-arm32v6"
- name: Cleanup build container
run: docker rm -f -v build
@ -121,8 +120,8 @@ jobs:
if: ${{ github.event_name == 'pull_request' && github.base_ref != 'refs/heads/develop' && github.base_ref != 'refs/heads/master'}}
uses: actions/upload-artifact@v2
with:
name: stash-osx
path: dist/stash-osx
name: Stash-macos.zip
path: dist/Stash-macos.zip
- name: Upload Linux binary
# only upload binaries for pull requests
@ -145,13 +144,12 @@ jobs:
automatic_release_tag: latest_develop
title: "${{ env.STASH_VERSION }}: Latest development build"
files: |
dist/stash-osx
dist/stash-osx-applesilicon
dist/Stash-macos.zip
dist/stash-win.exe
dist/stash-linux
dist/stash-linux-arm64v8
dist/stash-linux-arm32v7
dist/stash-pi
dist/stash-linux-arm32v6
CHECKSUMS_SHA1
- name: Master release
@ -161,13 +159,12 @@ jobs:
token: "${{ secrets.GITHUB_TOKEN }}"
allow_override: true
files: |
dist/stash-osx
dist/stash-osx-applesilicon
dist/Stash-macos.zip
dist/stash-win.exe
dist/stash-linux
dist/stash-linux-arm64v8
dist/stash-linux-arm32v7
dist/stash-pi
dist/stash-linux-arm32v6
CHECKSUMS_SHA1
gzip: false

View file

@ -9,7 +9,7 @@ on:
pull_request:
env:
COMPILER_IMAGE: stashapp/compiler:5
COMPILER_IMAGE: stashapp/compiler:6
jobs:
golangci:

View file

@ -1,12 +1,12 @@
IS_WIN =
IS_WIN_SHELL =
ifeq (${SHELL}, sh.exe)
IS_WIN = true
IS_WIN_SHELL = true
endif
ifeq (${SHELL}, cmd)
IS_WIN = true
IS_WIN_SHELL = true
endif
ifdef IS_WIN
ifdef IS_WIN_SHELL
SEPARATOR := &&
SET := set
else
@ -14,6 +14,11 @@ else
SET := export
endif
IS_WIN_OS =
ifeq ($(OS),Windows_NT)
IS_WIN_OS = true
endif
# set LDFLAGS environment variable to any extra ldflags required
# set OUTPUT to generate a specific binary name
@ -46,9 +51,13 @@ ifndef OFFICIAL_BUILD
endif
build: pre-build
ifdef IS_WIN_OS
PLATFORM_SPECIFIC_LDFLAGS := -H windowsgui
endif
build:
$(eval LDFLAGS := $(LDFLAGS) -X 'github.com/stashapp/stash/pkg/api.version=$(STASH_VERSION)' -X 'github.com/stashapp/stash/pkg/api.buildstamp=$(BUILD_DATE)' -X 'github.com/stashapp/stash/pkg/api.githash=$(GITHASH)')
$(eval LDFLAGS := $(LDFLAGS) -X 'github.com/stashapp/stash/pkg/api.officialBuild=$(OFFICIAL_BUILD)')
go build $(OUTPUT) -mod=vendor -v -tags "sqlite_omit_load_extension osusergo netgo" $(GO_BUILD_FLAGS) -ldflags "$(LDFLAGS) $(EXTRA_LDFLAGS)"
$(eval LDFLAGS := $(LDFLAGS) -X 'github.com/stashapp/stash/pkg/manager/config.officialBuild=$(OFFICIAL_BUILD)')
go build $(OUTPUT) -mod=vendor -v -tags "sqlite_omit_load_extension osusergo netgo" $(GO_BUILD_FLAGS) -ldflags "$(LDFLAGS) $(EXTRA_LDFLAGS) $(PLATFORM_SPECIFIC_LDFLAGS)"
# strips debug symbols from the release build
build-release: EXTRA_LDFLAGS := -s -w
@ -65,23 +74,38 @@ cross-compile-windows: export GOARCH := amd64
cross-compile-windows: export CC := x86_64-w64-mingw32-gcc
cross-compile-windows: export CXX := x86_64-w64-mingw32-g++
cross-compile-windows: OUTPUT := -o dist/stash-win.exe
cross-compile-windows: PLATFORM_SPECIFIC_LDFLAGS := -H windowsgui
cross-compile-windows: build-release-static
cross-compile-osx-intel: export GOOS := darwin
cross-compile-osx-intel: export GOARCH := amd64
cross-compile-osx-intel: export CC := o64-clang
cross-compile-osx-intel: export CXX := o64-clang++
cross-compile-osx-intel: OUTPUT := -o dist/stash-osx
cross-compile-macos-intel: export GOOS := darwin
cross-compile-macos-intel: export GOARCH := amd64
cross-compile-macos-intel: export CC := o64-clang
cross-compile-macos-intel: export CXX := o64-clang++
cross-compile-macos-intel: OUTPUT := -o dist/stash-macos-intel
# can't use static build for OSX
cross-compile-osx-intel: build-release
cross-compile-macos-intel: build-release
cross-compile-osx-applesilicon: export GOOS := darwin
cross-compile-osx-applesilicon: export GOARCH := arm64
cross-compile-osx-applesilicon: export CC := oa64e-clang
cross-compile-osx-applesilicon: export CXX := oa64e-clang++
cross-compile-osx-applesilicon: OUTPUT := -o dist/stash-osx-applesilicon
cross-compile-macos-applesilicon: export GOOS := darwin
cross-compile-macos-applesilicon: export GOARCH := arm64
cross-compile-macos-applesilicon: export CC := oa64e-clang
cross-compile-macos-applesilicon: export CXX := oa64e-clang++
cross-compile-macos-applesilicon: OUTPUT := -o dist/stash-macos-applesilicon
# can't use static build for OSX
cross-compile-osx-applesilicon: build-release
cross-compile-macos-applesilicon: build-release
cross-compile-macos:
rm -rf dist/Stash.app dist/Stash-macos.zip
make cross-compile-macos-applesilicon
make cross-compile-macos-intel
# Combine into one universal binary
lipo -create -output dist/stash-macos-universal dist/stash-macos-intel dist/stash-macos-applesilicon
rm dist/stash-macos-intel dist/stash-macos-applesilicon
# Place into bundle and zip up
cp -R scripts/macos-bundle dist/Stash.app
mkdir dist/Stash.app/Contents/MacOS
mv dist/stash-macos-universal dist/Stash.app/Contents/MacOS/stash
cd dist && zip -r Stash-macos.zip Stash.app && cd ..
rm -rf dist/Stash.app
cross-compile-linux: export GOOS := linux
cross-compile-linux: export GOARCH := amd64
@ -101,21 +125,20 @@ cross-compile-linux-arm32v7: export CC := arm-linux-gnueabihf-gcc
cross-compile-linux-arm32v7: OUTPUT := -o dist/stash-linux-arm32v7
cross-compile-linux-arm32v7: build-release-static
cross-compile-pi: export GOOS := linux
cross-compile-pi: export GOARCH := arm
cross-compile-pi: export GOARM := 6
cross-compile-pi: export CC := arm-linux-gnueabi-gcc
cross-compile-pi: OUTPUT := -o dist/stash-pi
cross-compile-pi: build-release-static
cross-compile-linux-arm32v6: export GOOS := linux
cross-compile-linux-arm32v6: export GOARCH := arm
cross-compile-linux-arm32v6: export GOARM := 6
cross-compile-linux-arm32v6: export CC := arm-linux-gnueabi-gcc
cross-compile-linux-arm32v6: OUTPUT := -o dist/stash-linux-arm32v6
cross-compile-linux-arm32v6: build-release-static
cross-compile-all:
make cross-compile-windows
make cross-compile-osx-intel
make cross-compile-osx-applesilicon
make cross-compile-macos
make cross-compile-linux
make cross-compile-linux-arm64v8
make cross-compile-linux-arm32v7
make cross-compile-pi
make cross-compile-linux-arm32v6
# Regenerates GraphQL files
generate: generate-backend generate-frontend

View file

@ -22,10 +22,12 @@ For further information you can [read the in-app manual](ui/v2.5/src/docs/en).
<img src="docs/readme_assets/windows_logo.svg" width="100%" height="75"> Windows | <img src="docs/readme_assets/mac_logo.svg" width="100%" height="75"> MacOS| <img src="docs/readme_assets/linux_logo.svg" width="100%" height="75"> Linux | <img src="docs/readme_assets/docker_logo.svg" width="100%" height="75"> Docker
:---:|:---:|:---:|:---:
[Latest Release](https://github.com/stashapp/stash/releases/latest/download/stash-win.exe) <br /> <sup><sub>[Development Preview](https://github.com/stashapp/stash/releases/download/latest_develop/stash-win.exe)</sub></sup> | [Latest Release (Apple Silicon)](https://github.com/stashapp/stash/releases/latest/download/stash-osx-applesilicon) <br /> <sup><sub>[Development Preview (Apple Silicon)](https://github.com/stashapp/stash/releases/download/latest_develop/stash-osx-applesilicon)</sub></sup> <br>[Latest Release (Intel)](https://github.com/stashapp/stash/releases/latest/download/stash-osx) <br /> <sup><sub>[Development Preview (Intel)](https://github.com/stashapp/stash/releases/download/latest_develop/stash-osx)</sub></sup> | [Latest Release (amd64)](https://github.com/stashapp/stash/releases/latest/download/stash-linux) <br /> <sup><sub>[Development Preview (amd64)](https://github.com/stashapp/stash/releases/download/latest_develop/stash-linux)</sub></sup> <br /> [More Architectures...](https://github.com/stashapp/stash/releases/latest) | [Instructions](docker/production/README.md) <br /> <sup><sub> [Sample docker-compose.yml](docker/production/docker-compose.yml)</sub></sup>
[Latest Release](https://github.com/stashapp/stash/releases/latest/download/stash-win.exe) <br /> <sup><sub>[Development Preview](https://github.com/stashapp/stash/releases/download/latest_develop/stash-win.exe)</sub></sup> | [Latest Release](https://github.com/stashapp/stash/releases/latest/download/Stash-macos.app.zip) <br /> <sup><sub>[Development Preview](https://github.com/stashapp/stash/releases/download/latest_develop/Stash-macos.app.zip)</sub></sup> | [Latest Release (amd64)](https://github.com/stashapp/stash/releases/latest/download/stash-linux) <br /> <sup><sub>[Development Preview (amd64)](https://github.com/stashapp/stash/releases/download/latest_develop/stash-linux)</sub></sup> <br /> [More Architectures...](https://github.com/stashapp/stash/releases/latest) | [Instructions](docker/production/README.md) <br /> <sup><sub> [Sample docker-compose.yml](docker/production/docker-compose.yml)</sub></sup>
## Getting Started
Run the executable (double click the exe on windows or run `./stash-osx` / `./stash-linux` from the terminal on macOS / Linux) to get started.
Run the executable by double-clicking it.
*Note for Mac users:* Running the app will present a security prompt since the binary isn't yet signed. Bypass this by right (ctrl) clicking on the app and hitting "Open", then "Open" in the next popup.
*Note for Windows users:* Running the app might present a security prompt since the binary isn't yet signed. Bypass this by clicking "more info" and then the "run anyway" button.

View file

@ -20,7 +20,7 @@ RUN apt-get update && \
gcc-arm-linux-gnueabi libc-dev-armel-cross linux-libc-dev-armel-cross \
gcc-arm-linux-gnueabihf libc-dev-armhf-cross \
gcc-aarch64-linux-gnu libc-dev-arm64-cross \
nodejs yarn --no-install-recommends || exit 1; \
nodejs yarn zip --no-install-recommends || exit 1; \
rm -rf /var/lib/apt/lists/*;
# Cross compile setup

View file

@ -1,6 +1,6 @@
user=stashapp
repo=compiler
version=5
version=6
latest:
docker build -t ${user}/${repo}:latest .

View file

@ -1,5 +1,3 @@
Modified from https://github.com/bep/dockerfiles/tree/master/ci-goreleaser
When the dockerfile is changed, the version number should be incremented in the Makefile and the new version tag should be pushed to docker hub. The `scripts/cross-compile.sh` script should also be updated to use the new version number tag, and `.travis.yml` needs to be updated to pull the correct image tag.
A MacOS univeral binary can be created using `lipo -create -output stash-osx-universal stash-osx stash-osx-applesilicon`, available in the image.
When the dockerfile is changed, the version number should be incremented in the Makefile and the new version tag should be pushed to docker hub. The `scripts/cross-compile.sh` script should also be updated to use the new version number tag, and the github workflow files need to be updated to pull the correct image tag.

14
go.mod
View file

@ -38,8 +38,8 @@ require (
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b
golang.org/x/text v0.3.7
golang.org/x/tools v0.1.5 // indirect
gopkg.in/sourcemap.v1 v1.0.5 // indirect
@ -47,6 +47,11 @@ require (
)
require (
github.com/apenwarr/fixconsole v0.0.0-20191012055117-5a9f6489cc29
github.com/go-chi/httplog v0.2.1
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4
github.com/kermieisinthehouse/gosx-notifier v0.1.1
github.com/kermieisinthehouse/systray v1.2.3
github.com/lucasb-eyer/go-colorful v1.2.0
github.com/vearutop/statigz v1.1.6
github.com/vektah/gqlparser/v2 v2.0.1
@ -55,10 +60,12 @@ require (
require (
github.com/agnivade/levenshtein v1.1.0 // indirect
github.com/antchfx/xpath v1.2.0 // indirect
github.com/apenwarr/w32 v0.0.0-20190407065021-aa00fece76ab // indirect
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-chi/chi/v5 v5.0.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.1.0-rc.5 // indirect
@ -77,10 +84,11 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rs/zerolog v1.18.0 // indirect
github.com/rs/zerolog v1.18.1-0.20200514152719-663cbb4c8469 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/spf13/cast v1.4.1 // indirect

24
go.sum
View file

@ -88,6 +88,10 @@ github.com/antchfx/xpath v1.2.0/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwq
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apache/arrow/go/arrow v0.0.0-20200601151325-b2287a20f230/go.mod h1:QNYViu/X0HXDHw7m3KXzWSVXIbfUvJqBFe6Gj8/pYA0=
github.com/apache/arrow/go/arrow v0.0.0-20210521153258-78c88a9f517b/go.mod h1:R4hW3Ug0s+n4CUsWHKOj00Pu01ZqU4x/hSF5kXUcXKQ=
github.com/apenwarr/fixconsole v0.0.0-20191012055117-5a9f6489cc29 h1:muXWUcay7DDy1/hEQWrYlBy+g0EuwT70sBHg65SeUc4=
github.com/apenwarr/fixconsole v0.0.0-20191012055117-5a9f6489cc29/go.mod h1:JYWahgHer+Z2xbsgHPtaDYVWzeHDminu+YIBWkxpCAY=
github.com/apenwarr/w32 v0.0.0-20190407065021-aa00fece76ab h1:CMGzRRCjnD50RjUFSArBLuCxiDvdp7b8YPAcikBEQ+k=
github.com/apenwarr/w32 v0.0.0-20190407065021-aa00fece76ab/go.mod h1:nfFtvHn2Hgs9G1u0/J6LHQv//EksNC+7G8vXmd1VTJ8=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@ -214,6 +218,10 @@ github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1T
github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi/v5 v5.0.0 h1:DBPx88FjZJH3FsICfDAfIfnb7XxKIYVGG6lOPlhENAg=
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
github.com/go-chi/httplog v0.2.1 h1:KgCtIUkYNlfIsUPzE3utxd1KDKOvCrnAKaqdo0rmrh0=
github.com/go-chi/httplog v0.2.1/go.mod h1:JyHOFO9twSfGoTin/RoP25Lx2a9Btq10ug+sgxe0+bo=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@ -224,6 +232,8 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 h1:qZNfIGkIANxGv/OqtnntR4DfOY2+BgwR60cAcu/i3SE=
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4/go.mod h1:kW3HQ4UdaAyrUCSSDR4xUzBKW6O2iA4uHhk7AtyYp10=
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
@ -484,6 +494,10 @@ github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALr
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kermieisinthehouse/gosx-notifier v0.1.1 h1:lVXyKsa1c1RUkckp3KayloNLoI//fUwVYye3RPSPtEw=
github.com/kermieisinthehouse/gosx-notifier v0.1.1/go.mod h1:xyWT07azFtUOcHl96qMVvKhvKzsMcS7rKTHQyv8WTho=
github.com/kermieisinthehouse/systray v1.2.3 h1:tawLahcam/Ccs/F2n6EOQo8qJnSTD2hLzOYqTGsUsbA=
github.com/kermieisinthehouse/systray v1.2.3/go.mod h1:axh6C/jNuSyC0QGtidZJURc9h+h41HNoMySoLVrhVR4=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@ -576,6 +590,8 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
@ -633,8 +649,9 @@ github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rs/zerolog v1.18.0 h1:CbAm3kP2Tptby1i9sYy2MGRg0uxIN9cyDb59Ys7W8z8=
github.com/rs/zerolog v1.18.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
github.com/rs/zerolog v1.18.1-0.20200514152719-663cbb4c8469 h1:DuXsEWHUTO5lsxxzKM4KUKGDIOi7nawNDs6d+AiulEA=
github.com/rs/zerolog v1.18.1-0.20200514152719-663cbb4c8469/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
@ -661,6 +678,7 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
@ -917,6 +935,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190415145633-3fd5a3612ccd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -984,8 +1003,9 @@ golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

View file

@ -53,6 +53,7 @@ fragment ConfigInterfaceData on ConfigInterfaceResult {
wallPlayback
maximumLoopDuration
noBrowser
notificationsEnabled
autostartVideo
autostartVideoOnPlaySelected
continuePlaylistDefault

View file

@ -239,6 +239,8 @@ input ConfigInterfaceInput {
funscriptOffset: Int
"""True if we should not auto-open a browser window on startup"""
noBrowser: Boolean
"""True if we should send notifications to the desktop"""
notificationsEnabled: Boolean
}
type ConfigDisableDropdownCreate {
@ -261,8 +263,10 @@ type ConfigInterfaceResult {
"""Maximum duration (in seconds) in which a scene video will loop in the scene player"""
maximumLoopDuration: Int
""""True if we should not auto-open a browser window on startup"""
"""True if we should not auto-open a browser window on startup"""
noBrowser: Boolean
"""True if we should send desktop notifications"""
notificationsEnabled: Boolean
"""If true, video will autostart on load in the scene player"""
autostartVideo: Boolean
"""If true, video will autostart when loading from play random or play selected"""

16
main.go
View file

@ -3,13 +3,14 @@ package main
import (
"embed"
"fmt"
"os"
"os/signal"
"runtime/pprof"
"syscall"
"github.com/apenwarr/fixconsole"
"github.com/stashapp/stash/pkg/api"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/manager"
_ "github.com/golang-migrate/migrate/v4/database/sqlite3"
@ -22,6 +23,14 @@ var uiBox embed.FS
//go:embed ui/login
var loginUIBox embed.FS
func init() {
// On Windows, attach to parent shell
err := fixconsole.FixConsoleIfNeeded()
if err != nil {
fmt.Printf("FixConsoleOutput: %v\n", err)
}
}
func main() {
manager.Initialize()
api.Start(uiBox, loginUIBox)
@ -30,10 +39,7 @@ func main() {
defer pprof.StopCPUProfile()
blockForever()
err := manager.GetInstance().Shutdown()
if err != nil {
logger.Errorf("Error when closing: %s", err)
}
manager.GetInstance().Shutdown(0)
}
func blockForever() {

View file

@ -130,9 +130,4 @@ func securityActivateTripwireAccessedFromInternetWithoutAuth(c *config.Instance,
if err != nil {
logger.Error(err)
}
err = manager.GetInstance().Shutdown()
if err != nil {
logger.Error(err)
}
}

28
pkg/api/favicon.go Normal file
View file

@ -0,0 +1,28 @@
package api
import (
"embed"
"runtime"
)
const faviconDir = "ui/v2.5/build/"
type FaviconProvider struct {
uiBox embed.FS
}
func (p *FaviconProvider) GetFavicon() []byte {
if runtime.GOOS == "windows" {
faviconPath := faviconDir + "favicon.ico"
ret, _ := p.uiBox.ReadFile(faviconPath)
return ret
}
return p.GetFaviconPng()
}
func (p *FaviconProvider) GetFaviconPng() []byte {
faviconPath := faviconDir + "favicon.png"
ret, _ := p.uiBox.ReadFile(faviconPath)
return ret
}

View file

@ -294,6 +294,8 @@ func (r *mutationResolver) ConfigureInterface(ctx context.Context, input models.
setBool(config.NoBrowser, input.NoBrowser)
setBool(config.NotificationsEnabled, input.NotificationsEnabled)
if input.WallPlayback != nil {
c.Set(config.WallPlayback, *input.WallPlayback)
}

View file

@ -111,6 +111,7 @@ func makeConfigInterfaceResult() *models.ConfigInterfaceResult {
wallShowTitle := config.GetWallShowTitle()
wallPlayback := config.GetWallPlayback()
noBrowser := config.GetNoBrowser()
notificationsEnabled := config.GetNotificationsEnabled()
maximumLoopDuration := config.GetMaximumLoopDuration()
autostartVideo := config.GetAutostartVideo()
autostartVideoOnPlaySelected := config.GetAutostartVideoOnPlaySelected()
@ -133,6 +134,7 @@ func makeConfigInterfaceResult() *models.ConfigInterfaceResult {
WallPlayback: &wallPlayback,
MaximumLoopDuration: &maximumLoopDuration,
NoBrowser: &noBrowser,
NotificationsEnabled: &notificationsEnabled,
AutostartVideo: &autostartVideo,
ShowStudioAsText: &showStudioAsText,
AutostartVideoOnPlaySelected: &autostartVideoOnPlaySelected,

View file

@ -23,8 +23,10 @@ import (
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/gorilla/websocket"
"github.com/pkg/browser"
"github.com/go-chi/httplog"
"github.com/rs/cors"
"github.com/stashapp/stash/pkg/desktop"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/manager"
"github.com/stashapp/stash/pkg/manager/config"
@ -36,7 +38,6 @@ import (
var version string
var buildstamp string
var githash string
var officialBuild string
func Start(uiBox embed.FS, loginUIBox embed.FS) {
initialiseImages()
@ -52,7 +53,10 @@ func Start(uiBox embed.FS, loginUIBox embed.FS) {
c := config.GetInstance()
if c.GetLogAccess() {
r.Use(middleware.Logger)
httpLogger := httplog.NewLogger("Stash", httplog.Options{
Concise: true,
})
r.Use(httplog.RequestLogger(httpLogger))
}
r.Use(SecurityHeadersMiddleware)
r.Use(middleware.DefaultCompress)
@ -246,9 +250,8 @@ func Start(uiBox embed.FS, loginUIBox embed.FS) {
TLSConfig: tlsConfig,
}
go func() {
printVersion()
printLatestVersion(context.TODO())
go printLatestVersion(context.TODO())
logger.Infof("stash is listening on " + address)
if tlsConfig != nil {
displayAddress = "https://" + displayAddress + "/"
@ -256,15 +259,7 @@ func Start(uiBox embed.FS, loginUIBox embed.FS) {
displayAddress = "http://" + displayAddress + "/"
}
// This can be done before actually starting the server, as modern browsers will
// automatically reload the page if a local port is closed at page load and then opened.
if !c.GetNoBrowser() && manager.GetInstance().IsDesktop() {
err = browser.OpenURL(displayAddress)
if err != nil {
logger.Error("Could not open browser: " + err.Error())
}
}
go func() {
if tlsConfig != nil {
logger.Infof("stash is running at " + displayAddress)
logger.Error(server.ListenAndServeTLS("", ""))
@ -272,12 +267,14 @@ func Start(uiBox embed.FS, loginUIBox embed.FS) {
logger.Infof("stash is running at " + displayAddress)
logger.Error(server.ListenAndServe())
}
manager.GetInstance().Shutdown(0)
}()
desktop.Start(manager.GetInstance(), &FaviconProvider{uiBox: uiBox})
}
func printVersion() {
versionString := githash
if IsOfficialBuild() {
if config.IsOfficialBuild() {
versionString += " - Official Build"
} else {
versionString += " - Unofficial Build"
@ -288,10 +285,6 @@ func printVersion() {
fmt.Printf("stash version: %s - %s\n", versionString, buildstamp)
}
func IsOfficialBuild() bool {
return officialBuild == "true"
}
func GetVersion() (string, string, string) {
return version, githash, buildstamp
}

170
pkg/desktop/desktop.go Normal file
View file

@ -0,0 +1,170 @@
package desktop
import (
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
"github.com/pkg/browser"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/utils"
"golang.org/x/term"
)
type ShutdownHandler interface {
Shutdown(code int)
}
type FaviconProvider interface {
GetFavicon() []byte
GetFaviconPng() []byte
}
func Start(shutdownHandler ShutdownHandler, faviconProvider FaviconProvider) {
if IsDesktop() {
c := config.GetInstance()
if !c.GetNoBrowser() {
openURLInBrowser("")
}
writeStashIcon(faviconProvider)
startSystray(shutdownHandler, faviconProvider)
}
}
// openURLInBrowser opens a browser to the Stash UI. Path can be an empty string for main page.
func openURLInBrowser(path string) {
// This can be done before actually starting the server, as modern browsers will
// automatically reload the page if a local port is closed at page load and then opened.
serverAddress := getServerURL(path)
err := browser.OpenURL(serverAddress)
if err != nil {
logger.Error("Could not open browser: " + err.Error())
}
}
func SendNotification(title string, text string) {
if IsDesktop() {
c := config.GetInstance()
if c.GetNotificationsEnabled() {
sendNotification(title, text)
}
}
}
func IsDesktop() bool {
// Check if running under root
if os.Getuid() == 0 {
return false
}
// Check if stdin is a terminal
if term.IsTerminal(int(os.Stdin.Fd())) {
return false
}
if isService() {
return false
}
if IsServerDockerized() {
return false
}
return true
}
func IsServerDockerized() bool {
return isServerDockerized()
}
// Set a command to execute in the background, instead of spawning a shell window
func HideExecShell(cmd *exec.Cmd) {
hideExecShell(cmd)
}
// writeStashIcon writes the current stash logo to config/icon.png
func writeStashIcon(faviconProvider FaviconProvider) {
c := config.GetInstance()
if !c.IsNewSystem() {
iconPath := path.Join(c.GetConfigPath(), "icon.png")
err := ioutil.WriteFile(iconPath, faviconProvider.GetFaviconPng(), 0644)
if err != nil {
logger.Errorf("Couldn't write icon file: %s", err.Error())
}
}
}
// IsAllowedAutoUpdate tries to determine if the stash binary was installed from a
// package manager or if touching the executable is otherwise a bad idea
func IsAllowedAutoUpdate() bool {
// Only try to update if downloaded from official sources
if !config.IsOfficialBuild() {
return false
}
// Avoid updating if installed from package manager
if runtime.GOOS == "linux" {
executablePath, err := os.Executable()
if err != nil {
logger.Errorf("Cannot get executable path: %s", err)
return false
}
executablePath, err = filepath.EvalSymlinks(executablePath)
if err != nil {
logger.Errorf("Cannot get executable path: %s", err)
return false
}
if utils.IsPathInDir("/usr", executablePath) || utils.IsPathInDir("/opt", executablePath) {
return false
}
if isServerDockerized() {
return false
}
}
return true
}
func getIconPath() string {
return path.Join(config.GetInstance().GetConfigPath(), "icon.png")
}
func RevealInFileManager(path string) {
exists, err := utils.FileExists(path)
if err != nil {
logger.Errorf("Error checking file: %s", err)
return
}
if exists && IsDesktop() {
revealInFileManager(path)
}
}
func getServerURL(path string) string {
c := config.GetInstance()
serverAddress := c.GetHost()
if serverAddress == "0.0.0.0" {
serverAddress = "localhost"
}
serverAddress = serverAddress + ":" + strconv.Itoa(c.GetPort())
proto := ""
if c.HasTLSConfig() {
proto = "https://"
} else {
proto = "http://"
}
serverAddress = proto + serverAddress + "/"
if path != "" {
serverAddress += strings.TrimPrefix(path, "/")
}
return serverAddress
}

View file

@ -0,0 +1,40 @@
//go:build darwin
// +build darwin
package desktop
import (
"os/exec"
"github.com/kermieisinthehouse/gosx-notifier"
"github.com/stashapp/stash/pkg/logger"
)
func isService() bool {
// MacOS /does/ support services, using launchd, but there is no straightforward way to check if it was used.
return false
}
func isServerDockerized() bool {
return false
}
func hideExecShell(cmd *exec.Cmd) {
}
func sendNotification(notificationTitle string, notificationText string) {
notification := gosxnotifier.NewNotification(notificationText)
notification.Title = notificationTitle
notification.AppIcon = getIconPath()
notification.Link = getServerURL("")
err := notification.Push()
if err != nil {
logger.Errorf("Could not send MacOS notification: %s", err.Error())
}
}
func revealInFileManager(path string) {
exec.Command(`open`, `-R`, path)
}

View file

@ -0,0 +1,43 @@
//go:build linux
// +build linux
package desktop
import (
"io/ioutil"
"os"
"os/exec"
"strings"
"github.com/stashapp/stash/pkg/logger"
)
// isService checks if started by init, e.g. stash is a *nix systemd service
func isService() bool {
return os.Getppid() == 1
}
func isServerDockerized() bool {
_, dockerEnvErr := os.Stat("/.dockerenv")
cgroups, _ := ioutil.ReadFile("/proc/self/cgroup")
if !os.IsNotExist(dockerEnvErr) || strings.Contains(string(cgroups), "docker") {
return true
}
return false
}
func hideExecShell(cmd *exec.Cmd) {
}
func sendNotification(notificationTitle string, notificationText string) {
err := exec.Command("notify-send", "-i", getIconPath(), notificationTitle, notificationText, "-a", "Stash").Run()
if err != nil {
logger.Errorf("Error sending notification on Linux: %s", err.Error())
}
}
func revealInFileManager(path string) {
}

View file

@ -0,0 +1,56 @@
//go:build windows
// +build windows
package desktop
import (
"os/exec"
"syscall"
"golang.org/x/sys/windows"
"github.com/go-toast/toast"
"github.com/stashapp/stash/pkg/logger"
"golang.org/x/sys/windows/svc"
)
func isService() bool {
result, err := svc.IsWindowsService()
if err != nil {
logger.Errorf("Encountered error checking if running as Windows service: %s", err.Error())
return false
}
return result
}
func isServerDockerized() bool {
return false
}
// On Windows, calling exec.Cmd.Start() will create a cmd window, even if we live in the taskbar.
// We don't want every ffmpeg / plugin to pop up a window.
func hideExecShell(cmd *exec.Cmd) {
cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: windows.DETACHED_PROCESS}
}
func sendNotification(notificationTitle string, notificationText string) {
notification := toast.Notification{
AppID: "Stash",
Title: notificationTitle,
Message: notificationText,
Icon: getIconPath(),
Actions: []toast.Action{{
Type: "protocol",
Label: "Open Stash",
Arguments: getServerURL(""),
}},
}
err := notification.Push()
if err != nil {
logger.Errorf("Error creating Windows notification: %s", err.Error())
}
}
func revealInFileManager(path string) {
exec.Command(`explorer`, `\select`, path)
}

Binary file not shown.

View file

@ -0,0 +1,10 @@
//go:build linux
// +build linux
package desktop
func startSystray(shutdownHandler ShutdownHandler, favicon FaviconProvider) {
// The systray is not available on linux because the required libraries (libappindicator3 and gtk+3.0)
// are not able to be statically compiled. Technically, the systray works perfectly fine when dynamically
// linked, but we cannot distribute it for compatibility reasons.
}

View file

@ -0,0 +1,94 @@
//go:build windows || darwin || !linux
// +build windows darwin !linux
package desktop
import (
"strings"
"github.com/kermieisinthehouse/systray"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/manager/config"
)
// MUST be run on the main goroutine or will have no effect on macOS
func startSystray(shutdownHandler ShutdownHandler, faviconProvider FaviconProvider) {
// Shows a small notification to inform that Stash will no longer show a terminal window,
// and instead will be available in the tray. Will only show the first time a pre-desktop integration
// system is started from a non-terminal method, e.g. double-clicking an icon.
c := config.GetInstance()
if c.GetShowOneTimeMovedNotification() {
SendNotification("Stash has moved!", "Stash now runs in your tray, instead of a terminal window.")
c.Set(config.ShowOneTimeMovedNotification, false)
if err := c.Write(); err != nil {
logger.Errorf("Error while writing configuration file: %s", err.Error())
}
}
// Listen for changes to rerender systray
// TODO: This is disabled for now. The systray package does not clean up all of its resources when Quit() is called.
// TODO: This results in this only working once, or changes being ignored. Our fork of systray fixes a crash(!) on macOS here.
// go func() {
// for {
// <-config.GetInstance().GetConfigUpdatesChannel()
// systray.Quit()
// }
// }()
for {
systray.Run(func() {
systrayInitialize(shutdownHandler, faviconProvider)
}, nil)
}
}
func systrayInitialize(shutdownHandler ShutdownHandler, faviconProvider FaviconProvider) {
favicon := faviconProvider.GetFavicon()
systray.SetTemplateIcon(favicon, favicon)
systray.SetTooltip("🟢 Stash is Running.")
openStashButton := systray.AddMenuItem("Open Stash", "Open a browser window to Stash")
var menuItems []string
systray.AddSeparator()
c := config.GetInstance()
if !c.IsNewSystem() {
menuItems = c.GetMenuItems()
for _, item := range menuItems {
titleCaseItem := strings.Title(strings.ToLower(item))
curr := systray.AddMenuItem(titleCaseItem, "Open to "+titleCaseItem)
go func(item string) {
for {
<-curr.ClickedCh
if item == "markers" {
item = "scenes/markers"
}
if c.GetNoBrowser() {
openURLInBrowser(item)
}
}
}(item)
}
systray.AddSeparator()
// TODO - Some ideas for future expansions
// systray.AddMenuItem("Start a Scan", "Scan all libraries with default settings")
// systray.AddMenuItem("Start Auto Tagging", "Auto Tag all libraries")
// systray.AddMenuItem("Check for updates", "Check for a new Stash release")
// systray.AddSeparator()
}
quitStashButton := systray.AddMenuItem("Quit Stash Server", "Quits the Stash server")
go func() {
for {
select {
case <-openStashButton.ClickedCh:
if !c.GetNoBrowser() {
openURLInBrowser("")
}
case <-quitStashButton.ClickedCh:
shutdownHandler.Shutdown(0)
}
}
}()
}

View file

@ -13,6 +13,7 @@ import (
"runtime"
"strings"
"github.com/stashapp/stash/pkg/desktop"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/utils"
)
@ -202,7 +203,9 @@ func pathBinaryHasCorrectFlags() bool {
if err != nil {
return false
}
bytes, _ := exec.Command(ffmpegPath).CombinedOutput()
cmd := exec.Command(ffmpegPath)
desktop.HideExecShell(cmd)
bytes, _ := cmd.CombinedOutput()
output := string(bytes)
hasOpus := strings.Contains(output, "--enable-libopus")
hasVpx := strings.Contains(output, "--enable-libvpx")

View file

@ -9,6 +9,7 @@ import (
"sync"
"time"
"github.com/stashapp/stash/pkg/desktop"
"github.com/stashapp/stash/pkg/logger"
)
@ -90,6 +91,7 @@ func (e *Encoder) runTranscode(probeResult VideoFile, args []string) (string, er
logger.Error("FFMPEG stdout not available: " + err.Error())
}
desktop.HideExecShell(cmd)
if err = cmd.Start(); err != nil {
return "", err
}
@ -141,6 +143,7 @@ func (e *Encoder) run(sourcePath string, args []string, stdin io.Reader) (string
cmd.Stderr = &stderr
cmd.Stdin = stdin
desktop.HideExecShell(cmd)
if err := cmd.Start(); err != nil {
return "", err
}

View file

@ -11,6 +11,7 @@ import (
"strings"
"time"
"github.com/stashapp/stash/pkg/desktop"
"github.com/stashapp/stash/pkg/logger"
)
@ -229,7 +230,9 @@ type FFProbe string
// Execute exec command and bind result to struct.
func (f *FFProbe) NewVideoFile(videoPath string, stripExt bool) (*VideoFile, error) {
args := []string{"-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", "-show_error", videoPath}
out, err := exec.Command(string(*f), args...).Output()
cmd := exec.Command(string(*f), args...)
desktop.HideExecShell(cmd)
out, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("FFProbe encountered an error with <%s>.\nError JSON:\n%s\nError: %s", videoPath, string(out), err.Error())

View file

@ -8,6 +8,7 @@ import (
"strconv"
"strings"
"github.com/stashapp/stash/pkg/desktop"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/models"
)
@ -220,6 +221,7 @@ func (e *Encoder) stream(probeResult VideoFile, options TranscodeStreamOptions)
return nil, err
}
desktop.HideExecShell(cmd)
if err = cmd.Start(); err != nil {
return nil, err
}

View file

@ -6,6 +6,7 @@ import (
"os/exec"
"strings"
"github.com/stashapp/stash/pkg/desktop"
"github.com/stashapp/stash/pkg/logger"
)
@ -32,6 +33,7 @@ func (e *vipsEncoder) run(args []string, stdin *bytes.Buffer) (string, error) {
cmd.Stderr = &stderr
cmd.Stdin = stdin
desktop.HideExecShell(cmd)
if err := cmd.Start(); err != nil {
return "", err
}

View file

@ -2,9 +2,13 @@ package job
import (
"context"
"fmt"
"strconv"
"strings"
"sync"
"time"
"github.com/stashapp/stash/pkg/desktop"
"github.com/stashapp/stash/pkg/utils"
)
@ -204,9 +208,14 @@ func (m *Manager) onJobFinish(job *Job) {
} else {
job.Status = StatusFinished
}
t := time.Now()
job.EndTime = &t
cleanDesc := strings.TrimRight(job.Description, ".")
timeElapsed := job.EndTime.Sub(*job.StartTime)
hours := fmt.Sprintf("%+02s", strconv.FormatFloat(timeElapsed.Hours(), 'f', 0, 64))
minutes := fmt.Sprintf("%+02s", strconv.FormatFloat(timeElapsed.Minutes(), 'f', 0, 64))
seconds := fmt.Sprintf("%+02s", strconv.FormatFloat(timeElapsed.Seconds(), 'f', 0, 64))
desktop.SendNotification("Task Finished", "Task \""+cleanDesc+"\" is finished in "+hours+":"+minutes+":"+seconds+".")
}
func (m *Manager) removeJob(job *Job) {

View file

@ -32,6 +32,7 @@ func Init(logFile string, logOut bool, logLevel string) {
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
customFormatter.ForceColors = true
customFormatter.FullTimestamp = true
logger.SetOutput(os.Stderr)
logger.SetFormatter(customFormatter)
// #1837 - trigger the console to use color-mode since it won't be

View file

@ -21,6 +21,8 @@ import (
"github.com/stashapp/stash/pkg/utils"
)
var officialBuild string
const (
Stash = "stash"
Cache = "cache"
@ -180,6 +182,10 @@ const (
// Desktop Integration Options
NoBrowser = "noBrowser"
NoBrowserDefault = false
NotificationsEnabled = "notifications_enabled"
NotificationsEnabledDefault = true
ShowOneTimeMovedNotification = "show_one_time_moved_notification"
ShowOneTimeMovedNotificationDefault = false
// File upload options
MaxUploadSize = "max_upload_size"
@ -211,6 +217,10 @@ func (s *StashBoxError) Error() string {
return "Stash-box: " + s.msg
}
func IsOfficialBuild() bool {
return officialBuild == "true"
}
type Instance struct {
// main instance - backed by config file
main *viper.Viper
@ -221,6 +231,7 @@ type Instance struct {
cpuProfilePath string
isNewSystem bool
// configUpdates chan int
certFile string
keyFile string
sync.RWMutex
@ -270,7 +281,25 @@ func (i *Instance) GetNoBrowser() bool {
return i.getBool(NoBrowser)
}
func (i *Instance) GetNotificationsEnabled() bool {
return i.getBool(NotificationsEnabled)
}
// func (i *Instance) GetConfigUpdatesChannel() chan int {
// return i.configUpdates
// }
// GetShowOneTimeMovedNotification shows whether a small notification to inform the user that Stash
// will no longer show a terminal window, and instead will be available in the tray, should be shown.
// It is true when an existing system is started after upgrading, and set to false forever after it is shown.
func (i *Instance) GetShowOneTimeMovedNotification() bool {
return i.getBool(ShowOneTimeMovedNotification)
}
func (i *Instance) Set(key string, value interface{}) {
// if key == MenuItems {
// i.configUpdates <- 0
// }
i.Lock()
defer i.Unlock()
i.main.Set(key, value)
@ -1184,6 +1213,8 @@ func (i *Instance) setDefaultValues(write bool) error {
i.main.SetDefault(Generated, i.main.GetString(Metadata))
i.main.SetDefault(NoBrowser, NoBrowserDefault)
i.main.SetDefault(NotificationsEnabled, NotificationsEnabledDefault)
i.main.SetDefault(ShowOneTimeMovedNotification, ShowOneTimeMovedNotificationDefault)
// Set default scrapers and plugins paths
i.main.SetDefault(ScrapersPath, defaultScrapersPath)
@ -1210,6 +1241,12 @@ func (i *Instance) setExistingSystemDefaults() error {
i.main.Set(NoBrowser, true)
}
// Existing systems as of the introduction of the taskbar should inform users.
if !i.main.InConfig(ShowOneTimeMovedNotification) {
configDirtied = true
i.main.Set(ShowOneTimeMovedNotification, true)
}
if configDirtied {
return i.main.WriteConfig()
}
@ -1247,4 +1284,5 @@ func (i *Instance) setInitialConfig(write bool) error {
func (i *Instance) FinalizeSetup() {
i.isNewSystem = false
// i.configUpdates <- 0
}

View file

@ -45,6 +45,7 @@ func Initialize() (*Instance, error) {
_ = GetInstance()
instance.overrides = overrides
instance.cpuProfilePath = flags.cpuProfilePath
// instance.configUpdates = make(chan int)
if err = initConfig(instance, flags); err != nil {
return

View file

@ -9,6 +9,7 @@ import (
"strconv"
"strings"
"github.com/stashapp/stash/pkg/desktop"
"github.com/stashapp/stash/pkg/ffmpeg"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/utils"
@ -72,6 +73,7 @@ func (g *GeneratorInfo) calculateFrameRate(videoStream *ffmpeg.FFProbeStream) er
}
command := exec.Command(string(instance.FFMPEG), args...)
desktop.HideExecShell(command)
var stdErrBuffer bytes.Buffer
command.Stderr = &stdErrBuffer // Frames go to stderr rather than stdout
if err := command.Run(); err == nil {

View file

@ -4,12 +4,9 @@ import (
"context"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"runtime/pprof"
"strings"
"sync"
"time"
@ -407,34 +404,6 @@ func (s *singleton) Migrate(ctx context.Context, input models.MigrateInput) erro
return nil
}
func (s *singleton) IsDesktop() bool {
// check if running under root
if os.Getuid() == 0 {
return false
}
// check if started by init, e.g. stash is a *nix systemd service / MacOS launchd service
if os.Getppid() == 1 {
return false
}
if IsServerDockerized() {
return false
}
return true
}
func IsServerDockerized() bool {
if runtime.GOOS == "linux" {
_, dockerEnvErr := os.Stat("/.dockerenv")
cgroups, _ := ioutil.ReadFile("/proc/self/cgroup")
if os.IsExist(dockerEnvErr) || strings.Contains(string(cgroups), "docker") {
return true
}
}
return false
}
func (s *singleton) GetSystemStatus() *models.SystemStatus {
status := models.SystemStatusEnumOk
dbSchema := int(database.Version())
@ -458,8 +427,15 @@ func (s *singleton) GetSystemStatus() *models.SystemStatus {
}
// Shutdown gracefully stops the manager
func (s *singleton) Shutdown() error {
func (s *singleton) Shutdown(code int) {
// TODO: Each part of the manager needs to gracefully stop at some point
// for now, we just close the database.
return database.Close()
err := database.Close()
if err != nil {
logger.Errorf("Error closing database: %s", err)
if code == 0 {
os.Exit(1)
}
}
os.Exit(code)
}

View file

@ -8,6 +8,7 @@ import (
"os/exec"
"sync"
"github.com/stashapp/stash/pkg/desktop"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/plugin/common"
)
@ -87,6 +88,7 @@ func (t *rawPluginTask) Start() error {
t.waitGroup.Add(1)
t.done = make(chan bool, 1)
desktop.HideExecShell(cmd)
if err = cmd.Start(); err != nil {
return fmt.Errorf("error running plugin: %v", err)
}

View file

@ -10,6 +10,7 @@ import (
"path/filepath"
"strings"
"github.com/stashapp/stash/pkg/desktop"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/models"
)
@ -66,6 +67,7 @@ func (s *scriptScraper) runScraperScript(inString string, out interface{}) error
logger.Error("Scraper stdout not available: " + err.Error())
}
desktop.HideExecShell(cmd)
if err = cmd.Start(); err != nil {
logger.Error("Error running scraper script: " + err.Error())
return errors.New("error running scraper script")

View file

@ -1,7 +1,6 @@
#!/bin/bash
# "stashapp/compiler:develop" "stashapp/compiler:4"
COMPILER_CONTAINER="stashapp/compiler:5"
COMPILER_CONTAINER="stashapp/compiler:6"
BUILD_DATE=`go run -mod=vendor scripts/getDate.go`
GITHASH=`git rev-parse --short HEAD`
@ -10,8 +9,8 @@ STASH_VERSION=`git describe --tags --exclude latest_develop`
SETENV="BUILD_DATE=\"$BUILD_DATE\" GITHASH=$GITHASH STASH_VERSION=\"$STASH_VERSION\""
SETUP="export CGO_ENABLED=1;"
WINDOWS="echo '=== Building Windows binary ==='; $SETENV make cross-compile-windows;"
DARWIN="echo '=== Building OSX binary ==='; $SETENV make cross-compile-osx-intel;"
DARWIN_ARM64="echo '=== Building OSX (arm64) binary ==='; $SETENV make cross-compile-osx-applesilicon;"
DARWIN="echo '=== Building OSX binary ==='; $SETENV make cross-compile-macos-intel;"
DARWIN_ARM64="echo '=== Building OSX (arm64) binary ==='; $SETENV make cross-compile-macos-applesilicon;"
LINUX_AMD64="echo '=== Building Linux (amd64) binary ==='; $SETENV make cross-compile-linux;"
LINUX_ARM64v8="echo '=== Building Linux (armv8/arm64) binary ==='; $SETENV make cross-compile-linux-arm64v8;"
LINUX_ARM32v7="echo '=== Building Linux (armv7/armhf) binary ==='; $SETENV make cross-compile-linux-arm32v7;"

50
scripts/generate_icons.sh Executable file
View file

@ -0,0 +1,50 @@
#!/bin/bash
# Update the Stash icon throughout the project from a master stash-logo.png
# Imagemagick, and go packages icns and rsrc are required.
# Copy a high-resolution stash-logo.png to this stash/scripts folder
# and run this script from said folder, commit the result.
if [ ! -f "stash-logo.png" ]; then
echo "stash-logo.png not found."
exit
fi
if [ -z "$GOPATH" ]; then
echo "GOPATH environment variable not set"
exit
fi
if [ ! -e "$GOPATH/bin/rsrc" ]; then
echo "Missing Dependency:"
echo "Please run the following /outside/ of the stash folder:"
echo "go install github.com/akavel/rsrc@latest"
exit
fi
if [ ! -e "$GOPATH/bin/icnsify" ]; then
echo "Missing Dependency:"
echo "Please run the following /outside/ of the stash folder:"
echo "go install github.com/jackmordaunt/icns/v2/cmd/icnsify@latest"
exit
fi
# Favicon, used for web favicon, windows systray icon, windows executable icon
convert stash-logo.png -define icon:auto-resize=256,64,48,32,16 favicon.ico
cp favicon.ico ../ui/v2.5/public/
# Build .syso for Windows icon, consumed by linker while building stash-win.exe
"$GOPATH"/bin/rsrc -ico favicon.ico -o icon_windows.syso
mv icon_windows.syso ../pkg/desktop/
# *nixes systray icon
convert stash-logo.png -resize x256 favicon.png
cp favicon.png ../ui/v2.5/public/
# MacOS, used for bundle icon
# https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html
"$GOPATH"/bin/icnsify -i stash-logo.png -o icon.icns
mv icon.icns macos-bundle/Contents/Resources/icon.icns
# cleanup
rm favicon.png favicon.ico

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>stash</string>
<key>CFBundleIconFile</key>
<string>icon.icns</string>
<key>CFBundleTypeIconFile</key>
<string>icon.icns</string>
<key>CFBundleIdentifier</key>
<string>org.stashapp.stash</string>
<key>NSHighResolutionCapable</key>
<string>True</string>
<key>LSUIElement</key>
<string>1</string>
</dict>
</plist>

Binary file not shown.

BIN
scripts/stash-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 41 KiB

BIN
ui/v2.5/public/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -8,7 +8,8 @@
"type": "image/x-icon"
}
],
"start_url": ".",
"start_url": "/",
"scope": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"

View file

@ -1,4 +1,6 @@
### ✨ New Features
* Open stash in system tray on Windows/MacOS when not running via terminal. ([#2073](https://github.com/stashapp/stash/pull/2073))
* Optionally send desktop notifications when a task completes. ([#2073](https://github.com/stashapp/stash/pull/2073))
* Added button to image card to view image in Lightbox. ([#2275](https://github.com/stashapp/stash/pull/2275))
* Added support for submitting performer/scene drafts to stash-box. ([#2234](https://github.com/stashapp/stash/pull/2234))

View file

@ -93,6 +93,13 @@ export const SettingsInterfacePanel: React.FC = () => {
checked={iface.noBrowser ?? undefined}
onChange={(v) => saveInterface({ noBrowser: v })}
/>
<BooleanSetting
id="notifications-enabled"
headingID="config.ui.desktop_integration.notifications_enabled"
subHeadingID="config.ui.desktop_integration.send_desktop_notifications_for_events"
checked={iface.notificationsEnabled ?? undefined}
onChange={(v) => saveInterface({ notificationsEnabled: v })}
/>
</SettingSection>
<SettingSection headingID="config.ui.scene_wall.heading">

View file

@ -414,7 +414,9 @@
"desktop_integration": {
"desktop_integration": "Desktop Integration",
"skip_opening_browser": "Skip Opening Browser",
"skip_opening_browser_on_startup": "Skip auto-opening browser during startup"
"skip_opening_browser_on_startup": "Skip auto-opening browser during startup",
"notifications_enabled": "Enable Notifications",
"send_desktop_notifications_for_events": "Send desktop notifications for events"
},
"editing": {
"disable_dropdown_create": {

1
vendor/github.com/apenwarr/fixconsole/.gitignore generated vendored Normal file
View file

@ -0,0 +1 @@
*~

202
vendor/github.com/apenwarr/fixconsole/LICENSE generated vendored Normal file
View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View file

@ -0,0 +1,14 @@
// +build !windows
package fixconsole
// On non-windows platforms, we don't need to do anything. The console
// starts off attached already, if it exists.
func AttachConsole() error {
return nil
}
func FixConsoleIfNeeded() error {
return nil
}

View file

@ -0,0 +1,132 @@
package fixconsole
import (
"fmt"
"github.com/apenwarr/w32"
"golang.org/x/sys/windows"
"os"
"syscall"
)
func AttachConsole() error {
const ATTACH_PARENT_PROCESS = ^uintptr(0)
proc := syscall.MustLoadDLL("kernel32.dll").MustFindProc("AttachConsole")
r1, _, err := proc.Call(ATTACH_PARENT_PROCESS)
if r1 == 0 {
errno, ok := err.(syscall.Errno)
if ok && errno == w32.ERROR_INVALID_HANDLE {
// console handle doesn't exist; not a real
// error, but the console handle will be
// invalid.
return nil
}
return err
} else {
return nil
}
}
var oldStdin, oldStdout, oldStderr *os.File
// Windows console output is a mess.
//
// If you compile as "-H windows", then if you launch your program without
// a console, Windows forcibly creates one to use as your stdin/stdout, which
// is silly for a GUI app, so we can't do that.
//
// If you compile as "-H windowsgui", then it doesn't create a console for
// your app... but also doesn't provide a working stdin/stdout/stderr even if
// you *did* launch from the console. However, you can use AttachConsole()
// to get a handle to your parent process's console, if any, and then
// os.NewFile() to turn that handle into a fd usable as stdout/stderr.
//
// However, then you have the problem that if you redirect stdout or stderr
// from the shell, you end up ignoring the redirection by forcing it to the
// console.
//
// To fix *that*, we have to detect whether there was a pre-existing stdout
// or not. We can check GetStdHandle(), which returns 0 for "should be
// console" and nonzero for "already pointing at a file."
//
// Be careful though! As soon as you run AttachConsole(), it resets *all*
// the GetStdHandle() handles to point them at the console instead, thus
// throwing away the original file redirects. So we have to GetStdHandle()
// *before* AttachConsole().
//
// For some reason, powershell redirections provide a valid file handle, but
// writing to that handle doesn't write to the file. I haven't found a way
// to work around that. (Windows 10.0.17763.379)
//
// Net result is as follows.
// Before:
// SHELL NON-REDIRECTED REDIRECTED
// explorer.exe no console n/a
// cmd.exe broken works
// powershell broken broken
// WSL bash broken works
// After
// SHELL NON-REDIRECTED REDIRECTED
// explorer.exe no console n/a
// cmd.exe works works
// powershell works broken
// WSL bash works works
//
// We don't seem to make anything worse, at least.
func FixConsoleIfNeeded() error {
// Retain the original console objects, to prevent Go from automatically
// closing their file descriptors when they get garbage collected.
// You never want to close file descriptors 0, 1, and 2.
oldStdin, oldStdout, oldStderr = os.Stdin, os.Stdout, os.Stderr
stdin, _ := syscall.GetStdHandle(syscall.STD_INPUT_HANDLE)
stdout, _ := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE)
stderr, _ := syscall.GetStdHandle(syscall.STD_ERROR_HANDLE)
var invalid syscall.Handle
con := invalid
if stdin == invalid || stdout == invalid || stderr == invalid {
err := AttachConsole()
if err != nil {
return fmt.Errorf("attachconsole: %v", err)
}
if stdin == invalid {
stdin, _ = syscall.GetStdHandle(syscall.STD_INPUT_HANDLE)
}
if stdout == invalid {
stdout, _ = syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE)
con = stdout
}
if stderr == invalid {
stderr, _ = syscall.GetStdHandle(syscall.STD_ERROR_HANDLE)
con = stderr
}
}
if con != invalid {
// Make sure the console is configured to convert
// \n to \r\n, like Go programs expect.
h := windows.Handle(con)
var st uint32
err := windows.GetConsoleMode(h, &st)
if err != nil {
return fmt.Errorf("GetConsoleMode: %v", err)
}
err = windows.SetConsoleMode(h, st&^windows.DISABLE_NEWLINE_AUTO_RETURN)
if err != nil {
return fmt.Errorf("SetConsoleMode: %v", err)
}
}
if stdin != invalid {
os.Stdin = os.NewFile(uintptr(stdin), "stdin")
}
if stdout != invalid {
os.Stdout = os.NewFile(uintptr(stdout), "stdout")
}
if stderr != invalid {
os.Stderr = os.NewFile(uintptr(stderr), "stderr")
}
return nil
}

19
vendor/github.com/apenwarr/w32/AUTHORS generated vendored Normal file
View file

@ -0,0 +1,19 @@
# This is the official list of 'w32' authors for copyright purposes.
# Names should be added to this file as
# Name or Organization <email address>
# The email address is not required for organizations.
# Please keep the list sorted.
# Contributors
# ============
Allen Dang <allengnr@gmail.com>
Benny Siegert <bsiegert@gmail.com>
Bruno Bigras <bigras.bruno@gmail.com>
Daniel Joos
Gerald Rosenberg <gerald.rosenberg@gmail.com>
Liam Bowen <liambowen@gmail.com>
Michael Henke
Paul Maddox <paul.maddox@gmail.com>

23
vendor/github.com/apenwarr/w32/LICENSE generated vendored Normal file
View file

@ -0,0 +1,23 @@
Copyright (c) 2010-2012 The w32 Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

33
vendor/github.com/apenwarr/w32/README.md generated vendored Normal file
View file

@ -0,0 +1,33 @@
About w32
==========
w32 is a wrapper of windows apis for the Go Programming Language.
It wraps win32 apis to "Go style" to make them easier to use.
Setup
=====
1. Make sure you have a working Go installation and build environment,
see this go-nuts post for details:
http://groups.google.com/group/golang-nuts/msg/5c87630a84f4fd0c
Updated versions of the Windows Go build are available here:
http://code.google.com/p/gomingw/downloads/list
2. Create a "gopath" directory if you do not have one yet and set the
GOPATH variable accordingly. For example:
mkdir -p go-externals/src
export GOPATH=${PWD}/go-externals
3. go get github.com/AllenDang/w32
4. go install github.com/AllenDang/w32...
Contribute
==========
Contributions in form of design, code, documentation, bug reporting or other
ways you see fit are very welcome.
Thank You!

389
vendor/github.com/apenwarr/w32/advapi32.go generated vendored Normal file
View file

@ -0,0 +1,389 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"errors"
"fmt"
"syscall"
"unsafe"
)
var (
modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
// procRegSetKeyValue = modadvapi32.NewProc("RegSetKeyValueW")
procCloseEventLog = modadvapi32.NewProc("CloseEventLog")
procCloseServiceHandle = modadvapi32.NewProc("CloseServiceHandle")
procControlService = modadvapi32.NewProc("ControlService")
procControlTrace = modadvapi32.NewProc("ControlTraceW")
procInitializeSecurityDescriptor = modadvapi32.NewProc("InitializeSecurityDescriptor")
procOpenEventLog = modadvapi32.NewProc("OpenEventLogW")
procOpenSCManager = modadvapi32.NewProc("OpenSCManagerW")
procOpenService = modadvapi32.NewProc("OpenServiceW")
procReadEventLog = modadvapi32.NewProc("ReadEventLogW")
procRegCloseKey = modadvapi32.NewProc("RegCloseKey")
procRegCreateKeyEx = modadvapi32.NewProc("RegCreateKeyExW")
procRegEnumKeyEx = modadvapi32.NewProc("RegEnumKeyExW")
procRegGetValue = modadvapi32.NewProc("RegGetValueW")
procRegOpenKeyEx = modadvapi32.NewProc("RegOpenKeyExW")
procRegSetValueEx = modadvapi32.NewProc("RegSetValueExW")
procSetSecurityDescriptorDacl = modadvapi32.NewProc("SetSecurityDescriptorDacl")
procStartService = modadvapi32.NewProc("StartServiceW")
procStartTrace = modadvapi32.NewProc("StartTraceW")
)
var (
SystemTraceControlGuid = GUID{
0x9e814aad,
0x3204,
0x11d2,
[8]byte{0x9a, 0x82, 0x00, 0x60, 0x08, 0xa8, 0x69, 0x39},
}
)
func RegCreateKey(hKey HKEY, subKey string) HKEY {
var result HKEY
ret, _, _ := procRegCreateKeyEx.Call(
uintptr(hKey),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
uintptr(0),
uintptr(0),
uintptr(0),
uintptr(KEY_ALL_ACCESS),
uintptr(0),
uintptr(unsafe.Pointer(&result)),
uintptr(0))
_ = ret
return result
}
func RegOpenKeyEx(hKey HKEY, subKey string, samDesired uint32) HKEY {
var result HKEY
ret, _, _ := procRegOpenKeyEx.Call(
uintptr(hKey),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
uintptr(0),
uintptr(samDesired),
uintptr(unsafe.Pointer(&result)))
if ret != ERROR_SUCCESS {
panic(fmt.Sprintf("RegOpenKeyEx(%d, %s, %d) failed", hKey, subKey, samDesired))
}
return result
}
func RegCloseKey(hKey HKEY) error {
var err error
ret, _, _ := procRegCloseKey.Call(
uintptr(hKey))
if ret != ERROR_SUCCESS {
err = errors.New("RegCloseKey failed")
}
return err
}
func RegGetRaw(hKey HKEY, subKey string, value string) []byte {
var bufLen uint32
var valptr unsafe.Pointer
if len(value) > 0 {
valptr = unsafe.Pointer(syscall.StringToUTF16Ptr(value))
}
procRegGetValue.Call(
uintptr(hKey),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
uintptr(valptr),
uintptr(RRF_RT_ANY),
0,
0,
uintptr(unsafe.Pointer(&bufLen)))
if bufLen == 0 {
return nil
}
buf := make([]byte, bufLen)
ret, _, _ := procRegGetValue.Call(
uintptr(hKey),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
uintptr(valptr),
uintptr(RRF_RT_ANY),
0,
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&bufLen)))
if ret != ERROR_SUCCESS {
return nil
}
return buf
}
func RegSetBinary(hKey HKEY, subKey string, value []byte) (errno int) {
var lptr, vptr unsafe.Pointer
if len(subKey) > 0 {
lptr = unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))
}
if len(value) > 0 {
vptr = unsafe.Pointer(&value[0])
}
ret, _, _ := procRegSetValueEx.Call(
uintptr(hKey),
uintptr(lptr),
uintptr(0),
uintptr(REG_BINARY),
uintptr(vptr),
uintptr(len(value)))
return int(ret)
}
func RegGetString(hKey HKEY, subKey string, value string) string {
var bufLen uint32
procRegGetValue.Call(
uintptr(hKey),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(value))),
uintptr(RRF_RT_REG_SZ),
0,
0,
uintptr(unsafe.Pointer(&bufLen)))
if bufLen == 0 {
return ""
}
buf := make([]uint16, bufLen)
ret, _, _ := procRegGetValue.Call(
uintptr(hKey),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(value))),
uintptr(RRF_RT_REG_SZ),
0,
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&bufLen)))
if ret != ERROR_SUCCESS {
return ""
}
return syscall.UTF16ToString(buf)
}
/*
func RegSetKeyValue(hKey HKEY, subKey string, valueName string, dwType uint32, data uintptr, cbData uint16) (errno int) {
ret, _, _ := procRegSetKeyValue.Call(
uintptr(hKey),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(valueName))),
uintptr(dwType),
data,
uintptr(cbData))
return int(ret)
}
*/
func RegEnumKeyEx(hKey HKEY, index uint32) string {
var bufLen uint32 = 255
buf := make([]uint16, bufLen)
procRegEnumKeyEx.Call(
uintptr(hKey),
uintptr(index),
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&bufLen)),
0,
0,
0,
0)
return syscall.UTF16ToString(buf)
}
func OpenEventLog(servername string, sourcename string) HANDLE {
ret, _, _ := procOpenEventLog.Call(
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(servername))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(sourcename))))
return HANDLE(ret)
}
func ReadEventLog(eventlog HANDLE, readflags, recordoffset uint32, buffer []byte, numberofbytestoread uint32, bytesread, minnumberofbytesneeded *uint32) bool {
ret, _, _ := procReadEventLog.Call(
uintptr(eventlog),
uintptr(readflags),
uintptr(recordoffset),
uintptr(unsafe.Pointer(&buffer[0])),
uintptr(numberofbytestoread),
uintptr(unsafe.Pointer(bytesread)),
uintptr(unsafe.Pointer(minnumberofbytesneeded)))
return ret != 0
}
func CloseEventLog(eventlog HANDLE) bool {
ret, _, _ := procCloseEventLog.Call(
uintptr(eventlog))
return ret != 0
}
func OpenSCManager(lpMachineName, lpDatabaseName string, dwDesiredAccess uint32) (HANDLE, error) {
var p1, p2 uintptr
if len(lpMachineName) > 0 {
p1 = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpMachineName)))
}
if len(lpDatabaseName) > 0 {
p2 = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDatabaseName)))
}
ret, _, _ := procOpenSCManager.Call(
p1,
p2,
uintptr(dwDesiredAccess))
if ret == 0 {
return 0, syscall.GetLastError()
}
return HANDLE(ret), nil
}
func CloseServiceHandle(hSCObject HANDLE) error {
ret, _, _ := procCloseServiceHandle.Call(uintptr(hSCObject))
if ret == 0 {
return syscall.GetLastError()
}
return nil
}
func OpenService(hSCManager HANDLE, lpServiceName string, dwDesiredAccess uint32) (HANDLE, error) {
ret, _, _ := procOpenService.Call(
uintptr(hSCManager),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpServiceName))),
uintptr(dwDesiredAccess))
if ret == 0 {
return 0, syscall.GetLastError()
}
return HANDLE(ret), nil
}
func StartService(hService HANDLE, lpServiceArgVectors []string) error {
l := len(lpServiceArgVectors)
var ret uintptr
if l == 0 {
ret, _, _ = procStartService.Call(
uintptr(hService),
0,
0)
} else {
lpArgs := make([]uintptr, l)
for i := 0; i < l; i++ {
lpArgs[i] = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpServiceArgVectors[i])))
}
ret, _, _ = procStartService.Call(
uintptr(hService),
uintptr(l),
uintptr(unsafe.Pointer(&lpArgs[0])))
}
if ret == 0 {
return syscall.GetLastError()
}
return nil
}
func ControlService(hService HANDLE, dwControl uint32, lpServiceStatus *SERVICE_STATUS) bool {
if lpServiceStatus == nil {
panic("ControlService:lpServiceStatus cannot be nil")
}
ret, _, _ := procControlService.Call(
uintptr(hService),
uintptr(dwControl),
uintptr(unsafe.Pointer(lpServiceStatus)))
return ret != 0
}
func ControlTrace(hTrace TRACEHANDLE, lpSessionName string, props *EVENT_TRACE_PROPERTIES, dwControl uint32) (success bool, e error) {
ret, _, _ := procControlTrace.Call(
uintptr(unsafe.Pointer(hTrace)),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpSessionName))),
uintptr(unsafe.Pointer(props)),
uintptr(dwControl))
if ret == ERROR_SUCCESS {
return true, nil
}
e = errors.New(fmt.Sprintf("error: 0x%x", ret))
return
}
func StartTrace(lpSessionName string, props *EVENT_TRACE_PROPERTIES) (hTrace TRACEHANDLE, e error) {
ret, _, _ := procStartTrace.Call(
uintptr(unsafe.Pointer(&hTrace)),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpSessionName))),
uintptr(unsafe.Pointer(props)))
if ret == ERROR_SUCCESS {
return
}
e = errors.New(fmt.Sprintf("error: 0x%x", ret))
return
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa378863(v=vs.85).aspx
func InitializeSecurityDescriptor(rev uint16) (pSecurityDescriptor *SECURITY_DESCRIPTOR, e error) {
pSecurityDescriptor = &SECURITY_DESCRIPTOR{}
ret, _, _ := procInitializeSecurityDescriptor.Call(
uintptr(unsafe.Pointer(pSecurityDescriptor)),
uintptr(rev),
)
if ret != 0 {
return
}
e = syscall.GetLastError()
return
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa379583(v=vs.85).aspx
func SetSecurityDescriptorDacl(pSecurityDescriptor *SECURITY_DESCRIPTOR, pDacl *ACL) (e error) {
if pSecurityDescriptor == nil {
return errors.New("null descriptor")
}
var ret uintptr
if pDacl == nil {
ret, _, _ = procSetSecurityDescriptorDacl.Call(
uintptr(unsafe.Pointer(pSecurityDescriptor)),
uintptr(1), // DaclPresent
uintptr(0), // pDacl
uintptr(0), // DaclDefaulted
)
} else {
ret, _, _ = procSetSecurityDescriptorDacl.Call(
uintptr(unsafe.Pointer(pSecurityDescriptor)),
uintptr(1), // DaclPresent
uintptr(unsafe.Pointer(pDacl)),
uintptr(0), //DaclDefaulted
)
}
if ret != 0 {
return
}
e = syscall.GetLastError()
return
}

300
vendor/github.com/apenwarr/w32/advapi32_constants.go generated vendored Normal file
View file

@ -0,0 +1,300 @@
package w32
// Registry predefined keys
const (
HKEY_CLASSES_ROOT HKEY = 0x80000000
HKEY_CURRENT_USER HKEY = 0x80000001
HKEY_LOCAL_MACHINE HKEY = 0x80000002
HKEY_USERS HKEY = 0x80000003
HKEY_PERFORMANCE_DATA HKEY = 0x80000004
HKEY_CURRENT_CONFIG HKEY = 0x80000005
HKEY_DYN_DATA HKEY = 0x80000006
)
// Registry Key Security and Access Rights
const (
KEY_ALL_ACCESS = 0xF003F
KEY_CREATE_SUB_KEY = 0x0004
KEY_ENUMERATE_SUB_KEYS = 0x0008
KEY_NOTIFY = 0x0010
KEY_QUERY_VALUE = 0x0001
KEY_SET_VALUE = 0x0002
KEY_READ = 0x20019
KEY_WRITE = 0x20006
)
const (
NFR_ANSI = 1
NFR_UNICODE = 2
NF_QUERY = 3
NF_REQUERY = 4
)
// Registry value types
const (
RRF_RT_REG_NONE = 0x00000001
RRF_RT_REG_SZ = 0x00000002
RRF_RT_REG_EXPAND_SZ = 0x00000004
RRF_RT_REG_BINARY = 0x00000008
RRF_RT_REG_DWORD = 0x00000010
RRF_RT_REG_MULTI_SZ = 0x00000020
RRF_RT_REG_QWORD = 0x00000040
RRF_RT_DWORD = (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD)
RRF_RT_QWORD = (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD)
RRF_RT_ANY = 0x0000ffff
RRF_NOEXPAND = 0x10000000
RRF_ZEROONFAILURE = 0x20000000
REG_PROCESS_APPKEY = 0x00000001
REG_MUI_STRING_TRUNCATE = 0x00000001
)
// Service Control Manager object specific access types
const (
SC_MANAGER_CONNECT = 0x0001
SC_MANAGER_CREATE_SERVICE = 0x0002
SC_MANAGER_ENUMERATE_SERVICE = 0x0004
SC_MANAGER_LOCK = 0x0008
SC_MANAGER_QUERY_LOCK_STATUS = 0x0010
SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020
SC_MANAGER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_LOCK | SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG
)
// Service Types (Bit Mask)
const (
SERVICE_KERNEL_DRIVER = 0x00000001
SERVICE_FILE_SYSTEM_DRIVER = 0x00000002
SERVICE_ADAPTER = 0x00000004
SERVICE_RECOGNIZER_DRIVER = 0x00000008
SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER
SERVICE_WIN32_OWN_PROCESS = 0x00000010
SERVICE_WIN32_SHARE_PROCESS = 0x00000020
SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS
SERVICE_INTERACTIVE_PROCESS = 0x00000100
SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS
)
// Service State -- for CurrentState
const (
SERVICE_STOPPED = 0x00000001
SERVICE_START_PENDING = 0x00000002
SERVICE_STOP_PENDING = 0x00000003
SERVICE_RUNNING = 0x00000004
SERVICE_CONTINUE_PENDING = 0x00000005
SERVICE_PAUSE_PENDING = 0x00000006
SERVICE_PAUSED = 0x00000007
)
// Controls Accepted (Bit Mask)
const (
SERVICE_ACCEPT_STOP = 0x00000001
SERVICE_ACCEPT_PAUSE_CONTINUE = 0x00000002
SERVICE_ACCEPT_SHUTDOWN = 0x00000004
SERVICE_ACCEPT_PARAMCHANGE = 0x00000008
SERVICE_ACCEPT_NETBINDCHANGE = 0x00000010
SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 0x00000020
SERVICE_ACCEPT_POWEREVENT = 0x00000040
SERVICE_ACCEPT_SESSIONCHANGE = 0x00000080
SERVICE_ACCEPT_PRESHUTDOWN = 0x00000100
SERVICE_ACCEPT_TIMECHANGE = 0x00000200
SERVICE_ACCEPT_TRIGGEREVENT = 0x00000400
)
// Service object specific access type
const (
SERVICE_QUERY_CONFIG = 0x0001
SERVICE_CHANGE_CONFIG = 0x0002
SERVICE_QUERY_STATUS = 0x0004
SERVICE_ENUMERATE_DEPENDENTS = 0x0008
SERVICE_START = 0x0010
SERVICE_STOP = 0x0020
SERVICE_PAUSE_CONTINUE = 0x0040
SERVICE_INTERROGATE = 0x0080
SERVICE_USER_DEFINED_CONTROL = 0x0100
SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
SERVICE_QUERY_CONFIG |
SERVICE_CHANGE_CONFIG |
SERVICE_QUERY_STATUS |
SERVICE_ENUMERATE_DEPENDENTS |
SERVICE_START |
SERVICE_STOP |
SERVICE_PAUSE_CONTINUE |
SERVICE_INTERROGATE |
SERVICE_USER_DEFINED_CONTROL
)
const (
KERNEL_LOGGER_NAME = "NT Kernel Logger"
)
// WNODE flags, for ETW (Event Tracing for Windows) / WMI
const (
WNODE_FLAG_ALL_DATA = 0x00000001
WNODE_FLAG_SINGLE_INSTANCE = 0x00000002
WNODE_FLAG_SINGLE_ITEM = 0x00000004
WNODE_FLAG_EVENT_ITEM = 0x00000008
WNODE_FLAG_FIXED_INSTANCE_SIZE = 0x00000010
WNODE_FLAG_TOO_SMALL = 0x00000020
WNODE_FLAG_INSTANCES_SAME = 0x00000040
WNODE_FLAG_STATIC_INSTANCE_NAMES = 0x00000080
WNODE_FLAG_INTERNAL = 0x00000100
WNODE_FLAG_USE_TIMESTAMP = 0x00000200
WNODE_FLAG_PERSIST_EVENT = 0x00000400
WNODE_FLAG_EVENT_REFERENCE = 0x00002000
WNODE_FLAG_ANSI_INSTANCENAMES = 0x00004000
WNODE_FLAG_METHOD_ITEM = 0x00008000
WNODE_FLAG_PDO_INSTANCE_NAMES = 0x00010000
WNODE_FLAG_TRACED_GUID = 0x00020000
WNODE_FLAG_LOG_WNODE = 0x00040000
WNODE_FLAG_USE_GUID_PTR = 0x00080000
WNODE_FLAG_USE_MOF_PTR = 0x00100000
WNODE_FLAG_NO_HEADER = 0x00200000
WNODE_FLAG_SEVERITY_MASK = 0xff000000
)
// ETW flags and types etc
const (
EVENT_TRACE_TYPE_INFO = 0x00
EVENT_TRACE_TYPE_START = 0x01
EVENT_TRACE_TYPE_END = 0x02
EVENT_TRACE_TYPE_STOP = 0x02
EVENT_TRACE_TYPE_DC_START = 0x03
EVENT_TRACE_TYPE_DC_END = 0x04
EVENT_TRACE_TYPE_EXTENSION = 0x05
EVENT_TRACE_TYPE_REPLY = 0x06
EVENT_TRACE_TYPE_DEQUEUE = 0x07
EVENT_TRACE_TYPE_RESUME = 0x07
EVENT_TRACE_TYPE_CHECKPOINT = 0x08
EVENT_TRACE_TYPE_SUSPEND = 0x08
EVENT_TRACE_TYPE_WINEVT_SEND = 0x09
EVENT_TRACE_TYPE_WINEVT_RECEIVE = 0XF0
TRACE_LEVEL_NONE = 0
TRACE_LEVEL_CRITICAL = 1
TRACE_LEVEL_FATAL = 1
TRACE_LEVEL_ERROR = 2
TRACE_LEVEL_WARNING = 3
TRACE_LEVEL_INFORMATION = 4
TRACE_LEVEL_VERBOSE = 5
TRACE_LEVEL_RESERVED6 = 6
TRACE_LEVEL_RESERVED7 = 7
TRACE_LEVEL_RESERVED8 = 8
TRACE_LEVEL_RESERVED9 = 9
EVENT_TRACE_TYPE_LOAD = 0x0A
EVENT_TRACE_TYPE_IO_READ = 0x0A
EVENT_TRACE_TYPE_IO_WRITE = 0x0B
EVENT_TRACE_TYPE_IO_READ_INIT = 0x0C
EVENT_TRACE_TYPE_IO_WRITE_INIT = 0x0D
EVENT_TRACE_TYPE_IO_FLUSH = 0x0E
EVENT_TRACE_TYPE_IO_FLUSH_INIT = 0x0F
EVENT_TRACE_TYPE_MM_TF = 0x0A
EVENT_TRACE_TYPE_MM_DZF = 0x0B
EVENT_TRACE_TYPE_MM_COW = 0x0C
EVENT_TRACE_TYPE_MM_GPF = 0x0D
EVENT_TRACE_TYPE_MM_HPF = 0x0E
EVENT_TRACE_TYPE_MM_AV = 0x0F
EVENT_TRACE_TYPE_SEND = 0x0A
EVENT_TRACE_TYPE_RECEIVE = 0x0B
EVENT_TRACE_TYPE_CONNECT = 0x0C
EVENT_TRACE_TYPE_DISCONNECT = 0x0D
EVENT_TRACE_TYPE_RETRANSMIT = 0x0E
EVENT_TRACE_TYPE_ACCEPT = 0x0F
EVENT_TRACE_TYPE_RECONNECT = 0x10
EVENT_TRACE_TYPE_CONNFAIL = 0x11
EVENT_TRACE_TYPE_COPY_TCP = 0x12
EVENT_TRACE_TYPE_COPY_ARP = 0x13
EVENT_TRACE_TYPE_ACKFULL = 0x14
EVENT_TRACE_TYPE_ACKPART = 0x15
EVENT_TRACE_TYPE_ACKDUP = 0x16
EVENT_TRACE_TYPE_GUIDMAP = 0x0A
EVENT_TRACE_TYPE_CONFIG = 0x0B
EVENT_TRACE_TYPE_SIDINFO = 0x0C
EVENT_TRACE_TYPE_SECURITY = 0x0D
EVENT_TRACE_TYPE_REGCREATE = 0x0A
EVENT_TRACE_TYPE_REGOPEN = 0x0B
EVENT_TRACE_TYPE_REGDELETE = 0x0C
EVENT_TRACE_TYPE_REGQUERY = 0x0D
EVENT_TRACE_TYPE_REGSETVALUE = 0x0E
EVENT_TRACE_TYPE_REGDELETEVALUE = 0x0F
EVENT_TRACE_TYPE_REGQUERYVALUE = 0x10
EVENT_TRACE_TYPE_REGENUMERATEKEY = 0x11
EVENT_TRACE_TYPE_REGENUMERATEVALUEKEY = 0x12
EVENT_TRACE_TYPE_REGQUERYMULTIPLEVALUE = 0x13
EVENT_TRACE_TYPE_REGSETINFORMATION = 0x14
EVENT_TRACE_TYPE_REGFLUSH = 0x15
EVENT_TRACE_TYPE_REGKCBCREATE = 0x16
EVENT_TRACE_TYPE_REGKCBDELETE = 0x17
EVENT_TRACE_TYPE_REGKCBRUNDOWNBEGIN = 0x18
EVENT_TRACE_TYPE_REGKCBRUNDOWNEND = 0x19
EVENT_TRACE_TYPE_REGVIRTUALIZE = 0x1A
EVENT_TRACE_TYPE_REGCLOSE = 0x1B
EVENT_TRACE_TYPE_REGSETSECURITY = 0x1C
EVENT_TRACE_TYPE_REGQUERYSECURITY = 0x1D
EVENT_TRACE_TYPE_REGCOMMIT = 0x1E
EVENT_TRACE_TYPE_REGPREPARE = 0x1F
EVENT_TRACE_TYPE_REGROLLBACK = 0x20
EVENT_TRACE_TYPE_REGMOUNTHIVE = 0x21
EVENT_TRACE_TYPE_CONFIG_CPU = 0x0A
EVENT_TRACE_TYPE_CONFIG_PHYSICALDISK = 0x0B
EVENT_TRACE_TYPE_CONFIG_LOGICALDISK = 0x0C
EVENT_TRACE_TYPE_CONFIG_NIC = 0x0D
EVENT_TRACE_TYPE_CONFIG_VIDEO = 0x0E
EVENT_TRACE_TYPE_CONFIG_SERVICES = 0x0F
EVENT_TRACE_TYPE_CONFIG_POWER = 0x10
EVENT_TRACE_TYPE_CONFIG_NETINFO = 0x11
EVENT_TRACE_TYPE_CONFIG_IRQ = 0x15
EVENT_TRACE_TYPE_CONFIG_PNP = 0x16
EVENT_TRACE_TYPE_CONFIG_IDECHANNEL = 0x17
EVENT_TRACE_TYPE_CONFIG_PLATFORM = 0x19
EVENT_TRACE_FLAG_PROCESS = 0x00000001
EVENT_TRACE_FLAG_THREAD = 0x00000002
EVENT_TRACE_FLAG_IMAGE_LOAD = 0x00000004
EVENT_TRACE_FLAG_DISK_IO = 0x00000100
EVENT_TRACE_FLAG_DISK_FILE_IO = 0x00000200
EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS = 0x00001000
EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS = 0x00002000
EVENT_TRACE_FLAG_NETWORK_TCPIP = 0x00010000
EVENT_TRACE_FLAG_REGISTRY = 0x00020000
EVENT_TRACE_FLAG_DBGPRINT = 0x00040000
EVENT_TRACE_FLAG_PROCESS_COUNTERS = 0x00000008
EVENT_TRACE_FLAG_CSWITCH = 0x00000010
EVENT_TRACE_FLAG_DPC = 0x00000020
EVENT_TRACE_FLAG_INTERRUPT = 0x00000040
EVENT_TRACE_FLAG_SYSTEMCALL = 0x00000080
EVENT_TRACE_FLAG_DISK_IO_INIT = 0x00000400
EVENT_TRACE_FLAG_ALPC = 0x00100000
EVENT_TRACE_FLAG_SPLIT_IO = 0x00200000
EVENT_TRACE_FLAG_DRIVER = 0x00800000
EVENT_TRACE_FLAG_PROFILE = 0x01000000
EVENT_TRACE_FLAG_FILE_IO = 0x02000000
EVENT_TRACE_FLAG_FILE_IO_INIT = 0x04000000
EVENT_TRACE_FLAG_DISPATCHER = 0x00000800
EVENT_TRACE_FLAG_VIRTUAL_ALLOC = 0x00004000
EVENT_TRACE_FLAG_EXTENSION = 0x80000000
EVENT_TRACE_FLAG_FORWARD_WMI = 0x40000000
EVENT_TRACE_FLAG_ENABLE_RESERVE = 0x20000000
EVENT_TRACE_FILE_MODE_NONE = 0x00000000
EVENT_TRACE_FILE_MODE_SEQUENTIAL = 0x00000001
EVENT_TRACE_FILE_MODE_CIRCULAR = 0x00000002
EVENT_TRACE_FILE_MODE_APPEND = 0x00000004
EVENT_TRACE_REAL_TIME_MODE = 0x00000100
EVENT_TRACE_DELAY_OPEN_FILE_MODE = 0x00000200
EVENT_TRACE_BUFFERING_MODE = 0x00000400
EVENT_TRACE_PRIVATE_LOGGER_MODE = 0x00000800
EVENT_TRACE_ADD_HEADER_MODE = 0x00001000
EVENT_TRACE_USE_GLOBAL_SEQUENCE = 0x00004000
EVENT_TRACE_USE_LOCAL_SEQUENCE = 0x00008000
EVENT_TRACE_RELOG_MODE = 0x00010000
EVENT_TRACE_USE_PAGED_MEMORY = 0x01000000
EVENT_TRACE_FILE_MODE_NEWFILE = 0x00000008
EVENT_TRACE_FILE_MODE_PREALLOCATE = 0x00000020
EVENT_TRACE_NONSTOPPABLE_MODE = 0x00000040
EVENT_TRACE_SECURE_MODE = 0x00000080
EVENT_TRACE_USE_KBYTES_FOR_SIZE = 0x00002000
EVENT_TRACE_PRIVATE_IN_PROC = 0x00020000
EVENT_TRACE_MODE_RESERVED = 0x00100000
EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING = 0x10000000
EVENT_TRACE_CONTROL_QUERY = 0
EVENT_TRACE_CONTROL_STOP = 1
EVENT_TRACE_CONTROL_UPDATE = 2
EVENT_TRACE_CONTROL_FLUSH = 3
)

122
vendor/github.com/apenwarr/w32/advapi32_typedef.go generated vendored Normal file
View file

@ -0,0 +1,122 @@
package w32
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa374931(v=vs.85).aspx
type ACL struct {
AclRevision byte
Sbz1 byte
AclSize uint16
AceCount uint16
Sbz2 uint16
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa379561(v=vs.85).aspx
type SECURITY_DESCRIPTOR_CONTROL uint16
type SECURITY_DESCRIPTOR struct {
Revision byte
Sbz1 byte
Control SECURITY_DESCRIPTOR_CONTROL
Owner uintptr
Group uintptr
Sacl *ACL
Dacl *ACL
}
type SID_IDENTIFIER_AUTHORITY struct {
Value [6]byte
}
// typedef struct _SID // 4 elements, 0xC bytes (sizeof)
// {
// /*0x000*/ UINT8 Revision;
// /*0x001*/ UINT8 SubAuthorityCount;
// /*0x002*/ struct _SID_IDENTIFIER_AUTHORITY IdentifierAuthority; // 1 elements, 0x6 bytes (sizeof)
// /*0x008*/ ULONG32 SubAuthority[1];
// }SID, *PSID;
type SID struct {
Revision byte
SubAuthorityCount byte
IdentifierAuthority SID_IDENTIFIER_AUTHORITY
SubAuthority uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363646.aspx
type EVENTLOGRECORD struct {
Length uint32
Reserved uint32
RecordNumber uint32
TimeGenerated uint32
TimeWritten uint32
EventID uint32
EventType uint16
NumStrings uint16
EventCategory uint16
ReservedFlags uint16
ClosingRecordNumber uint32
StringOffset uint32
UserSidLength uint32
UserSidOffset uint32
DataLength uint32
DataOffset uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms685996.aspx
type SERVICE_STATUS struct {
DwServiceType uint32
DwCurrentState uint32
DwControlsAccepted uint32
DwWin32ExitCode uint32
DwServiceSpecificExitCode uint32
DwCheckPoint uint32
DwWaitHint uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa364160(v=vs.85).aspx
type WNODE_HEADER struct {
BufferSize uint32
ProviderId uint32
HistoricalContext uint64
KernelHandle HANDLE
Guid GUID
ClientContext uint32
Flags uint32
}
// These partially compensate for the anonymous unions we removed, but there
// are no setters.
func (w WNODE_HEADER) TimeStamp() uint64 {
// TODO: Cast to the stupid LARGE_INTEGER struct which is, itself, nasty
// and union-y
return uint64(w.KernelHandle)
}
func (w WNODE_HEADER) Version() uint32 {
return uint32(w.HistoricalContext >> 32)
}
func (w WNODE_HEADER) Linkage() uint32 {
return uint32(w.HistoricalContext)
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363784(v=vs.85).aspx
type EVENT_TRACE_PROPERTIES struct {
Wnode WNODE_HEADER
BufferSize uint32
MinimumBuffers uint32
MaximumBuffers uint32
MaximumFileSize uint32
LogFileMode uint32
FlushTimer uint32
EnableFlags uint32
AgeLimit int32
NumberOfBuffers uint32
FreeBuffers uint32
EventsLost uint32
BuffersWritten uint32
LogBuffersLost uint32
RealTimeBuffersLost uint32
LoggerThreadId HANDLE
LogFileNameOffset uint32
LoggerNameOffset uint32
}

304
vendor/github.com/apenwarr/w32/alpc.go generated vendored Normal file
View file

@ -0,0 +1,304 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"fmt"
// "github.com/davecgh/go-spew/spew"
"syscall"
"unsafe"
)
var (
modntdll = syscall.NewLazyDLL("ntdll.dll")
procAlpcGetMessageAttribute = modntdll.NewProc("AlpcGetMessageAttribute")
procNtAlpcAcceptConnectPort = modntdll.NewProc("NtAlpcAcceptConnectPort")
procNtAlpcCancelMessage = modntdll.NewProc("NtAlpcCancelMessage")
procNtAlpcConnectPort = modntdll.NewProc("NtAlpcConnectPort")
procNtAlpcCreatePort = modntdll.NewProc("NtAlpcCreatePort")
procNtAlpcDisconnectPort = modntdll.NewProc("NtAlpcDisconnectPort")
procNtAlpcSendWaitReceivePort = modntdll.NewProc("NtAlpcSendWaitReceivePort")
procRtlCreateUnicodeStringFromAsciiz = modntdll.NewProc("RtlCreateUnicodeStringFromAsciiz")
)
//func RtlCreateUnicodeStringFromAsciiz(s string) (us UNICODE_STRING, e error) {
//
// cs := C.CString(s)
// defer C.free(unsafe.Pointer(cs))
//
// ret, _, lastErr := procRtlCreateUnicodeStringFromAsciiz.Call(
// uintptr(unsafe.Pointer(&us)),
// uintptr(unsafe.Pointer(cs)),
// )
//
// if ret != 1 { // ret is a BOOL ( I think )
// e = lastErr
// }
//
// return
//}
//func newUnicodeString(s string) (us UNICODE_STRING, e error) {
// // TODO probably not the most efficient way to do this, but I couldn't
// // work out how to manually initialize the UNICODE_STRING struct in a way
// // that the ALPC subsystem liked.
// us, e = RtlCreateUnicodeStringFromAsciiz(s)
// return
//}
// (this is a macro)
// VOID InitializeObjectAttributes(
// [out] POBJECT_ATTRIBUTES InitializedAttributes,
// [in] PUNICODE_STRING ObjectName,
// [in] ULONG Attributes,
// [in] HANDLE RootDirectory,
// [in, optional] PSECURITY_DESCRIPTOR SecurityDescriptor
// )
//func InitializeObjectAttributes(
// name string,
// attributes uint32,
// rootDir HANDLE,
// pSecurityDescriptor *SECURITY_DESCRIPTOR,
//) (oa OBJECT_ATTRIBUTES, e error) {
//
// oa = OBJECT_ATTRIBUTES{
// RootDirectory: rootDir,
// Attributes: attributes,
// SecurityDescriptor: pSecurityDescriptor,
// }
// oa.Length = uint32(unsafe.Sizeof(oa))
//
// if len(name) > 0 {
// us, err := newUnicodeString(name)
// if err != nil {
// e = err
// return
// }
// oa.ObjectName = &us
// }
//
// return
//}
// NTSTATUS
// NtAlpcCreatePort(
// __out PHANDLE PortHandle,
// __in POBJECT_ATTRIBUTES ObjectAttributes,
// __in_opt PALPC_PORT_ATTRIBUTES PortAttributes
// );
func NtAlpcCreatePort(pObjectAttributes *OBJECT_ATTRIBUTES, pPortAttributes *ALPC_PORT_ATTRIBUTES) (hPort HANDLE, e error) {
ret, _, _ := procNtAlpcCreatePort.Call(
uintptr(unsafe.Pointer(&hPort)),
uintptr(unsafe.Pointer(pObjectAttributes)),
uintptr(unsafe.Pointer(pPortAttributes)),
)
if ret != ERROR_SUCCESS {
return hPort, fmt.Errorf("0x%x", ret)
}
return
}
// NTSTATUS
// NtAlpcConnectPort(
// __out PHANDLE PortHandle,
// __in PUNICODE_STRING PortName,
// __in POBJECT_ATTRIBUTES ObjectAttributes,
// __in_opt PALPC_PORT_ATTRIBUTES PortAttributes,
// __in ULONG Flags,
// __in_opt PSID RequiredServerSid,
// __inout PPORT_MESSAGE ConnectionMessage,
// __inout_opt PULONG BufferLength,
// __inout_opt PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes,
// __inout_opt PALPC_MESSAGE_ATTRIBUTES InMessageAttributes,
// __in_opt PLARGE_INTEGER Timeout
// );
//func NtAlpcConnectPort(
// destPort string,
// pClientObjAttrs *OBJECT_ATTRIBUTES,
// pClientAlpcPortAttrs *ALPC_PORT_ATTRIBUTES,
// flags uint32,
// pRequiredServerSid *SID,
// pConnMsg *AlpcShortMessage,
// pBufLen *uint32,
// pOutMsgAttrs *ALPC_MESSAGE_ATTRIBUTES,
// pInMsgAttrs *ALPC_MESSAGE_ATTRIBUTES,
// timeout *int64,
//) (hPort HANDLE, e error) {
//
// destPortU, e := newUnicodeString(destPort)
// if e != nil {
// return
// }
//
// ret, _, _ := procNtAlpcConnectPort.Call(
// uintptr(unsafe.Pointer(&hPort)),
// uintptr(unsafe.Pointer(&destPortU)),
// uintptr(unsafe.Pointer(pClientObjAttrs)),
// uintptr(unsafe.Pointer(pClientAlpcPortAttrs)),
// uintptr(flags),
// uintptr(unsafe.Pointer(pRequiredServerSid)),
// uintptr(unsafe.Pointer(pConnMsg)),
// uintptr(unsafe.Pointer(pBufLen)),
// uintptr(unsafe.Pointer(pOutMsgAttrs)),
// uintptr(unsafe.Pointer(pInMsgAttrs)),
// uintptr(unsafe.Pointer(timeout)),
// )
//
// if ret != ERROR_SUCCESS {
// e = fmt.Errorf("0x%x", ret)
// }
// return
//}
// NTSTATUS
// NtAlpcAcceptConnectPort(
// __out PHANDLE PortHandle,
// __in HANDLE ConnectionPortHandle,
// __in ULONG Flags,
// __in POBJECT_ATTRIBUTES ObjectAttributes,
// __in PALPC_PORT_ATTRIBUTES PortAttributes,
// __in_opt PVOID PortContext,
// __in PPORT_MESSAGE ConnectionRequest,
// __inout_opt PALPC_MESSAGE_ATTRIBUTES ConnectionMessageAttributes,
// __in BOOLEAN AcceptConnection
// );
func NtAlpcAcceptConnectPort(
hSrvConnPort HANDLE,
flags uint32,
pObjAttr *OBJECT_ATTRIBUTES,
pPortAttr *ALPC_PORT_ATTRIBUTES,
pContext *AlpcPortContext,
pConnReq *AlpcShortMessage,
pConnMsgAttrs *ALPC_MESSAGE_ATTRIBUTES,
accept uintptr,
) (hPort HANDLE, e error) {
ret, _, _ := procNtAlpcAcceptConnectPort.Call(
uintptr(unsafe.Pointer(&hPort)),
uintptr(hSrvConnPort),
uintptr(flags),
uintptr(unsafe.Pointer(pObjAttr)),
uintptr(unsafe.Pointer(pPortAttr)),
uintptr(unsafe.Pointer(pContext)),
uintptr(unsafe.Pointer(pConnReq)),
uintptr(unsafe.Pointer(pConnMsgAttrs)),
accept,
)
if ret != ERROR_SUCCESS {
e = fmt.Errorf("0x%x", ret)
}
return
}
// NTSTATUS
// NtAlpcSendWaitReceivePort(
// __in HANDLE PortHandle,
// __in ULONG Flags,
// __in_opt PPORT_MESSAGE SendMessage,
// __in_opt PALPC_MESSAGE_ATTRIBUTES SendMessageAttributes,
// __inout_opt PPORT_MESSAGE ReceiveMessage,
// __inout_opt PULONG BufferLength,
// __inout_opt PALPC_MESSAGE_ATTRIBUTES ReceiveMessageAttributes,
// __in_opt PLARGE_INTEGER Timeout
// );
func NtAlpcSendWaitReceivePort(
hPort HANDLE,
flags uint32,
sendMsg *AlpcShortMessage, // Should actually point to PORT_MESSAGE + payload
sendMsgAttrs *ALPC_MESSAGE_ATTRIBUTES,
recvMsg *AlpcShortMessage,
recvBufLen *uint32,
recvMsgAttrs *ALPC_MESSAGE_ATTRIBUTES,
timeout *int64, // use native int64
) (e error) {
ret, _, _ := procNtAlpcSendWaitReceivePort.Call(
uintptr(hPort),
uintptr(flags),
uintptr(unsafe.Pointer(sendMsg)),
uintptr(unsafe.Pointer(sendMsgAttrs)),
uintptr(unsafe.Pointer(recvMsg)),
uintptr(unsafe.Pointer(recvBufLen)),
uintptr(unsafe.Pointer(recvMsgAttrs)),
uintptr(unsafe.Pointer(timeout)),
)
if ret != ERROR_SUCCESS {
e = fmt.Errorf("0x%x", ret)
}
return
}
// NTSYSAPI
// PVOID
// NTAPI
// AlpcGetMessageAttribute(
// __in PALPC_MESSAGE_ATTRIBUTES Buffer,
// __in ULONG AttributeFlag
// );
// This basically returns a pointer to the correct struct for whichever
// message attribute you asked for. In Go terms, it returns unsafe.Pointer
// which you should then cast. Example:
// ptr := AlpcGetMessageAttribute(&recvMsgAttrs, ALPC_MESSAGE_CONTEXT_ATTRIBUTE)
// if ptr != nil {
// context := (*ALPC_CONTEXT_ATTR)(ptr)
// }
func AlpcGetMessageAttribute(buf *ALPC_MESSAGE_ATTRIBUTES, attr uint32) unsafe.Pointer {
ret, _, _ := procAlpcGetMessageAttribute.Call(
uintptr(unsafe.Pointer(buf)),
uintptr(attr),
)
return unsafe.Pointer(ret)
}
// NTSYSCALLAPI
// NTSTATUS
// NTAPI
// NtAlpcCancelMessage(
// __in HANDLE PortHandle,
// __in ULONG Flags,
// __in PALPC_CONTEXT_ATTR MessageContext
// );
func NtAlpcCancelMessage(hPort HANDLE, flags uint32, pMsgContext *ALPC_CONTEXT_ATTR) (e error) {
ret, _, _ := procNtAlpcCancelMessage.Call(
uintptr(hPort),
uintptr(flags),
uintptr(unsafe.Pointer(pMsgContext)),
)
if ret != ERROR_SUCCESS {
e = fmt.Errorf("0x%x", ret)
}
return
}
// NTSYSCALLAPI
// NTSTATUS
// NTAPI
// NtAlpcDisconnectPort(
// __in HANDLE PortHandle,
// __in ULONG Flags
// );
func NtAlpcDisconnectPort(hPort HANDLE, flags uint32) (e error) {
ret, _, _ := procNtAlpcDisconnectPort.Call(
uintptr(hPort),
uintptr(flags),
)
if ret != ERROR_SUCCESS {
e = fmt.Errorf("0x%x", ret)
}
return
}

64
vendor/github.com/apenwarr/w32/alpc_constants.go generated vendored Normal file
View file

@ -0,0 +1,64 @@
package w32
const (
ALPC_PORFLG_ALLOW_LPC_REQUESTS = 0x20000
ALPC_PORFLG_SYSTEM_PROCESS = 0x100000
ALPC_PORFLG_WAITABLE_PORT = 0x40000
)
const (
ALPC_MSGFLG_REPLY_MESSAGE = 0x1
ALPC_MSGFLG_LPC_MODE = 0x2 // ?
ALPC_MSGFLG_RELEASE_MESSAGE = 0x10000 // dbg
ALPC_MSGFLG_SYNC_REQUEST = 0x20000 // dbg
ALPC_MSGFLG_WAIT_USER_MODE = 0x100000
ALPC_MSGFLG_WAIT_ALERTABLE = 0x200000
ALPC_MSGFLG_WOW64_CALL = 0x80000000 // dbg
)
const (
ALPC_MESSAGE_SECURITY_ATTRIBUTE = 0x80000000
ALPC_MESSAGE_VIEW_ATTRIBUTE = 0x40000000
ALPC_MESSAGE_CONTEXT_ATTRIBUTE = 0x20000000
ALPC_MESSAGE_HANDLE_ATTRIBUTE = 0x10000000
)
const (
OBJ_INHERIT = 0x00000002
OBJ_PERMANENT = 0x00000010
OBJ_EXCLUSIVE = 0x00000020
OBJ_CASE_INSENSITIVE = 0x00000040
OBJ_OPENIF = 0x00000080
OBJ_OPENLINK = 0x00000100
OBJ_KERNEL_HANDLE = 0x00000200
)
const (
LPC_REQUEST = 1
LPC_REPLY = 2
LPC_DATAGRAM = 3
LPC_LOST_REPLY = 4
LPC_PORT_CLOSED = 5
LPC_CLIENT_DIED = 6
LPC_EXCEPTION = 7
LPC_DEBUG_EVENT = 8
LPC_ERROR_EVENT = 9
LPC_CONNECTION_REQUEST = 10
LPC_CONTINUATION_REQUIRED = 0x2000
)
const (
SecurityAnonymous uint32 = 1
SecurityIdentification uint32 = 2
SecurityImpersonation uint32 = 3
SecurityDelegation uint32 = 4
)
const (
SECURITY_DYNAMIC_TRACKING byte = 1
SECURITY_STATIC_TRACKING byte = 0
)
const (
ALPC_SYNC_OBJECT_TYPE uint32 = 2
ALPC_THREAD_OBJECT_TYPE uint32 = 4
)

181
vendor/github.com/apenwarr/w32/alpc_typedef.go generated vendored Normal file
View file

@ -0,0 +1,181 @@
package w32
import (
"errors"
)
// nt!_ALPC_MESSAGE_ATTRIBUTES
// +0x000 AllocatedAttributes : Uint4B
// +0x004 ValidAttributes : Uint4B
type ALPC_MESSAGE_ATTRIBUTES struct {
AllocatedAttributes uint32
ValidAttributes uint32
}
type ALPC_CONTEXT_ATTR struct {
PortContext *AlpcPortContext
MessageContext uintptr
Sequence uint32
MessageId uint32
CallbackId uint32
}
type ALPC_HANDLE_ATTR struct {
Flags uint32
Handle HANDLE
ObjectType uint32
DesiredAccess uint32
}
// nt!_CLIENT_ID
// +0x000 UniqueProcess : Ptr64 Void
// +0x008 UniqueThread : Ptr64 Void
type CLIENT_ID struct {
UniqueProcess uintptr
UniqueThread uintptr
}
// nt!_UNICODE_STRING
// +0x000 Length : Uint2B
// +0x002 MaximumLength : Uint2B
// +0x008 Buffer : Ptr64 Uint2B
type UNICODE_STRING struct {
Length uint16
MaximumLength uint16
_ [4]byte // align to 0x08
Buffer *uint16
}
// nt!_OBJECT_ATTRIBUTES
// +0x000 Length : Uint4B
// +0x008 RootDirectory : Ptr64 Void
// +0x010 ObjectName : Ptr64 _UNICODE_STRING
// +0x018 Attributes : Uint4B
// +0x020 SecurityDescriptor : Ptr64 Void
// +0x028 SecurityQualityOfService : Ptr64 Void
type OBJECT_ATTRIBUTES struct {
Length uint32
_ [4]byte // align to 0x08
RootDirectory HANDLE
ObjectName *UNICODE_STRING
Attributes uint32
_ [4]byte // align to 0x20
SecurityDescriptor *SECURITY_DESCRIPTOR
SecurityQualityOfService *SECURITY_QUALITY_OF_SERVICE
}
// cf: http://j00ru.vexillium.org/?p=502 for legacy RPC
// nt!_PORT_MESSAGE
// +0x000 u1 : <unnamed-tag>
// +0x004 u2 : <unnamed-tag>
// +0x008 ClientId : _CLIENT_ID
// +0x008 DoNotUseThisField : Float
// +0x018 MessageId : Uint4B
// +0x020 ClientViewSize : Uint8B
// +0x020 CallbackId : Uint4B
type PORT_MESSAGE struct {
DataLength uint16 // These are the two unnamed unions
TotalLength uint16 // without Length and ZeroInit
Type uint16
DataInfoOffset uint16
ClientId CLIENT_ID
MessageId uint32
_ [4]byte // align up to 0x20
ClientViewSize uint64
}
func (pm PORT_MESSAGE) CallbackId() uint32 {
return uint32(pm.ClientViewSize >> 32)
}
func (pm PORT_MESSAGE) DoNotUseThisField() float64 {
panic("WE TOLD YOU NOT TO USE THIS FIELD")
}
const PORT_MESSAGE_SIZE = 0x28
// http://www.nirsoft.net/kernel_struct/vista/SECURITY_QUALITY_OF_SERVICE.html
type SECURITY_QUALITY_OF_SERVICE struct {
Length uint32
ImpersonationLevel uint32
ContextTrackingMode byte
EffectiveOnly byte
_ [2]byte // align to 12 bytes
}
const SECURITY_QOS_SIZE = 12
// nt!_ALPC_PORT_ATTRIBUTES
// +0x000 Flags : Uint4B
// +0x004 SecurityQos : _SECURITY_QUALITY_OF_SERVICE
// +0x010 MaxMessageLength : Uint8B
// +0x018 MemoryBandwidth : Uint8B
// +0x020 MaxPoolUsage : Uint8B
// +0x028 MaxSectionSize : Uint8B
// +0x030 MaxViewSize : Uint8B
// +0x038 MaxTotalSectionSize : Uint8B
// +0x040 DupObjectTypes : Uint4B
// +0x044 Reserved : Uint4B
type ALPC_PORT_ATTRIBUTES struct {
Flags uint32
SecurityQos SECURITY_QUALITY_OF_SERVICE
MaxMessageLength uint64 // must be filled out
MemoryBandwidth uint64
MaxPoolUsage uint64
MaxSectionSize uint64
MaxViewSize uint64
MaxTotalSectionSize uint64
DupObjectTypes uint32
Reserved uint32
}
const SHORT_MESSAGE_MAX_SIZE uint16 = 65535 // MAX_USHORT
const SHORT_MESSAGE_MAX_PAYLOAD uint16 = SHORT_MESSAGE_MAX_SIZE - PORT_MESSAGE_SIZE
// LPC uses the first 4 bytes of the payload as an LPC Command, but this is
// NOT represented here, to allow the use of raw ALPC. For legacy LPC, callers
// must include the command as part of their payload.
type AlpcShortMessage struct {
PORT_MESSAGE
Data [SHORT_MESSAGE_MAX_PAYLOAD]byte
}
func NewAlpcShortMessage() AlpcShortMessage {
sm := AlpcShortMessage{}
sm.TotalLength = SHORT_MESSAGE_MAX_SIZE
return sm
}
func (sm *AlpcShortMessage) SetData(d []byte) (e error) {
copy(sm.Data[:], d)
if len(d) > int(SHORT_MESSAGE_MAX_PAYLOAD) {
e = errors.New("data too big - truncated")
sm.DataLength = SHORT_MESSAGE_MAX_PAYLOAD
sm.TotalLength = SHORT_MESSAGE_MAX_SIZE
return
}
sm.TotalLength = uint16(PORT_MESSAGE_SIZE + len(d))
sm.DataLength = uint16(len(d))
return
}
// TODO - is this still useful?
func (sm *AlpcShortMessage) GetData() []byte {
if int(sm.DataLength) > int(SHORT_MESSAGE_MAX_PAYLOAD) {
return sm.Data[:] // truncate
}
return sm.Data[:sm.DataLength]
}
func (sm *AlpcShortMessage) Reset() {
// zero the PORT_MESSAGE header
sm.PORT_MESSAGE = PORT_MESSAGE{}
sm.TotalLength = SHORT_MESSAGE_MAX_SIZE
sm.DataLength = 0
}
type AlpcPortContext struct {
Handle HANDLE
}

109
vendor/github.com/apenwarr/w32/comctl32.go generated vendored Normal file
View file

@ -0,0 +1,109 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"syscall"
"unsafe"
)
var (
modcomctl32 = syscall.NewLazyDLL("comctl32.dll")
procInitCommonControlsEx = modcomctl32.NewProc("InitCommonControlsEx")
procImageList_Create = modcomctl32.NewProc("ImageList_Create")
procImageList_Destroy = modcomctl32.NewProc("ImageList_Destroy")
procImageList_GetImageCount = modcomctl32.NewProc("ImageList_GetImageCount")
procImageList_SetImageCount = modcomctl32.NewProc("ImageList_SetImageCount")
procImageList_Add = modcomctl32.NewProc("ImageList_Add")
procImageList_ReplaceIcon = modcomctl32.NewProc("ImageList_ReplaceIcon")
procImageList_Remove = modcomctl32.NewProc("ImageList_Remove")
procTrackMouseEvent = modcomctl32.NewProc("_TrackMouseEvent")
)
func InitCommonControlsEx(lpInitCtrls *INITCOMMONCONTROLSEX) bool {
ret, _, _ := procInitCommonControlsEx.Call(
uintptr(unsafe.Pointer(lpInitCtrls)))
return ret != 0
}
func ImageList_Create(cx, cy int, flags uint, cInitial, cGrow int) HIMAGELIST {
ret, _, _ := procImageList_Create.Call(
uintptr(cx),
uintptr(cy),
uintptr(flags),
uintptr(cInitial),
uintptr(cGrow))
if ret == 0 {
panic("Create image list failed")
}
return HIMAGELIST(ret)
}
func ImageList_Destroy(himl HIMAGELIST) bool {
ret, _, _ := procImageList_Destroy.Call(
uintptr(himl))
return ret != 0
}
func ImageList_GetImageCount(himl HIMAGELIST) int {
ret, _, _ := procImageList_GetImageCount.Call(
uintptr(himl))
return int(ret)
}
func ImageList_SetImageCount(himl HIMAGELIST, uNewCount uint) bool {
ret, _, _ := procImageList_SetImageCount.Call(
uintptr(himl),
uintptr(uNewCount))
return ret != 0
}
func ImageList_Add(himl HIMAGELIST, hbmImage, hbmMask HBITMAP) int {
ret, _, _ := procImageList_Add.Call(
uintptr(himl),
uintptr(hbmImage),
uintptr(hbmMask))
return int(ret)
}
func ImageList_ReplaceIcon(himl HIMAGELIST, i int, hicon HICON) int {
ret, _, _ := procImageList_ReplaceIcon.Call(
uintptr(himl),
uintptr(i),
uintptr(hicon))
return int(ret)
}
func ImageList_AddIcon(himl HIMAGELIST, hicon HICON) int {
return ImageList_ReplaceIcon(himl, -1, hicon)
}
func ImageList_Remove(himl HIMAGELIST, i int) bool {
ret, _, _ := procImageList_Remove.Call(
uintptr(himl),
uintptr(i))
return ret != 0
}
func ImageList_RemoveAll(himl HIMAGELIST) bool {
return ImageList_Remove(himl, -1)
}
func TrackMouseEvent(tme *TRACKMOUSEEVENT) bool {
ret, _, _ := procTrackMouseEvent.Call(
uintptr(unsafe.Pointer(tme)))
return ret != 0
}

38
vendor/github.com/apenwarr/w32/comdlg32.go generated vendored Normal file
View file

@ -0,0 +1,38 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"syscall"
"unsafe"
)
var (
modcomdlg32 = syscall.NewLazyDLL("comdlg32.dll")
procGetSaveFileName = modcomdlg32.NewProc("GetSaveFileNameW")
procGetOpenFileName = modcomdlg32.NewProc("GetOpenFileNameW")
procCommDlgExtendedError = modcomdlg32.NewProc("CommDlgExtendedError")
)
func GetOpenFileName(ofn *OPENFILENAME) bool {
ret, _, _ := procGetOpenFileName.Call(
uintptr(unsafe.Pointer(ofn)))
return ret != 0
}
func GetSaveFileName(ofn *OPENFILENAME) bool {
ret, _, _ := procGetSaveFileName.Call(
uintptr(unsafe.Pointer(ofn)))
return ret != 0
}
func CommDlgExtendedError() uint {
ret, _, _ := procCommDlgExtendedError.Call()
return uint(ret)
}

2628
vendor/github.com/apenwarr/w32/constants.go generated vendored Normal file

File diff suppressed because it is too large Load diff

152
vendor/github.com/apenwarr/w32/create_process.go generated vendored Normal file
View file

@ -0,0 +1,152 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"syscall"
"unsafe"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procCreateProcessW = kernel32.NewProc("CreateProcessW")
procTerminateProcess = kernel32.NewProc("TerminateProcess")
procGetExitCodeProcess = kernel32.NewProc("GetExitCodeProcess")
procWaitForSingleObject = kernel32.NewProc("WaitForSingleObject")
)
// WINBASEAPI WINBOOL WINAPI
// CreateProcessW (
// LPCWSTR lpApplicationName,
// LPWSTR lpCommandLine,
// LPSECURITY_ATTRIBUTES lpProcessAttributes,
// LPSECURITY_ATTRIBUTES lpThreadAttributes
// WINBOOL bInheritHandles
// DWORD dwCreationFlags
// LPVOID lpEnvironment
// LPCWSTR lpCurrentDirectory
// LPSTARTUPINFOW lpStartupInfo
// LPPROCESS_INFORMATION lpProcessInformation
//);
func CreateProcessW(
lpApplicationName, lpCommandLine string,
lpProcessAttributes, lpThreadAttributes *SECURITY_ATTRIBUTES,
bInheritHandles BOOL,
dwCreationFlags uint32,
lpEnvironment unsafe.Pointer,
lpCurrentDirectory string,
lpStartupInfo *STARTUPINFOW,
lpProcessInformation *PROCESS_INFORMATION,
) (e error) {
var lpAN, lpCL, lpCD *uint16
if len(lpApplicationName) > 0 {
lpAN, e = syscall.UTF16PtrFromString(lpApplicationName)
if e != nil {
return
}
}
if len(lpCommandLine) > 0 {
lpCL, e = syscall.UTF16PtrFromString(lpCommandLine)
if e != nil {
return
}
}
if len(lpCurrentDirectory) > 0 {
lpCD, e = syscall.UTF16PtrFromString(lpCurrentDirectory)
if e != nil {
return
}
}
ret, _, lastErr := procCreateProcessW.Call(
uintptr(unsafe.Pointer(lpAN)),
uintptr(unsafe.Pointer(lpCL)),
uintptr(unsafe.Pointer(lpProcessAttributes)),
uintptr(unsafe.Pointer(lpProcessInformation)),
uintptr(bInheritHandles),
uintptr(dwCreationFlags),
uintptr(lpEnvironment),
uintptr(unsafe.Pointer(lpCD)),
uintptr(unsafe.Pointer(lpStartupInfo)),
uintptr(unsafe.Pointer(lpProcessInformation)),
)
if ret == 0 {
e = lastErr
}
return
}
func CreateProcessQuick(cmd string) (pi PROCESS_INFORMATION, e error) {
si := &STARTUPINFOW{}
e = CreateProcessW(
"",
cmd,
nil,
nil,
0,
0,
unsafe.Pointer(nil),
"",
si,
&pi,
)
return
}
func TerminateProcess(hProcess HANDLE, exitCode uint32) (e error) {
ret, _, lastErr := procTerminateProcess.Call(
uintptr(hProcess),
uintptr(exitCode),
)
if ret == 0 {
e = lastErr
}
return
}
func GetExitCodeProcess(hProcess HANDLE) (code uintptr, e error) {
ret, _, lastErr := procGetExitCodeProcess.Call(
uintptr(hProcess),
uintptr(unsafe.Pointer(&code)),
)
if ret == 0 {
e = lastErr
}
return
}
// DWORD WINAPI WaitForSingleObject(
// _In_ HANDLE hHandle,
// _In_ DWORD dwMilliseconds
// );
func WaitForSingleObject(hHandle HANDLE, msecs uint32) (ok bool, e error) {
ret, _, lastErr := procWaitForSingleObject.Call(
uintptr(hHandle),
uintptr(msecs),
)
if ret == WAIT_OBJECT_0 {
ok = true
return
}
// don't set e for timeouts, or it will be ERROR_SUCCESS which is
// confusing
if ret != WAIT_TIMEOUT {
e = lastErr
}
return
}

View file

@ -0,0 +1,9 @@
package w32
const (
WAIT_ABANDONED = 0x00000080
WAIT_OBJECT_0 = 0x00000000
WAIT_TIMEOUT = 0x00000102
WAIT_FAILED = 0xFFFFFFFF
INFINITE = 0xFFFFFFFF
)

View file

@ -0,0 +1,68 @@
package w32
// typedef struct _PROCESS_INFORMATION {
// HANDLE hProcess;
// HANDLE hThread;
// DWORD dwProcessId;
// DWORD dwThreadId;
// } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
type PROCESS_INFORMATION struct {
Process HANDLE
Thread HANDLE
ProcessId uint32
ThreadId uint32
}
// typedef struct _STARTUPINFOW {
// DWORD cb;
// LPWSTR lpReserved;
// LPWSTR lpDesktop;
// LPWSTR lpTitle;
// DWORD dwX;
// DWORD dwY;
// DWORD dwXSize;
// DWORD dwYSize;
// DWORD dwXCountChars;
// DWORD dwYCountChars;
// DWORD dwFillAttribute;
// DWORD dwFlags;
// WORD wShowWindow;
// WORD cbReserved2;
// LPBYTE lpReserved2;
// HANDLE hStdInput;
// HANDLE hStdOutput;
// HANDLE hStdError;
// } STARTUPINFOW, *LPSTARTUPINFOW;
type STARTUPINFOW struct {
cb uint32
_ *uint16
Desktop *uint16
Title *uint16
X uint32
Y uint32
XSize uint32
YSize uint32
XCountChars uint32
YCountChars uint32
FillAttribute uint32
Flags uint32
ShowWindow uint16
_ uint16
_ *uint8
StdInput HANDLE
StdOutput HANDLE
StdError HANDLE
}
// combase!_SECURITY_ATTRIBUTES
// +0x000 nLength : Uint4B
// +0x008 lpSecurityDescriptor : Ptr64 Void
// +0x010 bInheritHandle : Int4B
type SECURITY_ATTRIBUTES struct {
Length uint32
SecurityDescriptor uintptr
InheritHandle BOOL
}

254
vendor/github.com/apenwarr/w32/dwmapi.go generated vendored Normal file
View file

@ -0,0 +1,254 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"fmt"
"syscall"
"unsafe"
)
// DEFINED IN THE DWM API BUT NOT IMPLEMENTED BY MS:
// DwmAttachMilContent
// DwmDetachMilContent
// DwmEnableComposition
// DwmGetGraphicsStreamClient
// DwmGetGraphicsStreamTransformHint
var (
moddwmapi = syscall.NewLazyDLL("dwmapi.dll")
procDwmDefWindowProc = moddwmapi.NewProc("DwmDefWindowProc")
procDwmEnableBlurBehindWindow = moddwmapi.NewProc("DwmEnableBlurBehindWindow")
procDwmEnableMMCSS = moddwmapi.NewProc("DwmEnableMMCSS")
procDwmExtendFrameIntoClientArea = moddwmapi.NewProc("DwmExtendFrameIntoClientArea")
procDwmFlush = moddwmapi.NewProc("DwmFlush")
procDwmGetColorizationColor = moddwmapi.NewProc("DwmGetColorizationColor")
procDwmGetCompositionTimingInfo = moddwmapi.NewProc("DwmGetCompositionTimingInfo")
procDwmGetTransportAttributes = moddwmapi.NewProc("DwmGetTransportAttributes")
procDwmGetWindowAttribute = moddwmapi.NewProc("DwmGetWindowAttribute")
procDwmInvalidateIconicBitmaps = moddwmapi.NewProc("DwmInvalidateIconicBitmaps")
procDwmIsCompositionEnabled = moddwmapi.NewProc("DwmIsCompositionEnabled")
procDwmModifyPreviousDxFrameDuration = moddwmapi.NewProc("DwmModifyPreviousDxFrameDuration")
procDwmQueryThumbnailSourceSize = moddwmapi.NewProc("DwmQueryThumbnailSourceSize")
procDwmRegisterThumbnail = moddwmapi.NewProc("DwmRegisterThumbnail")
procDwmRenderGesture = moddwmapi.NewProc("DwmRenderGesture")
procDwmSetDxFrameDuration = moddwmapi.NewProc("DwmSetDxFrameDuration")
procDwmSetIconicLivePreviewBitmap = moddwmapi.NewProc("DwmSetIconicLivePreviewBitmap")
procDwmSetIconicThumbnail = moddwmapi.NewProc("DwmSetIconicThumbnail")
procDwmSetPresentParameters = moddwmapi.NewProc("DwmSetPresentParameters")
procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute")
procDwmShowContact = moddwmapi.NewProc("DwmShowContact")
procDwmTetherContact = moddwmapi.NewProc("DwmTetherContact")
procDwmTransitionOwnedWindow = moddwmapi.NewProc("DwmTransitionOwnedWindow")
procDwmUnregisterThumbnail = moddwmapi.NewProc("DwmUnregisterThumbnail")
procDwmUpdateThumbnailProperties = moddwmapi.NewProc("DwmUpdateThumbnailProperties")
)
func DwmDefWindowProc(hWnd HWND, msg uint, wParam, lParam uintptr) (bool, uint) {
var result uint
ret, _, _ := procDwmDefWindowProc.Call(
uintptr(hWnd),
uintptr(msg),
wParam,
lParam,
uintptr(unsafe.Pointer(&result)))
return ret != 0, result
}
func DwmEnableBlurBehindWindow(hWnd HWND, pBlurBehind *DWM_BLURBEHIND) HRESULT {
ret, _, _ := procDwmEnableBlurBehindWindow.Call(
uintptr(hWnd),
uintptr(unsafe.Pointer(pBlurBehind)))
return HRESULT(ret)
}
func DwmEnableMMCSS(fEnableMMCSS bool) HRESULT {
ret, _, _ := procDwmEnableMMCSS.Call(
uintptr(BoolToBOOL(fEnableMMCSS)))
return HRESULT(ret)
}
func DwmExtendFrameIntoClientArea(hWnd HWND, pMarInset *MARGINS) HRESULT {
ret, _, _ := procDwmExtendFrameIntoClientArea.Call(
uintptr(hWnd),
uintptr(unsafe.Pointer(pMarInset)))
return HRESULT(ret)
}
func DwmFlush() HRESULT {
ret, _, _ := procDwmFlush.Call()
return HRESULT(ret)
}
func DwmGetColorizationColor(pcrColorization *uint32, pfOpaqueBlend *BOOL) HRESULT {
ret, _, _ := procDwmGetColorizationColor.Call(
uintptr(unsafe.Pointer(pcrColorization)),
uintptr(unsafe.Pointer(pfOpaqueBlend)))
return HRESULT(ret)
}
func DwmGetCompositionTimingInfo(hWnd HWND, pTimingInfo *DWM_TIMING_INFO) HRESULT {
ret, _, _ := procDwmGetCompositionTimingInfo.Call(
uintptr(hWnd),
uintptr(unsafe.Pointer(pTimingInfo)))
return HRESULT(ret)
}
func DwmGetTransportAttributes(pfIsRemoting *BOOL, pfIsConnected *BOOL, pDwGeneration *uint32) HRESULT {
ret, _, _ := procDwmGetTransportAttributes.Call(
uintptr(unsafe.Pointer(pfIsRemoting)),
uintptr(unsafe.Pointer(pfIsConnected)),
uintptr(unsafe.Pointer(pDwGeneration)))
return HRESULT(ret)
}
// TODO: verify handling of variable arguments
func DwmGetWindowAttribute(hWnd HWND, dwAttribute uint32) (pAttribute interface{}, result HRESULT) {
var pvAttribute, pvAttrSize uintptr
switch dwAttribute {
case DWMWA_NCRENDERING_ENABLED:
v := new(BOOL)
pAttribute = v
pvAttribute = uintptr(unsafe.Pointer(v))
pvAttrSize = unsafe.Sizeof(*v)
case DWMWA_CAPTION_BUTTON_BOUNDS, DWMWA_EXTENDED_FRAME_BOUNDS:
v := new(RECT)
pAttribute = v
pvAttribute = uintptr(unsafe.Pointer(v))
pvAttrSize = unsafe.Sizeof(*v)
case DWMWA_CLOAKED:
panic(fmt.Sprintf("DwmGetWindowAttribute(%d) is not currently supported.", dwAttribute))
default:
panic(fmt.Sprintf("DwmGetWindowAttribute(%d) is not valid.", dwAttribute))
}
ret, _, _ := procDwmGetWindowAttribute.Call(
uintptr(hWnd),
uintptr(dwAttribute),
pvAttribute,
pvAttrSize)
result = HRESULT(ret)
return
}
func DwmInvalidateIconicBitmaps(hWnd HWND) HRESULT {
ret, _, _ := procDwmInvalidateIconicBitmaps.Call(
uintptr(hWnd))
return HRESULT(ret)
}
func DwmIsCompositionEnabled(pfEnabled *BOOL) HRESULT {
ret, _, _ := procDwmIsCompositionEnabled.Call(
uintptr(unsafe.Pointer(pfEnabled)))
return HRESULT(ret)
}
func DwmModifyPreviousDxFrameDuration(hWnd HWND, cRefreshes int, fRelative bool) HRESULT {
ret, _, _ := procDwmModifyPreviousDxFrameDuration.Call(
uintptr(hWnd),
uintptr(cRefreshes),
uintptr(BoolToBOOL(fRelative)))
return HRESULT(ret)
}
func DwmQueryThumbnailSourceSize(hThumbnail HTHUMBNAIL, pSize *SIZE) HRESULT {
ret, _, _ := procDwmQueryThumbnailSourceSize.Call(
uintptr(hThumbnail),
uintptr(unsafe.Pointer(pSize)))
return HRESULT(ret)
}
func DwmRegisterThumbnail(hWndDestination HWND, hWndSource HWND, phThumbnailId *HTHUMBNAIL) HRESULT {
ret, _, _ := procDwmRegisterThumbnail.Call(
uintptr(hWndDestination),
uintptr(hWndSource),
uintptr(unsafe.Pointer(phThumbnailId)))
return HRESULT(ret)
}
func DwmRenderGesture(gt GESTURE_TYPE, cContacts uint, pdwPointerID *uint32, pPoints *POINT) {
procDwmRenderGesture.Call(
uintptr(gt),
uintptr(cContacts),
uintptr(unsafe.Pointer(pdwPointerID)),
uintptr(unsafe.Pointer(pPoints)))
return
}
func DwmSetDxFrameDuration(hWnd HWND, cRefreshes int) HRESULT {
ret, _, _ := procDwmSetDxFrameDuration.Call(
uintptr(hWnd),
uintptr(cRefreshes))
return HRESULT(ret)
}
func DwmSetIconicLivePreviewBitmap(hWnd HWND, hbmp HBITMAP, pptClient *POINT, dwSITFlags uint32) HRESULT {
ret, _, _ := procDwmSetIconicLivePreviewBitmap.Call(
uintptr(hWnd),
uintptr(hbmp),
uintptr(unsafe.Pointer(pptClient)),
uintptr(dwSITFlags))
return HRESULT(ret)
}
func DwmSetIconicThumbnail(hWnd HWND, hbmp HBITMAP, dwSITFlags uint32) HRESULT {
ret, _, _ := procDwmSetIconicThumbnail.Call(
uintptr(hWnd),
uintptr(hbmp),
uintptr(dwSITFlags))
return HRESULT(ret)
}
func DwmSetPresentParameters(hWnd HWND, pPresentParams *DWM_PRESENT_PARAMETERS) HRESULT {
ret, _, _ := procDwmSetPresentParameters.Call(
uintptr(hWnd),
uintptr(unsafe.Pointer(pPresentParams)))
return HRESULT(ret)
}
func DwmSetWindowAttribute(hWnd HWND, dwAttribute uint32, pvAttribute LPCVOID, cbAttribute uint32) HRESULT {
ret, _, _ := procDwmSetWindowAttribute.Call(
uintptr(hWnd),
uintptr(dwAttribute),
uintptr(pvAttribute),
uintptr(cbAttribute))
return HRESULT(ret)
}
func DwmShowContact(dwPointerID uint32, eShowContact DWM_SHOWCONTACT) {
procDwmShowContact.Call(
uintptr(dwPointerID),
uintptr(eShowContact))
return
}
func DwmTetherContact(dwPointerID uint32, fEnable bool, ptTether POINT) {
procDwmTetherContact.Call(
uintptr(dwPointerID),
uintptr(BoolToBOOL(fEnable)),
uintptr(unsafe.Pointer(&ptTether)))
return
}
func DwmTransitionOwnedWindow(hWnd HWND, target DWMTRANSITION_OWNEDWINDOW_TARGET) {
procDwmTransitionOwnedWindow.Call(
uintptr(hWnd),
uintptr(target))
return
}
func DwmUnregisterThumbnail(hThumbnailId HTHUMBNAIL) HRESULT {
ret, _, _ := procDwmUnregisterThumbnail.Call(
uintptr(hThumbnailId))
return HRESULT(ret)
}
func DwmUpdateThumbnailProperties(hThumbnailId HTHUMBNAIL, ptnProperties *DWM_THUMBNAIL_PROPERTIES) HRESULT {
ret, _, _ := procDwmUpdateThumbnailProperties.Call(
uintptr(hThumbnailId),
uintptr(unsafe.Pointer(ptnProperties)))
return HRESULT(ret)
}

174
vendor/github.com/apenwarr/w32/fork.go generated vendored Normal file
View file

@ -0,0 +1,174 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
// #include <stdlib.h>
//import (
// "C"
//)
// Based on C code found here https://gist.github.com/juntalis/4366916
// Original code license:
/*
* fork.c
* Experimental fork() on Windows. Requires NT 6 subsystem or
* newer.
*
* Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
import (
"fmt"
"syscall"
"unsafe"
)
var (
ntdll = syscall.NewLazyDLL("ntdll.dll")
procRtlCloneUserProcess = ntdll.NewProc("RtlCloneUserProcess")
procAllocConsole = modkernel32.NewProc("AllocConsole")
procOpenProcess = modkernel32.NewProc("OpenProcess")
procOpenThread = modkernel32.NewProc("OpenThread")
procResumeThread = modkernel32.NewProc("ResumeThread")
)
func OpenProcess(desiredAccess int, inheritHandle bool, processId uintptr) (h HANDLE, e error) {
inherit := uintptr(0)
if inheritHandle {
inherit = 1
}
ret, _, lastErr := procOpenProcess.Call(
uintptr(desiredAccess),
inherit,
uintptr(processId),
)
if ret == 0 {
e = lastErr
}
h = HANDLE(ret)
return
}
func OpenThread(desiredAccess int, inheritHandle bool, threadId uintptr) (h HANDLE, e error) {
inherit := uintptr(0)
if inheritHandle {
inherit = 1
}
ret, _, lastErr := procOpenThread.Call(
uintptr(desiredAccess),
inherit,
uintptr(threadId),
)
if ret == 0 {
e = lastErr
}
h = HANDLE(ret)
return
}
// DWORD WINAPI ResumeThread(
// _In_ HANDLE hThread
// );
func ResumeThread(ht HANDLE) (e error) {
ret, _, lastErr := procResumeThread.Call(
uintptr(ht),
)
if ret == ^uintptr(0) { // -1
e = lastErr
}
return
}
// BOOL WINAPI AllocConsole(void);
func AllocConsole() (e error) {
ret, _, lastErr := procAllocConsole.Call()
if ret != ERROR_SUCCESS {
e = lastErr
}
return
}
// NTSYSAPI
// NTSTATUS
// NTAPI RtlCloneUserProcess (
// _In_ ULONG ProcessFlags,
// _In_opt_ PSECURITY_DESCRIPTOR ProcessSecurityDescriptor,
// _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,
// _In_opt_ HANDLE DebugPort,
// _Out_ PRTL_USER_PROCESS_INFORMATION ProcessInformation
// )
func RtlCloneUserProcess(
ProcessFlags uint32,
ProcessSecurityDescriptor, ThreadSecurityDescriptor *SECURITY_DESCRIPTOR, // in advapi32_typedef.go
DebugPort HANDLE,
ProcessInformation *RTL_USER_PROCESS_INFORMATION,
) (status uintptr) {
status, _, _ = procRtlCloneUserProcess.Call(
uintptr(ProcessFlags),
uintptr(unsafe.Pointer(ProcessSecurityDescriptor)),
uintptr(unsafe.Pointer(ThreadSecurityDescriptor)),
uintptr(DebugPort),
uintptr(unsafe.Pointer(ProcessInformation)),
)
return
}
// Fork creates a clone of the current process using the undocumented
// RtlCloneUserProcess call in ntdll, similar to unix fork(). The
// return value in the parent is the child PID. In the child it is 0.
func Fork() (pid uintptr, e error) {
pi := &RTL_USER_PROCESS_INFORMATION{}
ret := RtlCloneUserProcess(
RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED|RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES,
nil,
nil,
HANDLE(0),
pi,
)
switch ret {
case RTL_CLONE_PARENT:
pid = pi.ClientId.UniqueProcess
ht, err := OpenThread(THREAD_ALL_ACCESS, false, pi.ClientId.UniqueThread)
if err != nil {
e = fmt.Errorf("OpenThread: %s", err)
}
err = ResumeThread(ht)
if err != nil {
e = fmt.Errorf("ResumeThread: %s", err)
}
CloseHandle(ht)
case RTL_CLONE_CHILD:
pid = 0
err := AllocConsole()
if err != nil {
e = fmt.Errorf("AllocConsole: %s", err)
}
default:
e = fmt.Errorf("0x%x", ret)
}
return
}

26
vendor/github.com/apenwarr/w32/fork_constants.go generated vendored Normal file
View file

@ -0,0 +1,26 @@
package w32
const (
RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED = 0x00000001
RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES = 0x00000002
RTL_CLONE_PROCESS_FLAGS_NO_SYNCHRONIZE = 0x00000004
RTL_CLONE_PARENT = 0
RTL_CLONE_CHILD = 297
THREAD_TERMINATE = 0x0001
THREAD_SUSPEND_RESUME = 0x0002
THREAD_GET_CONTEXT = 0x0008
THREAD_SET_CONTEXT = 0x0010
THREAD_SET_INFORMATION = 0x0020
THREAD_QUERY_INFORMATION = 0x0040
THREAD_SET_THREAD_TOKEN = 0x0080
THREAD_IMPERSONATE = 0x0100
THREAD_DIRECT_IMPERSONATION = 0x0200
THREAD_SET_LIMITED_INFORMATION = 0x0400
THREAD_QUERY_LIMITED_INFORMATION = 0x0800
THREAD_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff
PROCESS_SET_SESSIONID = 0x0004
PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff
)

89
vendor/github.com/apenwarr/w32/fork_typedef.go generated vendored Normal file
View file

@ -0,0 +1,89 @@
package w32
// combase!_SECTION_IMAGE_INFORMATION
// +0x000 TransferAddress : Ptr64 Void
// +0x008 ZeroBits : Uint4B
// +0x010 MaximumStackSize : Uint8B
// +0x018 CommittedStackSize : Uint8B
// +0x020 SubSystemType : Uint4B
// +0x024 SubSystemMinorVersion : Uint2B
// +0x026 SubSystemMajorVersion : Uint2B
// +0x024 SubSystemVersion : Uint4B
// +0x028 MajorOperatingSystemVersion : Uint2B
// +0x02a MinorOperatingSystemVersion : Uint2B
// +0x028 OperatingSystemVersion : Uint4B
// +0x02c ImageCharacteristics : Uint2B
// +0x02e DllCharacteristics : Uint2B
// +0x030 Machine : Uint2B
// +0x032 ImageContainsCode : UChar
// +0x033 ImageFlags : UChar
// +0x033 ComPlusNativeReady : Pos 0, 1 Bit
// +0x033 ComPlusILOnly : Pos 1, 1 Bit
// +0x033 ImageDynamicallyRelocated : Pos 2, 1 Bit
// +0x033 ImageMappedFlat : Pos 3, 1 Bit
// +0x033 BaseBelow4gb : Pos 4, 1 Bit
// +0x033 ComPlusPrefer32bit : Pos 5, 1 Bit
// +0x033 Reserved : Pos 6, 2 Bits
// +0x034 LoaderFlags : Uint4B
// +0x038 ImageFileSize : Uint4B
// +0x03c CheckSum : Uint4B
type SECTION_IMAGE_INFORMATION struct {
TransferAddress uintptr
ZeroBits uint32
MaximumStackSize uint64
CommittedStackSize uint64
SubSystemType uint32
SubSystemMinorVersion uint16
SubSystemMajorVersion uint16
SubSystemVersion uint32
MajorOperatingSystemVersion uint16
MinorOperatingSystemVersion uint16
OperatingSystemVersion uint32
ImageCharacteristics uint16
DllCharacteristics uint16
Machine uint16
ImageContainsCode uint8
ImageFlags uint8
ComPlusFlags uint8
LoaderFlags uint32
ImageFileSize uint32
CheckSum uint32
}
func (si *SECTION_IMAGE_INFORMATION) ComPlusNativeReady() bool {
return (si.ComPlusFlags & (1 << 0)) == 1
}
func (si *SECTION_IMAGE_INFORMATION) ComPlusILOnly() bool {
return (si.ComPlusFlags & (1 << 1)) == 1
}
func (si *SECTION_IMAGE_INFORMATION) ImageDynamicallyRelocated() bool {
return (si.ComPlusFlags & (1 << 2)) == 1
}
func (si *SECTION_IMAGE_INFORMATION) ImageMappedFlat() bool {
return (si.ComPlusFlags & (1 << 3)) == 1
}
func (si *SECTION_IMAGE_INFORMATION) BaseBelow4gb() bool {
return (si.ComPlusFlags & (1 << 4)) == 1
}
func (si *SECTION_IMAGE_INFORMATION) ComPlusPrefer32bit() bool {
return (si.ComPlusFlags & (1 << 5)) == 1
}
// combase!_RTL_USER_PROCESS_INFORMATION
// +0x000 Length : Uint4B
// +0x008 Process : Ptr64 Void
// +0x010 Thread : Ptr64 Void
// +0x018 ClientId : _CLIENT_ID
// +0x028 ImageInformation : _SECTION_IMAGE_INFORMATION
type RTL_USER_PROCESS_INFORMATION struct {
Length uint32
Process HANDLE
Thread HANDLE
ClientId CLIENT_ID
ImageInformation SECTION_IMAGE_INFORMATION
}

543
vendor/github.com/apenwarr/w32/gdi32.go generated vendored Normal file
View file

@ -0,0 +1,543 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"syscall"
"unsafe"
)
var (
modgdi32 = syscall.NewLazyDLL("gdi32.dll")
procGetDeviceCaps = modgdi32.NewProc("GetDeviceCaps")
procGetCurrentObject = modgdi32.NewProc("GetCurrentObject")
procDeleteObject = modgdi32.NewProc("DeleteObject")
procCreateFontIndirect = modgdi32.NewProc("CreateFontIndirectW")
procAbortDoc = modgdi32.NewProc("AbortDoc")
procBitBlt = modgdi32.NewProc("BitBlt")
procPatBlt = modgdi32.NewProc("PatBlt")
procCloseEnhMetaFile = modgdi32.NewProc("CloseEnhMetaFile")
procCopyEnhMetaFile = modgdi32.NewProc("CopyEnhMetaFileW")
procCreateBrushIndirect = modgdi32.NewProc("CreateBrushIndirect")
procCreateCompatibleDC = modgdi32.NewProc("CreateCompatibleDC")
procCreateDC = modgdi32.NewProc("CreateDCW")
procCreateCompatibleBitmap = modgdi32.NewProc("CreateCompatibleBitmap")
procCreateDIBSection = modgdi32.NewProc("CreateDIBSection")
procCreateEnhMetaFile = modgdi32.NewProc("CreateEnhMetaFileW")
procCreateIC = modgdi32.NewProc("CreateICW")
procDeleteDC = modgdi32.NewProc("DeleteDC")
procDeleteEnhMetaFile = modgdi32.NewProc("DeleteEnhMetaFile")
procEllipse = modgdi32.NewProc("Ellipse")
procEndDoc = modgdi32.NewProc("EndDoc")
procEndPage = modgdi32.NewProc("EndPage")
procExtCreatePen = modgdi32.NewProc("ExtCreatePen")
procGetEnhMetaFile = modgdi32.NewProc("GetEnhMetaFileW")
procGetEnhMetaFileHeader = modgdi32.NewProc("GetEnhMetaFileHeader")
procGetObject = modgdi32.NewProc("GetObjectW")
procGetStockObject = modgdi32.NewProc("GetStockObject")
procGetTextExtentExPoint = modgdi32.NewProc("GetTextExtentExPointW")
procGetTextExtentPoint32 = modgdi32.NewProc("GetTextExtentPoint32W")
procGetTextMetrics = modgdi32.NewProc("GetTextMetricsW")
procLineTo = modgdi32.NewProc("LineTo")
procMoveToEx = modgdi32.NewProc("MoveToEx")
procPlayEnhMetaFile = modgdi32.NewProc("PlayEnhMetaFile")
procRectangle = modgdi32.NewProc("Rectangle")
procResetDC = modgdi32.NewProc("ResetDCW")
procSelectObject = modgdi32.NewProc("SelectObject")
procSetBkMode = modgdi32.NewProc("SetBkMode")
procSetBrushOrgEx = modgdi32.NewProc("SetBrushOrgEx")
procSetStretchBltMode = modgdi32.NewProc("SetStretchBltMode")
procSetTextColor = modgdi32.NewProc("SetTextColor")
procSetBkColor = modgdi32.NewProc("SetBkColor")
procStartDoc = modgdi32.NewProc("StartDocW")
procStartPage = modgdi32.NewProc("StartPage")
procStretchBlt = modgdi32.NewProc("StretchBlt")
procSetDIBitsToDevice = modgdi32.NewProc("SetDIBitsToDevice")
procChoosePixelFormat = modgdi32.NewProc("ChoosePixelFormat")
procDescribePixelFormat = modgdi32.NewProc("DescribePixelFormat")
procGetEnhMetaFilePixelFormat = modgdi32.NewProc("GetEnhMetaFilePixelFormat")
procGetPixelFormat = modgdi32.NewProc("GetPixelFormat")
procSetPixelFormat = modgdi32.NewProc("SetPixelFormat")
procSwapBuffers = modgdi32.NewProc("SwapBuffers")
)
func GetDeviceCaps(hdc HDC, index int) int {
ret, _, _ := procGetDeviceCaps.Call(
uintptr(hdc),
uintptr(index))
return int(ret)
}
func GetCurrentObject(hdc HDC, uObjectType uint32) HGDIOBJ {
ret, _, _ := procGetCurrentObject.Call(
uintptr(hdc),
uintptr(uObjectType))
return HGDIOBJ(ret)
}
func DeleteObject(hObject HGDIOBJ) bool {
ret, _, _ := procDeleteObject.Call(
uintptr(hObject))
return ret != 0
}
func CreateFontIndirect(logFont *LOGFONT) HFONT {
ret, _, _ := procCreateFontIndirect.Call(
uintptr(unsafe.Pointer(logFont)))
return HFONT(ret)
}
func AbortDoc(hdc HDC) int {
ret, _, _ := procAbortDoc.Call(
uintptr(hdc))
return int(ret)
}
func BitBlt(hdcDest HDC, nXDest, nYDest, nWidth, nHeight int, hdcSrc HDC, nXSrc, nYSrc int, dwRop uint) {
ret, _, _ := procBitBlt.Call(
uintptr(hdcDest),
uintptr(nXDest),
uintptr(nYDest),
uintptr(nWidth),
uintptr(nHeight),
uintptr(hdcSrc),
uintptr(nXSrc),
uintptr(nYSrc),
uintptr(dwRop))
if ret == 0 {
panic("BitBlt failed")
}
}
func PatBlt(hdc HDC, nXLeft, nYLeft, nWidth, nHeight int, dwRop uint) {
ret, _, _ := procPatBlt.Call(
uintptr(hdc),
uintptr(nXLeft),
uintptr(nYLeft),
uintptr(nWidth),
uintptr(nHeight),
uintptr(dwRop))
if ret == 0 {
panic("PatBlt failed")
}
}
func CloseEnhMetaFile(hdc HDC) HENHMETAFILE {
ret, _, _ := procCloseEnhMetaFile.Call(
uintptr(hdc))
return HENHMETAFILE(ret)
}
func CopyEnhMetaFile(hemfSrc HENHMETAFILE, lpszFile *uint16) HENHMETAFILE {
ret, _, _ := procCopyEnhMetaFile.Call(
uintptr(hemfSrc),
uintptr(unsafe.Pointer(lpszFile)))
return HENHMETAFILE(ret)
}
func CreateBrushIndirect(lplb *LOGBRUSH) HBRUSH {
ret, _, _ := procCreateBrushIndirect.Call(
uintptr(unsafe.Pointer(lplb)))
return HBRUSH(ret)
}
func CreateCompatibleDC(hdc HDC) HDC {
ret, _, _ := procCreateCompatibleDC.Call(
uintptr(hdc))
if ret == 0 {
panic("Create compatible DC failed")
}
return HDC(ret)
}
func CreateDC(lpszDriver, lpszDevice, lpszOutput *uint16, lpInitData *DEVMODE) HDC {
ret, _, _ := procCreateDC.Call(
uintptr(unsafe.Pointer(lpszDriver)),
uintptr(unsafe.Pointer(lpszDevice)),
uintptr(unsafe.Pointer(lpszOutput)),
uintptr(unsafe.Pointer(lpInitData)))
return HDC(ret)
}
func CreateCompatibleBitmap(hdc HDC, width, height uint) HBITMAP {
ret, _, _ := procCreateCompatibleBitmap.Call(
uintptr(hdc),
uintptr(width),
uintptr(height))
return HBITMAP(ret)
}
func CreateDIBSection(hdc HDC, pbmi *BITMAPINFO, iUsage uint, ppvBits *unsafe.Pointer, hSection HANDLE, dwOffset uint) HBITMAP {
ret, _, _ := procCreateDIBSection.Call(
uintptr(hdc),
uintptr(unsafe.Pointer(pbmi)),
uintptr(iUsage),
uintptr(unsafe.Pointer(ppvBits)),
uintptr(hSection),
uintptr(dwOffset))
return HBITMAP(ret)
}
func CreateEnhMetaFile(hdcRef HDC, lpFilename *uint16, lpRect *RECT, lpDescription *uint16) HDC {
ret, _, _ := procCreateEnhMetaFile.Call(
uintptr(hdcRef),
uintptr(unsafe.Pointer(lpFilename)),
uintptr(unsafe.Pointer(lpRect)),
uintptr(unsafe.Pointer(lpDescription)))
return HDC(ret)
}
func CreateIC(lpszDriver, lpszDevice, lpszOutput *uint16, lpdvmInit *DEVMODE) HDC {
ret, _, _ := procCreateIC.Call(
uintptr(unsafe.Pointer(lpszDriver)),
uintptr(unsafe.Pointer(lpszDevice)),
uintptr(unsafe.Pointer(lpszOutput)),
uintptr(unsafe.Pointer(lpdvmInit)))
return HDC(ret)
}
func DeleteDC(hdc HDC) bool {
ret, _, _ := procDeleteDC.Call(
uintptr(hdc))
return ret != 0
}
func DeleteEnhMetaFile(hemf HENHMETAFILE) bool {
ret, _, _ := procDeleteEnhMetaFile.Call(
uintptr(hemf))
return ret != 0
}
func Ellipse(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int) bool {
ret, _, _ := procEllipse.Call(
uintptr(hdc),
uintptr(nLeftRect),
uintptr(nTopRect),
uintptr(nRightRect),
uintptr(nBottomRect))
return ret != 0
}
func EndDoc(hdc HDC) int {
ret, _, _ := procEndDoc.Call(
uintptr(hdc))
return int(ret)
}
func EndPage(hdc HDC) int {
ret, _, _ := procEndPage.Call(
uintptr(hdc))
return int(ret)
}
func ExtCreatePen(dwPenStyle, dwWidth uint, lplb *LOGBRUSH, dwStyleCount uint, lpStyle *uint) HPEN {
ret, _, _ := procExtCreatePen.Call(
uintptr(dwPenStyle),
uintptr(dwWidth),
uintptr(unsafe.Pointer(lplb)),
uintptr(dwStyleCount),
uintptr(unsafe.Pointer(lpStyle)))
return HPEN(ret)
}
func GetEnhMetaFile(lpszMetaFile *uint16) HENHMETAFILE {
ret, _, _ := procGetEnhMetaFile.Call(
uintptr(unsafe.Pointer(lpszMetaFile)))
return HENHMETAFILE(ret)
}
func GetEnhMetaFileHeader(hemf HENHMETAFILE, cbBuffer uint, lpemh *ENHMETAHEADER) uint {
ret, _, _ := procGetEnhMetaFileHeader.Call(
uintptr(hemf),
uintptr(cbBuffer),
uintptr(unsafe.Pointer(lpemh)))
return uint(ret)
}
func GetObject(hgdiobj HGDIOBJ, cbBuffer uintptr, lpvObject unsafe.Pointer) int {
ret, _, _ := procGetObject.Call(
uintptr(hgdiobj),
uintptr(cbBuffer),
uintptr(lpvObject))
return int(ret)
}
func GetStockObject(fnObject int) HGDIOBJ {
ret, _, _ := procGetStockObject.Call(
uintptr(fnObject))
return HGDIOBJ(ret)
}
func GetTextExtentExPoint(hdc HDC, lpszStr *uint16, cchString, nMaxExtent int, lpnFit, alpDx *int, lpSize *SIZE) bool {
ret, _, _ := procGetTextExtentExPoint.Call(
uintptr(hdc),
uintptr(unsafe.Pointer(lpszStr)),
uintptr(cchString),
uintptr(nMaxExtent),
uintptr(unsafe.Pointer(lpnFit)),
uintptr(unsafe.Pointer(alpDx)),
uintptr(unsafe.Pointer(lpSize)))
return ret != 0
}
func GetTextExtentPoint32(hdc HDC, lpString *uint16, c int, lpSize *SIZE) bool {
ret, _, _ := procGetTextExtentPoint32.Call(
uintptr(hdc),
uintptr(unsafe.Pointer(lpString)),
uintptr(c),
uintptr(unsafe.Pointer(lpSize)))
return ret != 0
}
func GetTextMetrics(hdc HDC, lptm *TEXTMETRIC) bool {
ret, _, _ := procGetTextMetrics.Call(
uintptr(hdc),
uintptr(unsafe.Pointer(lptm)))
return ret != 0
}
func LineTo(hdc HDC, nXEnd, nYEnd int) bool {
ret, _, _ := procLineTo.Call(
uintptr(hdc),
uintptr(nXEnd),
uintptr(nYEnd))
return ret != 0
}
func MoveToEx(hdc HDC, x, y int, lpPoint *POINT) bool {
ret, _, _ := procMoveToEx.Call(
uintptr(hdc),
uintptr(x),
uintptr(y),
uintptr(unsafe.Pointer(lpPoint)))
return ret != 0
}
func PlayEnhMetaFile(hdc HDC, hemf HENHMETAFILE, lpRect *RECT) bool {
ret, _, _ := procPlayEnhMetaFile.Call(
uintptr(hdc),
uintptr(hemf),
uintptr(unsafe.Pointer(lpRect)))
return ret != 0
}
func Rectangle(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int) bool {
ret, _, _ := procRectangle.Call(
uintptr(hdc),
uintptr(nLeftRect),
uintptr(nTopRect),
uintptr(nRightRect),
uintptr(nBottomRect))
return ret != 0
}
func ResetDC(hdc HDC, lpInitData *DEVMODE) HDC {
ret, _, _ := procResetDC.Call(
uintptr(hdc),
uintptr(unsafe.Pointer(lpInitData)))
return HDC(ret)
}
func SelectObject(hdc HDC, hgdiobj HGDIOBJ) HGDIOBJ {
ret, _, _ := procSelectObject.Call(
uintptr(hdc),
uintptr(hgdiobj))
if ret == 0 {
panic("SelectObject failed")
}
return HGDIOBJ(ret)
}
func SetBkMode(hdc HDC, iBkMode int) int {
ret, _, _ := procSetBkMode.Call(
uintptr(hdc),
uintptr(iBkMode))
if ret == 0 {
panic("SetBkMode failed")
}
return int(ret)
}
func SetBrushOrgEx(hdc HDC, nXOrg, nYOrg int, lppt *POINT) bool {
ret, _, _ := procSetBrushOrgEx.Call(
uintptr(hdc),
uintptr(nXOrg),
uintptr(nYOrg),
uintptr(unsafe.Pointer(lppt)))
return ret != 0
}
func SetStretchBltMode(hdc HDC, iStretchMode int) int {
ret, _, _ := procSetStretchBltMode.Call(
uintptr(hdc),
uintptr(iStretchMode))
return int(ret)
}
func SetTextColor(hdc HDC, crColor COLORREF) COLORREF {
ret, _, _ := procSetTextColor.Call(
uintptr(hdc),
uintptr(crColor))
if ret == CLR_INVALID {
panic("SetTextColor failed")
}
return COLORREF(ret)
}
func SetBkColor(hdc HDC, crColor COLORREF) COLORREF {
ret, _, _ := procSetBkColor.Call(
uintptr(hdc),
uintptr(crColor))
if ret == CLR_INVALID {
panic("SetBkColor failed")
}
return COLORREF(ret)
}
func StartDoc(hdc HDC, lpdi *DOCINFO) int {
ret, _, _ := procStartDoc.Call(
uintptr(hdc),
uintptr(unsafe.Pointer(lpdi)))
return int(ret)
}
func StartPage(hdc HDC) int {
ret, _, _ := procStartPage.Call(
uintptr(hdc))
return int(ret)
}
func StretchBlt(hdcDest HDC, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest int, hdcSrc HDC, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc int, dwRop uint) {
ret, _, _ := procStretchBlt.Call(
uintptr(hdcDest),
uintptr(nXOriginDest),
uintptr(nYOriginDest),
uintptr(nWidthDest),
uintptr(nHeightDest),
uintptr(hdcSrc),
uintptr(nXOriginSrc),
uintptr(nYOriginSrc),
uintptr(nWidthSrc),
uintptr(nHeightSrc),
uintptr(dwRop))
if ret == 0 {
panic("StretchBlt failed")
}
}
func SetDIBitsToDevice(hdc HDC, xDest, yDest, dwWidth, dwHeight, xSrc, ySrc int, uStartScan, cScanLines uint, lpvBits []byte, lpbmi *BITMAPINFO, fuColorUse uint) int {
ret, _, _ := procSetDIBitsToDevice.Call(
uintptr(hdc),
uintptr(xDest),
uintptr(yDest),
uintptr(dwWidth),
uintptr(dwHeight),
uintptr(xSrc),
uintptr(ySrc),
uintptr(uStartScan),
uintptr(cScanLines),
uintptr(unsafe.Pointer(&lpvBits[0])),
uintptr(unsafe.Pointer(lpbmi)),
uintptr(fuColorUse))
return int(ret)
}
func ChoosePixelFormat(hdc HDC, pfd *PIXELFORMATDESCRIPTOR) int {
ret, _, _ := procChoosePixelFormat.Call(
uintptr(hdc),
uintptr(unsafe.Pointer(pfd)),
)
return int(ret)
}
func DescribePixelFormat(hdc HDC, iPixelFormat int, nBytes uint, pfd *PIXELFORMATDESCRIPTOR) int {
ret, _, _ := procDescribePixelFormat.Call(
uintptr(hdc),
uintptr(iPixelFormat),
uintptr(nBytes),
uintptr(unsafe.Pointer(pfd)),
)
return int(ret)
}
func GetEnhMetaFilePixelFormat(hemf HENHMETAFILE, cbBuffer uint32, pfd *PIXELFORMATDESCRIPTOR) uint {
ret, _, _ := procGetEnhMetaFilePixelFormat.Call(
uintptr(hemf),
uintptr(cbBuffer),
uintptr(unsafe.Pointer(pfd)),
)
return uint(ret)
}
func GetPixelFormat(hdc HDC) int {
ret, _, _ := procGetPixelFormat.Call(
uintptr(hdc),
)
return int(ret)
}
func SetPixelFormat(hdc HDC, iPixelFormat int, pfd *PIXELFORMATDESCRIPTOR) bool {
ret, _, _ := procSetPixelFormat.Call(
uintptr(hdc),
uintptr(iPixelFormat),
uintptr(unsafe.Pointer(pfd)),
)
return ret == TRUE
}
func SwapBuffers(hdc HDC) bool {
ret, _, _ := procSwapBuffers.Call(uintptr(hdc))
return ret == TRUE
}

175
vendor/github.com/apenwarr/w32/gdiplus.go generated vendored Normal file
View file

@ -0,0 +1,175 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"errors"
"fmt"
"syscall"
"unsafe"
)
const (
Ok = 0
GenericError = 1
InvalidParameter = 2
OutOfMemory = 3
ObjectBusy = 4
InsufficientBuffer = 5
NotImplemented = 6
Win32Error = 7
WrongState = 8
Aborted = 9
FileNotFound = 10
ValueOverflow = 11
AccessDenied = 12
UnknownImageFormat = 13
FontFamilyNotFound = 14
FontStyleNotFound = 15
NotTrueTypeFont = 16
UnsupportedGdiplusVersion = 17
GdiplusNotInitialized = 18
PropertyNotFound = 19
PropertyNotSupported = 20
ProfileNotFound = 21
)
func GetGpStatus(s int32) string {
switch s {
case Ok:
return "Ok"
case GenericError:
return "GenericError"
case InvalidParameter:
return "InvalidParameter"
case OutOfMemory:
return "OutOfMemory"
case ObjectBusy:
return "ObjectBusy"
case InsufficientBuffer:
return "InsufficientBuffer"
case NotImplemented:
return "NotImplemented"
case Win32Error:
return "Win32Error"
case WrongState:
return "WrongState"
case Aborted:
return "Aborted"
case FileNotFound:
return "FileNotFound"
case ValueOverflow:
return "ValueOverflow"
case AccessDenied:
return "AccessDenied"
case UnknownImageFormat:
return "UnknownImageFormat"
case FontFamilyNotFound:
return "FontFamilyNotFound"
case FontStyleNotFound:
return "FontStyleNotFound"
case NotTrueTypeFont:
return "NotTrueTypeFont"
case UnsupportedGdiplusVersion:
return "UnsupportedGdiplusVersion"
case GdiplusNotInitialized:
return "GdiplusNotInitialized"
case PropertyNotFound:
return "PropertyNotFound"
case PropertyNotSupported:
return "PropertyNotSupported"
case ProfileNotFound:
return "ProfileNotFound"
}
return "Unknown Status Value"
}
var (
token uintptr
modgdiplus = syscall.NewLazyDLL("gdiplus.dll")
procGdipCreateBitmapFromFile = modgdiplus.NewProc("GdipCreateBitmapFromFile")
procGdipCreateBitmapFromHBITMAP = modgdiplus.NewProc("GdipCreateBitmapFromHBITMAP")
procGdipCreateHBITMAPFromBitmap = modgdiplus.NewProc("GdipCreateHBITMAPFromBitmap")
procGdipCreateBitmapFromResource = modgdiplus.NewProc("GdipCreateBitmapFromResource")
procGdipCreateBitmapFromStream = modgdiplus.NewProc("GdipCreateBitmapFromStream")
procGdipDisposeImage = modgdiplus.NewProc("GdipDisposeImage")
procGdiplusShutdown = modgdiplus.NewProc("GdiplusShutdown")
procGdiplusStartup = modgdiplus.NewProc("GdiplusStartup")
)
func GdipCreateBitmapFromFile(filename string) (*uintptr, error) {
var bitmap *uintptr
ret, _, _ := procGdipCreateBitmapFromFile.Call(
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(filename))),
uintptr(unsafe.Pointer(&bitmap)))
if ret != Ok {
return nil, errors.New(fmt.Sprintf("GdipCreateBitmapFromFile failed with status '%s' for file '%s'", GetGpStatus(int32(ret)), filename))
}
return bitmap, nil
}
func GdipCreateBitmapFromResource(instance HINSTANCE, resId *uint16) (*uintptr, error) {
var bitmap *uintptr
ret, _, _ := procGdipCreateBitmapFromResource.Call(
uintptr(instance),
uintptr(unsafe.Pointer(resId)),
uintptr(unsafe.Pointer(&bitmap)))
if ret != Ok {
return nil, errors.New(fmt.Sprintf("GdiCreateBitmapFromResource failed with status '%s'", GetGpStatus(int32(ret))))
}
return bitmap, nil
}
func GdipCreateBitmapFromStream(stream *IStream) (*uintptr, error) {
var bitmap *uintptr
ret, _, _ := procGdipCreateBitmapFromStream.Call(
uintptr(unsafe.Pointer(stream)),
uintptr(unsafe.Pointer(&bitmap)))
if ret != Ok {
return nil, errors.New(fmt.Sprintf("GdipCreateBitmapFromStream failed with status '%s'", GetGpStatus(int32(ret))))
}
return bitmap, nil
}
func GdipCreateHBITMAPFromBitmap(bitmap *uintptr, background uint32) (HBITMAP, error) {
var hbitmap HBITMAP
ret, _, _ := procGdipCreateHBITMAPFromBitmap.Call(
uintptr(unsafe.Pointer(bitmap)),
uintptr(unsafe.Pointer(&hbitmap)),
uintptr(background))
if ret != Ok {
return 0, errors.New(fmt.Sprintf("GdipCreateHBITMAPFromBitmap failed with status '%s'", GetGpStatus(int32(ret))))
}
return hbitmap, nil
}
func GdipDisposeImage(image *uintptr) {
procGdipDisposeImage.Call(uintptr(unsafe.Pointer(image)))
}
func GdiplusShutdown() {
procGdiplusShutdown.Call(token)
}
func GdiplusStartup(input *GdiplusStartupInput, output *GdiplusStartupOutput) {
ret, _, _ := procGdiplusStartup.Call(
uintptr(unsafe.Pointer(&token)),
uintptr(unsafe.Pointer(input)),
uintptr(unsafe.Pointer(output)))
if ret != Ok {
panic("GdiplusStartup failed with status " + GetGpStatus(int32(ret)))
}
}

43
vendor/github.com/apenwarr/w32/idispatch.go generated vendored Normal file
View file

@ -0,0 +1,43 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"unsafe"
)
type pIDispatchVtbl struct {
pQueryInterface uintptr
pAddRef uintptr
pRelease uintptr
pGetTypeInfoCount uintptr
pGetTypeInfo uintptr
pGetIDsOfNames uintptr
pInvoke uintptr
}
type IDispatch struct {
lpVtbl *pIDispatchVtbl
}
func (this *IDispatch) QueryInterface(id *GUID) *IDispatch {
return ComQueryInterface((*IUnknown)(unsafe.Pointer(this)), id)
}
func (this *IDispatch) AddRef() int32 {
return ComAddRef((*IUnknown)(unsafe.Pointer(this)))
}
func (this *IDispatch) Release() int32 {
return ComRelease((*IUnknown)(unsafe.Pointer(this)))
}
func (this *IDispatch) GetIDsOfName(names []string) []int32 {
return ComGetIDsOfName(this, names)
}
func (this *IDispatch) Invoke(dispid int32, dispatch int16, params ...interface{}) *VARIANT {
return ComInvoke(this, dispid, dispatch, params...)
}

31
vendor/github.com/apenwarr/w32/istream.go generated vendored Normal file
View file

@ -0,0 +1,31 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"unsafe"
)
type pIStreamVtbl struct {
pQueryInterface uintptr
pAddRef uintptr
pRelease uintptr
}
type IStream struct {
lpVtbl *pIStreamVtbl
}
func (this *IStream) QueryInterface(id *GUID) *IDispatch {
return ComQueryInterface((*IUnknown)(unsafe.Pointer(this)), id)
}
func (this *IStream) AddRef() int32 {
return ComAddRef((*IUnknown)(unsafe.Pointer(this)))
}
func (this *IStream) Release() int32 {
return ComRelease((*IUnknown)(unsafe.Pointer(this)))
}

27
vendor/github.com/apenwarr/w32/iunknown.go generated vendored Normal file
View file

@ -0,0 +1,27 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
type pIUnknownVtbl struct {
pQueryInterface uintptr
pAddRef uintptr
pRelease uintptr
}
type IUnknown struct {
lpVtbl *pIUnknownVtbl
}
func (this *IUnknown) QueryInterface(id *GUID) *IDispatch {
return ComQueryInterface(this, id)
}
func (this *IUnknown) AddRef() int32 {
return ComAddRef(this)
}
func (this *IUnknown) Release() int32 {
return ComRelease(this)
}

388
vendor/github.com/apenwarr/w32/kernel32.go generated vendored Normal file
View file

@ -0,0 +1,388 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"syscall"
"unsafe"
)
var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetModuleHandle = modkernel32.NewProc("GetModuleHandleW")
procMulDiv = modkernel32.NewProc("MulDiv")
procGetConsoleWindow = modkernel32.NewProc("GetConsoleWindow")
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
procGetLogicalDrives = modkernel32.NewProc("GetLogicalDrives")
procGetUserDefaultLCID = modkernel32.NewProc("GetUserDefaultLCID")
procLstrlen = modkernel32.NewProc("lstrlenW")
procLstrcpy = modkernel32.NewProc("lstrcpyW")
procGlobalAlloc = modkernel32.NewProc("GlobalAlloc")
procGlobalFree = modkernel32.NewProc("GlobalFree")
procGlobalLock = modkernel32.NewProc("GlobalLock")
procGlobalUnlock = modkernel32.NewProc("GlobalUnlock")
procMoveMemory = modkernel32.NewProc("RtlMoveMemory")
procFindResource = modkernel32.NewProc("FindResourceW")
procSizeofResource = modkernel32.NewProc("SizeofResource")
procLockResource = modkernel32.NewProc("LockResource")
procLoadResource = modkernel32.NewProc("LoadResource")
procGetLastError = modkernel32.NewProc("GetLastError")
// procOpenProcess = modkernel32.NewProc("OpenProcess")
// procTerminateProcess = modkernel32.NewProc("TerminateProcess")
procCloseHandle = modkernel32.NewProc("CloseHandle")
procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot")
procModule32First = modkernel32.NewProc("Module32FirstW")
procModule32Next = modkernel32.NewProc("Module32NextW")
procGetSystemTimes = modkernel32.NewProc("GetSystemTimes")
procGetConsoleScreenBufferInfo = modkernel32.NewProc("GetConsoleScreenBufferInfo")
procSetConsoleTextAttribute = modkernel32.NewProc("SetConsoleTextAttribute")
procGetDiskFreeSpaceEx = modkernel32.NewProc("GetDiskFreeSpaceExW")
procGetProcessTimes = modkernel32.NewProc("GetProcessTimes")
procSetSystemTime = modkernel32.NewProc("SetSystemTime")
procGetSystemTime = modkernel32.NewProc("GetSystemTime")
procVirtualAllocEx = modkernel32.NewProc("VirtualAllocEx")
procVirtualFreeEx = modkernel32.NewProc("VirtualFreeEx")
procWriteProcessMemory = modkernel32.NewProc("WriteProcessMemory")
procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory")
procQueryPerformanceCounter = modkernel32.NewProc("QueryPerformanceCounter")
procQueryPerformanceFrequency = modkernel32.NewProc("QueryPerformanceFrequency")
)
func GetModuleHandle(modulename string) HINSTANCE {
var mn uintptr
if modulename == "" {
mn = 0
} else {
mn = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(modulename)))
}
ret, _, _ := procGetModuleHandle.Call(mn)
return HINSTANCE(ret)
}
func MulDiv(number, numerator, denominator int) int {
ret, _, _ := procMulDiv.Call(
uintptr(number),
uintptr(numerator),
uintptr(denominator))
return int(ret)
}
func GetConsoleWindow() HWND {
ret, _, _ := procGetConsoleWindow.Call()
return HWND(ret)
}
func GetCurrentThread() HANDLE {
ret, _, _ := procGetCurrentThread.Call()
return HANDLE(ret)
}
func GetLogicalDrives() uint32 {
ret, _, _ := procGetLogicalDrives.Call()
return uint32(ret)
}
func GetUserDefaultLCID() uint32 {
ret, _, _ := procGetUserDefaultLCID.Call()
return uint32(ret)
}
func Lstrlen(lpString *uint16) int {
ret, _, _ := procLstrlen.Call(uintptr(unsafe.Pointer(lpString)))
return int(ret)
}
func Lstrcpy(buf []uint16, lpString *uint16) {
procLstrcpy.Call(
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(lpString)))
}
func GlobalAlloc(uFlags uint, dwBytes uint32) HGLOBAL {
ret, _, _ := procGlobalAlloc.Call(
uintptr(uFlags),
uintptr(dwBytes))
if ret == 0 {
panic("GlobalAlloc failed")
}
return HGLOBAL(ret)
}
func GlobalFree(hMem HGLOBAL) {
ret, _, _ := procGlobalFree.Call(uintptr(hMem))
if ret != 0 {
panic("GlobalFree failed")
}
}
func GlobalLock(hMem HGLOBAL) unsafe.Pointer {
ret, _, _ := procGlobalLock.Call(uintptr(hMem))
if ret == 0 {
panic("GlobalLock failed")
}
return unsafe.Pointer(ret)
}
func GlobalUnlock(hMem HGLOBAL) bool {
ret, _, _ := procGlobalUnlock.Call(uintptr(hMem))
return ret != 0
}
func MoveMemory(destination, source unsafe.Pointer, length uint32) {
procMoveMemory.Call(
uintptr(unsafe.Pointer(destination)),
uintptr(source),
uintptr(length))
}
func FindResource(hModule HMODULE, lpName, lpType *uint16) (HRSRC, error) {
ret, _, _ := procFindResource.Call(
uintptr(hModule),
uintptr(unsafe.Pointer(lpName)),
uintptr(unsafe.Pointer(lpType)))
if ret == 0 {
return 0, syscall.GetLastError()
}
return HRSRC(ret), nil
}
func SizeofResource(hModule HMODULE, hResInfo HRSRC) uint32 {
ret, _, _ := procSizeofResource.Call(
uintptr(hModule),
uintptr(hResInfo))
if ret == 0 {
panic("SizeofResource failed")
}
return uint32(ret)
}
func LockResource(hResData HGLOBAL) unsafe.Pointer {
ret, _, _ := procLockResource.Call(uintptr(hResData))
if ret == 0 {
panic("LockResource failed")
}
return unsafe.Pointer(ret)
}
func LoadResource(hModule HMODULE, hResInfo HRSRC) HGLOBAL {
ret, _, _ := procLoadResource.Call(
uintptr(hModule),
uintptr(hResInfo))
if ret == 0 {
panic("LoadResource failed")
}
return HGLOBAL(ret)
}
func GetLastError() uint32 {
ret, _, _ := procGetLastError.Call()
return uint32(ret)
}
// func OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) HANDLE {
// inherit := 0
// if inheritHandle {
// inherit = 1
// }
// ret, _, _ := procOpenProcess.Call(
// uintptr(desiredAccess),
// uintptr(inherit),
// uintptr(processId))
// return HANDLE(ret)
// }
// func TerminateProcess(hProcess HANDLE, uExitCode uint) bool {
// ret, _, _ := procTerminateProcess.Call(
// uintptr(hProcess),
// uintptr(uExitCode))
// return ret != 0
// }
func CloseHandle(object HANDLE) bool {
ret, _, _ := procCloseHandle.Call(
uintptr(object))
return ret != 0
}
func CreateToolhelp32Snapshot(flags, processId uint32) HANDLE {
ret, _, _ := procCreateToolhelp32Snapshot.Call(
uintptr(flags),
uintptr(processId))
if ret <= 0 {
return HANDLE(0)
}
return HANDLE(ret)
}
func Module32First(snapshot HANDLE, me *MODULEENTRY32) bool {
ret, _, _ := procModule32First.Call(
uintptr(snapshot),
uintptr(unsafe.Pointer(me)))
return ret != 0
}
func Module32Next(snapshot HANDLE, me *MODULEENTRY32) bool {
ret, _, _ := procModule32Next.Call(
uintptr(snapshot),
uintptr(unsafe.Pointer(me)))
return ret != 0
}
func GetSystemTimes(lpIdleTime, lpKernelTime, lpUserTime *FILETIME) bool {
ret, _, _ := procGetSystemTimes.Call(
uintptr(unsafe.Pointer(lpIdleTime)),
uintptr(unsafe.Pointer(lpKernelTime)),
uintptr(unsafe.Pointer(lpUserTime)))
return ret != 0
}
func GetProcessTimes(hProcess HANDLE, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime *FILETIME) bool {
ret, _, _ := procGetProcessTimes.Call(
uintptr(hProcess),
uintptr(unsafe.Pointer(lpCreationTime)),
uintptr(unsafe.Pointer(lpExitTime)),
uintptr(unsafe.Pointer(lpKernelTime)),
uintptr(unsafe.Pointer(lpUserTime)))
return ret != 0
}
func GetConsoleScreenBufferInfo(hConsoleOutput HANDLE) *CONSOLE_SCREEN_BUFFER_INFO {
var csbi CONSOLE_SCREEN_BUFFER_INFO
ret, _, _ := procGetConsoleScreenBufferInfo.Call(
uintptr(hConsoleOutput),
uintptr(unsafe.Pointer(&csbi)))
if ret == 0 {
return nil
}
return &csbi
}
func SetConsoleTextAttribute(hConsoleOutput HANDLE, wAttributes uint16) bool {
ret, _, _ := procSetConsoleTextAttribute.Call(
uintptr(hConsoleOutput),
uintptr(wAttributes))
return ret != 0
}
func GetDiskFreeSpaceEx(dirName string) (r bool,
freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes uint64) {
ret, _, _ := procGetDiskFreeSpaceEx.Call(
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(dirName))),
uintptr(unsafe.Pointer(&freeBytesAvailable)),
uintptr(unsafe.Pointer(&totalNumberOfBytes)),
uintptr(unsafe.Pointer(&totalNumberOfFreeBytes)))
return ret != 0,
freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes
}
func GetSystemTime() *SYSTEMTIME {
var time SYSTEMTIME
procGetSystemTime.Call(
uintptr(unsafe.Pointer(&time)))
return &time
}
func SetSystemTime(time *SYSTEMTIME) bool {
ret, _, _ := procSetSystemTime.Call(
uintptr(unsafe.Pointer(time)))
return ret != 0
}
func VirtualAllocEx(hProcess HANDLE, lpAddress, dwSize uintptr, flAllocationType, flProtect uint32) uintptr {
ret, _, _ := procVirtualAllocEx.Call(
uintptr(hProcess),
lpAddress,
dwSize,
uintptr(flAllocationType),
uintptr(flProtect),
)
return ret
}
func VirtualFreeEx(hProcess HANDLE, lpAddress, dwSize uintptr, dwFreeType uint32) bool {
ret, _, _ := procVirtualFreeEx.Call(
uintptr(hProcess),
lpAddress,
dwSize,
uintptr(dwFreeType),
)
return ret != 0
}
func WriteProcessMemory(hProcess HANDLE, lpBaseAddress, lpBuffer, nSize uintptr) (int, bool) {
var nBytesWritten int
ret, _, _ := procWriteProcessMemory.Call(
uintptr(hProcess),
lpBaseAddress,
lpBuffer,
nSize,
uintptr(unsafe.Pointer(&nBytesWritten)),
)
return nBytesWritten, ret != 0
}
func ReadProcessMemory(hProcess HANDLE, lpBaseAddress, nSize uintptr) (lpBuffer []uint16, lpNumberOfBytesRead int, ok bool) {
var nBytesRead int
buf := make([]uint16, nSize)
ret, _, _ := procReadProcessMemory.Call(
uintptr(hProcess),
lpBaseAddress,
uintptr(unsafe.Pointer(&buf[0])),
nSize,
uintptr(unsafe.Pointer(&nBytesRead)),
)
return buf, nBytesRead, ret != 0
}
func QueryPerformanceCounter() uint64 {
result := uint64(0)
procQueryPerformanceCounter.Call(
uintptr(unsafe.Pointer(&result)),
)
return result
}
func QueryPerformanceFrequency() uint64 {
result := uint64(0)
procQueryPerformanceFrequency.Call(
uintptr(unsafe.Pointer(&result)),
)
return result
}

63
vendor/github.com/apenwarr/w32/ole32.go generated vendored Normal file
View file

@ -0,0 +1,63 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"syscall"
"unsafe"
)
var (
modole32 = syscall.NewLazyDLL("ole32.dll")
procCoInitializeEx = modole32.NewProc("CoInitializeEx")
procCoInitialize = modole32.NewProc("CoInitialize")
procCoUninitialize = modole32.NewProc("CoUninitialize")
procCreateStreamOnHGlobal = modole32.NewProc("CreateStreamOnHGlobal")
)
func CoInitializeEx(coInit uintptr) HRESULT {
ret, _, _ := procCoInitializeEx.Call(
0,
coInit)
switch uint32(ret) {
case E_INVALIDARG:
panic("CoInitializeEx failed with E_INVALIDARG")
case E_OUTOFMEMORY:
panic("CoInitializeEx failed with E_OUTOFMEMORY")
case E_UNEXPECTED:
panic("CoInitializeEx failed with E_UNEXPECTED")
}
return HRESULT(ret)
}
func CoInitialize() {
procCoInitialize.Call(0)
}
func CoUninitialize() {
procCoUninitialize.Call()
}
func CreateStreamOnHGlobal(hGlobal HGLOBAL, fDeleteOnRelease bool) *IStream {
stream := new(IStream)
ret, _, _ := procCreateStreamOnHGlobal.Call(
uintptr(hGlobal),
uintptr(BoolToBOOL(fDeleteOnRelease)),
uintptr(unsafe.Pointer(&stream)))
switch uint32(ret) {
case E_INVALIDARG:
panic("CreateStreamOnHGlobal failed with E_INVALIDARG")
case E_OUTOFMEMORY:
panic("CreateStreamOnHGlobal failed with E_OUTOFMEMORY")
case E_UNEXPECTED:
panic("CreateStreamOnHGlobal failed with E_UNEXPECTED")
}
return stream
}

48
vendor/github.com/apenwarr/w32/oleaut32.go generated vendored Normal file
View file

@ -0,0 +1,48 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"syscall"
"unsafe"
)
var (
modoleaut32 = syscall.NewLazyDLL("oleaut32")
procVariantInit = modoleaut32.NewProc("VariantInit")
procSysAllocString = modoleaut32.NewProc("SysAllocString")
procSysFreeString = modoleaut32.NewProc("SysFreeString")
procSysStringLen = modoleaut32.NewProc("SysStringLen")
procCreateDispTypeInfo = modoleaut32.NewProc("CreateDispTypeInfo")
procCreateStdDispatch = modoleaut32.NewProc("CreateStdDispatch")
)
func VariantInit(v *VARIANT) {
hr, _, _ := procVariantInit.Call(uintptr(unsafe.Pointer(v)))
if hr != 0 {
panic("Invoke VariantInit error.")
}
return
}
func SysAllocString(v string) (ss *int16) {
pss, _, _ := procSysAllocString.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(v))))
ss = (*int16)(unsafe.Pointer(pss))
return
}
func SysFreeString(v *int16) {
hr, _, _ := procSysFreeString.Call(uintptr(unsafe.Pointer(v)))
if hr != 0 {
panic("Invoke SysFreeString error.")
}
return
}
func SysStringLen(v *int16) uint {
l, _, _ := procSysStringLen.Call(uintptr(unsafe.Pointer(v)))
return uint(l)
}

72
vendor/github.com/apenwarr/w32/opengl32.go generated vendored Normal file
View file

@ -0,0 +1,72 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"syscall"
"unsafe"
)
var (
modopengl32 = syscall.NewLazyDLL("opengl32.dll")
procwglCreateContext = modopengl32.NewProc("wglCreateContext")
procwglCreateLayerContext = modopengl32.NewProc("wglCreateLayerContext")
procwglDeleteContext = modopengl32.NewProc("wglDeleteContext")
procwglGetProcAddress = modopengl32.NewProc("wglGetProcAddress")
procwglMakeCurrent = modopengl32.NewProc("wglMakeCurrent")
procwglShareLists = modopengl32.NewProc("wglShareLists")
)
func WglCreateContext(hdc HDC) HGLRC {
ret, _, _ := procwglCreateContext.Call(
uintptr(hdc),
)
return HGLRC(ret)
}
func WglCreateLayerContext(hdc HDC, iLayerPlane int) HGLRC {
ret, _, _ := procwglCreateLayerContext.Call(
uintptr(hdc),
uintptr(iLayerPlane),
)
return HGLRC(ret)
}
func WglDeleteContext(hglrc HGLRC) bool {
ret, _, _ := procwglDeleteContext.Call(
uintptr(hglrc),
)
return ret == TRUE
}
func WglGetProcAddress(szProc string) uintptr {
ret, _, _ := procwglGetProcAddress.Call(
uintptr(unsafe.Pointer(syscall.StringBytePtr(szProc))),
)
return ret
}
func WglMakeCurrent(hdc HDC, hglrc HGLRC) bool {
ret, _, _ := procwglMakeCurrent.Call(
uintptr(hdc),
uintptr(hglrc),
)
return ret == TRUE
}
func WglShareLists(hglrc1, hglrc2 HGLRC) bool {
ret, _, _ := procwglShareLists.Call(
uintptr(hglrc1),
uintptr(hglrc2),
)
return ret == TRUE
}

25
vendor/github.com/apenwarr/w32/psapi.go generated vendored Normal file
View file

@ -0,0 +1,25 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"syscall"
"unsafe"
)
var (
modpsapi = syscall.NewLazyDLL("psapi.dll")
procEnumProcesses = modpsapi.NewProc("EnumProcesses")
)
func EnumProcesses(processIds []uint32, cb uint32, bytesReturned *uint32) bool {
ret, _, _ := procEnumProcesses.Call(
uintptr(unsafe.Pointer(&processIds[0])),
uintptr(cb),
uintptr(unsafe.Pointer(bytesReturned)))
return ret != 0
}

153
vendor/github.com/apenwarr/w32/shell32.go generated vendored Normal file
View file

@ -0,0 +1,153 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"errors"
"fmt"
"syscall"
"unsafe"
)
var (
modshell32 = syscall.NewLazyDLL("shell32.dll")
procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolderW")
procSHGetPathFromIDList = modshell32.NewProc("SHGetPathFromIDListW")
procDragAcceptFiles = modshell32.NewProc("DragAcceptFiles")
procDragQueryFile = modshell32.NewProc("DragQueryFileW")
procDragQueryPoint = modshell32.NewProc("DragQueryPoint")
procDragFinish = modshell32.NewProc("DragFinish")
procShellExecute = modshell32.NewProc("ShellExecuteW")
procExtractIcon = modshell32.NewProc("ExtractIconW")
)
func SHBrowseForFolder(bi *BROWSEINFO) uintptr {
ret, _, _ := procSHBrowseForFolder.Call(uintptr(unsafe.Pointer(bi)))
return ret
}
func SHGetPathFromIDList(idl uintptr) string {
buf := make([]uint16, 1024)
procSHGetPathFromIDList.Call(
idl,
uintptr(unsafe.Pointer(&buf[0])))
return syscall.UTF16ToString(buf)
}
func DragAcceptFiles(hwnd HWND, accept bool) {
procDragAcceptFiles.Call(
uintptr(hwnd),
uintptr(BoolToBOOL(accept)))
}
func DragQueryFile(hDrop HDROP, iFile uint) (fileName string, fileCount uint) {
ret, _, _ := procDragQueryFile.Call(
uintptr(hDrop),
uintptr(iFile),
0,
0)
fileCount = uint(ret)
if iFile != 0xFFFFFFFF {
buf := make([]uint16, fileCount+1)
ret, _, _ := procDragQueryFile.Call(
uintptr(hDrop),
uintptr(iFile),
uintptr(unsafe.Pointer(&buf[0])),
uintptr(fileCount+1))
if ret == 0 {
panic("Invoke DragQueryFile error.")
}
fileName = syscall.UTF16ToString(buf)
}
return
}
func DragQueryPoint(hDrop HDROP) (x, y int, isClientArea bool) {
var pt POINT
ret, _, _ := procDragQueryPoint.Call(
uintptr(hDrop),
uintptr(unsafe.Pointer(&pt)))
return int(pt.X), int(pt.Y), (ret == 1)
}
func DragFinish(hDrop HDROP) {
procDragFinish.Call(uintptr(hDrop))
}
func ShellExecute(hwnd HWND, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error {
var op, param, directory uintptr
if len(lpOperation) != 0 {
op = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpOperation)))
}
if len(lpParameters) != 0 {
param = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpParameters)))
}
if len(lpDirectory) != 0 {
directory = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDirectory)))
}
ret, _, _ := procShellExecute.Call(
uintptr(hwnd),
op,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpFile))),
param,
directory,
uintptr(nShowCmd))
errorMsg := ""
if ret != 0 && ret <= 32 {
switch int(ret) {
case ERROR_FILE_NOT_FOUND:
errorMsg = "The specified file was not found."
case ERROR_PATH_NOT_FOUND:
errorMsg = "The specified path was not found."
case ERROR_BAD_FORMAT:
errorMsg = "The .exe file is invalid (non-Win32 .exe or error in .exe image)."
case SE_ERR_ACCESSDENIED:
errorMsg = "The operating system denied access to the specified file."
case SE_ERR_ASSOCINCOMPLETE:
errorMsg = "The file name association is incomplete or invalid."
case SE_ERR_DDEBUSY:
errorMsg = "The DDE transaction could not be completed because other DDE transactions were being processed."
case SE_ERR_DDEFAIL:
errorMsg = "The DDE transaction failed."
case SE_ERR_DDETIMEOUT:
errorMsg = "The DDE transaction could not be completed because the request timed out."
case SE_ERR_DLLNOTFOUND:
errorMsg = "The specified DLL was not found."
case SE_ERR_NOASSOC:
errorMsg = "There is no application associated with the given file name extension. This error will also be returned if you attempt to print a file that is not printable."
case SE_ERR_OOM:
errorMsg = "There was not enough memory to complete the operation."
case SE_ERR_SHARE:
errorMsg = "A sharing violation occurred."
default:
errorMsg = fmt.Sprintf("Unknown error occurred with error code %v", ret)
}
} else {
return nil
}
return errors.New(errorMsg)
}
func ExtractIcon(lpszExeFileName string, nIconIndex int) HICON {
ret, _, _ := procExtractIcon.Call(
0,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpszExeFileName))),
uintptr(nIconIndex))
return HICON(ret)
}

891
vendor/github.com/apenwarr/w32/typedef.go generated vendored Normal file
View file

@ -0,0 +1,891 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"unsafe"
)
// From MSDN: Windows Data Types
// http://msdn.microsoft.com/en-us/library/s3f49ktz.aspx
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751.aspx
// ATOM WORD
// BOOL int32
// BOOLEAN byte
// BYTE byte
// CCHAR int8
// CHAR int8
// COLORREF DWORD
// DWORD uint32
// DWORDLONG ULONGLONG
// DWORD_PTR ULONG_PTR
// DWORD32 uint32
// DWORD64 uint64
// FLOAT float32
// HACCEL HANDLE
// HALF_PTR struct{} // ???
// HANDLE PVOID
// HBITMAP HANDLE
// HBRUSH HANDLE
// HCOLORSPACE HANDLE
// HCONV HANDLE
// HCONVLIST HANDLE
// HCURSOR HANDLE
// HDC HANDLE
// HDDEDATA HANDLE
// HDESK HANDLE
// HDROP HANDLE
// HDWP HANDLE
// HENHMETAFILE HANDLE
// HFILE HANDLE
// HFONT HANDLE
// HGDIOBJ HANDLE
// HGLOBAL HANDLE
// HHOOK HANDLE
// HICON HANDLE
// HINSTANCE HANDLE
// HKEY HANDLE
// HKL HANDLE
// HLOCAL HANDLE
// HMENU HANDLE
// HMETAFILE HANDLE
// HMODULE HANDLE
// HPALETTE HANDLE
// HPEN HANDLE
// HRESULT int32
// HRGN HANDLE
// HSZ HANDLE
// HWINSTA HANDLE
// HWND HANDLE
// INT int32
// INT_PTR uintptr
// INT8 int8
// INT16 int16
// INT32 int32
// INT64 int64
// LANGID WORD
// LCID DWORD
// LCTYPE DWORD
// LGRPID DWORD
// LONG int32
// LONGLONG int64
// LONG_PTR uintptr
// LONG32 int32
// LONG64 int64
// LPARAM LONG_PTR
// LPBOOL *BOOL
// LPBYTE *BYTE
// LPCOLORREF *COLORREF
// LPCSTR *int8
// LPCTSTR LPCWSTR
// LPCVOID unsafe.Pointer
// LPCWSTR *WCHAR
// LPDWORD *DWORD
// LPHANDLE *HANDLE
// LPINT *INT
// LPLONG *LONG
// LPSTR *CHAR
// LPTSTR LPWSTR
// LPVOID unsafe.Pointer
// LPWORD *WORD
// LPWSTR *WCHAR
// LRESULT LONG_PTR
// PBOOL *BOOL
// PBOOLEAN *BOOLEAN
// PBYTE *BYTE
// PCHAR *CHAR
// PCSTR *CHAR
// PCTSTR PCWSTR
// PCWSTR *WCHAR
// PDWORD *DWORD
// PDWORDLONG *DWORDLONG
// PDWORD_PTR *DWORD_PTR
// PDWORD32 *DWORD32
// PDWORD64 *DWORD64
// PFLOAT *FLOAT
// PHALF_PTR *HALF_PTR
// PHANDLE *HANDLE
// PHKEY *HKEY
// PINT_PTR *INT_PTR
// PINT8 *INT8
// PINT16 *INT16
// PINT32 *INT32
// PINT64 *INT64
// PLCID *LCID
// PLONG *LONG
// PLONGLONG *LONGLONG
// PLONG_PTR *LONG_PTR
// PLONG32 *LONG32
// PLONG64 *LONG64
// POINTER_32 struct{} // ???
// POINTER_64 struct{} // ???
// POINTER_SIGNED uintptr
// POINTER_UNSIGNED uintptr
// PSHORT *SHORT
// PSIZE_T *SIZE_T
// PSSIZE_T *SSIZE_T
// PSTR *CHAR
// PTBYTE *TBYTE
// PTCHAR *TCHAR
// PTSTR PWSTR
// PUCHAR *UCHAR
// PUHALF_PTR *UHALF_PTR
// PUINT *UINT
// PUINT_PTR *UINT_PTR
// PUINT8 *UINT8
// PUINT16 *UINT16
// PUINT32 *UINT32
// PUINT64 *UINT64
// PULONG *ULONG
// PULONGLONG *ULONGLONG
// PULONG_PTR *ULONG_PTR
// PULONG32 *ULONG32
// PULONG64 *ULONG64
// PUSHORT *USHORT
// PVOID unsafe.Pointer
// PWCHAR *WCHAR
// PWORD *WORD
// PWSTR *WCHAR
// QWORD uint64
// SC_HANDLE HANDLE
// SC_LOCK LPVOID
// SERVICE_STATUS_HANDLE HANDLE
// SHORT int16
// SIZE_T ULONG_PTR
// SSIZE_T LONG_PTR
// TBYTE WCHAR
// TCHAR WCHAR
// UCHAR uint8
// UHALF_PTR struct{} // ???
// UINT uint32
// UINT_PTR uintptr
// UINT8 uint8
// UINT16 uint16
// UINT32 uint32
// UINT64 uint64
// ULONG uint32
// ULONGLONG uint64
// ULONG_PTR uintptr
// ULONG32 uint32
// ULONG64 uint64
// USHORT uint16
// USN LONGLONG
// WCHAR uint16
// WORD uint16
// WPARAM UINT_PTR
type (
ATOM uint16
BOOL int32
COLORREF uint32
DWM_FRAME_COUNT uint64
DWORD uint32
HACCEL HANDLE
HANDLE uintptr
HBITMAP HANDLE
HBRUSH HANDLE
HCURSOR HANDLE
HDC HANDLE
HDROP HANDLE
HDWP HANDLE
HENHMETAFILE HANDLE
HFONT HANDLE
HGDIOBJ HANDLE
HGLOBAL HANDLE
HGLRC HANDLE
HHOOK HANDLE
HICON HANDLE
HIMAGELIST HANDLE
HINSTANCE HANDLE
HKEY HANDLE
HKL HANDLE
HMENU HANDLE
HMODULE HANDLE
HMONITOR HANDLE
HPEN HANDLE
HRESULT int32
HRGN HANDLE
HRSRC HANDLE
HTHUMBNAIL HANDLE
HWND HANDLE
LPARAM uintptr
LPCVOID unsafe.Pointer
LRESULT uintptr
PVOID unsafe.Pointer
QPC_TIME uint64
ULONG_PTR uintptr
WPARAM uintptr
TRACEHANDLE uintptr
)
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162805.aspx
type POINT struct {
X, Y int32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162897.aspx
type RECT struct {
Left, Top, Right, Bottom int32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms633577.aspx
type WNDCLASSEX struct {
Size uint32
Style uint32
WndProc uintptr
ClsExtra int32
WndExtra int32
Instance HINSTANCE
Icon HICON
Cursor HCURSOR
Background HBRUSH
MenuName *uint16
ClassName *uint16
IconSm HICON
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644958.aspx
type MSG struct {
Hwnd HWND
Message uint32
WParam uintptr
LParam uintptr
Time uint32
Pt POINT
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145037.aspx
type LOGFONT struct {
Height int32
Width int32
Escapement int32
Orientation int32
Weight int32
Italic byte
Underline byte
StrikeOut byte
CharSet byte
OutPrecision byte
ClipPrecision byte
Quality byte
PitchAndFamily byte
FaceName [LF_FACESIZE]uint16
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646839.aspx
type OPENFILENAME struct {
StructSize uint32
Owner HWND
Instance HINSTANCE
Filter *uint16
CustomFilter *uint16
MaxCustomFilter uint32
FilterIndex uint32
File *uint16
MaxFile uint32
FileTitle *uint16
MaxFileTitle uint32
InitialDir *uint16
Title *uint16
Flags uint32
FileOffset uint16
FileExtension uint16
DefExt *uint16
CustData uintptr
FnHook uintptr
TemplateName *uint16
PvReserved unsafe.Pointer
DwReserved uint32
FlagsEx uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773205.aspx
type BROWSEINFO struct {
Owner HWND
Root *uint16
DisplayName *uint16
Title *uint16
Flags uint32
CallbackFunc uintptr
LParam uintptr
Image int32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931.aspx
type GUID struct {
Data1 uint32
Data2 uint16
Data3 uint16
Data4 [8]byte
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221627.aspx
type VARIANT struct {
VT uint16 // 2
WReserved1 uint16 // 4
WReserved2 uint16 // 6
WReserved3 uint16 // 8
Val int64 // 16
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221416.aspx
type DISPPARAMS struct {
Rgvarg uintptr
RgdispidNamedArgs uintptr
CArgs uint32
CNamedArgs uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221133.aspx
type EXCEPINFO struct {
WCode uint16
WReserved uint16
BstrSource *uint16
BstrDescription *uint16
BstrHelpFile *uint16
DwHelpContext uint32
PvReserved uintptr
PfnDeferredFillIn uintptr
Scode int32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145035.aspx
type LOGBRUSH struct {
LbStyle uint32
LbColor COLORREF
LbHatch uintptr
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183565.aspx
type DEVMODE struct {
DmDeviceName [CCHDEVICENAME]uint16
DmSpecVersion uint16
DmDriverVersion uint16
DmSize uint16
DmDriverExtra uint16
DmFields uint32
DmOrientation int16
DmPaperSize int16
DmPaperLength int16
DmPaperWidth int16
DmScale int16
DmCopies int16
DmDefaultSource int16
DmPrintQuality int16
DmColor int16
DmDuplex int16
DmYResolution int16
DmTTOption int16
DmCollate int16
DmFormName [CCHFORMNAME]uint16
DmLogPixels uint16
DmBitsPerPel uint32
DmPelsWidth uint32
DmPelsHeight uint32
DmDisplayFlags uint32
DmDisplayFrequency uint32
DmICMMethod uint32
DmICMIntent uint32
DmMediaType uint32
DmDitherType uint32
DmReserved1 uint32
DmReserved2 uint32
DmPanningWidth uint32
DmPanningHeight uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376.aspx
type BITMAPINFOHEADER struct {
BiSize uint32
BiWidth int32
BiHeight int32
BiPlanes uint16
BiBitCount uint16
BiCompression uint32
BiSizeImage uint32
BiXPelsPerMeter int32
BiYPelsPerMeter int32
BiClrUsed uint32
BiClrImportant uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162938.aspx
type RGBQUAD struct {
RgbBlue byte
RgbGreen byte
RgbRed byte
RgbReserved byte
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183375.aspx
type BITMAPINFO struct {
BmiHeader BITMAPINFOHEADER
BmiColors *RGBQUAD
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183371.aspx
type BITMAP struct {
BmType int32
BmWidth int32
BmHeight int32
BmWidthBytes int32
BmPlanes uint16
BmBitsPixel uint16
BmBits unsafe.Pointer
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183567.aspx
type DIBSECTION struct {
DsBm BITMAP
DsBmih BITMAPINFOHEADER
DsBitfields [3]uint32
DshSection HANDLE
DsOffset uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162607.aspx
type ENHMETAHEADER struct {
IType uint32
NSize uint32
RclBounds RECT
RclFrame RECT
DSignature uint32
NVersion uint32
NBytes uint32
NRecords uint32
NHandles uint16
SReserved uint16
NDescription uint32
OffDescription uint32
NPalEntries uint32
SzlDevice SIZE
SzlMillimeters SIZE
CbPixelFormat uint32
OffPixelFormat uint32
BOpenGL uint32
SzlMicrometers SIZE
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145106.aspx
type SIZE struct {
CX, CY int32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145132.aspx
type TEXTMETRIC struct {
TmHeight int32
TmAscent int32
TmDescent int32
TmInternalLeading int32
TmExternalLeading int32
TmAveCharWidth int32
TmMaxCharWidth int32
TmWeight int32
TmOverhang int32
TmDigitizedAspectX int32
TmDigitizedAspectY int32
TmFirstChar uint16
TmLastChar uint16
TmDefaultChar uint16
TmBreakChar uint16
TmItalic byte
TmUnderlined byte
TmStruckOut byte
TmPitchAndFamily byte
TmCharSet byte
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183574.aspx
type DOCINFO struct {
CbSize int32
LpszDocName *uint16
LpszOutput *uint16
LpszDatatype *uint16
FwType uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775514.aspx
type NMHDR struct {
HwndFrom HWND
IdFrom uintptr
Code uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774743.aspx
type LVCOLUMN struct {
Mask uint32
Fmt int32
Cx int32
PszText *uint16
CchTextMax int32
ISubItem int32
IImage int32
IOrder int32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774760.aspx
type LVITEM struct {
Mask uint32
IItem int32
ISubItem int32
State uint32
StateMask uint32
PszText *uint16
CchTextMax int32
IImage int32
LParam uintptr
IIndent int32
IGroupId int32
CColumns uint32
PuColumns uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774754.aspx
type LVHITTESTINFO struct {
Pt POINT
Flags uint32
IItem int32
ISubItem int32
IGroup int32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774771.aspx
type NMITEMACTIVATE struct {
Hdr NMHDR
IItem int32
ISubItem int32
UNewState uint32
UOldState uint32
UChanged uint32
PtAction POINT
LParam uintptr
UKeyFlags uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774773.aspx
type NMLISTVIEW struct {
Hdr NMHDR
IItem int32
ISubItem int32
UNewState uint32
UOldState uint32
UChanged uint32
PtAction POINT
LParam uintptr
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774780.aspx
type NMLVDISPINFO struct {
Hdr NMHDR
Item LVITEM
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775507.aspx
type INITCOMMONCONTROLSEX struct {
DwSize uint32
DwICC uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb760256.aspx
type TOOLINFO struct {
CbSize uint32
UFlags uint32
Hwnd HWND
UId uintptr
Rect RECT
Hinst HINSTANCE
LpszText *uint16
LParam uintptr
LpReserved unsafe.Pointer
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms645604.aspx
type TRACKMOUSEEVENT struct {
CbSize uint32
DwFlags uint32
HwndTrack HWND
DwHoverTime uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms534067.aspx
type GdiplusStartupInput struct {
GdiplusVersion uint32
DebugEventCallback uintptr
SuppressBackgroundThread BOOL
SuppressExternalCodecs BOOL
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms534068.aspx
type GdiplusStartupOutput struct {
NotificationHook uintptr
NotificationUnhook uintptr
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162768.aspx
type PAINTSTRUCT struct {
Hdc HDC
FErase BOOL
RcPaint RECT
FRestore BOOL
FIncUpdate BOOL
RgbReserved [32]byte
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms684225.aspx
type MODULEENTRY32 struct {
Size uint32
ModuleID uint32
ProcessID uint32
GlblcntUsage uint32
ProccntUsage uint32
ModBaseAddr *uint8
ModBaseSize uint32
HModule HMODULE
SzModule [MAX_MODULE_NAME32 + 1]uint16
SzExePath [MAX_PATH]uint16
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx
type FILETIME struct {
DwLowDateTime uint32
DwHighDateTime uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119.aspx
type COORD struct {
X, Y int16
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311.aspx
type SMALL_RECT struct {
Left, Top, Right, Bottom int16
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093.aspx
type CONSOLE_SCREEN_BUFFER_INFO struct {
DwSize COORD
DwCursorPosition COORD
WAttributes uint16
SrWindow SMALL_RECT
DwMaximumWindowSize COORD
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773244.aspx
type MARGINS struct {
CxLeftWidth, CxRightWidth, CyTopHeight, CyBottomHeight int32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969500.aspx
type DWM_BLURBEHIND struct {
DwFlags uint32
fEnable BOOL
hRgnBlur HRGN
fTransitionOnMaximized BOOL
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969501.aspx
type DWM_PRESENT_PARAMETERS struct {
cbSize uint32
fQueue BOOL
cRefreshStart DWM_FRAME_COUNT
cBuffer uint32
fUseSourceRate BOOL
rateSource UNSIGNED_RATIO
cRefreshesPerFrame uint32
eSampling DWM_SOURCE_FRAME_SAMPLING
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969502.aspx
type DWM_THUMBNAIL_PROPERTIES struct {
dwFlags uint32
rcDestination RECT
rcSource RECT
opacity byte
fVisible BOOL
fSourceClientAreaOnly BOOL
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969503.aspx
type DWM_TIMING_INFO struct {
cbSize uint32
rateRefresh UNSIGNED_RATIO
qpcRefreshPeriod QPC_TIME
rateCompose UNSIGNED_RATIO
qpcVBlank QPC_TIME
cRefresh DWM_FRAME_COUNT
cDXRefresh uint32
qpcCompose QPC_TIME
cFrame DWM_FRAME_COUNT
cDXPresent uint32
cRefreshFrame DWM_FRAME_COUNT
cFrameSubmitted DWM_FRAME_COUNT
cDXPresentSubmitted uint32
cFrameConfirmed DWM_FRAME_COUNT
cDXPresentConfirmed uint32
cRefreshConfirmed DWM_FRAME_COUNT
cDXRefreshConfirmed uint32
cFramesLate DWM_FRAME_COUNT
cFramesOutstanding uint32
cFrameDisplayed DWM_FRAME_COUNT
qpcFrameDisplayed QPC_TIME
cRefreshFrameDisplayed DWM_FRAME_COUNT
cFrameComplete DWM_FRAME_COUNT
qpcFrameComplete QPC_TIME
cFramePending DWM_FRAME_COUNT
qpcFramePending QPC_TIME
cFramesDisplayed DWM_FRAME_COUNT
cFramesComplete DWM_FRAME_COUNT
cFramesPending DWM_FRAME_COUNT
cFramesAvailable DWM_FRAME_COUNT
cFramesDropped DWM_FRAME_COUNT
cFramesMissed DWM_FRAME_COUNT
cRefreshNextDisplayed DWM_FRAME_COUNT
cRefreshNextPresented DWM_FRAME_COUNT
cRefreshesDisplayed DWM_FRAME_COUNT
cRefreshesPresented DWM_FRAME_COUNT
cRefreshStarted DWM_FRAME_COUNT
cPixelsReceived uint64
cPixelsDrawn uint64
cBuffersEmpty DWM_FRAME_COUNT
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd389402.aspx
type MilMatrix3x2D struct {
S_11, S_12, S_21, S_22 float64
DX, DY float64
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969505.aspx
type UNSIGNED_RATIO struct {
uiNumerator uint32
uiDenominator uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms632603.aspx
type CREATESTRUCT struct {
CreateParams uintptr
Instance HINSTANCE
Menu HMENU
Parent HWND
Cy, Cx int32
Y, X int32
Style int32
Name *uint16
Class *uint16
dwExStyle uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145065.aspx
type MONITORINFO struct {
CbSize uint32
RcMonitor RECT
RcWork RECT
DwFlags uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145066.aspx
type MONITORINFOEX struct {
MONITORINFO
SzDevice [CCHDEVICENAME]uint16
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd368826.aspx
type PIXELFORMATDESCRIPTOR struct {
Size uint16
Version uint16
DwFlags uint32
IPixelType byte
ColorBits byte
RedBits, RedShift byte
GreenBits, GreenShift byte
BlueBits, BlueShift byte
AlphaBits, AlphaShift byte
AccumBits byte
AccumRedBits byte
AccumGreenBits byte
AccumBlueBits byte
AccumAlphaBits byte
DepthBits, StencilBits byte
AuxBuffers byte
ILayerType byte
Reserved byte
DwLayerMask uint32
DwVisibleMask uint32
DwDamageMask uint32
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
type INPUT struct {
Type uint32
Mi MOUSEINPUT
Ki KEYBDINPUT
Hi HARDWAREINPUT
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646273(v=vs.85).aspx
type MOUSEINPUT struct {
Dx int32
Dy int32
MouseData uint32
DwFlags uint32
Time uint32
DwExtraInfo uintptr
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646271(v=vs.85).aspx
type KEYBDINPUT struct {
WVk uint16
WScan uint16
DwFlags uint32
Time uint32
DwExtraInfo uintptr
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646269(v=vs.85).aspx
type HARDWAREINPUT struct {
UMsg uint32
WParamL uint16
WParamH uint16
}
type KbdInput struct {
typ uint32
ki KEYBDINPUT
}
type MouseInput struct {
typ uint32
mi MOUSEINPUT
}
type HardwareInput struct {
typ uint32
hi HARDWAREINPUT
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
type SYSTEMTIME struct {
Year uint16
Month uint16
DayOfWeek uint16
Day uint16
Hour uint16
Minute uint16
Second uint16
Milliseconds uint16
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644967(v=vs.85).aspx
type KBDLLHOOKSTRUCT struct {
VkCode DWORD
ScanCode DWORD
Flags DWORD
Time DWORD
DwExtraInfo ULONG_PTR
}
type HOOKPROC func(int, WPARAM, LPARAM) LRESULT
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms633498(v=vs.85).aspx
type WNDENUMPROC func(HWND, LPARAM) LRESULT

1046
vendor/github.com/apenwarr/w32/user32.go generated vendored Normal file

File diff suppressed because it is too large Load diff

201
vendor/github.com/apenwarr/w32/utils.go generated vendored Normal file
View file

@ -0,0 +1,201 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
import (
"syscall"
"unicode/utf16"
"unsafe"
)
func MakeIntResource(id uint16) *uint16 {
return (*uint16)(unsafe.Pointer(uintptr(id)))
}
func LOWORD(dw uint32) uint16 {
return uint16(dw)
}
func HIWORD(dw uint32) uint16 {
return uint16(dw >> 16 & 0xffff)
}
func BoolToBOOL(value bool) BOOL {
if value {
return 1
}
return 0
}
func UTF16PtrToString(cstr *uint16) string {
if cstr != nil {
us := make([]uint16, 0, 256)
for p := uintptr(unsafe.Pointer(cstr)); ; p += 2 {
u := *(*uint16)(unsafe.Pointer(p))
if u == 0 {
return string(utf16.Decode(us))
}
us = append(us, u)
}
}
return ""
}
func ComAddRef(unknown *IUnknown) int32 {
ret, _, _ := syscall.Syscall(unknown.lpVtbl.pAddRef, 1,
uintptr(unsafe.Pointer(unknown)),
0,
0)
return int32(ret)
}
func ComRelease(unknown *IUnknown) int32 {
ret, _, _ := syscall.Syscall(unknown.lpVtbl.pRelease, 1,
uintptr(unsafe.Pointer(unknown)),
0,
0)
return int32(ret)
}
func ComQueryInterface(unknown *IUnknown, id *GUID) *IDispatch {
var disp *IDispatch
hr, _, _ := syscall.Syscall(unknown.lpVtbl.pQueryInterface, 3,
uintptr(unsafe.Pointer(unknown)),
uintptr(unsafe.Pointer(id)),
uintptr(unsafe.Pointer(&disp)))
if hr != 0 {
panic("Invoke QieryInterface error.")
}
return disp
}
func ComGetIDsOfName(disp *IDispatch, names []string) []int32 {
wnames := make([]*uint16, len(names))
dispid := make([]int32, len(names))
for i := 0; i < len(names); i++ {
wnames[i] = syscall.StringToUTF16Ptr(names[i])
}
hr, _, _ := syscall.Syscall6(disp.lpVtbl.pGetIDsOfNames, 6,
uintptr(unsafe.Pointer(disp)),
uintptr(unsafe.Pointer(IID_NULL)),
uintptr(unsafe.Pointer(&wnames[0])),
uintptr(len(names)),
uintptr(GetUserDefaultLCID()),
uintptr(unsafe.Pointer(&dispid[0])))
if hr != 0 {
panic("Invoke GetIDsOfName error.")
}
return dispid
}
func ComInvoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{}) (result *VARIANT) {
var dispparams DISPPARAMS
if dispatch&DISPATCH_PROPERTYPUT != 0 {
dispnames := [1]int32{DISPID_PROPERTYPUT}
dispparams.RgdispidNamedArgs = uintptr(unsafe.Pointer(&dispnames[0]))
dispparams.CNamedArgs = 1
}
var vargs []VARIANT
if len(params) > 0 {
vargs = make([]VARIANT, len(params))
for i, v := range params {
//n := len(params)-i-1
n := len(params) - i - 1
VariantInit(&vargs[n])
switch v.(type) {
case bool:
if v.(bool) {
vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0xffff}
} else {
vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0}
}
case *bool:
vargs[n] = VARIANT{VT_BOOL | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*bool))))}
case byte:
vargs[n] = VARIANT{VT_I1, 0, 0, 0, int64(v.(byte))}
case *byte:
vargs[n] = VARIANT{VT_I1 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*byte))))}
case int16:
vargs[n] = VARIANT{VT_I2, 0, 0, 0, int64(v.(int16))}
case *int16:
vargs[n] = VARIANT{VT_I2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int16))))}
case uint16:
vargs[n] = VARIANT{VT_UI2, 0, 0, 0, int64(v.(int16))}
case *uint16:
vargs[n] = VARIANT{VT_UI2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint16))))}
case int, int32:
vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(int))}
case *int, *int32:
vargs[n] = VARIANT{VT_I4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int))))}
case uint, uint32:
vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(uint))}
case *uint, *uint32:
vargs[n] = VARIANT{VT_UI4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint))))}
case int64:
vargs[n] = VARIANT{VT_I8, 0, 0, 0, v.(int64)}
case *int64:
vargs[n] = VARIANT{VT_I8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int64))))}
case uint64:
vargs[n] = VARIANT{VT_UI8, 0, 0, 0, int64(v.(uint64))}
case *uint64:
vargs[n] = VARIANT{VT_UI8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint64))))}
case float32:
vargs[n] = VARIANT{VT_R4, 0, 0, 0, int64(v.(float32))}
case *float32:
vargs[n] = VARIANT{VT_R4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float32))))}
case float64:
vargs[n] = VARIANT{VT_R8, 0, 0, 0, int64(v.(float64))}
case *float64:
vargs[n] = VARIANT{VT_R8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float64))))}
case string:
vargs[n] = VARIANT{VT_BSTR, 0, 0, 0, int64(uintptr(unsafe.Pointer(SysAllocString(v.(string)))))}
case *string:
vargs[n] = VARIANT{VT_BSTR | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*string))))}
case *IDispatch:
vargs[n] = VARIANT{VT_DISPATCH, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*IDispatch))))}
case **IDispatch:
vargs[n] = VARIANT{VT_DISPATCH | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(**IDispatch))))}
case nil:
vargs[n] = VARIANT{VT_NULL, 0, 0, 0, 0}
case *VARIANT:
vargs[n] = VARIANT{VT_VARIANT | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*VARIANT))))}
default:
panic("unknown type")
}
}
dispparams.Rgvarg = uintptr(unsafe.Pointer(&vargs[0]))
dispparams.CArgs = uint32(len(params))
}
var ret VARIANT
var excepInfo EXCEPINFO
VariantInit(&ret)
hr, _, _ := syscall.Syscall9(disp.lpVtbl.pInvoke, 8,
uintptr(unsafe.Pointer(disp)),
uintptr(dispid),
uintptr(unsafe.Pointer(IID_NULL)),
uintptr(GetUserDefaultLCID()),
uintptr(dispatch),
uintptr(unsafe.Pointer(&dispparams)),
uintptr(unsafe.Pointer(&ret)),
uintptr(unsafe.Pointer(&excepInfo)),
0)
if hr != 0 {
if excepInfo.BstrDescription != nil {
bs := UTF16PtrToString(excepInfo.BstrDescription)
panic(bs)
}
}
for _, varg := range vargs {
if varg.VT == VT_BSTR && varg.Val != 0 {
SysFreeString(((*int16)(unsafe.Pointer(uintptr(varg.Val)))))
}
}
result = &ret
return
}

13
vendor/github.com/apenwarr/w32/vars.go generated vendored Normal file
View file

@ -0,0 +1,13 @@
// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package w32
var (
IID_NULL = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
IID_IUnknown = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}
IID_IDispatch = &GUID{0x00020400, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}
IID_IConnectionPointContainer = &GUID{0xB196B284, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}
IID_IConnectionPoint = &GUID{0xB196B286, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}
)

3
vendor/github.com/go-chi/chi/v5/.gitignore generated vendored Normal file
View file

@ -0,0 +1,3 @@
.idea
*.sw?
.vscode

279
vendor/github.com/go-chi/chi/v5/CHANGELOG.md generated vendored Normal file
View file

@ -0,0 +1,279 @@
# Changelog
## v5.0.0 (2021-02-27)
- chi v5, `github.com/go-chi/chi/v5` introduces the adoption of Go's SIV to adhere to the current state-of-the-tools in Go.
- chi v1.5.x did not work out as planned, as the Go tooling is too powerful and chi's adoption is too wide.
The most responsible thing to do for everyone's benefit is to just release v5 with SIV, so I present to you all,
chi v5 at `github.com/go-chi/chi/v5`. I hope someday the developer experience and ergonomics I've been seeking
will still come to fruition in some form, see https://github.com/golang/go/issues/44550
- History of changes: see https://github.com/go-chi/chi/compare/v1.5.4...v5.0.0
## v1.5.4 (2021-02-27)
- Undo prior retraction in v1.5.3 as we prepare for v5.0.0 release
- History of changes: see https://github.com/go-chi/chi/compare/v1.5.3...v1.5.4
## v1.5.3 (2021-02-21)
- Update go.mod to go 1.16 with new retract directive marking all versions without prior go.mod support
- History of changes: see https://github.com/go-chi/chi/compare/v1.5.2...v1.5.3
## v1.5.2 (2021-02-10)
- Reverting allocation optimization as a precaution as go test -race fails.
- Minor improvements, see history below
- History of changes: see https://github.com/go-chi/chi/compare/v1.5.1...v1.5.2
## v1.5.1 (2020-12-06)
- Performance improvement: removing 1 allocation by foregoing context.WithValue, thank you @bouk for
your contribution (https://github.com/go-chi/chi/pull/555). Note: new benchmarks posted in README.
- `middleware.CleanPath`: new middleware that clean's request path of double slashes
- deprecate & remove `chi.ServerBaseContext` in favour of stdlib `http.Server#BaseContext`
- plus other tiny improvements, see full commit history below
- History of changes: see https://github.com/go-chi/chi/compare/v4.1.2...v1.5.1
## v1.5.0 (2020-11-12) - now with go.mod support
`chi` dates back to 2016 with it's original implementation as one of the first routers to adopt the newly introduced
context.Context api to the stdlib -- set out to design a router that is faster, more modular and simpler than anything
else out there -- while not introducing any custom handler types or dependencies. Today, `chi` still has zero dependencies,
and in many ways is future proofed from changes, given it's minimal nature. Between versions, chi's iterations have been very
incremental, with the architecture and api being the same today as it was originally designed in 2016. For this reason it
makes chi a pretty easy project to maintain, as well thanks to the many amazing community contributions over the years
to who all help make chi better (total of 86 contributors to date -- thanks all!).
Chi has been an labour of love, art and engineering, with the goals to offer beautiful ergonomics, flexibility, performance
and simplicity when building HTTP services with Go. I've strived to keep the router very minimal in surface area / code size,
and always improving the code wherever possible -- and as of today the `chi` package is just 1082 lines of code (not counting
middlewares, which are all optional). As well, I don't have the exact metrics, but from my analysis and email exchanges from
companies and developers, chi is used by thousands of projects around the world -- thank you all as there is no better form of
joy for me than to have art I had started be helpful and enjoyed by others. And of course I use chi in all of my own projects too :)
For me, the asthetics of chi's code and usage are very important. With the introduction of Go's module support
(which I'm a big fan of), chi's past versioning scheme choice to v2, v3 and v4 would mean I'd require the import path
of "github.com/go-chi/chi/v4", leading to the lengthy discussion at https://github.com/go-chi/chi/issues/462.
Haha, to some, you may be scratching your head why I've spent > 1 year stalling to adopt "/vXX" convention in the import
path -- which isn't horrible in general -- but for chi, I'm unable to accept it as I strive for perfection in it's API design,
aesthetics and simplicity. It just doesn't feel good to me given chi's simple nature -- I do not foresee a "v5" or "v6",
and upgrading between versions in the future will also be just incremental.
I do understand versioning is a part of the API design as well, which is why the solution for a while has been to "do nothing",
as Go supports both old and new import paths with/out go.mod. However, now that Go module support has had time to iron out kinks and
is adopted everywhere, it's time for chi to get with the times. Luckily, I've discovered a path forward that will make me happy,
while also not breaking anyone's app who adopted a prior versioning from tags in v2/v3/v4. I've made an experimental release of
v1.5.0 with go.mod silently, and tested it with new and old projects, to ensure the developer experience is preserved, and it's
largely unnoticed. Fortunately, Go's toolchain will check the tags of a repo and consider the "latest" tag the one with go.mod.
However, you can still request a specific older tag such as v4.1.2, and everything will "just work". But new users can just
`go get github.com/go-chi/chi` or `go get github.com/go-chi/chi@latest` and they will get the latest version which contains
go.mod support, which is v1.5.0+. `chi` will not change very much over the years, just like it hasn't changed much from 4 years ago.
Therefore, we will stay on v1.x from here on, starting from v1.5.0. Any breaking changes will bump a "minor" release and
backwards-compatible improvements/fixes will bump a "tiny" release.
For existing projects who want to upgrade to the latest go.mod version, run: `go get -u github.com/go-chi/chi@v1.5.0`,
which will get you on the go.mod version line (as Go's mod cache may still remember v4.x). Brand new systems can run
`go get -u github.com/go-chi/chi` or `go get -u github.com/go-chi/chi@latest` to install chi, which will install v1.5.0+
built with go.mod support.
My apologies to the developers who will disagree with the decisions above, but, hope you'll try it and see it's a very
minor request which is backwards compatible and won't break your existing installations.
Cheers all, happy coding!
---
## v4.1.2 (2020-06-02)
- fix that handles MethodNotAllowed with path variables, thank you @caseyhadden for your contribution
- fix to replace nested wildcards correctly in RoutePattern, thank you @@unmultimedio for your contribution
- History of changes: see https://github.com/go-chi/chi/compare/v4.1.1...v4.1.2
## v4.1.1 (2020-04-16)
- fix for issue https://github.com/go-chi/chi/issues/411 which allows for overlapping regexp
route to the correct handler through a recursive tree search, thanks to @Jahaja for the PR/fix!
- new middleware.RouteHeaders as a simple router for request headers with wildcard support
- History of changes: see https://github.com/go-chi/chi/compare/v4.1.0...v4.1.1
## v4.1.0 (2020-04-1)
- middleware.LogEntry: Write method on interface now passes the response header
and an extra interface type useful for custom logger implementations.
- middleware.WrapResponseWriter: minor fix
- middleware.Recoverer: a bit prettier
- History of changes: see https://github.com/go-chi/chi/compare/v4.0.4...v4.1.0
## v4.0.4 (2020-03-24)
- middleware.Recoverer: new pretty stack trace printing (https://github.com/go-chi/chi/pull/496)
- a few minor improvements and fixes
- History of changes: see https://github.com/go-chi/chi/compare/v4.0.3...v4.0.4
## v4.0.3 (2020-01-09)
- core: fix regexp routing to include default value when param is not matched
- middleware: rewrite of middleware.Compress
- middleware: suppress http.ErrAbortHandler in middleware.Recoverer
- History of changes: see https://github.com/go-chi/chi/compare/v4.0.2...v4.0.3
## v4.0.2 (2019-02-26)
- Minor fixes
- History of changes: see https://github.com/go-chi/chi/compare/v4.0.1...v4.0.2
## v4.0.1 (2019-01-21)
- Fixes issue with compress middleware: #382 #385
- History of changes: see https://github.com/go-chi/chi/compare/v4.0.0...v4.0.1
## v4.0.0 (2019-01-10)
- chi v4 requires Go 1.10.3+ (or Go 1.9.7+) - we have deprecated support for Go 1.7 and 1.8
- router: respond with 404 on router with no routes (#362)
- router: additional check to ensure wildcard is at the end of a url pattern (#333)
- middleware: deprecate use of http.CloseNotifier (#347)
- middleware: fix RedirectSlashes to include query params on redirect (#334)
- History of changes: see https://github.com/go-chi/chi/compare/v3.3.4...v4.0.0
## v3.3.4 (2019-01-07)
- Minor middleware improvements. No changes to core library/router. Moving v3 into its
- own branch as a version of chi for Go 1.7, 1.8, 1.9, 1.10, 1.11
- History of changes: see https://github.com/go-chi/chi/compare/v3.3.3...v3.3.4
## v3.3.3 (2018-08-27)
- Minor release
- See https://github.com/go-chi/chi/compare/v3.3.2...v3.3.3
## v3.3.2 (2017-12-22)
- Support to route trailing slashes on mounted sub-routers (#281)
- middleware: new `ContentCharset` to check matching charsets. Thank you
@csucu for your community contribution!
## v3.3.1 (2017-11-20)
- middleware: new `AllowContentType` handler for explicit whitelist of accepted request Content-Types
- middleware: new `SetHeader` handler for short-hand middleware to set a response header key/value
- Minor bug fixes
## v3.3.0 (2017-10-10)
- New chi.RegisterMethod(method) to add support for custom HTTP methods, see _examples/custom-method for usage
- Deprecated LINK and UNLINK methods from the default list, please use `chi.RegisterMethod("LINK")` and `chi.RegisterMethod("UNLINK")` in an `init()` function
## v3.2.1 (2017-08-31)
- Add new `Match(rctx *Context, method, path string) bool` method to `Routes` interface
and `Mux`. Match searches the mux's routing tree for a handler that matches the method/path
- Add new `RouteMethod` to `*Context`
- Add new `Routes` pointer to `*Context`
- Add new `middleware.GetHead` to route missing HEAD requests to GET handler
- Updated benchmarks (see README)
## v3.1.5 (2017-08-02)
- Setup golint and go vet for the project
- As per golint, we've redefined `func ServerBaseContext(h http.Handler, baseCtx context.Context) http.Handler`
to `func ServerBaseContext(baseCtx context.Context, h http.Handler) http.Handler`
## v3.1.0 (2017-07-10)
- Fix a few minor issues after v3 release
- Move `docgen` sub-pkg to https://github.com/go-chi/docgen
- Move `render` sub-pkg to https://github.com/go-chi/render
- Add new `URLFormat` handler to chi/middleware sub-pkg to make working with url mime
suffixes easier, ie. parsing `/articles/1.json` and `/articles/1.xml`. See comments in
https://github.com/go-chi/chi/blob/master/middleware/url_format.go for example usage.
## v3.0.0 (2017-06-21)
- Major update to chi library with many exciting updates, but also some *breaking changes*
- URL parameter syntax changed from `/:id` to `/{id}` for even more flexible routing, such as
`/articles/{month}-{day}-{year}-{slug}`, `/articles/{id}`, and `/articles/{id}.{ext}` on the
same router
- Support for regexp for routing patterns, in the form of `/{paramKey:regExp}` for example:
`r.Get("/articles/{name:[a-z]+}", h)` and `chi.URLParam(r, "name")`
- Add `Method` and `MethodFunc` to `chi.Router` to allow routing definitions such as
`r.Method("GET", "/", h)` which provides a cleaner interface for custom handlers like
in `_examples/custom-handler`
- Deprecating `mux#FileServer` helper function. Instead, we encourage users to create their
own using file handler with the stdlib, see `_examples/fileserver` for an example
- Add support for LINK/UNLINK http methods via `r.Method()` and `r.MethodFunc()`
- Moved the chi project to its own organization, to allow chi-related community packages to
be easily discovered and supported, at: https://github.com/go-chi
- *NOTE:* please update your import paths to `"github.com/go-chi/chi"`
- *NOTE:* chi v2 is still available at https://github.com/go-chi/chi/tree/v2
## v2.1.0 (2017-03-30)
- Minor improvements and update to the chi core library
- Introduced a brand new `chi/render` sub-package to complete the story of building
APIs to offer a pattern for managing well-defined request / response payloads. Please
check out the updated `_examples/rest` example for how it works.
- Added `MethodNotAllowed(h http.HandlerFunc)` to chi.Router interface
## v2.0.0 (2017-01-06)
- After many months of v2 being in an RC state with many companies and users running it in
production, the inclusion of some improvements to the middlewares, we are very pleased to
announce v2.0.0 of chi.
## v2.0.0-rc1 (2016-07-26)
- Huge update! chi v2 is a large refactor targetting Go 1.7+. As of Go 1.7, the popular
community `"net/context"` package has been included in the standard library as `"context"` and
utilized by `"net/http"` and `http.Request` to managing deadlines, cancelation signals and other
request-scoped values. We're very excited about the new context addition and are proud to
introduce chi v2, a minimal and powerful routing package for building large HTTP services,
with zero external dependencies. Chi focuses on idiomatic design and encourages the use of
stdlib HTTP handlers and middlwares.
- chi v2 deprecates its `chi.Handler` interface and requires `http.Handler` or `http.HandlerFunc`
- chi v2 stores URL routing parameters and patterns in the standard request context: `r.Context()`
- chi v2 lower-level routing context is accessible by `chi.RouteContext(r.Context()) *chi.Context`,
which provides direct access to URL routing parameters, the routing path and the matching
routing patterns.
- Users upgrading from chi v1 to v2, need to:
1. Update the old chi.Handler signature, `func(ctx context.Context, w http.ResponseWriter, r *http.Request)` to
the standard http.Handler: `func(w http.ResponseWriter, r *http.Request)`
2. Use `chi.URLParam(r *http.Request, paramKey string) string`
or `URLParamFromCtx(ctx context.Context, paramKey string) string` to access a url parameter value
## v1.0.0 (2016-07-01)
- Released chi v1 stable https://github.com/go-chi/chi/tree/v1.0.0 for Go 1.6 and older.
## v0.9.0 (2016-03-31)
- Reuse context objects via sync.Pool for zero-allocation routing [#33](https://github.com/go-chi/chi/pull/33)
- BREAKING NOTE: due to subtle API changes, previously `chi.URLParams(ctx)["id"]` used to access url parameters
has changed to: `chi.URLParam(ctx, "id")`

31
vendor/github.com/go-chi/chi/v5/CONTRIBUTING.md generated vendored Normal file
View file

@ -0,0 +1,31 @@
# Contributing
## Prerequisites
1. [Install Go][go-install].
2. Download the sources and switch the working directory:
```bash
go get -u -d github.com/go-chi/chi
cd $GOPATH/src/github.com/go-chi/chi
```
## Submitting a Pull Request
A typical workflow is:
1. [Fork the repository.][fork] [This tip maybe also helpful.][go-fork-tip]
2. [Create a topic branch.][branch]
3. Add tests for your change.
4. Run `go test`. If your tests pass, return to the step 3.
5. Implement the change and ensure the steps from the previous step pass.
6. Run `goimports -w .`, to ensure the new code conforms to Go formatting guideline.
7. [Add, commit and push your changes.][git-help]
8. [Submit a pull request.][pull-req]
[go-install]: https://golang.org/doc/install
[go-fork-tip]: http://blog.campoy.cat/2014/03/github-and-go-forking-pull-requests-and.html
[fork]: https://help.github.com/articles/fork-a-repo
[branch]: http://learn.github.com/p/branching.html
[git-help]: https://guides.github.com
[pull-req]: https://help.github.com/articles/using-pull-requests

20
vendor/github.com/go-chi/chi/v5/LICENSE generated vendored Normal file
View file

@ -0,0 +1,20 @@
Copyright (c) 2015-present Peter Kieltyka (https://github.com/pkieltyka), Google Inc.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

14
vendor/github.com/go-chi/chi/v5/Makefile generated vendored Normal file
View file

@ -0,0 +1,14 @@
all:
@echo "**********************************************************"
@echo "** chi build tool **"
@echo "**********************************************************"
test:
go clean -testcache && $(MAKE) test-router && $(MAKE) test-middleware
test-router:
go test -race -v .
test-middleware:
go test -race -v ./middleware

511
vendor/github.com/go-chi/chi/v5/README.md generated vendored Normal file
View file

@ -0,0 +1,511 @@
# <img alt="chi" src="https://cdn.rawgit.com/go-chi/chi/master/_examples/chi.svg" width="220" />
[![GoDoc Widget]][GoDoc] [![Travis Widget]][Travis]
`chi` is a lightweight, idiomatic and composable router for building Go HTTP services. It's
especially good at helping you write large REST API services that are kept maintainable as your
project grows and changes. `chi` is built on the new `context` package introduced in Go 1.7 to
handle signaling, cancelation and request-scoped values across a handler chain.
The focus of the project has been to seek out an elegant and comfortable design for writing
REST API servers, written during the development of the Pressly API service that powers our
public API service, which in turn powers all of our client-side applications.
The key considerations of chi's design are: project structure, maintainability, standard http
handlers (stdlib-only), developer productivity, and deconstructing a large system into many small
parts. The core router `github.com/go-chi/chi` is quite small (less than 1000 LOC), but we've also
included some useful/optional subpackages: [middleware](/middleware), [render](https://github.com/go-chi/render)
and [docgen](https://github.com/go-chi/docgen). We hope you enjoy it too!
## Install
`go get -u github.com/go-chi/chi/v5`
## Features
* **Lightweight** - cloc'd in ~1000 LOC for the chi router
* **Fast** - yes, see [benchmarks](#benchmarks)
* **100% compatible with net/http** - use any http or middleware pkg in the ecosystem that is also compatible with `net/http`
* **Designed for modular/composable APIs** - middlewares, inline middlewares, route groups and sub-router mounting
* **Context control** - built on new `context` package, providing value chaining, cancellations and timeouts
* **Robust** - in production at Pressly, CloudFlare, Heroku, 99Designs, and many others (see [discussion](https://github.com/go-chi/chi/issues/91))
* **Doc generation** - `docgen` auto-generates routing documentation from your source to JSON or Markdown
* **Go.mod support** - v1.x of chi (starting from v1.5.0), now has go.mod support (see [CHANGELOG](https://github.com/go-chi/chi/blob/master/CHANGELOG.md#v150-2020-11-12---now-with-gomod-support))
* **No external dependencies** - plain ol' Go stdlib + net/http
## Examples
See [_examples/](https://github.com/go-chi/chi/blob/master/_examples/) for a variety of examples.
**As easy as:**
```go
package main
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main() {
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("welcome"))
})
http.ListenAndServe(":3000", r)
}
```
**REST Preview:**
Here is a little preview of how routing looks like with chi. Also take a look at the generated routing docs
in JSON ([routes.json](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.json)) and in
Markdown ([routes.md](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.md)).
I highly recommend reading the source of the [examples](https://github.com/go-chi/chi/blob/master/_examples/) listed
above, they will show you all the features of chi and serve as a good form of documentation.
```go
import (
//...
"context"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main() {
r := chi.NewRouter()
// A good base middleware stack
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
// Set a timeout value on the request context (ctx), that will signal
// through ctx.Done() that the request has timed out and further
// processing should be stopped.
r.Use(middleware.Timeout(60 * time.Second))
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hi"))
})
// RESTy routes for "articles" resource
r.Route("/articles", func(r chi.Router) {
r.With(paginate).Get("/", listArticles) // GET /articles
r.With(paginate).Get("/{month}-{day}-{year}", listArticlesByDate) // GET /articles/01-16-2017
r.Post("/", createArticle) // POST /articles
r.Get("/search", searchArticles) // GET /articles/search
// Regexp url parameters:
r.Get("/{articleSlug:[a-z-]+}", getArticleBySlug) // GET /articles/home-is-toronto
// Subrouters:
r.Route("/{articleID}", func(r chi.Router) {
r.Use(ArticleCtx)
r.Get("/", getArticle) // GET /articles/123
r.Put("/", updateArticle) // PUT /articles/123
r.Delete("/", deleteArticle) // DELETE /articles/123
})
})
// Mount the admin sub-router
r.Mount("/admin", adminRouter())
http.ListenAndServe(":3333", r)
}
func ArticleCtx(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
articleID := chi.URLParam(r, "articleID")
article, err := dbGetArticle(articleID)
if err != nil {
http.Error(w, http.StatusText(404), 404)
return
}
ctx := context.WithValue(r.Context(), "article", article)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func getArticle(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
article, ok := ctx.Value("article").(*Article)
if !ok {
http.Error(w, http.StatusText(422), 422)
return
}
w.Write([]byte(fmt.Sprintf("title:%s", article.Title)))
}
// A completely separate router for administrator routes
func adminRouter() http.Handler {
r := chi.NewRouter()
r.Use(AdminOnly)
r.Get("/", adminIndex)
r.Get("/accounts", adminListAccounts)
return r
}
func AdminOnly(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
perm, ok := ctx.Value("acl.permission").(YourPermissionType)
if !ok || !perm.IsAdmin() {
http.Error(w, http.StatusText(403), 403)
return
}
next.ServeHTTP(w, r)
})
}
```
## Router interface
chi's router is based on a kind of [Patricia Radix trie](https://en.wikipedia.org/wiki/Radix_tree).
The router is fully compatible with `net/http`.
Built on top of the tree is the `Router` interface:
```go
// Router consisting of the core routing methods used by chi's Mux,
// using only the standard net/http.
type Router interface {
http.Handler
Routes
// Use appends one or more middlewares onto the Router stack.
Use(middlewares ...func(http.Handler) http.Handler)
// With adds inline middlewares for an endpoint handler.
With(middlewares ...func(http.Handler) http.Handler) Router
// Group adds a new inline-Router along the current routing
// path, with a fresh middleware stack for the inline-Router.
Group(fn func(r Router)) Router
// Route mounts a sub-Router along a `pattern`` string.
Route(pattern string, fn func(r Router)) Router
// Mount attaches another http.Handler along ./pattern/*
Mount(pattern string, h http.Handler)
// Handle and HandleFunc adds routes for `pattern` that matches
// all HTTP methods.
Handle(pattern string, h http.Handler)
HandleFunc(pattern string, h http.HandlerFunc)
// Method and MethodFunc adds routes for `pattern` that matches
// the `method` HTTP method.
Method(method, pattern string, h http.Handler)
MethodFunc(method, pattern string, h http.HandlerFunc)
// HTTP-method routing along `pattern`
Connect(pattern string, h http.HandlerFunc)
Delete(pattern string, h http.HandlerFunc)
Get(pattern string, h http.HandlerFunc)
Head(pattern string, h http.HandlerFunc)
Options(pattern string, h http.HandlerFunc)
Patch(pattern string, h http.HandlerFunc)
Post(pattern string, h http.HandlerFunc)
Put(pattern string, h http.HandlerFunc)
Trace(pattern string, h http.HandlerFunc)
// NotFound defines a handler to respond whenever a route could
// not be found.
NotFound(h http.HandlerFunc)
// MethodNotAllowed defines a handler to respond whenever a method is
// not allowed.
MethodNotAllowed(h http.HandlerFunc)
}
// Routes interface adds two methods for router traversal, which is also
// used by the github.com/go-chi/docgen package to generate documentation for Routers.
type Routes interface {
// Routes returns the routing tree in an easily traversable structure.
Routes() []Route
// Middlewares returns the list of middlewares in use by the router.
Middlewares() Middlewares
// Match searches the routing tree for a handler that matches
// the method/path - similar to routing a http request, but without
// executing the handler thereafter.
Match(rctx *Context, method, path string) bool
}
```
Each routing method accepts a URL `pattern` and chain of `handlers`. The URL pattern
supports named params (ie. `/users/{userID}`) and wildcards (ie. `/admin/*`). URL parameters
can be fetched at runtime by calling `chi.URLParam(r, "userID")` for named parameters
and `chi.URLParam(r, "*")` for a wildcard parameter.
### Middleware handlers
chi's middlewares are just stdlib net/http middleware handlers. There is nothing special
about them, which means the router and all the tooling is designed to be compatible and
friendly with any middleware in the community. This offers much better extensibility and reuse
of packages and is at the heart of chi's purpose.
Here is an example of a standard net/http middleware where we assign a context key `"user"`
the value of `"123"`. This middleware sets a hypothetical user identifier on the request
context and calls the next handler in the chain.
```go
// HTTP middleware setting a value on the request context
func MyMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// create new context from `r` request context, and assign key `"user"`
// to value of `"123"`
ctx := context.WithValue(r.Context(), "user", "123")
// call the next handler in the chain, passing the response writer and
// the updated request object with the new context value.
//
// note: context.Context values are nested, so any previously set
// values will be accessible as well, and the new `"user"` key
// will be accessible from this point forward.
next.ServeHTTP(w, r.WithContext(ctx))
})
}
```
### Request handlers
chi uses standard net/http request handlers. This little snippet is an example of a http.Handler
func that reads a user identifier from the request context - hypothetically, identifying
the user sending an authenticated request, validated+set by a previous middleware handler.
```go
// HTTP handler accessing data from the request context.
func MyRequestHandler(w http.ResponseWriter, r *http.Request) {
// here we read from the request context and fetch out `"user"` key set in
// the MyMiddleware example above.
user := r.Context().Value("user").(string)
// respond to the client
w.Write([]byte(fmt.Sprintf("hi %s", user)))
}
```
### URL parameters
chi's router parses and stores URL parameters right onto the request context. Here is
an example of how to access URL params in your net/http handlers. And of course, middlewares
are able to access the same information.
```go
// HTTP handler accessing the url routing parameters.
func MyRequestHandler(w http.ResponseWriter, r *http.Request) {
// fetch the url parameter `"userID"` from the request of a matching
// routing pattern. An example routing pattern could be: /users/{userID}
userID := chi.URLParam(r, "userID")
// fetch `"key"` from the request context
ctx := r.Context()
key := ctx.Value("key").(string)
// respond to the client
w.Write([]byte(fmt.Sprintf("hi %v, %v", userID, key)))
}
```
## Middlewares
chi comes equipped with an optional `middleware` package, providing a suite of standard
`net/http` middlewares. Please note, any middleware in the ecosystem that is also compatible
with `net/http` can be used with chi's mux.
### Core middlewares
----------------------------------------------------------------------------------------------------
| chi/middleware Handler | description |
| :--------------------- | :---------------------------------------------------------------------- |
| [AllowContentEncoding] | Enforces a whitelist of request Content-Encoding headers |
| [AllowContentType] | Explicit whitelist of accepted request Content-Types |
| [BasicAuth] | Basic HTTP authentication |
| [Compress] | Gzip compression for clients that accept compressed responses |
| [ContentCharset] | Ensure charset for Content-Type request headers |
| [CleanPath] | Clean double slashes from request path |
| [GetHead] | Automatically route undefined HEAD requests to GET handlers |
| [Heartbeat] | Monitoring endpoint to check the servers pulse |
| [Logger] | Logs the start and end of each request with the elapsed processing time |
| [NoCache] | Sets response headers to prevent clients from caching |
| [Profiler] | Easily attach net/http/pprof to your routers |
| [RealIP] | Sets a http.Request's RemoteAddr to either X-Forwarded-For or X-Real-IP |
| [Recoverer] | Gracefully absorb panics and prints the stack trace |
| [RequestID] | Injects a request ID into the context of each request |
| [RedirectSlashes] | Redirect slashes on routing paths |
| [RouteHeaders] | Route handling for request headers |
| [SetHeader] | Short-hand middleware to set a response header key/value |
| [StripSlashes] | Strip slashes on routing paths |
| [Throttle] | Puts a ceiling on the number of concurrent requests |
| [Timeout] | Signals to the request context when the timeout deadline is reached |
| [URLFormat] | Parse extension from url and put it on request context |
| [WithValue] | Short-hand middleware to set a key/value on the request context |
----------------------------------------------------------------------------------------------------
[AllowContentEncoding]: https://pkg.go.dev/github.com/go-chi/chi/middleware#AllowContentEncoding
[AllowContentType]: https://pkg.go.dev/github.com/go-chi/chi/middleware#AllowContentType
[BasicAuth]: https://pkg.go.dev/github.com/go-chi/chi/middleware#BasicAuth
[Compress]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Compress
[ContentCharset]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ContentCharset
[CleanPath]: https://pkg.go.dev/github.com/go-chi/chi/middleware#CleanPath
[GetHead]: https://pkg.go.dev/github.com/go-chi/chi/middleware#GetHead
[GetReqID]: https://pkg.go.dev/github.com/go-chi/chi/middleware#GetReqID
[Heartbeat]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Heartbeat
[Logger]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Logger
[NoCache]: https://pkg.go.dev/github.com/go-chi/chi/middleware#NoCache
[Profiler]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Profiler
[RealIP]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RealIP
[Recoverer]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Recoverer
[RedirectSlashes]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RedirectSlashes
[RequestLogger]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RequestLogger
[RequestID]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RequestID
[RouteHeaders]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RouteHeaders
[SetHeader]: https://pkg.go.dev/github.com/go-chi/chi/middleware#SetHeader
[StripSlashes]: https://pkg.go.dev/github.com/go-chi/chi/middleware#StripSlashes
[Throttle]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Throttle
[ThrottleBacklog]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ThrottleBacklog
[ThrottleWithOpts]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ThrottleWithOpts
[Timeout]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Timeout
[URLFormat]: https://pkg.go.dev/github.com/go-chi/chi/middleware#URLFormat
[WithLogEntry]: https://pkg.go.dev/github.com/go-chi/chi/middleware#WithLogEntry
[WithValue]: https://pkg.go.dev/github.com/go-chi/chi/middleware#WithValue
[Compressor]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Compressor
[DefaultLogFormatter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#DefaultLogFormatter
[EncoderFunc]: https://pkg.go.dev/github.com/go-chi/chi/middleware#EncoderFunc
[HeaderRoute]: https://pkg.go.dev/github.com/go-chi/chi/middleware#HeaderRoute
[HeaderRouter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#HeaderRouter
[LogEntry]: https://pkg.go.dev/github.com/go-chi/chi/middleware#LogEntry
[LogFormatter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#LogFormatter
[LoggerInterface]: https://pkg.go.dev/github.com/go-chi/chi/middleware#LoggerInterface
[ThrottleOpts]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ThrottleOpts
[WrapResponseWriter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#WrapResponseWriter
### Extra middlewares & packages
Please see https://github.com/go-chi for additional packages.
--------------------------------------------------------------------------------------------------------------------
| package | description |
|:---------------------------------------------------|:-------------------------------------------------------------
| [cors](https://github.com/go-chi/cors) | Cross-origin resource sharing (CORS) |
| [docgen](https://github.com/go-chi/docgen) | Print chi.Router routes at runtime |
| [jwtauth](https://github.com/go-chi/jwtauth) | JWT authentication |
| [hostrouter](https://github.com/go-chi/hostrouter) | Domain/host based request routing |
| [httplog](https://github.com/go-chi/httplog) | Small but powerful structured HTTP request logging |
| [httprate](https://github.com/go-chi/httprate) | HTTP request rate limiter |
| [httptracer](https://github.com/go-chi/httptracer) | HTTP request performance tracing library |
| [httpvcr](https://github.com/go-chi/httpvcr) | Write deterministic tests for external sources |
| [stampede](https://github.com/go-chi/stampede) | HTTP request coalescer |
--------------------------------------------------------------------------------------------------------------------
## context?
`context` is a tiny pkg that provides simple interface to signal context across call stacks
and goroutines. It was originally written by [Sameer Ajmani](https://github.com/Sajmani)
and is available in stdlib since go1.7.
Learn more at https://blog.golang.org/context
and..
* Docs: https://golang.org/pkg/context
* Source: https://github.com/golang/go/tree/master/src/context
## Benchmarks
The benchmark suite: https://github.com/pkieltyka/go-http-routing-benchmark
Results as of Nov 29, 2020 with Go 1.15.5 on Linux AMD 3950x
```shell
BenchmarkChi_Param 3075895 384 ns/op 400 B/op 2 allocs/op
BenchmarkChi_Param5 2116603 566 ns/op 400 B/op 2 allocs/op
BenchmarkChi_Param20 964117 1227 ns/op 400 B/op 2 allocs/op
BenchmarkChi_ParamWrite 2863413 420 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GithubStatic 3045488 395 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GithubParam 2204115 540 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GithubAll 10000 113811 ns/op 81203 B/op 406 allocs/op
BenchmarkChi_GPlusStatic 3337485 359 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GPlusParam 2825853 423 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GPlus2Params 2471697 483 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GPlusAll 194220 5950 ns/op 5200 B/op 26 allocs/op
BenchmarkChi_ParseStatic 3365324 356 ns/op 400 B/op 2 allocs/op
BenchmarkChi_ParseParam 2976614 404 ns/op 400 B/op 2 allocs/op
BenchmarkChi_Parse2Params 2638084 439 ns/op 400 B/op 2 allocs/op
BenchmarkChi_ParseAll 109567 11295 ns/op 10400 B/op 52 allocs/op
BenchmarkChi_StaticAll 16846 71308 ns/op 62802 B/op 314 allocs/op
```
Comparison with other routers: https://gist.github.com/pkieltyka/123032f12052520aaccab752bd3e78cc
NOTE: the allocs in the benchmark above are from the calls to http.Request's
`WithContext(context.Context)` method that clones the http.Request, sets the `Context()`
on the duplicated (alloc'd) request and returns it the new request object. This is just
how setting context on a request in Go works.
## Go module support & note on chi's versioning
* Go.mod support means we reset our versioning starting from v1.5 (see [CHANGELOG](https://github.com/go-chi/chi/blob/master/CHANGELOG.md#v150-2020-11-12---now-with-gomod-support))
* All older tags are preserved, are backwards-compatible and will "just work" as they
* Brand new systems can run `go get -u github.com/go-chi/chi` as normal, or `go get -u github.com/go-chi/chi@latest`
to install chi, which will install v1.x+ built with go.mod support, starting from v1.5.0.
* For existing projects who want to upgrade to the latest go.mod version, run: `go get -u github.com/go-chi/chi@v1.5.0`,
which will get you on the go.mod version line (as Go's mod cache may still remember v4.x).
* Any breaking changes will bump a "minor" release and backwards-compatible improvements/fixes will bump a "tiny" release.
## Credits
* Carl Jackson for https://github.com/zenazn/goji
* Parts of chi's thinking comes from goji, and chi's middleware package
sources from goji.
* Armon Dadgar for https://github.com/armon/go-radix
* Contributions: [@VojtechVitek](https://github.com/VojtechVitek)
We'll be more than happy to see [your contributions](./CONTRIBUTING.md)!
## Beyond REST
chi is just a http router that lets you decompose request handling into many smaller layers.
Many companies use chi to write REST services for their public APIs. But, REST is just a convention
for managing state via HTTP, and there's a lot of other pieces required to write a complete client-server
system or network of microservices.
Looking beyond REST, I also recommend some newer works in the field:
* [webrpc](https://github.com/webrpc/webrpc) - Web-focused RPC client+server framework with code-gen
* [gRPC](https://github.com/grpc/grpc-go) - Google's RPC framework via protobufs
* [graphql](https://github.com/99designs/gqlgen) - Declarative query language
* [NATS](https://nats.io) - lightweight pub-sub
## License
Copyright (c) 2015-present [Peter Kieltyka](https://github.com/pkieltyka)
Licensed under [MIT License](./LICENSE)
[GoDoc]: https://pkg.go.dev/github.com/go-chi/chi?tab=versions
[GoDoc Widget]: https://godoc.org/github.com/go-chi/chi?status.svg
[Travis]: https://travis-ci.org/go-chi/chi
[Travis Widget]: https://travis-ci.org/go-chi/chi.svg?branch=master

49
vendor/github.com/go-chi/chi/v5/chain.go generated vendored Normal file
View file

@ -0,0 +1,49 @@
package chi
import "net/http"
// Chain returns a Middlewares type from a slice of middleware handlers.
func Chain(middlewares ...func(http.Handler) http.Handler) Middlewares {
return Middlewares(middlewares)
}
// Handler builds and returns a http.Handler from the chain of middlewares,
// with `h http.Handler` as the final handler.
func (mws Middlewares) Handler(h http.Handler) http.Handler {
return &ChainHandler{mws, h, chain(mws, h)}
}
// HandlerFunc builds and returns a http.Handler from the chain of middlewares,
// with `h http.Handler` as the final handler.
func (mws Middlewares) HandlerFunc(h http.HandlerFunc) http.Handler {
return &ChainHandler{mws, h, chain(mws, h)}
}
// ChainHandler is a http.Handler with support for handler composition and
// execution.
type ChainHandler struct {
Middlewares Middlewares
Endpoint http.Handler
chain http.Handler
}
func (c *ChainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
c.chain.ServeHTTP(w, r)
}
// chain builds a http.Handler composed of an inline middleware stack and endpoint
// handler in the order they are passed.
func chain(middlewares []func(http.Handler) http.Handler, endpoint http.Handler) http.Handler {
// Return ahead of time if there aren't any middlewares for the chain
if len(middlewares) == 0 {
return endpoint
}
// Wrap the end handler with the middleware chain
h := middlewares[len(middlewares)-1](endpoint)
for i := len(middlewares) - 2; i >= 0; i-- {
h = middlewares[i](h)
}
return h
}

134
vendor/github.com/go-chi/chi/v5/chi.go generated vendored Normal file
View file

@ -0,0 +1,134 @@
//
// Package chi is a small, idiomatic and composable router for building HTTP services.
//
// chi requires Go 1.10 or newer.
//
// Example:
// package main
//
// import (
// "net/http"
//
// "github.com/go-chi/chi/v5"
// "github.com/go-chi/chi/v5/middleware"
// )
//
// func main() {
// r := chi.NewRouter()
// r.Use(middleware.Logger)
// r.Use(middleware.Recoverer)
//
// r.Get("/", func(w http.ResponseWriter, r *http.Request) {
// w.Write([]byte("root."))
// })
//
// http.ListenAndServe(":3333", r)
// }
//
// See github.com/go-chi/chi/_examples/ for more in-depth examples.
//
// URL patterns allow for easy matching of path components in HTTP
// requests. The matching components can then be accessed using
// chi.URLParam(). All patterns must begin with a slash.
//
// A simple named placeholder {name} matches any sequence of characters
// up to the next / or the end of the URL. Trailing slashes on paths must
// be handled explicitly.
//
// A placeholder with a name followed by a colon allows a regular
// expression match, for example {number:\\d+}. The regular expression
// syntax is Go's normal regexp RE2 syntax, except that regular expressions
// including { or } are not supported, and / will never be
// matched. An anonymous regexp pattern is allowed, using an empty string
// before the colon in the placeholder, such as {:\\d+}
//
// The special placeholder of asterisk matches the rest of the requested
// URL. Any trailing characters in the pattern are ignored. This is the only
// placeholder which will match / characters.
//
// Examples:
// "/user/{name}" matches "/user/jsmith" but not "/user/jsmith/info" or "/user/jsmith/"
// "/user/{name}/info" matches "/user/jsmith/info"
// "/page/*" matches "/page/intro/latest"
// "/page/*/index" also matches "/page/intro/latest"
// "/date/{yyyy:\\d\\d\\d\\d}/{mm:\\d\\d}/{dd:\\d\\d}" matches "/date/2017/04/01"
//
package chi
import "net/http"
// NewRouter returns a new Mux object that implements the Router interface.
func NewRouter() *Mux {
return NewMux()
}
// Router consisting of the core routing methods used by chi's Mux,
// using only the standard net/http.
type Router interface {
http.Handler
Routes
// Use appends one or more middlewares onto the Router stack.
Use(middlewares ...func(http.Handler) http.Handler)
// With adds inline middlewares for an endpoint handler.
With(middlewares ...func(http.Handler) http.Handler) Router
// Group adds a new inline-Router along the current routing
// path, with a fresh middleware stack for the inline-Router.
Group(fn func(r Router)) Router
// Route mounts a sub-Router along a `pattern`` string.
Route(pattern string, fn func(r Router)) Router
// Mount attaches another http.Handler along ./pattern/*
Mount(pattern string, h http.Handler)
// Handle and HandleFunc adds routes for `pattern` that matches
// all HTTP methods.
Handle(pattern string, h http.Handler)
HandleFunc(pattern string, h http.HandlerFunc)
// Method and MethodFunc adds routes for `pattern` that matches
// the `method` HTTP method.
Method(method, pattern string, h http.Handler)
MethodFunc(method, pattern string, h http.HandlerFunc)
// HTTP-method routing along `pattern`
Connect(pattern string, h http.HandlerFunc)
Delete(pattern string, h http.HandlerFunc)
Get(pattern string, h http.HandlerFunc)
Head(pattern string, h http.HandlerFunc)
Options(pattern string, h http.HandlerFunc)
Patch(pattern string, h http.HandlerFunc)
Post(pattern string, h http.HandlerFunc)
Put(pattern string, h http.HandlerFunc)
Trace(pattern string, h http.HandlerFunc)
// NotFound defines a handler to respond whenever a route could
// not be found.
NotFound(h http.HandlerFunc)
// MethodNotAllowed defines a handler to respond whenever a method is
// not allowed.
MethodNotAllowed(h http.HandlerFunc)
}
// Routes interface adds two methods for router traversal, which is also
// used by the `docgen` subpackage to generation documentation for Routers.
type Routes interface {
// Routes returns the routing tree in an easily traversable structure.
Routes() []Route
// Middlewares returns the list of middlewares in use by the router.
Middlewares() Middlewares
// Match searches the routing tree for a handler that matches
// the method/path - similar to routing a http request, but without
// executing the handler thereafter.
Match(rctx *Context, method, path string) bool
}
// Middlewares type is a slice of standard middleware handlers with methods
// to compose middleware chains and http.Handler's.
type Middlewares []func(http.Handler) http.Handler

157
vendor/github.com/go-chi/chi/v5/context.go generated vendored Normal file
View file

@ -0,0 +1,157 @@
package chi
import (
"context"
"net/http"
"strings"
)
// URLParam returns the url parameter from a http.Request object.
func URLParam(r *http.Request, key string) string {
if rctx := RouteContext(r.Context()); rctx != nil {
return rctx.URLParam(key)
}
return ""
}
// URLParamFromCtx returns the url parameter from a http.Request Context.
func URLParamFromCtx(ctx context.Context, key string) string {
if rctx := RouteContext(ctx); rctx != nil {
return rctx.URLParam(key)
}
return ""
}
// RouteContext returns chi's routing Context object from a
// http.Request Context.
func RouteContext(ctx context.Context) *Context {
val, _ := ctx.Value(RouteCtxKey).(*Context)
return val
}
// NewRouteContext returns a new routing Context object.
func NewRouteContext() *Context {
return &Context{}
}
var (
// RouteCtxKey is the context.Context key to store the request context.
RouteCtxKey = &contextKey{"RouteContext"}
)
// Context is the default routing context set on the root node of a
// request context to track route patterns, URL parameters and
// an optional routing path.
type Context struct {
Routes Routes
// Routing path/method override used during the route search.
// See Mux#routeHTTP method.
RoutePath string
RouteMethod string
// Routing pattern stack throughout the lifecycle of the request,
// across all connected routers. It is a record of all matching
// patterns across a stack of sub-routers.
RoutePatterns []string
// URLParams are the stack of routeParams captured during the
// routing lifecycle across a stack of sub-routers.
URLParams RouteParams
// The endpoint routing pattern that matched the request URI path
// or `RoutePath` of the current sub-router. This value will update
// during the lifecycle of a request passing through a stack of
// sub-routers.
routePattern string
// Route parameters matched for the current sub-router. It is
// intentionally unexported so it cant be tampered.
routeParams RouteParams
// methodNotAllowed hint
methodNotAllowed bool
// parentCtx is the parent of this one, for using Context as a
// context.Context directly. This is an optimization that saves
// 1 allocation.
parentCtx context.Context
}
// Reset a routing context to its initial state.
func (x *Context) Reset() {
x.Routes = nil
x.RoutePath = ""
x.RouteMethod = ""
x.RoutePatterns = x.RoutePatterns[:0]
x.URLParams.Keys = x.URLParams.Keys[:0]
x.URLParams.Values = x.URLParams.Values[:0]
x.routePattern = ""
x.routeParams.Keys = x.routeParams.Keys[:0]
x.routeParams.Values = x.routeParams.Values[:0]
x.methodNotAllowed = false
x.parentCtx = nil
}
// URLParam returns the corresponding URL parameter value from the request
// routing context.
func (x *Context) URLParam(key string) string {
for k := len(x.URLParams.Keys) - 1; k >= 0; k-- {
if x.URLParams.Keys[k] == key {
return x.URLParams.Values[k]
}
}
return ""
}
// RoutePattern builds the routing pattern string for the particular
// request, at the particular point during routing. This means, the value
// will change throughout the execution of a request in a router. That is
// why its advised to only use this value after calling the next handler.
//
// For example,
//
// func Instrument(next http.Handler) http.Handler {
// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// next.ServeHTTP(w, r)
// routePattern := chi.RouteContext(r.Context()).RoutePattern()
// measure(w, r, routePattern)
// })
// }
func (x *Context) RoutePattern() string {
routePattern := strings.Join(x.RoutePatterns, "")
return replaceWildcards(routePattern)
}
// replaceWildcards takes a route pattern and recursively replaces all
// occurrences of "/*/" to "/".
func replaceWildcards(p string) string {
if strings.Contains(p, "/*/") {
return replaceWildcards(strings.Replace(p, "/*/", "/", -1))
}
return p
}
// RouteParams is a structure to track URL routing parameters efficiently.
type RouteParams struct {
Keys, Values []string
}
// Add will append a URL parameter to the end of the route param
func (s *RouteParams) Add(key, value string) {
s.Keys = append(s.Keys, key)
s.Values = append(s.Values, value)
}
// contextKey is a value for use with context.WithValue. It's used as
// a pointer so it fits in an interface{} without allocation. This technique
// for defining context keys was copied from Go 1.7's new use of context in net/http.
type contextKey struct {
name string
}
func (k *contextKey) String() string {
return "chi context value " + k.name
}

View file

@ -0,0 +1,33 @@
package middleware
import (
"crypto/subtle"
"fmt"
"net/http"
)
// BasicAuth implements a simple middleware handler for adding basic http auth to a route.
func BasicAuth(realm string, creds map[string]string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user, pass, ok := r.BasicAuth()
if !ok {
basicAuthFailed(w, realm)
return
}
credPass, credUserOk := creds[user]
if !credUserOk || subtle.ConstantTimeCompare([]byte(pass), []byte(credPass)) != 1 {
basicAuthFailed(w, realm)
return
}
next.ServeHTTP(w, r)
})
}
}
func basicAuthFailed(w http.ResponseWriter, realm string) {
w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm))
w.WriteHeader(http.StatusUnauthorized)
}

View file

@ -0,0 +1,28 @@
package middleware
import (
"net/http"
"path"
"github.com/go-chi/chi/v5"
)
// CleanPath middleware will clean out double slash mistakes from a user's request path.
// For example, if a user requests /users//1 or //users////1 will both be treated as: /users/1
func CleanPath(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rctx := chi.RouteContext(r.Context())
routePath := rctx.RoutePath
if routePath == "" {
if r.URL.RawPath != "" {
routePath = r.URL.RawPath
} else {
routePath = r.URL.Path
}
rctx.RoutePath = path.Clean(routePath)
}
next.ServeHTTP(w, r)
})
}

399
vendor/github.com/go-chi/chi/v5/middleware/compress.go generated vendored Normal file
View file

@ -0,0 +1,399 @@
package middleware
import (
"bufio"
"compress/flate"
"compress/gzip"
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"strings"
"sync"
)
var defaultCompressibleContentTypes = []string{
"text/html",
"text/css",
"text/plain",
"text/javascript",
"application/javascript",
"application/x-javascript",
"application/json",
"application/atom+xml",
"application/rss+xml",
"image/svg+xml",
}
// Compress is a middleware that compresses response
// body of a given content types to a data format based
// on Accept-Encoding request header. It uses a given
// compression level.
//
// NOTE: make sure to set the Content-Type header on your response
// otherwise this middleware will not compress the response body. For ex, in
// your handler you should set w.Header().Set("Content-Type", http.DetectContentType(yourBody))
// or set it manually.
//
// Passing a compression level of 5 is sensible value
func Compress(level int, types ...string) func(next http.Handler) http.Handler {
compressor := NewCompressor(level, types...)
return compressor.Handler
}
// Compressor represents a set of encoding configurations.
type Compressor struct {
level int // The compression level.
// The mapping of encoder names to encoder functions.
encoders map[string]EncoderFunc
// The mapping of pooled encoders to pools.
pooledEncoders map[string]*sync.Pool
// The set of content types allowed to be compressed.
allowedTypes map[string]struct{}
allowedWildcards map[string]struct{}
// The list of encoders in order of decreasing precedence.
encodingPrecedence []string
}
// NewCompressor creates a new Compressor that will handle encoding responses.
//
// The level should be one of the ones defined in the flate package.
// The types are the content types that are allowed to be compressed.
func NewCompressor(level int, types ...string) *Compressor {
// If types are provided, set those as the allowed types. If none are
// provided, use the default list.
allowedTypes := make(map[string]struct{})
allowedWildcards := make(map[string]struct{})
if len(types) > 0 {
for _, t := range types {
if strings.Contains(strings.TrimSuffix(t, "/*"), "*") {
panic(fmt.Sprintf("middleware/compress: Unsupported content-type wildcard pattern '%s'. Only '/*' supported", t))
}
if strings.HasSuffix(t, "/*") {
allowedWildcards[strings.TrimSuffix(t, "/*")] = struct{}{}
} else {
allowedTypes[t] = struct{}{}
}
}
} else {
for _, t := range defaultCompressibleContentTypes {
allowedTypes[t] = struct{}{}
}
}
c := &Compressor{
level: level,
encoders: make(map[string]EncoderFunc),
pooledEncoders: make(map[string]*sync.Pool),
allowedTypes: allowedTypes,
allowedWildcards: allowedWildcards,
}
// Set the default encoders. The precedence order uses the reverse
// ordering that the encoders were added. This means adding new encoders
// will move them to the front of the order.
//
// TODO:
// lzma: Opera.
// sdch: Chrome, Android. Gzip output + dictionary header.
// br: Brotli, see https://github.com/go-chi/chi/pull/326
// HTTP 1.1 "deflate" (RFC 2616) stands for DEFLATE data (RFC 1951)
// wrapped with zlib (RFC 1950). The zlib wrapper uses Adler-32
// checksum compared to CRC-32 used in "gzip" and thus is faster.
//
// But.. some old browsers (MSIE, Safari 5.1) incorrectly expect
// raw DEFLATE data only, without the mentioned zlib wrapper.
// Because of this major confusion, most modern browsers try it
// both ways, first looking for zlib headers.
// Quote by Mark Adler: http://stackoverflow.com/a/9186091/385548
//
// The list of browsers having problems is quite big, see:
// http://zoompf.com/blog/2012/02/lose-the-wait-http-compression
// https://web.archive.org/web/20120321182910/http://www.vervestudios.co/projects/compression-tests/results
//
// That's why we prefer gzip over deflate. It's just more reliable
// and not significantly slower than gzip.
c.SetEncoder("deflate", encoderDeflate)
// TODO: Exception for old MSIE browsers that can't handle non-HTML?
// https://zoompf.com/blog/2012/02/lose-the-wait-http-compression
c.SetEncoder("gzip", encoderGzip)
// NOTE: Not implemented, intentionally:
// case "compress": // LZW. Deprecated.
// case "bzip2": // Too slow on-the-fly.
// case "zopfli": // Too slow on-the-fly.
// case "xz": // Too slow on-the-fly.
return c
}
// SetEncoder can be used to set the implementation of a compression algorithm.
//
// The encoding should be a standardised identifier. See:
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding
//
// For example, add the Brotli algortithm:
//
// import brotli_enc "gopkg.in/kothar/brotli-go.v0/enc"
//
// compressor := middleware.NewCompressor(5, "text/html")
// compressor.SetEncoder("br", func(w http.ResponseWriter, level int) io.Writer {
// params := brotli_enc.NewBrotliParams()
// params.SetQuality(level)
// return brotli_enc.NewBrotliWriter(params, w)
// })
func (c *Compressor) SetEncoder(encoding string, fn EncoderFunc) {
encoding = strings.ToLower(encoding)
if encoding == "" {
panic("the encoding can not be empty")
}
if fn == nil {
panic("attempted to set a nil encoder function")
}
// If we are adding a new encoder that is already registered, we have to
// clear that one out first.
if _, ok := c.pooledEncoders[encoding]; ok {
delete(c.pooledEncoders, encoding)
}
if _, ok := c.encoders[encoding]; ok {
delete(c.encoders, encoding)
}
// If the encoder supports Resetting (IoReseterWriter), then it can be pooled.
encoder := fn(ioutil.Discard, c.level)
if encoder != nil {
if _, ok := encoder.(ioResetterWriter); ok {
pool := &sync.Pool{
New: func() interface{} {
return fn(ioutil.Discard, c.level)
},
}
c.pooledEncoders[encoding] = pool
}
}
// If the encoder is not in the pooledEncoders, add it to the normal encoders.
if _, ok := c.pooledEncoders[encoding]; !ok {
c.encoders[encoding] = fn
}
for i, v := range c.encodingPrecedence {
if v == encoding {
c.encodingPrecedence = append(c.encodingPrecedence[:i], c.encodingPrecedence[i+1:]...)
}
}
c.encodingPrecedence = append([]string{encoding}, c.encodingPrecedence...)
}
// Handler returns a new middleware that will compress the response based on the
// current Compressor.
func (c *Compressor) Handler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
encoder, encoding, cleanup := c.selectEncoder(r.Header, w)
cw := &compressResponseWriter{
ResponseWriter: w,
w: w,
contentTypes: c.allowedTypes,
contentWildcards: c.allowedWildcards,
encoding: encoding,
compressable: false, // determined in post-handler
}
if encoder != nil {
cw.w = encoder
}
// Re-add the encoder to the pool if applicable.
defer cleanup()
defer cw.Close()
next.ServeHTTP(cw, r)
})
}
// selectEncoder returns the encoder, the name of the encoder, and a closer function.
func (c *Compressor) selectEncoder(h http.Header, w io.Writer) (io.Writer, string, func()) {
header := h.Get("Accept-Encoding")
// Parse the names of all accepted algorithms from the header.
accepted := strings.Split(strings.ToLower(header), ",")
// Find supported encoder by accepted list by precedence
for _, name := range c.encodingPrecedence {
if matchAcceptEncoding(accepted, name) {
if pool, ok := c.pooledEncoders[name]; ok {
encoder := pool.Get().(ioResetterWriter)
cleanup := func() {
pool.Put(encoder)
}
encoder.Reset(w)
return encoder, name, cleanup
}
if fn, ok := c.encoders[name]; ok {
return fn(w, c.level), name, func() {}
}
}
}
// No encoder found to match the accepted encoding
return nil, "", func() {}
}
func matchAcceptEncoding(accepted []string, encoding string) bool {
for _, v := range accepted {
if strings.Contains(v, encoding) {
return true
}
}
return false
}
// An EncoderFunc is a function that wraps the provided io.Writer with a
// streaming compression algorithm and returns it.
//
// In case of failure, the function should return nil.
type EncoderFunc func(w io.Writer, level int) io.Writer
// Interface for types that allow resetting io.Writers.
type ioResetterWriter interface {
io.Writer
Reset(w io.Writer)
}
type compressResponseWriter struct {
http.ResponseWriter
// The streaming encoder writer to be used if there is one. Otherwise,
// this is just the normal writer.
w io.Writer
encoding string
contentTypes map[string]struct{}
contentWildcards map[string]struct{}
wroteHeader bool
compressable bool
}
func (cw *compressResponseWriter) isCompressable() bool {
// Parse the first part of the Content-Type response header.
contentType := cw.Header().Get("Content-Type")
if idx := strings.Index(contentType, ";"); idx >= 0 {
contentType = contentType[0:idx]
}
// Is the content type compressable?
if _, ok := cw.contentTypes[contentType]; ok {
return true
}
if idx := strings.Index(contentType, "/"); idx > 0 {
contentType = contentType[0:idx]
_, ok := cw.contentWildcards[contentType]
return ok
}
return false
}
func (cw *compressResponseWriter) WriteHeader(code int) {
if cw.wroteHeader {
cw.ResponseWriter.WriteHeader(code) // Allow multiple calls to propagate.
return
}
cw.wroteHeader = true
defer cw.ResponseWriter.WriteHeader(code)
// Already compressed data?
if cw.Header().Get("Content-Encoding") != "" {
return
}
if !cw.isCompressable() {
cw.compressable = false
return
}
if cw.encoding != "" {
cw.compressable = true
cw.Header().Set("Content-Encoding", cw.encoding)
cw.Header().Set("Vary", "Accept-Encoding")
// The content-length after compression is unknown
cw.Header().Del("Content-Length")
}
}
func (cw *compressResponseWriter) Write(p []byte) (int, error) {
if !cw.wroteHeader {
cw.WriteHeader(http.StatusOK)
}
return cw.writer().Write(p)
}
func (cw *compressResponseWriter) writer() io.Writer {
if cw.compressable {
return cw.w
} else {
return cw.ResponseWriter
}
}
type compressFlusher interface {
Flush() error
}
func (cw *compressResponseWriter) Flush() {
if f, ok := cw.writer().(http.Flusher); ok {
f.Flush()
}
// If the underlying writer has a compression flush signature,
// call this Flush() method instead
if f, ok := cw.writer().(compressFlusher); ok {
f.Flush()
// Also flush the underlying response writer
if f, ok := cw.ResponseWriter.(http.Flusher); ok {
f.Flush()
}
}
}
func (cw *compressResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if hj, ok := cw.writer().(http.Hijacker); ok {
return hj.Hijack()
}
return nil, nil, errors.New("chi/middleware: http.Hijacker is unavailable on the writer")
}
func (cw *compressResponseWriter) Push(target string, opts *http.PushOptions) error {
if ps, ok := cw.writer().(http.Pusher); ok {
return ps.Push(target, opts)
}
return errors.New("chi/middleware: http.Pusher is unavailable on the writer")
}
func (cw *compressResponseWriter) Close() error {
if c, ok := cw.writer().(io.WriteCloser); ok {
return c.Close()
}
return errors.New("chi/middleware: io.WriteCloser is unavailable on the writer")
}
func encoderGzip(w io.Writer, level int) io.Writer {
gw, err := gzip.NewWriterLevel(w, level)
if err != nil {
return nil
}
return gw
}
func encoderDeflate(w io.Writer, level int) io.Writer {
dw, err := flate.NewWriter(w, level)
if err != nil {
return nil
}
return dw
}

View file

@ -0,0 +1,51 @@
package middleware
import (
"net/http"
"strings"
)
// ContentCharset generates a handler that writes a 415 Unsupported Media Type response if none of the charsets match.
// An empty charset will allow requests with no Content-Type header or no specified charset.
func ContentCharset(charsets ...string) func(next http.Handler) http.Handler {
for i, c := range charsets {
charsets[i] = strings.ToLower(c)
}
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !contentEncoding(r.Header.Get("Content-Type"), charsets...) {
w.WriteHeader(http.StatusUnsupportedMediaType)
return
}
next.ServeHTTP(w, r)
})
}
}
// Check the content encoding against a list of acceptable values.
func contentEncoding(ce string, charsets ...string) bool {
_, ce = split(strings.ToLower(ce), ";")
_, ce = split(ce, "charset=")
ce, _ = split(ce, ";")
for _, c := range charsets {
if ce == c {
return true
}
}
return false
}
// Split a string in two parts, cleaning any whitespace.
func split(str, sep string) (string, string) {
var a, b string
var parts = strings.SplitN(str, sep, 2)
a = strings.TrimSpace(parts[0])
if len(parts) == 2 {
b = strings.TrimSpace(parts[1])
}
return a, b
}

View file

@ -0,0 +1,34 @@
package middleware
import (
"net/http"
"strings"
)
// AllowContentEncoding enforces a whitelist of request Content-Encoding otherwise responds
// with a 415 Unsupported Media Type status.
func AllowContentEncoding(contentEncoding ...string) func(next http.Handler) http.Handler {
allowedEncodings := make(map[string]struct{}, len(contentEncoding))
for _, encoding := range contentEncoding {
allowedEncodings[strings.TrimSpace(strings.ToLower(encoding))] = struct{}{}
}
return func(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
requestEncodings := r.Header["Content-Encoding"]
// skip check for empty content body or no Content-Encoding
if r.ContentLength == 0 {
next.ServeHTTP(w, r)
return
}
// All encodings in the request must be allowed
for _, encoding := range requestEncodings {
if _, ok := allowedEncodings[strings.TrimSpace(strings.ToLower(encoding))]; !ok {
w.WriteHeader(http.StatusUnsupportedMediaType)
return
}
}
next.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
}

Some files were not shown because too many files have changed in this diff Show more