mirror of https://github.com/liamg/aminal.git
Windows support and enhancements. (#123)
* Windows support and enhancements. - Added basic platform abstraction layer for Pty and Process creation; - Added "platform" package that exposes a few interfaces and provides implementations for different platforms; - Windows build and dev env setup instructions; - Setup Travis and deploy git tags to GItHub releases; - Window scaling awares of monitor's dpi; - Resolved memory leaks on window resizing; - Default limit for terminal's buffer length. Co-authored-by: nikitar020 <nikitar020@mail.ru> Co-authored-by: Max Risuhin <risuhin.max@gmail.com> Co-authored-by: Roman Shevchenko <rrrooommmaaa@mail.ru> * ReadMe updated with Windows support; Detecting of currently used monitor.
This commit is contained in:
parent
4b97358eb0
commit
a8ed9d472e
|
@ -1 +1,4 @@
|
||||||
aminal
|
aminal
|
||||||
|
aminal.exe
|
||||||
|
*.syso
|
||||||
|
.idea
|
|
@ -0,0 +1,37 @@
|
||||||
|
language: go
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
go:
|
||||||
|
- 1.10.x
|
||||||
|
- 1.11.x
|
||||||
|
- master
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
- go: master
|
||||||
|
fast_finish: true
|
||||||
|
go_import_path: github.com/liamg/aminal
|
||||||
|
before_install:
|
||||||
|
- if [[ $TRAVIS_OS_NAME == 'linux' ]]; then sudo apt-get install -y xorg-dev libgl1-mesa-dev
|
||||||
|
gcc-multilib gcc-mingw-w64-x86-64 && go get github.com/mitchellh/gox; fi
|
||||||
|
script:
|
||||||
|
- make test
|
||||||
|
- if [[ $TRAVIS_OS_NAME == 'osx' ]]; then make build-darwin-native-travis; fi
|
||||||
|
- if [[ $TRAVIS_OS_NAME == 'linux' ]]; then make build-linux-travis; fi
|
||||||
|
- if [[ $TRAVIS_OS_NAME == 'linux' ]]; then make windows-cross-compile-travis; fi
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- secure: YOUR_SECURE_TOKEN
|
||||||
|
deploy:
|
||||||
|
provider: releases
|
||||||
|
skip_cleanup: true
|
||||||
|
api_key:
|
||||||
|
secure: YOUR_SECURE_TOKEN
|
||||||
|
file:
|
||||||
|
- bin/darwin/aminal-darwin-amd64
|
||||||
|
- bin/linux/aminal-linux-amd64
|
||||||
|
- bin/windows/aminal-windows-amd64.exe
|
||||||
|
on:
|
||||||
|
repo: liamg/aminal
|
||||||
|
tags: true
|
||||||
|
condition: "$TRAVIS_GO_VERSION =~ ^1\\.11"
|
22
Makefile
22
Makefile
|
@ -33,3 +33,25 @@ build-darwin:
|
||||||
.PHONY: package-debian
|
.PHONY: package-debian
|
||||||
package-debian: build-linux
|
package-debian: build-linux
|
||||||
./scripts/package-debian.sh "${CIRCLE_TAG}" bin/linux/${BINARY}-linux-amd64
|
./scripts/package-debian.sh "${CIRCLE_TAG}" bin/linux/${BINARY}-linux-amd64
|
||||||
|
|
||||||
|
.PHONY: build-linux-travis
|
||||||
|
build-linux-travis:
|
||||||
|
mkdir -p bin/linux
|
||||||
|
GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o bin/linux/${BINARY}-linux-amd64 -ldflags "-X github.com/liamg/aminal/version.Version=${TRAVIS_TAG}"
|
||||||
|
|
||||||
|
.PHONY: windows-cross-compile-travis
|
||||||
|
windows-cross-compile-travis:
|
||||||
|
mkdir -p bin/windows
|
||||||
|
x86_64-w64-mingw32-windres -o aminal.syso aminal.rc
|
||||||
|
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CXX=x86_64-w64-mingw32-g++ CC=x86_64-w64-mingw32-gcc go build -o bin/windows/${BINARY}-windows-amd64.exe -ldflags "-X github.com/liamg/aminal/version.Version=${TRAVIS_TAG}"
|
||||||
|
|
||||||
|
.PHONY: build-windows
|
||||||
|
build-windows:
|
||||||
|
windres -o aminal.syso aminal.rc
|
||||||
|
go build -o ${BINARY}-windows-amd64.exe
|
||||||
|
|
||||||
|
.PHONY: build-darwin-native-travis
|
||||||
|
build-darwin-native-travis:
|
||||||
|
mkdir -p bin/darwin
|
||||||
|
GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 go build -o bin/darwin/${BINARY}-darwin-amd64 -ldflags "-X github.com/liamg/aminal/version.Version=${TRAVIS_TAG}"
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ Ensure you have your latest graphics card drivers installed before use.
|
||||||
- Scrollback buffer
|
- Scrollback buffer
|
||||||
- Clipboard access
|
- Clipboard access
|
||||||
- Clickable URLs
|
- Clickable URLs
|
||||||
- Multi platform support (Windows coming soon...)
|
- Multi platform support (Windows, Linux, OSX)
|
||||||
- Sixel support
|
- Sixel support
|
||||||
- Hints/overlays
|
- Hints/overlays
|
||||||
- Built-in patched fonts for powerline
|
- Built-in patched fonts for powerline
|
||||||
|
@ -41,11 +41,11 @@ brew install aminal
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
A Windows version of Aminal is expected in the next 1-2 months.
|
Dev environment setup instructions are available [there](windows.md).
|
||||||
|
|
||||||
### Prebuilt Binaries
|
### Prebuilt Binaries
|
||||||
|
|
||||||
Prebuilt binaries are available for Linux and OSX on the [releases](https://github.com/liamg/aminal/releases) page.
|
Prebuilt binaries are available for Linux, OSX and Windows on the [releases](https://github.com/liamg/aminal/releases) page.
|
||||||
|
|
||||||
Download the binary and `sudo cp aminal-* /usr/local/bin/aminal && chmod +x /usr/local/bin/aminal`.
|
Download the binary and `sudo cp aminal-* /usr/local/bin/aminal && chmod +x /usr/local/bin/aminal`.
|
||||||
|
|
||||||
|
@ -97,6 +97,8 @@ Aminal looks for a config file in the following places, and stops when it finds
|
||||||
* `$HOME/.config/aminal/config.toml`
|
* `$HOME/.config/aminal/config.toml`
|
||||||
* `$HOME/.aminal.toml`
|
* `$HOME/.aminal.toml`
|
||||||
|
|
||||||
|
Note that on Windows Aminal uses `%USERPROFILE%` environment variable instead of `$HOME`
|
||||||
|
|
||||||
It will write a config file to whichever of those directories exists (preferring the top of the list) the first time it runs, if one doesn't already exist.
|
It will write a config file to whichever of those directories exists (preferring the top of the list) the first time it runs, if one doesn't already exist.
|
||||||
|
|
||||||
You can ignore the config and use defaults by specifying `--ignore-config` as a CLI flag.
|
You can ignore the config and use defaults by specifying `--ignore-config` as a CLI flag.
|
||||||
|
@ -108,6 +110,7 @@ debug = false # Enable debug logging to stdout. Defaults to false.
|
||||||
slomo = false # Enable slow motion output mode, useful for debugging shells/terminal GUI apps etc. Defaults to false.
|
slomo = false # Enable slow motion output mode, useful for debugging shells/terminal GUI apps etc. Defaults to false.
|
||||||
shell = "/bin/bash" # The shell to run for the terminal session. Defaults to the users shell.
|
shell = "/bin/bash" # The shell to run for the terminal session. Defaults to the users shell.
|
||||||
search_url = "https://www.google.com/search?q=$QUERY" # The search engine to use for the "search selected text" action. Defaults to google. Set this to your own search url using $QUERY as the keywords to replace when searching.
|
search_url = "https://www.google.com/search?q=$QUERY" # The search engine to use for the "search selected text" action. Defaults to google. Set this to your own search url using $QUERY as the keywords to replace when searching.
|
||||||
|
max_lines = 1000 # Maximum number of lines in the terminal buffer.
|
||||||
|
|
||||||
[colours]
|
[colours]
|
||||||
cursor = "#e8dfd6"
|
cursor = "#e8dfd6"
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<assemblyIdentity
|
||||||
|
version="1.0.0.0"
|
||||||
|
processorArchitecture="x86"
|
||||||
|
name="controls"
|
||||||
|
type="win32"
|
||||||
|
/>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity
|
||||||
|
type="win32"
|
||||||
|
name="Microsoft.Windows.Common-Controls"
|
||||||
|
version="6.0.0.0"
|
||||||
|
processorArchitecture="*"
|
||||||
|
publicKeyToken="6595b64144ccf1df"
|
||||||
|
language="*"
|
||||||
|
/>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
</assembly>
|
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,3 @@
|
||||||
|
100 ICON "aminal.ico"
|
||||||
|
100 24 "aminal.exe.manifest"
|
||||||
|
GLFW_ICON ICON "aminal.ico"
|
|
@ -28,6 +28,7 @@ type Buffer struct {
|
||||||
selectionExpanded bool // whether the selection to word expansion has already run on this point
|
selectionExpanded bool // whether the selection to word expansion has already run on this point
|
||||||
selectionClickTime time.Time
|
selectionClickTime time.Time
|
||||||
defaultCell Cell
|
defaultCell Cell
|
||||||
|
maxLines uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Position struct {
|
type Position struct {
|
||||||
|
@ -36,7 +37,7 @@ type Position struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBuffer creates a new terminal buffer
|
// NewBuffer creates a new terminal buffer
|
||||||
func NewBuffer(viewCols uint16, viewLines uint16, attr CellAttributes) *Buffer {
|
func NewBuffer(viewCols uint16, viewLines uint16, attr CellAttributes, maxLines uint64) *Buffer {
|
||||||
b := &Buffer{
|
b := &Buffer{
|
||||||
cursorX: 0,
|
cursorX: 0,
|
||||||
cursorY: 0,
|
cursorY: 0,
|
||||||
|
@ -44,6 +45,7 @@ func NewBuffer(viewCols uint16, viewLines uint16, attr CellAttributes) *Buffer {
|
||||||
cursorAttr: attr,
|
cursorAttr: attr,
|
||||||
autoWrap: true,
|
autoWrap: true,
|
||||||
defaultCell: Cell{attr: attr},
|
defaultCell: Cell{attr: attr},
|
||||||
|
maxLines: maxLines,
|
||||||
}
|
}
|
||||||
b.SetVerticalMargins(0, uint(viewLines-1))
|
b.SetVerticalMargins(0, uint(viewLines-1))
|
||||||
b.ResizeView(viewCols, viewLines)
|
b.ResizeView(viewCols, viewLines)
|
||||||
|
@ -479,8 +481,16 @@ func (buffer *Buffer) insertLine() {
|
||||||
|
|
||||||
if !buffer.InScrollableRegion() {
|
if !buffer.InScrollableRegion() {
|
||||||
pos := buffer.RawLine()
|
pos := buffer.RawLine()
|
||||||
out := make([]Line, len(buffer.lines)+1)
|
maxLines := buffer.getMaxLines()
|
||||||
copy(out[:pos], buffer.lines[:pos])
|
newLineCount := uint64(len(buffer.lines) + 1)
|
||||||
|
if newLineCount > maxLines {
|
||||||
|
newLineCount = maxLines
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make([]Line, newLineCount)
|
||||||
|
copy(
|
||||||
|
out[ : pos - ( uint64(len(buffer.lines)) + 1 - newLineCount )],
|
||||||
|
buffer.lines[ uint64(len(buffer.lines)) + 1 - newLineCount : pos] )
|
||||||
out[pos] = newLine()
|
out[pos] = newLine()
|
||||||
copy(out[pos+1:], buffer.lines[pos:])
|
copy(out[pos+1:], buffer.lines[pos:])
|
||||||
buffer.lines = out
|
buffer.lines = out
|
||||||
|
@ -575,6 +585,10 @@ func (buffer *Buffer) Index() {
|
||||||
|
|
||||||
if buffer.cursorY >= buffer.ViewHeight()-1 {
|
if buffer.cursorY >= buffer.ViewHeight()-1 {
|
||||||
buffer.lines = append(buffer.lines, newLine())
|
buffer.lines = append(buffer.lines, newLine())
|
||||||
|
maxLines := buffer.getMaxLines()
|
||||||
|
if uint64(len(buffer.lines)) > maxLines {
|
||||||
|
buffer.lines = buffer.lines[ uint64(len(buffer.lines)) - maxLines : ]
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
buffer.cursorY++
|
buffer.cursorY++
|
||||||
}
|
}
|
||||||
|
@ -1025,3 +1039,12 @@ func (buffer *Buffer) ResizeView(width uint16, height uint16) {
|
||||||
|
|
||||||
buffer.SetVerticalMargins(0, uint(buffer.viewHeight-1))
|
buffer.SetVerticalMargins(0, uint(buffer.viewHeight-1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (buffer *Buffer) getMaxLines() uint64 {
|
||||||
|
result := buffer.maxLines
|
||||||
|
if result < uint64(buffer.viewHeight) {
|
||||||
|
result = uint64(buffer.viewHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTabbing(t *testing.T) {
|
func TestTabbing(t *testing.T) {
|
||||||
b := NewBuffer(30, 3, CellAttributes{})
|
b := NewBuffer(30, 3, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello")...)
|
b.Write([]rune("hello")...)
|
||||||
b.Tab()
|
b.Tab()
|
||||||
b.Write([]rune("x")...)
|
b.Write([]rune("x")...)
|
||||||
|
@ -39,7 +39,7 @@ hell xxx good
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOffsets(t *testing.T) {
|
func TestOffsets(t *testing.T) {
|
||||||
b := NewBuffer(10, 3, CellAttributes{})
|
b := NewBuffer(10, 3, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello")...)
|
b.Write([]rune("hello")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.NewLine()
|
b.NewLine()
|
||||||
|
@ -60,7 +60,7 @@ func TestOffsets(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBufferCreation(t *testing.T) {
|
func TestBufferCreation(t *testing.T) {
|
||||||
b := NewBuffer(10, 20, CellAttributes{})
|
b := NewBuffer(10, 20, CellAttributes{}, 1000)
|
||||||
assert.Equal(t, uint16(10), b.Width())
|
assert.Equal(t, uint16(10), b.Width())
|
||||||
assert.Equal(t, uint16(20), b.ViewHeight())
|
assert.Equal(t, uint16(20), b.ViewHeight())
|
||||||
assert.Equal(t, uint16(0), b.CursorColumn())
|
assert.Equal(t, uint16(0), b.CursorColumn())
|
||||||
|
@ -70,7 +70,7 @@ func TestBufferCreation(t *testing.T) {
|
||||||
|
|
||||||
func TestBufferWriteIncrementsCursorCorrectly(t *testing.T) {
|
func TestBufferWriteIncrementsCursorCorrectly(t *testing.T) {
|
||||||
|
|
||||||
b := NewBuffer(5, 4, CellAttributes{})
|
b := NewBuffer(5, 4, CellAttributes{}, 1000)
|
||||||
|
|
||||||
/*01234
|
/*01234
|
||||||
|-----
|
|-----
|
||||||
|
@ -117,7 +117,7 @@ func TestBufferWriteIncrementsCursorCorrectly(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWritingNewLineAsFirstRuneOnWrappedLine(t *testing.T) {
|
func TestWritingNewLineAsFirstRuneOnWrappedLine(t *testing.T) {
|
||||||
b := NewBuffer(3, 20, CellAttributes{})
|
b := NewBuffer(3, 20, CellAttributes{}, 1000)
|
||||||
b.Write('a', 'b', 'c')
|
b.Write('a', 'b', 'c')
|
||||||
assert.Equal(t, uint16(3), b.cursorX)
|
assert.Equal(t, uint16(3), b.cursorX)
|
||||||
assert.Equal(t, uint16(0), b.cursorY)
|
assert.Equal(t, uint16(0), b.cursorY)
|
||||||
|
@ -140,7 +140,7 @@ func TestWritingNewLineAsFirstRuneOnWrappedLine(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWritingNewLineAsSecondRuneOnWrappedLine(t *testing.T) {
|
func TestWritingNewLineAsSecondRuneOnWrappedLine(t *testing.T) {
|
||||||
b := NewBuffer(3, 20, CellAttributes{})
|
b := NewBuffer(3, 20, CellAttributes{}, 1000)
|
||||||
/*
|
/*
|
||||||
|abc
|
|abc
|
||||||
|d
|
|d
|
||||||
|
@ -168,7 +168,7 @@ func TestWritingNewLineAsSecondRuneOnWrappedLine(t *testing.T) {
|
||||||
|
|
||||||
func TestSetPosition(t *testing.T) {
|
func TestSetPosition(t *testing.T) {
|
||||||
|
|
||||||
b := NewBuffer(120, 80, CellAttributes{})
|
b := NewBuffer(120, 80, CellAttributes{}, 1000)
|
||||||
assert.Equal(t, 0, int(b.CursorColumn()))
|
assert.Equal(t, 0, int(b.CursorColumn()))
|
||||||
assert.Equal(t, 0, int(b.CursorLine()))
|
assert.Equal(t, 0, int(b.CursorLine()))
|
||||||
b.SetPosition(60, 10)
|
b.SetPosition(60, 10)
|
||||||
|
@ -184,7 +184,7 @@ func TestSetPosition(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMovePosition(t *testing.T) {
|
func TestMovePosition(t *testing.T) {
|
||||||
b := NewBuffer(120, 80, CellAttributes{})
|
b := NewBuffer(120, 80, CellAttributes{}, 1000)
|
||||||
assert.Equal(t, 0, int(b.CursorColumn()))
|
assert.Equal(t, 0, int(b.CursorColumn()))
|
||||||
assert.Equal(t, 0, int(b.CursorLine()))
|
assert.Equal(t, 0, int(b.CursorLine()))
|
||||||
b.MovePosition(-1, -1)
|
b.MovePosition(-1, -1)
|
||||||
|
@ -206,7 +206,7 @@ func TestMovePosition(t *testing.T) {
|
||||||
|
|
||||||
func TestVisibleLines(t *testing.T) {
|
func TestVisibleLines(t *testing.T) {
|
||||||
|
|
||||||
b := NewBuffer(80, 10, CellAttributes{})
|
b := NewBuffer(80, 10, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello 1")...)
|
b.Write([]rune("hello 1")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.NewLine()
|
b.NewLine()
|
||||||
|
@ -256,7 +256,7 @@ func TestVisibleLines(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClearWithoutFullView(t *testing.T) {
|
func TestClearWithoutFullView(t *testing.T) {
|
||||||
b := NewBuffer(80, 10, CellAttributes{})
|
b := NewBuffer(80, 10, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello 1")...)
|
b.Write([]rune("hello 1")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.NewLine()
|
b.NewLine()
|
||||||
|
@ -272,7 +272,7 @@ func TestClearWithoutFullView(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClearWithFullView(t *testing.T) {
|
func TestClearWithFullView(t *testing.T) {
|
||||||
b := NewBuffer(80, 5, CellAttributes{})
|
b := NewBuffer(80, 5, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello 1")...)
|
b.Write([]rune("hello 1")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.NewLine()
|
b.NewLine()
|
||||||
|
@ -303,7 +303,7 @@ func TestClearWithFullView(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCarriageReturn(t *testing.T) {
|
func TestCarriageReturn(t *testing.T) {
|
||||||
b := NewBuffer(80, 20, CellAttributes{})
|
b := NewBuffer(80, 20, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello!")...)
|
b.Write([]rune("hello!")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.Write([]rune("secret")...)
|
b.Write([]rune("secret")...)
|
||||||
|
@ -312,7 +312,7 @@ func TestCarriageReturn(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCarriageReturnOnFullLine(t *testing.T) {
|
func TestCarriageReturnOnFullLine(t *testing.T) {
|
||||||
b := NewBuffer(20, 20, CellAttributes{})
|
b := NewBuffer(20, 20, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("abcdeabcdeabcdeabcde")...)
|
b.Write([]rune("abcdeabcdeabcdeabcde")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.Write([]rune("xxxxxxxxxxxxxxxxxxxx")...)
|
b.Write([]rune("xxxxxxxxxxxxxxxxxxxx")...)
|
||||||
|
@ -321,7 +321,7 @@ func TestCarriageReturnOnFullLine(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCarriageReturnOnFullLastLine(t *testing.T) {
|
func TestCarriageReturnOnFullLastLine(t *testing.T) {
|
||||||
b := NewBuffer(20, 2, CellAttributes{})
|
b := NewBuffer(20, 2, CellAttributes{}, 1000)
|
||||||
b.NewLine()
|
b.NewLine()
|
||||||
b.Write([]rune("abcdeabcdeabcdeabcde")...)
|
b.Write([]rune("abcdeabcdeabcdeabcde")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
|
@ -332,7 +332,7 @@ func TestCarriageReturnOnFullLastLine(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCarriageReturnOnWrappedLine(t *testing.T) {
|
func TestCarriageReturnOnWrappedLine(t *testing.T) {
|
||||||
b := NewBuffer(80, 6, CellAttributes{})
|
b := NewBuffer(80, 6, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello!")...)
|
b.Write([]rune("hello!")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.Write([]rune("secret")...)
|
b.Write([]rune("secret")...)
|
||||||
|
@ -342,7 +342,7 @@ func TestCarriageReturnOnWrappedLine(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCarriageReturnOnLineThatDoesntExist(t *testing.T) {
|
func TestCarriageReturnOnLineThatDoesntExist(t *testing.T) {
|
||||||
b := NewBuffer(6, 10, CellAttributes{})
|
b := NewBuffer(6, 10, CellAttributes{}, 1000)
|
||||||
b.cursorY = 3
|
b.cursorY = 3
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
assert.Equal(t, uint16(0), b.cursorX)
|
assert.Equal(t, uint16(0), b.cursorX)
|
||||||
|
@ -350,7 +350,7 @@ func TestCarriageReturnOnLineThatDoesntExist(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetCell(t *testing.T) {
|
func TestGetCell(t *testing.T) {
|
||||||
b := NewBuffer(80, 20, CellAttributes{})
|
b := NewBuffer(80, 20, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("Hello")...)
|
b.Write([]rune("Hello")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.NewLine()
|
b.NewLine()
|
||||||
|
@ -366,7 +366,7 @@ func TestGetCell(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetCellWithHistory(t *testing.T) {
|
func TestGetCellWithHistory(t *testing.T) {
|
||||||
b := NewBuffer(80, 2, CellAttributes{})
|
b := NewBuffer(80, 2, CellAttributes{}, 1000)
|
||||||
|
|
||||||
b.Write([]rune("Hello")...)
|
b.Write([]rune("Hello")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
|
@ -384,7 +384,7 @@ func TestGetCellWithHistory(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetCellWithBadCursor(t *testing.T) {
|
func TestGetCellWithBadCursor(t *testing.T) {
|
||||||
b := NewBuffer(80, 2, CellAttributes{})
|
b := NewBuffer(80, 2, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("Hello\r\nthere\r\nsomething...")...)
|
b.Write([]rune("Hello\r\nthere\r\nsomething...")...)
|
||||||
require.Nil(t, b.GetCell(8, 3))
|
require.Nil(t, b.GetCell(8, 3))
|
||||||
require.Nil(t, b.GetCell(90, 0))
|
require.Nil(t, b.GetCell(90, 0))
|
||||||
|
@ -392,12 +392,12 @@ func TestGetCellWithBadCursor(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCursorAttr(t *testing.T) {
|
func TestCursorAttr(t *testing.T) {
|
||||||
b := NewBuffer(80, 2, CellAttributes{})
|
b := NewBuffer(80, 2, CellAttributes{}, 1000)
|
||||||
assert.Equal(t, &b.cursorAttr, b.CursorAttr())
|
assert.Equal(t, &b.cursorAttr, b.CursorAttr())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCursorPositionQuerying(t *testing.T) {
|
func TestCursorPositionQuerying(t *testing.T) {
|
||||||
b := NewBuffer(80, 20, CellAttributes{})
|
b := NewBuffer(80, 20, CellAttributes{}, 1000)
|
||||||
b.cursorX = 17
|
b.cursorX = 17
|
||||||
b.cursorY = 9
|
b.cursorY = 9
|
||||||
assert.Equal(t, b.cursorX, b.CursorColumn())
|
assert.Equal(t, b.cursorX, b.CursorColumn())
|
||||||
|
@ -405,7 +405,7 @@ func TestCursorPositionQuerying(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRawPositionQuerying(t *testing.T) {
|
func TestRawPositionQuerying(t *testing.T) {
|
||||||
b := NewBuffer(80, 5, CellAttributes{})
|
b := NewBuffer(80, 5, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("a")...)
|
b.Write([]rune("a")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.NewLine()
|
b.NewLine()
|
||||||
|
@ -442,7 +442,7 @@ func TestRawPositionQuerying(t *testing.T) {
|
||||||
|
|
||||||
// CSI 2 K
|
// CSI 2 K
|
||||||
func TestEraseLine(t *testing.T) {
|
func TestEraseLine(t *testing.T) {
|
||||||
b := NewBuffer(80, 5, CellAttributes{})
|
b := NewBuffer(80, 5, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello, this is a test")...)
|
b.Write([]rune("hello, this is a test")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.NewLine()
|
b.NewLine()
|
||||||
|
@ -454,7 +454,7 @@ func TestEraseLine(t *testing.T) {
|
||||||
|
|
||||||
// CSI 1 K
|
// CSI 1 K
|
||||||
func TestEraseLineToCursor(t *testing.T) {
|
func TestEraseLineToCursor(t *testing.T) {
|
||||||
b := NewBuffer(80, 5, CellAttributes{})
|
b := NewBuffer(80, 5, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello, this is a test")...)
|
b.Write([]rune("hello, this is a test")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.NewLine()
|
b.NewLine()
|
||||||
|
@ -468,7 +468,7 @@ func TestEraseLineToCursor(t *testing.T) {
|
||||||
|
|
||||||
// CSI 0 K
|
// CSI 0 K
|
||||||
func TestEraseLineAfterCursor(t *testing.T) {
|
func TestEraseLineAfterCursor(t *testing.T) {
|
||||||
b := NewBuffer(80, 5, CellAttributes{})
|
b := NewBuffer(80, 5, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello, this is a test")...)
|
b.Write([]rune("hello, this is a test")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.NewLine()
|
b.NewLine()
|
||||||
|
@ -479,7 +479,7 @@ func TestEraseLineAfterCursor(t *testing.T) {
|
||||||
assert.Equal(t, "dele", b.lines[1].String())
|
assert.Equal(t, "dele", b.lines[1].String())
|
||||||
}
|
}
|
||||||
func TestEraseDisplay(t *testing.T) {
|
func TestEraseDisplay(t *testing.T) {
|
||||||
b := NewBuffer(80, 5, CellAttributes{})
|
b := NewBuffer(80, 5, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello")...)
|
b.Write([]rune("hello")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.NewLine()
|
b.NewLine()
|
||||||
|
@ -495,7 +495,7 @@ func TestEraseDisplay(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func TestEraseDisplayToCursor(t *testing.T) {
|
func TestEraseDisplayToCursor(t *testing.T) {
|
||||||
b := NewBuffer(80, 5, CellAttributes{})
|
b := NewBuffer(80, 5, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello")...)
|
b.Write([]rune("hello")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.NewLine()
|
b.NewLine()
|
||||||
|
@ -513,7 +513,7 @@ func TestEraseDisplayToCursor(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEraseDisplayFromCursor(t *testing.T) {
|
func TestEraseDisplayFromCursor(t *testing.T) {
|
||||||
b := NewBuffer(80, 5, CellAttributes{})
|
b := NewBuffer(80, 5, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello")...)
|
b.Write([]rune("hello")...)
|
||||||
b.CarriageReturn()
|
b.CarriageReturn()
|
||||||
b.NewLine()
|
b.NewLine()
|
||||||
|
@ -529,7 +529,7 @@ func TestEraseDisplayFromCursor(t *testing.T) {
|
||||||
assert.Equal(t, "", lines[2].String())
|
assert.Equal(t, "", lines[2].String())
|
||||||
}
|
}
|
||||||
func TestBackspace(t *testing.T) {
|
func TestBackspace(t *testing.T) {
|
||||||
b := NewBuffer(80, 5, CellAttributes{})
|
b := NewBuffer(80, 5, CellAttributes{}, 1000)
|
||||||
b.Write([]rune("hello")...)
|
b.Write([]rune("hello")...)
|
||||||
b.Backspace()
|
b.Backspace()
|
||||||
b.Backspace()
|
b.Backspace()
|
||||||
|
@ -539,7 +539,7 @@ func TestBackspace(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHorizontalResizeView(t *testing.T) {
|
func TestHorizontalResizeView(t *testing.T) {
|
||||||
b := NewBuffer(80, 10, CellAttributes{})
|
b := NewBuffer(80, 10, CellAttributes{}, 1000)
|
||||||
|
|
||||||
// 60 characters
|
// 60 characters
|
||||||
b.Write([]rune(`hellohellohellohellohellohellohellohellohellohellohellohello`)...)
|
b.Write([]rune(`hellohellohellohellohellohellohellohellohellohellohellohello`)...)
|
||||||
|
@ -621,3 +621,17 @@ hellohellohellohellohellohellohellohellohellohellohellohello
|
||||||
goodbyegoo
|
goodbyegoo
|
||||||
dbye
|
dbye
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
func TestBufferMaxLines(t *testing.T) {
|
||||||
|
b := NewBuffer(80, 2, CellAttributes{}, 2)
|
||||||
|
|
||||||
|
b.Write([]rune("hello")...)
|
||||||
|
b.NewLine()
|
||||||
|
b.Write([]rune("funny")...)
|
||||||
|
b.NewLine()
|
||||||
|
b.Write([]rune("world")...)
|
||||||
|
|
||||||
|
assert.Equal(t, 2, len(b.lines))
|
||||||
|
assert.Equal(t, "funny", b.lines[0].String())
|
||||||
|
assert.Equal(t, "world", b.lines[1].String())
|
||||||
|
}
|
36
config.go
36
config.go
|
@ -5,8 +5,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
"github.com/liamg/aminal/config"
|
"github.com/liamg/aminal/config"
|
||||||
"github.com/liamg/aminal/version"
|
"github.com/liamg/aminal/version"
|
||||||
)
|
)
|
||||||
|
@ -44,7 +44,13 @@ func getConfig() *config.Config {
|
||||||
|
|
||||||
func loadConfigFile() *config.Config {
|
func loadConfigFile() *config.Config {
|
||||||
|
|
||||||
home := os.Getenv("HOME")
|
usr, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to get current user information: %s\n", err)
|
||||||
|
return &config.DefaultConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
home := usr.HomeDir
|
||||||
if home == "" {
|
if home == "" {
|
||||||
return &config.DefaultConfig
|
return &config.DefaultConfig
|
||||||
}
|
}
|
||||||
|
@ -53,11 +59,11 @@ func loadConfigFile() *config.Config {
|
||||||
|
|
||||||
xdgHome := os.Getenv("XDG_CONFIG_HOME")
|
xdgHome := os.Getenv("XDG_CONFIG_HOME")
|
||||||
if xdgHome != "" {
|
if xdgHome != "" {
|
||||||
places = append(places, fmt.Sprintf("%s/aminal/config.toml", xdgHome))
|
places = append(places, filepath.Join(xdgHome, "aminal/config.toml"))
|
||||||
}
|
}
|
||||||
|
|
||||||
places = append(places, fmt.Sprintf("%s/.config/aminal/config.toml", home))
|
places = append(places, filepath.Join(home, ".config/aminal/config.toml"))
|
||||||
places = append(places, fmt.Sprintf("%s/.aminal.toml", home))
|
places = append(places, filepath.Join(home, ".aminal.toml"))
|
||||||
|
|
||||||
for _, place := range places {
|
for _, place := range places {
|
||||||
if b, err := ioutil.ReadFile(place); err == nil {
|
if b, err := ioutil.ReadFile(place); err == nil {
|
||||||
|
@ -69,20 +75,18 @@ func loadConfigFile() *config.Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parts := strings.Split(places[0], string(os.PathSeparator))
|
|
||||||
path := strings.Join(parts[0:len(parts)-1], string(os.PathSeparator))
|
|
||||||
|
|
||||||
err := os.MkdirAll(path, 0744)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if b, err := config.DefaultConfig.Encode(); err != nil {
|
if b, err := config.DefaultConfig.Encode(); err != nil {
|
||||||
fmt.Printf("Failed to encode config file: %s\n", err)
|
fmt.Printf("Failed to encode config file: %s\n", err)
|
||||||
} else {
|
} else {
|
||||||
if err := ioutil.WriteFile(fmt.Sprintf("%s/config.toml", path), b, 0644); err != nil {
|
err = os.MkdirAll(filepath.Dir(places[0]), 0744)
|
||||||
fmt.Printf("Failed to encode config file: %s\n", err)
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to create config file directory: %s\n", err)
|
||||||
|
} else {
|
||||||
|
if err = ioutil.WriteFile(places[0], b, 0644); err != nil {
|
||||||
|
fmt.Printf("Failed to encode config file: %s\n", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &config.DefaultConfig
|
return &config.DefaultConfig
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ type Config struct {
|
||||||
Shell string `toml:"shell"`
|
Shell string `toml:"shell"`
|
||||||
KeyMapping KeyMappingConfig `toml:"keys"`
|
KeyMapping KeyMappingConfig `toml:"keys"`
|
||||||
SearchURL string `toml:"search_url"`
|
SearchURL string `toml:"search_url"`
|
||||||
|
MaxLines uint64 `toml:"max_lines"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeyMappingConfig map[string]string
|
type KeyMappingConfig map[string]string
|
||||||
|
|
|
@ -28,6 +28,7 @@ var DefaultConfig = Config{
|
||||||
},
|
},
|
||||||
KeyMapping: KeyMappingConfig(map[string]string{}),
|
KeyMapping: KeyMappingConfig(map[string]string{}),
|
||||||
SearchURL: "https://www.google.com/search?q=$QUERY",
|
SearchURL: "https://www.google.com/search?q=$QUERY",
|
||||||
|
MaxLines: 1000,
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
@ -15,7 +15,7 @@ func (gui *GUI) getPackedFont(name string) (*glfont.Font, error) {
|
||||||
return nil, fmt.Errorf("packaged font '%s' could not be read: %s", name, err)
|
return nil, fmt.Errorf("packaged font '%s' could not be read: %s", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
font, err := glfont.LoadFont(bytes.NewReader(fontBytes), gui.fontScale/gui.scale(), gui.width, gui.height)
|
font, err := glfont.LoadFont(bytes.NewReader(fontBytes), gui.fontScale*gui.dpiScale/gui.scale(), gui.Width(), gui.Height())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("font '%s' failed to load: %v", name, err)
|
return nil, fmt.Errorf("font '%s' failed to load: %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
104
gui/gui.go
104
gui/gui.go
|
@ -25,6 +25,7 @@ type GUI struct {
|
||||||
terminal *terminal.Terminal
|
terminal *terminal.Terminal
|
||||||
width int //window width in pixels
|
width int //window width in pixels
|
||||||
height int //window height in pixels
|
height int //window height in pixels
|
||||||
|
dpiScale float32
|
||||||
fontMap *FontMap
|
fontMap *FontMap
|
||||||
fontScale float32
|
fontScale float32
|
||||||
renderer *OpenGLRenderer
|
renderer *OpenGLRenderer
|
||||||
|
@ -37,6 +38,85 @@ type GUI struct {
|
||||||
resizeLock *sync.Mutex
|
resizeLock *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Min(x, y int) int {
|
||||||
|
if x < y {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
|
||||||
|
func Max(x, y int) int {
|
||||||
|
if x > y {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GUI) GetMonitor() *glfw.Monitor {
|
||||||
|
|
||||||
|
if g.window == nil {
|
||||||
|
panic("to determine current monitor the window must be set")
|
||||||
|
}
|
||||||
|
monitors := glfw.GetMonitors()
|
||||||
|
|
||||||
|
if len(monitors) == 1 {
|
||||||
|
return glfw.GetPrimaryMonitor()
|
||||||
|
}
|
||||||
|
|
||||||
|
x, y := g.window.GetPos()
|
||||||
|
w, h := g.window.GetSize()
|
||||||
|
var currentMonitor *glfw.Monitor
|
||||||
|
bestMatch := 0
|
||||||
|
|
||||||
|
for _, monitor := range monitors {
|
||||||
|
mode := monitor.GetVideoMode()
|
||||||
|
mx, my := monitor.GetPos()
|
||||||
|
overlap := Max(0, Min(x + w, mx + mode.Width) - Max(x, mx)) *
|
||||||
|
Max(0, Min(y + h, my + mode.Height) - Max(y, my))
|
||||||
|
if bestMatch < overlap {
|
||||||
|
bestMatch = overlap
|
||||||
|
currentMonitor = monitor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentMonitor == nil {
|
||||||
|
panic("was not able to resolve current monitor")
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentMonitor
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecalculateDpiScale calculates dpi scale in comparison with "standard" monitor's dpi values
|
||||||
|
func (g *GUI) RecalculateDpiScale() {
|
||||||
|
const standardDpi = 96
|
||||||
|
const mmPerInch = 25.4
|
||||||
|
m := g.GetMonitor()
|
||||||
|
widthMM, _ := m.GetPhysicalSize()
|
||||||
|
|
||||||
|
if widthMM == 0 {
|
||||||
|
g.dpiScale = 1.0
|
||||||
|
} else {
|
||||||
|
monitorDpi := float32(m.GetVideoMode().Width) / (float32(widthMM) / mmPerInch)
|
||||||
|
g.dpiScale = monitorDpi / standardDpi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GUI) Width() int {
|
||||||
|
return int(float32(g.width) * g.dpiScale)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GUI) SetWidth(width int) {
|
||||||
|
g.width = int(float32(width) / g.dpiScale)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GUI) Height() int {
|
||||||
|
return int(float32(g.height) * g.dpiScale)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GUI) SetHeight(height int) {
|
||||||
|
g.height = int(float32(height) / g.dpiScale)
|
||||||
|
}
|
||||||
|
|
||||||
func New(config *config.Config, terminal *terminal.Terminal, logger *zap.SugaredLogger) (*GUI, error) {
|
func New(config *config.Config, terminal *terminal.Terminal, logger *zap.SugaredLogger) (*GUI, error) {
|
||||||
|
|
||||||
shortcuts, err := config.KeyMapping.GenerateActionMap()
|
shortcuts, err := config.KeyMapping.GenerateActionMap()
|
||||||
|
@ -49,6 +129,7 @@ func New(config *config.Config, terminal *terminal.Terminal, logger *zap.Sugared
|
||||||
logger: logger,
|
logger: logger,
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
|
dpiScale: 1,
|
||||||
terminal: terminal,
|
terminal: terminal,
|
||||||
fontScale: 14.0,
|
fontScale: 14.0,
|
||||||
terminalAlpha: 1,
|
terminalAlpha: 1,
|
||||||
|
@ -73,14 +154,14 @@ func (gui *GUI) resize(w *glfw.Window, width int, height int) {
|
||||||
|
|
||||||
gui.logger.Debugf("Initiating GUI resize to %dx%d", width, height)
|
gui.logger.Debugf("Initiating GUI resize to %dx%d", width, height)
|
||||||
|
|
||||||
gui.width = width
|
gui.SetWidth(width)
|
||||||
gui.height = height
|
gui.SetHeight(height)
|
||||||
|
|
||||||
gui.logger.Debugf("Updating font resolutions...")
|
gui.logger.Debugf("Updating font resolutions...")
|
||||||
gui.loadFonts()
|
gui.loadFonts()
|
||||||
|
|
||||||
gui.logger.Debugf("Setting renderer area...")
|
gui.logger.Debugf("Setting renderer area...")
|
||||||
gui.renderer.SetArea(0, 0, width, height)
|
gui.renderer.SetArea(0, 0, gui.Width(), gui.Height())
|
||||||
|
|
||||||
gui.logger.Debugf("Calculating size in cols/rows...")
|
gui.logger.Debugf("Calculating size in cols/rows...")
|
||||||
cols, rows := gui.renderer.GetTermSize()
|
cols, rows := gui.renderer.GetTermSize()
|
||||||
|
@ -91,7 +172,7 @@ func (gui *GUI) resize(w *glfw.Window, width int, height int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.logger.Debugf("Setting viewport size...")
|
gui.logger.Debugf("Setting viewport size...")
|
||||||
gl.Viewport(0, 0, int32(gui.width), int32(gui.height))
|
gl.Viewport(0, 0, int32(gui.Width()), int32(gui.Height()))
|
||||||
|
|
||||||
gui.terminal.SetCharSize(gui.renderer.cellWidth, gui.renderer.cellHeight)
|
gui.terminal.SetCharSize(gui.renderer.cellWidth, gui.renderer.cellHeight)
|
||||||
|
|
||||||
|
@ -120,6 +201,8 @@ func (gui *GUI) Render() error {
|
||||||
gui.logger.Debugf("Creating window...")
|
gui.logger.Debugf("Creating window...")
|
||||||
var err error
|
var err error
|
||||||
gui.window, err = gui.createWindow()
|
gui.window, err = gui.createWindow()
|
||||||
|
gui.RecalculateDpiScale()
|
||||||
|
gui.window.SetSize(gui.Width(), gui.Height())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to create window: %s", err)
|
return fmt.Errorf("Failed to create window: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -141,7 +224,7 @@ func (gui *GUI) Render() error {
|
||||||
|
|
||||||
titleChan := make(chan bool, 1)
|
titleChan := make(chan bool, 1)
|
||||||
|
|
||||||
gui.renderer = NewOpenGLRenderer(gui.config, gui.fontMap, 0, 0, gui.width, gui.height, gui.colourAttr, program)
|
gui.renderer = NewOpenGLRenderer(gui.config, gui.fontMap, 0, 0, gui.Width(), gui.Height(), gui.colourAttr, program)
|
||||||
|
|
||||||
gui.window.SetFramebufferSizeCallback(gui.resize)
|
gui.window.SetFramebufferSizeCallback(gui.resize)
|
||||||
gui.window.SetKeyCallback(gui.key)
|
gui.window.SetKeyCallback(gui.key)
|
||||||
|
@ -158,8 +241,10 @@ func (gui *GUI) Render() error {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
w, h := gui.window.GetFramebufferSize()
|
{
|
||||||
gui.resize(gui.window, w, h)
|
w, h := gui.window.GetFramebufferSize()
|
||||||
|
gui.resize(gui.window, w, h)
|
||||||
|
}
|
||||||
|
|
||||||
gui.logger.Debugf("Starting pty read handling...")
|
gui.logger.Debugf("Starting pty read handling...")
|
||||||
|
|
||||||
|
@ -401,7 +486,7 @@ func (gui *GUI) createWindow() (*glfw.Window, error) {
|
||||||
return nil, fmt.Errorf("failed to create window, please update your graphics drivers and try again")
|
return nil, fmt.Errorf("failed to create window, please update your graphics drivers and try again")
|
||||||
}
|
}
|
||||||
|
|
||||||
window.SetSizeLimits(300, 150, 10000, 10000)
|
window.SetSizeLimits(int(300 * gui.dpiScale), int(150 * gui.dpiScale), 10000, 10000)
|
||||||
window.MakeContextCurrent()
|
window.MakeContextCurrent()
|
||||||
window.Show()
|
window.Show()
|
||||||
window.Focus()
|
window.Focus()
|
||||||
|
@ -414,7 +499,7 @@ func (gui *GUI) createWindowWithOpenGLVersion(major int, minor int) (*glfw.Windo
|
||||||
glfw.WindowHint(glfw.ContextVersionMajor, major)
|
glfw.WindowHint(glfw.ContextVersionMajor, major)
|
||||||
glfw.WindowHint(glfw.ContextVersionMinor, minor)
|
glfw.WindowHint(glfw.ContextVersionMinor, minor)
|
||||||
|
|
||||||
window, err := glfw.CreateWindow(gui.width, gui.height, "Terminal", nil, nil)
|
window, err := glfw.CreateWindow(gui.Width(), gui.Height(), "Terminal", nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e := err.Error()
|
e := err.Error()
|
||||||
if i := strings.Index(e, ", got version "); i > -1 {
|
if i := strings.Index(e, ", got version "); i > -1 {
|
||||||
|
@ -425,7 +510,6 @@ func (gui *GUI) createWindowWithOpenGLVersion(major int, minor int) (*glfw.Windo
|
||||||
if min, miErr := strconv.Atoi(v[1]); miErr == nil {
|
if min, miErr := strconv.Atoi(v[1]); miErr == nil {
|
||||||
return gui.createWindowWithOpenGLVersion(maj, min)
|
return gui.createWindowWithOpenGLVersion(maj, min)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ type rectangle struct {
|
||||||
cv uint32
|
cv uint32
|
||||||
colourAttr uint32
|
colourAttr uint32
|
||||||
colour [3]float32
|
colour [3]float32
|
||||||
points []float32
|
points [18]float32
|
||||||
prog uint32
|
prog uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,10 +49,33 @@ func (r *OpenGLRenderer) CellHeight() float32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OpenGLRenderer) Clean() {
|
func (r *OpenGLRenderer) Clean() {
|
||||||
|
for _, rect := range r.rectangles {
|
||||||
|
rect.Free()
|
||||||
|
}
|
||||||
|
|
||||||
r.rectangles = map[[2]uint]*rectangle{}
|
r.rectangles = map[[2]uint]*rectangle{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OpenGLRenderer) newRectangle(x float32, y float32, colourAttr uint32) *rectangle {
|
func (r *OpenGLRenderer) initRectangle(rect *rectangle, x float32, y float32, colourAttr uint32) {
|
||||||
|
|
||||||
|
if rect == nil {
|
||||||
|
panic("rect pointer is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if rect.vao != 0 {
|
||||||
|
gl.DeleteVertexArrays(1, &rect.vao)
|
||||||
|
rect.vao = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if rect.vbo != 0 {
|
||||||
|
gl.DeleteBuffers(1, &rect.vbo)
|
||||||
|
rect.vbo = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if rect.cv != 0 {
|
||||||
|
gl.DeleteBuffers(1, &rect.cv)
|
||||||
|
rect.cv = 0
|
||||||
|
}
|
||||||
|
|
||||||
halfAreaWidth := float32(r.areaWidth / 2)
|
halfAreaWidth := float32(r.areaWidth / 2)
|
||||||
halfAreaHeight := float32(r.areaHeight / 2)
|
halfAreaHeight := float32(r.areaHeight / 2)
|
||||||
|
@ -62,8 +85,7 @@ func (r *OpenGLRenderer) newRectangle(x float32, y float32, colourAttr uint32) *
|
||||||
w := r.cellWidth / halfAreaWidth
|
w := r.cellWidth / halfAreaWidth
|
||||||
h := (r.cellHeight) / halfAreaHeight
|
h := (r.cellHeight) / halfAreaHeight
|
||||||
|
|
||||||
rect := &rectangle{
|
rect.points = [18]float32{
|
||||||
points: []float32{
|
|
||||||
x, y, 0,
|
x, y, 0,
|
||||||
x, y + h, 0,
|
x, y + h, 0,
|
||||||
x + w, y + h, 0,
|
x + w, y + h, 0,
|
||||||
|
@ -71,17 +93,15 @@ func (r *OpenGLRenderer) newRectangle(x float32, y float32, colourAttr uint32) *
|
||||||
x + w, y, 0,
|
x + w, y, 0,
|
||||||
x, y, 0,
|
x, y, 0,
|
||||||
x + w, y + h, 0,
|
x + w, y + h, 0,
|
||||||
},
|
}
|
||||||
colourAttr: colourAttr,
|
|
||||||
prog: r.program,
|
|
||||||
}
|
|
||||||
|
|
||||||
gl.UseProgram(rect.prog)
|
rect.colourAttr = colourAttr
|
||||||
|
rect.prog = r.program
|
||||||
|
|
||||||
// SHAPE
|
// SHAPE
|
||||||
gl.GenBuffers(1, &rect.vbo)
|
gl.GenBuffers(1, &rect.vbo)
|
||||||
gl.BindBuffer(gl.ARRAY_BUFFER, rect.vbo)
|
gl.BindBuffer(gl.ARRAY_BUFFER, rect.vbo)
|
||||||
gl.BufferData(gl.ARRAY_BUFFER, 4*len(rect.points), gl.Ptr(rect.points), gl.STATIC_DRAW)
|
gl.BufferData(gl.ARRAY_BUFFER, 4*len(rect.points), gl.Ptr(&rect.points[0]), gl.STATIC_DRAW)
|
||||||
|
|
||||||
gl.GenVertexArrays(1, &rect.vao)
|
gl.GenVertexArrays(1, &rect.vao)
|
||||||
gl.BindVertexArray(rect.vao)
|
gl.BindVertexArray(rect.vao)
|
||||||
|
@ -94,6 +114,13 @@ func (r *OpenGLRenderer) newRectangle(x float32, y float32, colourAttr uint32) *
|
||||||
gl.GenBuffers(1, &rect.cv)
|
gl.GenBuffers(1, &rect.cv)
|
||||||
|
|
||||||
rect.setColour([3]float32{0, 1, 0})
|
rect.setColour([3]float32{0, 1, 0})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *OpenGLRenderer) newRectangle(x float32, y float32, colourAttr uint32) *rectangle {
|
||||||
|
|
||||||
|
rect := &rectangle{}
|
||||||
|
|
||||||
|
r.initRectangle(rect, x, y, colourAttr)
|
||||||
|
|
||||||
return rect
|
return rect
|
||||||
}
|
}
|
||||||
|
@ -132,6 +159,10 @@ func (rect *rectangle) Free() {
|
||||||
gl.DeleteVertexArrays(1, &rect.vao)
|
gl.DeleteVertexArrays(1, &rect.vao)
|
||||||
gl.DeleteBuffers(1, &rect.vbo)
|
gl.DeleteBuffers(1, &rect.vbo)
|
||||||
gl.DeleteBuffers(1, &rect.cv)
|
gl.DeleteBuffers(1, &rect.cv)
|
||||||
|
|
||||||
|
rect.vao = 0
|
||||||
|
rect.vbo = 0
|
||||||
|
rect.cv = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOpenGLRenderer(config *config.Config, fontMap *FontMap, areaX int, areaY int, areaWidth int, areaHeight int, colourAttr uint32, program uint32) *OpenGLRenderer {
|
func NewOpenGLRenderer(config *config.Config, fontMap *FontMap, areaX int, areaY int, areaWidth int, areaHeight int, colourAttr uint32, program uint32) *OpenGLRenderer {
|
||||||
|
@ -167,21 +198,25 @@ func (r *OpenGLRenderer) SetArea(areaX int, areaY int, areaWidth int, areaHeight
|
||||||
//= f.LineHeight() // includes vertical padding
|
//= f.LineHeight() // includes vertical padding
|
||||||
r.termCols = uint(math.Floor(float64(float32(r.areaWidth) / r.cellWidth)))
|
r.termCols = uint(math.Floor(float64(float32(r.areaWidth) / r.cellWidth)))
|
||||||
r.termRows = uint(math.Floor(float64(float32(r.areaHeight) / r.cellHeight)))
|
r.termRows = uint(math.Floor(float64(float32(r.areaHeight) / r.cellHeight)))
|
||||||
r.rectangles = map[[2]uint]*rectangle{}
|
|
||||||
|
r.Clean()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OpenGLRenderer) getRectangle(col uint, row uint) *rectangle {
|
func (r *OpenGLRenderer) getRectangle(col uint, row uint) *rectangle {
|
||||||
|
|
||||||
rect, ok := r.rectangles[[2]uint{col, row}]
|
|
||||||
if ok {
|
|
||||||
rect.Free()
|
|
||||||
}
|
|
||||||
|
|
||||||
x := float32(float32(col) * r.cellWidth)
|
x := float32(float32(col) * r.cellWidth)
|
||||||
y := float32(float32(row)*r.cellHeight) + r.cellHeight
|
y := float32(float32(row) * r.cellHeight) + r.cellHeight
|
||||||
|
|
||||||
r.rectangles[[2]uint{col, row}] = r.newRectangle(x, y, r.colourAttr)
|
coords := [2]uint{col, row}
|
||||||
return r.rectangles[[2]uint{col, row}]
|
|
||||||
|
rect, ok := r.rectangles[coords]
|
||||||
|
if ok {
|
||||||
|
r.initRectangle(rect, x, y, r.colourAttr)
|
||||||
|
return rect
|
||||||
|
} else {
|
||||||
|
rect = r.newRectangle(x, y, r.colourAttr)
|
||||||
|
r.rectangles[coords] = rect
|
||||||
|
return rect
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OpenGLRenderer) DrawCursor(col uint, row uint, colour config.Colour) {
|
func (r *OpenGLRenderer) DrawCursor(col uint, row uint, colour config.Colour) {
|
||||||
|
|
24
main.go
24
main.go
|
@ -3,12 +3,10 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/kr/pty"
|
|
||||||
"github.com/liamg/aminal/gui"
|
"github.com/liamg/aminal/gui"
|
||||||
|
"github.com/liamg/aminal/platform"
|
||||||
"github.com/liamg/aminal/terminal"
|
"github.com/liamg/aminal/terminal"
|
||||||
"github.com/riywo/loginshell"
|
"github.com/riywo/loginshell"
|
||||||
)
|
)
|
||||||
|
@ -26,7 +24,8 @@ func main() {
|
||||||
defer logger.Sync()
|
defer logger.Sync()
|
||||||
|
|
||||||
logger.Infof("Allocating pty...")
|
logger.Infof("Allocating pty...")
|
||||||
pty, tty, err := pty.Open()
|
|
||||||
|
pty, err := platform.NewPty(80, 25)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatalf("Failed to allocate pty: %s", err)
|
logger.Fatalf("Failed to allocate pty: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -43,12 +42,8 @@ func main() {
|
||||||
os.Setenv("TERM", "xterm-256color") // controversial! easier than installing terminfo everywhere, but obviously going to be slightly different to xterm functionality, so we'll see...
|
os.Setenv("TERM", "xterm-256color") // controversial! easier than installing terminfo everywhere, but obviously going to be slightly different to xterm functionality, so we'll see...
|
||||||
os.Setenv("COLORTERM", "truecolor")
|
os.Setenv("COLORTERM", "truecolor")
|
||||||
|
|
||||||
shell := exec.Command(shellStr)
|
guestProcess, err := pty.CreateGuestProcess(shellStr)
|
||||||
shell.Stdout = tty
|
if err != nil {
|
||||||
shell.Stdin = tty
|
|
||||||
shell.Stderr = tty
|
|
||||||
shell.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
|
|
||||||
if err := shell.Start(); err != nil {
|
|
||||||
pty.Close()
|
pty.Close()
|
||||||
logger.Fatalf("Failed to start your shell: %s", err)
|
logger.Fatalf("Failed to start your shell: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -60,8 +55,15 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatalf("Cannot start: %s", err)
|
logger.Fatalf("Cannot start: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := guestProcess.Wait(); err != nil {
|
||||||
|
logger.Fatalf("Failed to wait for guest process: %s", err)
|
||||||
|
}
|
||||||
|
g.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
if err := g.Render(); err != nil {
|
if err := g.Render(); err != nil {
|
||||||
logger.Fatalf("Render error: %s", err)
|
logger.Fatalf("Render error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package platform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
type cmdProc struct {
|
||||||
|
cmd *exec.Cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCmdProc(c *exec.Cmd) *cmdProc {
|
||||||
|
return &cmdProc{
|
||||||
|
cmd: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *cmdProc) Wait() error {
|
||||||
|
return p.cmd.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *cmdProc) Close() error {
|
||||||
|
if p == nil || p.cmd == nil || p.cmd.Process == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ret := p.cmd.Process.Kill()
|
||||||
|
p.cmd = nil
|
||||||
|
return ret
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package platform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Process represents a child process by pid or HPROCESS in a platform-independent way
|
||||||
|
type Process interface {
|
||||||
|
io.Closer
|
||||||
|
|
||||||
|
Wait() error
|
||||||
|
// TODO: make useful stuff here
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pty represents a pseudo-terminal either by pty/tty file pair or by HCON
|
||||||
|
type Pty interface {
|
||||||
|
io.ReadWriteCloser
|
||||||
|
|
||||||
|
Resize(x int, y int) error
|
||||||
|
CreateGuestProcess(imagePath string) (Process, error)
|
||||||
|
GetPlatformDependentSettings() PlatformDependentSettings
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package platform
|
||||||
|
|
||||||
|
// PlatformDependentSettings Settings specific to the platform
|
||||||
|
type PlatformDependentSettings struct {
|
||||||
|
OSCTerminators map[rune]struct{}
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
//+build !windows
|
||||||
|
|
||||||
|
package platform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/kr/pty"
|
||||||
|
)
|
||||||
|
|
||||||
|
type unixPty struct {
|
||||||
|
pty *os.File
|
||||||
|
tty *os.File
|
||||||
|
platformDependentSettings PlatformDependentSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
type winsize struct {
|
||||||
|
Height uint16
|
||||||
|
Width uint16
|
||||||
|
x uint16 //ignored, but necessary for ioctl calls
|
||||||
|
y uint16 //ignored, but necessary for ioctl calls
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *unixPty) Read(b []byte) (int, error) {
|
||||||
|
if p == nil || p.pty == nil {
|
||||||
|
return 0, errors.New("Attempted to read from a deallocated pty")
|
||||||
|
}
|
||||||
|
return p.pty.Read(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *unixPty) Write(b []byte) (int, error) {
|
||||||
|
if p == nil || p.pty == nil {
|
||||||
|
return 0, errors.New("Attempted to write to a deallocated pty")
|
||||||
|
}
|
||||||
|
return p.pty.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *unixPty) Close() error {
|
||||||
|
if p == nil || p.pty == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ret := p.pty.Close()
|
||||||
|
p.pty = nil
|
||||||
|
p.tty = nil
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *unixPty) Resize(x, y int) error {
|
||||||
|
size := winsize{
|
||||||
|
Height: uint16(y),
|
||||||
|
Width: uint16(x),
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
}
|
||||||
|
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(p.pty.Fd()),
|
||||||
|
uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(&size)))
|
||||||
|
|
||||||
|
if errno != 0 {
|
||||||
|
return errors.New(errno.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *unixPty) CreateGuestProcess(imagePath string) (Process, error) {
|
||||||
|
if p == nil || p.tty == nil {
|
||||||
|
return nil, errors.New("Attempted to create a process on a deallocated pty")
|
||||||
|
}
|
||||||
|
shell := newCmdProc(exec.Command(imagePath))
|
||||||
|
shell.cmd.Stdout = p.tty
|
||||||
|
shell.cmd.Stdin = p.tty
|
||||||
|
shell.cmd.Stderr = p.tty
|
||||||
|
shell.cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
|
||||||
|
if err := shell.cmd.Start(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return shell, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pty *unixPty) GetPlatformDependentSettings() PlatformDependentSettings {
|
||||||
|
return pty.platformDependentSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPty(x, y int) (Pty, error) {
|
||||||
|
innerPty, innerTty, err := pty.Open()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &unixPty{
|
||||||
|
pty: innerPty,
|
||||||
|
tty: innerTty,
|
||||||
|
platformDependentSettings: PlatformDependentSettings{
|
||||||
|
OSCTerminators: map[rune]struct{}{0x07: {}, 0x5c: {}},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -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>
|
|
@ -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.
|
|
@ -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!
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
)
|
|
@ -0,0 +1,41 @@
|
||||||
|
package w32
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInitializeSecurityDescriptor(t *testing.T) {
|
||||||
|
sd, err := InitializeSecurityDescriptor(1)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed: %v", err)
|
||||||
|
}
|
||||||
|
t.Logf("SD:\n%#v\n", *sd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetSecurityDescriptorDacl(t *testing.T) {
|
||||||
|
|
||||||
|
sd, err := InitializeSecurityDescriptor(1)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to initialize: %v", err)
|
||||||
|
}
|
||||||
|
err = SetSecurityDescriptorDacl(sd, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to set NULL DACL: %v", err)
|
||||||
|
}
|
||||||
|
t.Logf("[OK] Set NULL DACL")
|
||||||
|
|
||||||
|
empty := &ACL{
|
||||||
|
AclRevision: 4,
|
||||||
|
Sbz1: 0,
|
||||||
|
AclSize: 4,
|
||||||
|
AceCount: 0,
|
||||||
|
Sbz2: 0,
|
||||||
|
}
|
||||||
|
err = SetSecurityDescriptorDacl(sd, empty)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to set empty DACL: %v", err)
|
||||||
|
}
|
||||||
|
t.Logf("[OK] Set empty DACL")
|
||||||
|
t.Logf("SD:\n%#v\n", *sd)
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
)
|
|
@ -0,0 +1,137 @@
|
||||||
|
package w32
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testPortName = "\\TestAlpcPort"
|
||||||
|
|
||||||
|
var basicPortAttr = ALPC_PORT_ATTRIBUTES{
|
||||||
|
MaxMessageLength: uint64(SHORT_MESSAGE_MAX_SIZE),
|
||||||
|
SecurityQos: SECURITY_QUALITY_OF_SERVICE{
|
||||||
|
Length: SECURITY_QOS_SIZE,
|
||||||
|
ContextTrackingMode: SECURITY_DYNAMIC_TRACKING,
|
||||||
|
EffectiveOnly: 1,
|
||||||
|
ImpersonationLevel: SecurityAnonymous,
|
||||||
|
},
|
||||||
|
Flags: ALPC_PORFLG_ALLOW_LPC_REQUESTS,
|
||||||
|
DupObjectTypes: ALPC_SYNC_OBJECT_TYPE,
|
||||||
|
}
|
||||||
|
|
||||||
|
func ObjectAttributes(name string) (oa OBJECT_ATTRIBUTES, e error) {
|
||||||
|
|
||||||
|
sd, e := InitializeSecurityDescriptor(1)
|
||||||
|
if e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e = SetSecurityDescriptorDacl(sd, nil)
|
||||||
|
if e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
oa, e = InitializeObjectAttributes(name, 0, 0, sd)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Send(
|
||||||
|
hPort HANDLE,
|
||||||
|
msg *AlpcShortMessage,
|
||||||
|
flags uint32,
|
||||||
|
pMsgAttrs *ALPC_MESSAGE_ATTRIBUTES,
|
||||||
|
timeout *int64,
|
||||||
|
) (e error) {
|
||||||
|
|
||||||
|
e = NtAlpcSendWaitReceivePort(hPort, flags, msg, pMsgAttrs, nil, nil, nil, timeout)
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Recv(
|
||||||
|
hPort HANDLE,
|
||||||
|
pMsg *AlpcShortMessage,
|
||||||
|
pMsgAttrs *ALPC_MESSAGE_ATTRIBUTES,
|
||||||
|
timeout *int64,
|
||||||
|
) (bufLen uint32, e error) {
|
||||||
|
|
||||||
|
bufLen = uint32(pMsg.TotalLength)
|
||||||
|
e = NtAlpcSendWaitReceivePort(hPort, 0, nil, nil, pMsg, &bufLen, pMsgAttrs, timeout)
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience method to create an ALPC port with a NULL DACL. Requires an
|
||||||
|
// absolute port name ( where / is the root of the kernel object directory )
|
||||||
|
func CreatePort(name string) (hPort HANDLE, e error) {
|
||||||
|
|
||||||
|
oa, e := ObjectAttributes(name)
|
||||||
|
if e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hPort, e = NtAlpcCreatePort(&oa, &basicPortAttr)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConnectPort(serverName, clientName string, pConnMsg *AlpcShortMessage) (hPort HANDLE, e error) {
|
||||||
|
|
||||||
|
oa, e := InitializeObjectAttributes(clientName, 0, 0, nil)
|
||||||
|
if e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hPort, e = NtAlpcConnectPort(
|
||||||
|
serverName,
|
||||||
|
&oa,
|
||||||
|
&basicPortAttr,
|
||||||
|
ALPC_PORFLG_ALLOW_LPC_REQUESTS,
|
||||||
|
nil,
|
||||||
|
pConnMsg,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Accept(
|
||||||
|
hSrv HANDLE,
|
||||||
|
context *AlpcPortContext,
|
||||||
|
pConnReq *AlpcShortMessage,
|
||||||
|
accept bool,
|
||||||
|
) (hPort HANDLE, e error) {
|
||||||
|
|
||||||
|
oa, _ := InitializeObjectAttributes("", 0, 0, nil)
|
||||||
|
|
||||||
|
var accepted uintptr
|
||||||
|
if accept {
|
||||||
|
accepted++
|
||||||
|
}
|
||||||
|
|
||||||
|
hPort, e = NtAlpcAcceptConnectPort(
|
||||||
|
hSrv,
|
||||||
|
0,
|
||||||
|
&oa,
|
||||||
|
&basicPortAttr,
|
||||||
|
context,
|
||||||
|
pConnReq,
|
||||||
|
nil,
|
||||||
|
accepted,
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNtAlpcCreatePort(t *testing.T) {
|
||||||
|
|
||||||
|
hPort, err := CreatePort(testPortName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to create ALPC port %v: %v", testPortName, err)
|
||||||
|
} else {
|
||||||
|
t.Logf("[OK] Created ALPC port %v with handle 0x%x", testPortName, hPort)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package w32
|
||||||
|
|
||||||
|
const (
|
||||||
|
WAIT_ABANDONED = 0x00000080
|
||||||
|
WAIT_OBJECT_0 = 0x00000000
|
||||||
|
WAIT_TIMEOUT = 0x00000102
|
||||||
|
WAIT_FAILED = 0xFFFFFFFF
|
||||||
|
INFINITE = 0xFFFFFFFF
|
||||||
|
)
|
|
@ -0,0 +1,47 @@
|
||||||
|
package w32
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testProcess = "notepad.exe"
|
||||||
|
var wantCode = uint32(42)
|
||||||
|
|
||||||
|
func TestCreateProcess(t *testing.T) {
|
||||||
|
|
||||||
|
pi, err := CreateProcessQuick(testProcess)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("[!!] Failed to create %s: %s", testProcess, err)
|
||||||
|
} else {
|
||||||
|
t.Logf("[OK] Created process %s with handle 0x%x, PID %d", testProcess, pi.Process, pi.ProcessId)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = TerminateProcess(pi.Process, wantCode)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("[!!]Failed to terminate %s: %s", testProcess, err)
|
||||||
|
} else {
|
||||||
|
t.Logf("[OK] Called TerminateProcess on PID %d", pi.ProcessId)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = WaitForSingleObject(pi.Process, 1000) // 1000ms
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("[!!] failed in WaitForSingleObject: %s", err)
|
||||||
|
} else {
|
||||||
|
t.Logf("[OK] WaitForSingleObject returned...")
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we see the magic exit code we asked for
|
||||||
|
code, err := GetExitCodeProcess(pi.Process)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("[!!] Failed to get exit code for PID %d: %s", pi.ProcessId, err)
|
||||||
|
} else {
|
||||||
|
t.Logf("[OK] PID %d Exited with code %d", pi.ProcessId, code)
|
||||||
|
}
|
||||||
|
if code != 42 {
|
||||||
|
t.Errorf("[!!] Unexpected exit code for PID %d - want %d, got %d", pi.ProcessId, wantCode, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(pi.Process)
|
||||||
|
CloseHandle(pi.Thread)
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
)
|
|
@ -0,0 +1,50 @@
|
||||||
|
package w32
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var forkFn = path.Join(os.TempDir(), "forktest.pid")
|
||||||
|
|
||||||
|
func TestFork(t *testing.T) {
|
||||||
|
|
||||||
|
ppid := os.Getpid()
|
||||||
|
t.Logf("[OK] I am PID %d", ppid)
|
||||||
|
pid, err := Fork()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("[!!] Failed to fork. PID: %d: %s", pid, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pid == 0 {
|
||||||
|
// We can't log anything here because our stdout doesn't point
|
||||||
|
// to the same console as our parent.
|
||||||
|
//
|
||||||
|
// This process won't show up in Task Manager, and os.Getpid() won't
|
||||||
|
// work, I guess because we haven't told CSRSS we exist.
|
||||||
|
f, _ := os.Create(forkFn)
|
||||||
|
f.WriteString(fmt.Sprintf("%d", ppid))
|
||||||
|
f.Close()
|
||||||
|
} else {
|
||||||
|
t.Logf("[OK] Forked child with PID %d", pid)
|
||||||
|
t.Logf("[OK] Sleeping, then trying to read checkfile.")
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
raw, err := ioutil.ReadFile(forkFn)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("[!!] Failed to read PID checkfile: %s", err)
|
||||||
|
}
|
||||||
|
if string(raw) == strconv.Itoa(ppid) {
|
||||||
|
t.Logf("[OK] Found PID checkfile - PID matches!")
|
||||||
|
} else {
|
||||||
|
t.Errorf("[!] Child reported PID %q vs %q!", string(raw), strconv.Itoa(ppid))
|
||||||
|
}
|
||||||
|
os.Remove(forkFn)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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)))
|
||||||
|
}
|
||||||
|
}
|
|
@ -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...)
|
||||||
|
}
|
|
@ -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)))
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
}
|
|
@ -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}}
|
||||||
|
)
|
|
@ -0,0 +1,198 @@
|
||||||
|
// +build windows,cgo
|
||||||
|
|
||||||
|
package platform
|
||||||
|
|
||||||
|
// #include "windows.h"
|
||||||
|
//
|
||||||
|
// /* Until we can specify the platform SDK and target version for Windows.h *
|
||||||
|
// * without breaking our ability to gracefully display an error message, these *
|
||||||
|
// * definitions will be copied from the platform SDK headers and made to work. *
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
// typedef BOOL (* InitializeProcThreadAttributeListProcType)(LPPROC_THREAD_ATTRIBUTE_LIST, DWORD, DWORD, PSIZE_T);
|
||||||
|
// typedef BOOL (* UpdateProcThreadAttributeProcType)(
|
||||||
|
// LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
|
||||||
|
// DWORD dwFlags,
|
||||||
|
// DWORD_PTR Attribute,
|
||||||
|
// PVOID lpValue,
|
||||||
|
// SIZE_T cbSize,
|
||||||
|
// PVOID lpPreviousValue,
|
||||||
|
// PSIZE_T lpReturnSize
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// InitializeProcThreadAttributeListProcType pfnInitializeProcThreadAttributeList = NULL;
|
||||||
|
// UpdateProcThreadAttributeProcType pfnUpdateProcThreadAttribute = NULL;
|
||||||
|
//
|
||||||
|
// #define ProcThreadAttributePseudoConsole 22
|
||||||
|
//
|
||||||
|
// #define PROC_THREAD_ATTRIBUTE_NUMBER 0x0000FFFF
|
||||||
|
// #define PROC_THREAD_ATTRIBUTE_THREAD 0x00010000 // Attribute may be used with thread creation
|
||||||
|
// #define PROC_THREAD_ATTRIBUTE_INPUT 0x00020000 // Attribute is input only
|
||||||
|
// #define PROC_THREAD_ATTRIBUTE_ADDITIVE 0x00040000 // Attribute may be "accumulated," e.g. bitmasks, counters, etc.
|
||||||
|
//
|
||||||
|
// #define ProcThreadAttributeValue(Number, Thread, Input, Additive) \
|
||||||
|
// (((Number) & PROC_THREAD_ATTRIBUTE_NUMBER) | \
|
||||||
|
// ((Thread != FALSE) ? PROC_THREAD_ATTRIBUTE_THREAD : 0) | \
|
||||||
|
// ((Input != FALSE) ? PROC_THREAD_ATTRIBUTE_INPUT : 0) | \
|
||||||
|
// ((Additive != FALSE) ? PROC_THREAD_ATTRIBUTE_ADDITIVE : 0))
|
||||||
|
//
|
||||||
|
// #define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE ProcThreadAttributeValue (ProcThreadAttributePseudoConsole, FALSE, TRUE, FALSE)
|
||||||
|
//
|
||||||
|
// typedef struct _STARTUPINFOEXW {
|
||||||
|
// STARTUPINFOW StartupInfo;
|
||||||
|
// LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
|
||||||
|
// } STARTUPINFOEXW, *LPSTARTUPINFOEXW;
|
||||||
|
//
|
||||||
|
// HMODULE hLibKernel32_Proc = NULL;
|
||||||
|
//
|
||||||
|
// DWORD initProcKernFuncs()
|
||||||
|
// {
|
||||||
|
// hLibKernel32_Proc = LoadLibrary( "kernel32.dll" );
|
||||||
|
// if( hLibKernel32_Proc == NULL )
|
||||||
|
// {
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pfnInitializeProcThreadAttributeList = (InitializeProcThreadAttributeListProcType) GetProcAddress(hLibKernel32_Proc, "InitializeProcThreadAttributeList" );
|
||||||
|
// if( pfnInitializeProcThreadAttributeList == NULL )
|
||||||
|
// {
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pfnUpdateProcThreadAttribute = (UpdateProcThreadAttributeProcType) GetProcAddress(hLibKernel32_Proc, "UpdateProcThreadAttribute" );
|
||||||
|
// if( pfnUpdateProcThreadAttribute == NULL )
|
||||||
|
// {
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// DWORD createGuestProcHelper( uintptr_t hpc, LPCWSTR imagePath, uintptr_t * hProcess, DWORD * dwProcessID )
|
||||||
|
// {
|
||||||
|
// STARTUPINFOEXW si;
|
||||||
|
// ZeroMemory( &si, sizeof(si) );
|
||||||
|
// si.StartupInfo.cb = sizeof(si);
|
||||||
|
//
|
||||||
|
// SIZE_T bytesRequired;
|
||||||
|
// (*pfnInitializeProcThreadAttributeList)( NULL, 1, 0, &bytesRequired );
|
||||||
|
//
|
||||||
|
// si.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, bytesRequired);
|
||||||
|
// if( !si.lpAttributeList )
|
||||||
|
// {
|
||||||
|
// return E_OUTOFMEMORY;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!(*pfnInitializeProcThreadAttributeList)(si.lpAttributeList, 1, 0, &bytesRequired))
|
||||||
|
// {
|
||||||
|
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
|
||||||
|
// return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!(*pfnUpdateProcThreadAttribute)(si.lpAttributeList,
|
||||||
|
// 0,
|
||||||
|
// PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
||||||
|
// (PVOID) hpc,
|
||||||
|
// sizeof(hpc),
|
||||||
|
// NULL,
|
||||||
|
// NULL))
|
||||||
|
// {
|
||||||
|
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
|
||||||
|
// return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// bytesRequired = (wcslen(imagePath) + 1) * sizeof(wchar_t); // +1 null terminator
|
||||||
|
// PWSTR cmdLineMutable = (PWSTR)HeapAlloc(GetProcessHeap(), 0, bytesRequired);
|
||||||
|
//
|
||||||
|
// if (!cmdLineMutable)
|
||||||
|
// {
|
||||||
|
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
|
||||||
|
// return E_OUTOFMEMORY;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// wcscpy_s(cmdLineMutable, bytesRequired, imagePath);
|
||||||
|
//
|
||||||
|
// PROCESS_INFORMATION pi;
|
||||||
|
// ZeroMemory(&pi, sizeof(pi));
|
||||||
|
//
|
||||||
|
// if (!CreateProcessW(NULL,
|
||||||
|
// cmdLineMutable,
|
||||||
|
// NULL,
|
||||||
|
// NULL,
|
||||||
|
// FALSE,
|
||||||
|
// EXTENDED_STARTUPINFO_PRESENT,
|
||||||
|
// NULL,
|
||||||
|
// NULL,
|
||||||
|
// &si.StartupInfo,
|
||||||
|
// &pi))
|
||||||
|
// {
|
||||||
|
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
|
||||||
|
// HeapFree(GetProcessHeap(), 0, cmdLineMutable);
|
||||||
|
// return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// *hProcess = (uintptr_t) pi.hProcess;
|
||||||
|
// *dwProcessID = pi.dwProcessId;
|
||||||
|
//
|
||||||
|
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
|
||||||
|
// HeapFree(GetProcessHeap(), 0, cmdLineMutable);
|
||||||
|
// return S_OK;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// int hr_succeeded( DWORD hResult );
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"syscall"
|
||||||
|
"unicode/utf16"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var procsInitSucceeded = false
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ret := int(C.initProcKernFuncs())
|
||||||
|
procsInitSucceeded = (ret == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
type winProcess struct {
|
||||||
|
hproc uintptr
|
||||||
|
processID uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func createPtyChildProcess(imagePath string, hcon uintptr) (*winProcess, error) {
|
||||||
|
path16 := utf16.Encode([]rune(imagePath))
|
||||||
|
|
||||||
|
cpath16 := C.calloc(C.size_t(len(path16)+1), 2)
|
||||||
|
pp := (*[0xffff]uint16)(cpath16)
|
||||||
|
copy(pp[:], path16)
|
||||||
|
|
||||||
|
hproc := C.uintptr_t(0)
|
||||||
|
dwProcessID := C.DWORD(0)
|
||||||
|
|
||||||
|
hr := C.createGuestProcHelper(C.uintptr_t(hcon), (C.LPCWSTR)(cpath16), &hproc, &dwProcessID)
|
||||||
|
|
||||||
|
C.free(cpath16)
|
||||||
|
|
||||||
|
if int(C.hr_succeeded(hr)) == 0 {
|
||||||
|
return nil, errors.New("Failed to create process: " + imagePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &winProcess{
|
||||||
|
hproc: uintptr(hproc),
|
||||||
|
processID: uint32(dwProcessID),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (process *winProcess) Wait() error {
|
||||||
|
rc := uint(C.WaitForSingleObject(C.HANDLE(process.hproc), C.INFINITE))
|
||||||
|
if rc == C.WAIT_OBJECT_0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("error 0x%.8X while waiting for external process ID = %d ", uint(C.GetLastError()), process.processID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (process *winProcess) Close() error {
|
||||||
|
return syscall.CloseHandle(syscall.Handle(process.hproc))
|
||||||
|
}
|
|
@ -0,0 +1,231 @@
|
||||||
|
// +build windows,cgo
|
||||||
|
|
||||||
|
package platform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/MaxRis/w32"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #include "windows.h"
|
||||||
|
//
|
||||||
|
// /* Until we can specify the platform SDK and target version for Windows.h *
|
||||||
|
// * without breaking our ability to gracefully display an error message, these *
|
||||||
|
// * definitions will be copied from the platform SDK headers and made to work. *
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
// typedef HRESULT (* CreatePseudoConsoleProcType)( COORD, HANDLE, HANDLE, DWORD, uintptr_t * );
|
||||||
|
// typedef HRESULT (* ResizePseudoConsoleProcType)( uintptr_t, COORD );
|
||||||
|
// typedef HRESULT (* ClosePseudoConsoleProcType)( uintptr_t );
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// CreatePseudoConsoleProcType pfnCreatePseudoConsole = NULL;
|
||||||
|
// ResizePseudoConsoleProcType pfnResizePseudoConsole = NULL;
|
||||||
|
// ClosePseudoConsoleProcType pfnClosePseudoConsole = NULL;
|
||||||
|
//
|
||||||
|
// HMODULE hLibKernel32_Kern = NULL;
|
||||||
|
//
|
||||||
|
// DWORD initPtyKernFuncs()
|
||||||
|
// {
|
||||||
|
// hLibKernel32_Kern = LoadLibrary( "kernel32.dll" );
|
||||||
|
// if( hLibKernel32_Kern == NULL )
|
||||||
|
// {
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pfnCreatePseudoConsole = (CreatePseudoConsoleProcType) GetProcAddress(hLibKernel32_Kern, "CreatePseudoConsole" );
|
||||||
|
// if( pfnCreatePseudoConsole == NULL )
|
||||||
|
// {
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pfnResizePseudoConsole = (ResizePseudoConsoleProcType) GetProcAddress(hLibKernel32_Kern, "ResizePseudoConsole" );
|
||||||
|
// if( pfnResizePseudoConsole == NULL )
|
||||||
|
// {
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pfnClosePseudoConsole = (ClosePseudoConsoleProcType) GetProcAddress(hLibKernel32_Kern, "ClosePseudoConsole" );
|
||||||
|
// if( pfnClosePseudoConsole == NULL )
|
||||||
|
// {
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// DWORD createPtyHelper( int xSize, int ySize, HANDLE input, HANDLE output, DWORD flags, uintptr_t * phPC )
|
||||||
|
// {
|
||||||
|
// COORD size;
|
||||||
|
// size.X = xSize;
|
||||||
|
// size.Y = ySize;
|
||||||
|
// return (DWORD) (*pfnCreatePseudoConsole)( size, input, output, flags, phPC );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// DWORD resizePtyHelper( uintptr_t hpc, int xSize, int ySize )
|
||||||
|
// {
|
||||||
|
// COORD size;
|
||||||
|
// size.X = xSize;
|
||||||
|
// size.Y = ySize;
|
||||||
|
// return (DWORD) (*pfnResizePseudoConsole)( hpc, size );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// DWORD closePtyHelper( uintptr_t hpc )
|
||||||
|
// {
|
||||||
|
// return (DWORD) (*pfnClosePseudoConsole)( hpc );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// int hr_succeeded( DWORD hResult )
|
||||||
|
// {
|
||||||
|
// return SUCCEEDED( hResult );
|
||||||
|
// }
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
var ptyInitSucceeded = false
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ret := int(C.initPtyKernFuncs())
|
||||||
|
ptyInitSucceeded = (ret == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
type winConPty struct {
|
||||||
|
inPipe syscall.Handle
|
||||||
|
outPipe syscall.Handle
|
||||||
|
innerInPipe syscall.Handle
|
||||||
|
innerOutPipe syscall.Handle
|
||||||
|
hcon uintptr
|
||||||
|
platformDependentSettings PlatformDependentSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pty *winConPty) Read(p []byte) (n int, err error) {
|
||||||
|
return syscall.Read(pty.inPipe, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pty *winConPty) Write(p []byte) (n int, err error) {
|
||||||
|
return syscall.Write(pty.outPipe, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pty *winConPty) Close() error {
|
||||||
|
C.closePtyHelper(C.uintptr_t(pty.hcon))
|
||||||
|
|
||||||
|
err := syscall.CloseHandle(pty.inPipe)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = syscall.CloseHandle(pty.outPipe)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = syscall.CloseHandle(pty.innerInPipe)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = syscall.CloseHandle(pty.innerOutPipe)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pty.hcon = 0
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pty *winConPty) CreateGuestProcess(imagePath string) (Process, error) {
|
||||||
|
process, err := createPtyChildProcess(imagePath, pty.hcon)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
setupChildConsole(C.DWORD(process.processID), C.STD_OUTPUT_HANDLE, C.ENABLE_PROCESSED_OUTPUT|C.ENABLE_WRAP_AT_EOL_OUTPUT)
|
||||||
|
}
|
||||||
|
|
||||||
|
return process, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupChildConsole(processID C.DWORD, nStdHandle C.DWORD, mode uint) bool {
|
||||||
|
C.FreeConsole()
|
||||||
|
defer C.AttachConsole(^C.DWORD(0)) // attach to parent process console
|
||||||
|
|
||||||
|
// process may not be ready so we'll do retries
|
||||||
|
const maxWaitMilliSeconds = 5000
|
||||||
|
const waitStepMilliSeconds = 200
|
||||||
|
count := maxWaitMilliSeconds / waitStepMilliSeconds
|
||||||
|
|
||||||
|
for {
|
||||||
|
if r := C.AttachConsole(processID); r != 0 {
|
||||||
|
break // success
|
||||||
|
}
|
||||||
|
lastError := C.GetLastError()
|
||||||
|
if lastError != C.ERROR_GEN_FAILURE || count <= 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Millisecond * time.Duration(waitStepMilliSeconds))
|
||||||
|
count--
|
||||||
|
}
|
||||||
|
|
||||||
|
h := C.GetStdHandle(nStdHandle)
|
||||||
|
C.SetConsoleMode(h, C.DWORD(mode))
|
||||||
|
C.FreeConsole()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pty *winConPty) Resize(x, y int) error {
|
||||||
|
cret := C.resizePtyHelper(C.uintptr_t(pty.hcon), C.int(x), C.int(y))
|
||||||
|
|
||||||
|
if int(C.hr_succeeded(cret)) == 0 {
|
||||||
|
return errors.New("Failed to resize ConPTY")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pty *winConPty) GetPlatformDependentSettings() PlatformDependentSettings {
|
||||||
|
return pty.platformDependentSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPty creates a new instance of a Pty implementation for Windows on a newly allocated ConPTY
|
||||||
|
func NewPty(x, y int) (pty Pty, err error) {
|
||||||
|
if !ptyInitSucceeded {
|
||||||
|
w32.MessageBox(0, "Aminal requires APIs that are only available on Windows 10 1809 (October 2018 Update) or above. Please upgrade", "Aminal", 0)
|
||||||
|
return nil, errors.New("Windows PseudoConsole API unavailable on this version of Windows")
|
||||||
|
}
|
||||||
|
pty = nil
|
||||||
|
|
||||||
|
var inputReadSide, inputWriteSide syscall.Handle
|
||||||
|
var outputReadSide, outputWriteSide syscall.Handle
|
||||||
|
|
||||||
|
err = syscall.CreatePipe(&inputReadSide, &inputWriteSide, nil, 0)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = syscall.CreatePipe(&outputReadSide, &outputWriteSide, nil, 0)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var hc C.uintptr_t
|
||||||
|
|
||||||
|
cret := C.createPtyHelper(C.int(x), C.int(y), C.HANDLE(inputReadSide), C.HANDLE(outputWriteSide), 0, &hc)
|
||||||
|
ret := int(cret)
|
||||||
|
|
||||||
|
if ret != 0 {
|
||||||
|
return nil, errors.New("Failed to allocate a ConPTY instance")
|
||||||
|
}
|
||||||
|
|
||||||
|
pty = &winConPty{
|
||||||
|
inPipe: outputReadSide,
|
||||||
|
outPipe: inputWriteSide,
|
||||||
|
innerInPipe: inputReadSide,
|
||||||
|
innerOutPipe: outputWriteSide,
|
||||||
|
hcon: uintptr(hc),
|
||||||
|
platformDependentSettings: PlatformDependentSettings{
|
||||||
|
OSCTerminators: map[rune]struct{}{0x00: {}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return pty, nil
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ func oscHandler(pty chan rune, terminal *Terminal) error {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
b := <-pty
|
b := <-pty
|
||||||
if b == 0x07 || b == 0x5c {
|
if terminal.IsOSCTerminator(b) {
|
||||||
params = append(params, param)
|
params = append(params, param)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,10 @@ func sixelHandler(pty chan rune, terminal *Terminal) error {
|
||||||
for {
|
for {
|
||||||
b := <-pty
|
b := <-pty
|
||||||
if b == 0x1b { // terminated by ESC bell or ESC \
|
if b == 0x1b { // terminated by ESC bell or ESC \
|
||||||
_ = <-pty // swallow \ or bell
|
t := <-pty
|
||||||
|
if t != 0x07 && t != 0x5c {
|
||||||
|
return fmt.Errorf("Incorrect terminator in sixel sequence: 0x%02X [%c]", t, t)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if b >= 33 {
|
if b >= 33 {
|
||||||
|
|
|
@ -4,13 +4,11 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/liamg/aminal/buffer"
|
"github.com/liamg/aminal/buffer"
|
||||||
"github.com/liamg/aminal/config"
|
"github.com/liamg/aminal/config"
|
||||||
|
"github.com/liamg/aminal/platform"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,23 +30,24 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Terminal struct {
|
type Terminal struct {
|
||||||
program uint32
|
program uint32
|
||||||
buffers []*buffer.Buffer
|
buffers []*buffer.Buffer
|
||||||
activeBuffer *buffer.Buffer
|
activeBuffer *buffer.Buffer
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
pty *os.File
|
pty platform.Pty
|
||||||
logger *zap.SugaredLogger
|
logger *zap.SugaredLogger
|
||||||
title string
|
title string
|
||||||
size Winsize
|
size Winsize
|
||||||
config *config.Config
|
config *config.Config
|
||||||
titleHandlers []chan bool
|
titleHandlers []chan bool
|
||||||
modes Modes
|
modes Modes
|
||||||
mouseMode MouseMode
|
mouseMode MouseMode
|
||||||
bracketedPasteMode bool
|
bracketedPasteMode bool
|
||||||
isDirty bool
|
isDirty bool
|
||||||
charWidth float32
|
charWidth float32
|
||||||
charHeight float32
|
charHeight float32
|
||||||
lastBuffer uint8
|
lastBuffer uint8
|
||||||
|
platformDependentSettings platform.PlatformDependentSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
type Modes struct {
|
type Modes struct {
|
||||||
|
@ -64,21 +63,21 @@ type Winsize struct {
|
||||||
y uint16 //ignored, but necessary for ioctl calls
|
y uint16 //ignored, but necessary for ioctl calls
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(pty *os.File, logger *zap.SugaredLogger, config *config.Config) *Terminal {
|
func New(pty platform.Pty, logger *zap.SugaredLogger, config *config.Config) *Terminal {
|
||||||
t := &Terminal{
|
t := &Terminal{
|
||||||
buffers: []*buffer.Buffer{
|
buffers: []*buffer.Buffer{
|
||||||
buffer.NewBuffer(1, 1, buffer.CellAttributes{
|
buffer.NewBuffer(1, 1, buffer.CellAttributes{
|
||||||
FgColour: config.ColourScheme.Foreground,
|
FgColour: config.ColourScheme.Foreground,
|
||||||
BgColour: config.ColourScheme.Background,
|
BgColour: config.ColourScheme.Background,
|
||||||
}),
|
}, config.MaxLines),
|
||||||
buffer.NewBuffer(1, 1, buffer.CellAttributes{
|
buffer.NewBuffer(1, 1, buffer.CellAttributes{
|
||||||
FgColour: config.ColourScheme.Foreground,
|
FgColour: config.ColourScheme.Foreground,
|
||||||
BgColour: config.ColourScheme.Background,
|
BgColour: config.ColourScheme.Background,
|
||||||
}),
|
}, config.MaxLines),
|
||||||
buffer.NewBuffer(1, 1, buffer.CellAttributes{
|
buffer.NewBuffer(1, 1, buffer.CellAttributes{
|
||||||
FgColour: config.ColourScheme.Foreground,
|
FgColour: config.ColourScheme.Foreground,
|
||||||
BgColour: config.ColourScheme.Background,
|
BgColour: config.ColourScheme.Background,
|
||||||
}),
|
}, config.MaxLines),
|
||||||
},
|
},
|
||||||
pty: pty,
|
pty: pty,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
@ -87,6 +86,7 @@ func New(pty *os.File, logger *zap.SugaredLogger, config *config.Config) *Termin
|
||||||
modes: Modes{
|
modes: Modes{
|
||||||
ShowCursor: true,
|
ShowCursor: true,
|
||||||
},
|
},
|
||||||
|
platformDependentSettings: pty.GetPlatformDependentSettings(),
|
||||||
}
|
}
|
||||||
t.activeBuffer = t.buffers[0]
|
t.activeBuffer = t.buffers[0]
|
||||||
return t
|
return t
|
||||||
|
@ -123,6 +123,11 @@ func (terminal *Terminal) GetMouseMode() MouseMode {
|
||||||
return terminal.mouseMode
|
return terminal.mouseMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (terminal *Terminal) IsOSCTerminator(char rune) bool {
|
||||||
|
_, ok := terminal.platformDependentSettings.OSCTerminators[char]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
func (terminal *Terminal) UseMainBuffer() {
|
func (terminal *Terminal) UseMainBuffer() {
|
||||||
terminal.activeBuffer = terminal.buffers[MainBuffer]
|
terminal.activeBuffer = terminal.buffers[MainBuffer]
|
||||||
terminal.SetSize(uint(terminal.size.Width), uint(terminal.size.Height))
|
terminal.SetSize(uint(terminal.size.Width), uint(terminal.size.Height))
|
||||||
|
@ -280,9 +285,8 @@ func (terminal *Terminal) SetSize(newCols uint, newLines uint) error {
|
||||||
terminal.size.Width = uint16(newCols)
|
terminal.size.Width = uint16(newCols)
|
||||||
terminal.size.Height = uint16(newLines)
|
terminal.size.Height = uint16(newLines)
|
||||||
|
|
||||||
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(terminal.pty.Fd()),
|
err := terminal.pty.Resize(int(newCols), int(newLines))
|
||||||
uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(&terminal.size)))
|
if err != nil {
|
||||||
if err != 0 {
|
|
||||||
return fmt.Errorf("Failed to set terminal size vai ioctl: Error no %d", err)
|
return fmt.Errorf("Failed to set terminal size vai ioctl: Error no %d", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,15 +17,29 @@ func Shell() (string, error) {
|
||||||
return LinuxShell()
|
return LinuxShell()
|
||||||
case "darwin":
|
case "darwin":
|
||||||
return DarwinShell()
|
return DarwinShell()
|
||||||
|
case "windows":
|
||||||
|
return WindowsShell()
|
||||||
}
|
}
|
||||||
return "", errors.New("Undefined GOOS: " + runtime.GOOS)
|
return "", errors.New("Undefined GOOS: " + runtime.GOOS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WindowsShell() (string, error) {
|
||||||
|
consoleApp := os.Getenv("COMSPEC")
|
||||||
|
if consoleApp == "" {
|
||||||
|
consoleApp = "cmd.exe"
|
||||||
|
}
|
||||||
|
return consoleApp, nil
|
||||||
|
}
|
||||||
|
|
||||||
func LinuxShell() (string, error) {
|
func LinuxShell() (string, error) {
|
||||||
user, err := user.Current()
|
user, err := user.Current()
|
||||||
if err != nil { return "", err }
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
out, err := exec.Command("getent", "passwd", user.Uid).Output()
|
out, err := exec.Command("getent", "passwd", user.Uid).Output()
|
||||||
if err != nil { return "", err }
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
ent := strings.Split(strings.TrimSuffix(string(out), "\n"), ":")
|
ent := strings.Split(strings.TrimSuffix(string(out), "\n"), ":")
|
||||||
return ent[6], nil
|
return ent[6], nil
|
||||||
|
@ -34,11 +48,15 @@ func LinuxShell() (string, error) {
|
||||||
func DarwinShell() (string, error) {
|
func DarwinShell() (string, error) {
|
||||||
dir := "Local/Default/Users/" + os.Getenv("USER")
|
dir := "Local/Default/Users/" + os.Getenv("USER")
|
||||||
out, err := exec.Command("dscl", "localhost", "-read", dir, "UserShell").Output()
|
out, err := exec.Command("dscl", "localhost", "-read", dir, "UserShell").Output()
|
||||||
if err != nil { return "", err }
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
re := regexp.MustCompile("UserShell: (/[^ ]+)\n")
|
re := regexp.MustCompile("UserShell: (/[^ ]+)\n")
|
||||||
matched := re.FindStringSubmatch(string(out))
|
matched := re.FindStringSubmatch(string(out))
|
||||||
shell := matched[1]
|
shell := matched[1]
|
||||||
if shell == "" { return "", errors.New(fmt.Sprintf("Invalid output: %s", string(out))) }
|
if shell == "" {
|
||||||
|
return "", errors.New(fmt.Sprintf("Invalid output: %s", string(out)))
|
||||||
|
}
|
||||||
return shell, nil
|
return shell, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"os"
|
"os"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestShell(t *testing.T) {
|
func TestShell(t *testing.T) {
|
||||||
|
@ -12,8 +13,14 @@ func TestShell(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentShell := os.Getenv("SHELL")
|
if runtime.GOOS == "windows" {
|
||||||
if shell != currentShell {
|
if shell == "" {
|
||||||
t.Error(fmt.Sprintf("Output: %s, Current login shell: %s", shell, currentShell))
|
t.Error("Output is empty!")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentShell := os.Getenv("SHELL")
|
||||||
|
if shell != currentShell {
|
||||||
|
t.Error(fmt.Sprintf("Output: %s, Current login shell: %s", shell, currentShell))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
### Windows dev env setup and build instructions:
|
||||||
|
|
||||||
|
1. Setup choco package manager https://chocolatey.org/docs/installation
|
||||||
|
2. Use `choco` to install golang and mingw
|
||||||
|
```choco install golang mingw```
|
||||||
|
|
||||||
|
|
||||||
|
### Setting aminal GoLang build env and directories structures for the project:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd %YOUR_PROJECT_WORKING_DIR%
|
||||||
|
mkdir go\src\github.com\liamg
|
||||||
|
cd go\src\github.com\liamg
|
||||||
|
git clone git@github.com:jumptrading/aminal-mirror.git
|
||||||
|
move aminal-mirror aminal
|
||||||
|
|
||||||
|
set GOPATH=%YOUR_PROJECT_WORKING_DIR%\go
|
||||||
|
set GOBIN=%GOPATH%/bin
|
||||||
|
set PATH=%GOBIN%;%PATH%
|
||||||
|
|
||||||
|
cd aminal
|
||||||
|
go get
|
||||||
|
windres -o aminal.syso aminal.rc
|
||||||
|
go build
|
||||||
|
go install
|
||||||
|
```
|
||||||
|
|
||||||
|
Look for the aminal.exe built binary under your %GOBIN% path
|
||||||
|
|
Loading…
Reference in New Issue