5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-08 19:01:29 +08:00

[windows] Support AlwaysOnTop, EnableResize at runtime. Added Solid/Transparent/Translucent options.

This commit is contained in:
Lea Anthony 2023-04-28 21:11:49 +10:00
parent ef184ec8bf
commit 7f3f51e36b
No known key found for this signature in database
GPG Key ID: 33DAF7BB90A58405
41 changed files with 5679 additions and 8207 deletions

View File

@ -180,3 +180,25 @@ const MyEnum = {
- Why use `float64`? Can't we use `int`?
- Because JavaScript doesn't have a concept of `int`. Everything is a `number`, which translates to `float64` in Go. There are also restrictions on casting types in Go's reflection package, which means using `int` doesn't work.
### BackgroundColour
In v2, this was a pointer to an `RGBA` struct. In v3, this is an `RGBA` struct value.
### WindowIsTranslucent
This flag has been removed. Now there is a `BackgroundType` flag that can be used to set the type of background the window should have.
This flag can be set to any of the following values:
- `BackgroundTypeSolid` - The window will have a solid background
- `BackgroundTypeTransparent` - The window will have a transparent background
- `BackgroundTypeTranslucent` - The window will have a translucent background
On Windows, if the `BackgroundType` is set to `BackgroundTypeTranslucent`, the type of translucency can be set using the
`BackdropType` flag in the `WindowsWindow` options. This can be set to any of the following values:
- `Auto` - The window will use an effect determined by the system
- `None` - The window will have no background
- `Mica` - The window will use the Mica effect
- `Acrylic` - The window will use the acrylic effect
- `Tabbed` - The window will use the tabbed effect

View File

@ -4,7 +4,6 @@ go 1.19
require (
github.com/go-task/task/v3 v3.20.0
github.com/gonutz/w32/v2 v2.7.0
github.com/google/go-cmp v0.5.9
github.com/jackmordaunt/icns/v2 v2.2.1
github.com/json-iterator/go v1.1.12
@ -18,6 +17,7 @@ require (
github.com/samber/lo v1.37.0
github.com/tc-hib/winres v0.1.6
github.com/wailsapp/wails/v2 v2.3.2-0.20230117193915-45c3a501d9e6
golang.org/x/sys v0.7.0
modernc.org/sqlite v1.21.0
)
@ -54,7 +54,6 @@ require (
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/term v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/tools v0.1.12 // indirect

View File

@ -27,8 +27,6 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8Wd
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/task/v3 v3.20.0 h1:pTavuhP+AiEpKLzh5I6Lja9Ux7ypYO5QMsEPTbhYEDc=
github.com/go-task/task/v3 v3.20.0/go.mod h1:y7rWakbLR5gFElGgo6rA2dyr6vU/zNIDVfn3S4Of6OI=
github.com/gonutz/w32/v2 v2.7.0 h1:O9lx/5tZ+WjZdxdvQFTh+/kP/7y95YCaL5MHqPrIHn4=
github.com/gonutz/w32/v2 v2.7.0/go.mod h1:MgtHx0AScDVNKyB+kjyPder4xIi3XAcHS6LDDU2DmdE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@ -184,8 +182,8 @@ golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

View File

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

View File

@ -1,20 +0,0 @@
This is a fork of [gonutz/w32](https://github.com/gonutz/w32).
-----------------------
About w32
==========
w32 is a wrapper for a number of Windows APIs for the [Go Programming Language](https://golang.org/).
This library has no other dependencies and you need no C-compiler, it is written in pure Go. Some function signatures have been adapted to make them work in Go, e.g. functions that take a pointer to an array and a count of items in C will now simply accept a slice in Go.
If you miss any Windows API functions, just write an issue or create a pull request, the Win32 API is very large and has many rarely used functions in it so this wrapper is supposed to grow as needed by the Go community.
Installation
============
Get the latest version with:
go get github.com/gonutz/w32/v2

View File

@ -0,0 +1,143 @@
//go:build windows
/*
* Based on code originally from https://github.com/atotto/clipboard. Copyright (c) 2013 Ato Araki. All rights reserved.
*/
package w32
import (
"runtime"
"syscall"
"time"
"unsafe"
)
const (
cfUnicodetext = 13
gmemMoveable = 0x0002
)
// waitOpenClipboard opens the clipboard, waiting for up to a second to do so.
func waitOpenClipboard() error {
started := time.Now()
limit := started.Add(time.Second)
var r uintptr
var err error
for time.Now().Before(limit) {
r, _, err = procOpenClipboard.Call(0)
if r != 0 {
return nil
}
time.Sleep(time.Millisecond)
}
return err
}
func GetClipboardText() (string, error) {
// LockOSThread ensure that the whole method will keep executing on the same thread from begin to end (it actually locks the goroutine thread attribution).
// Otherwise if the goroutine switch thread during execution (which is a common practice), the OpenClipboard and CloseClipboard will happen on two different threads, and it will result in a clipboard deadlock.
runtime.LockOSThread()
defer runtime.UnlockOSThread()
if formatAvailable, _, err := procIsClipboardFormatAvailable.Call(cfUnicodetext); formatAvailable == 0 {
return "", err
}
err := waitOpenClipboard()
if err != nil {
return "", err
}
h, _, err := procGetClipboardData.Call(cfUnicodetext)
if h == 0 {
_, _, _ = procCloseClipboard.Call()
return "", err
}
l, _, err := kernelGlobalLock.Call(h)
if l == 0 {
_, _, _ = procCloseClipboard.Call()
return "", err
}
text := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(l))[:])
r, _, err := kernelGlobalUnlock.Call(h)
if r == 0 {
_, _, _ = procCloseClipboard.Call()
return "", err
}
closed, _, err := procCloseClipboard.Call()
if closed == 0 {
return "", err
}
return text, nil
}
func SetClipboardText(text string) error {
// LockOSThread ensure that the whole method will keep executing on the same thread from begin to end (it actually locks the goroutine thread attribution).
// Otherwise if the goroutine switch thread during execution (which is a common practice), the OpenClipboard and CloseClipboard will happen on two different threads, and it will result in a clipboard deadlock.
runtime.LockOSThread()
defer runtime.UnlockOSThread()
err := waitOpenClipboard()
if err != nil {
return err
}
r, _, err := procEmptyClipboard.Call(0)
if r == 0 {
_, _, _ = procCloseClipboard.Call()
return err
}
data, err := syscall.UTF16FromString(text)
if err != nil {
return err
}
// "If the hMem parameter identifies a memory object, the object must have
// been allocated using the function with the GMEM_MOVEABLE flag."
h, _, err := kernelGlobalAlloc.Call(gmemMoveable, uintptr(len(data)*int(unsafe.Sizeof(data[0]))))
if h == 0 {
_, _, _ = procCloseClipboard.Call()
return err
}
defer func() {
if h != 0 {
kernelGlobalFree.Call(h)
}
}()
l, _, err := kernelGlobalLock.Call(h)
if l == 0 {
_, _, _ = procCloseClipboard.Call()
return err
}
r, _, err = kernelLstrcpy.Call(l, uintptr(unsafe.Pointer(&data[0])))
if r == 0 {
_, _, _ = procCloseClipboard.Call()
return err
}
r, _, err = kernelGlobalUnlock.Call(h)
if r == 0 {
if err.(syscall.Errno) != 0 {
_, _, _ = procCloseClipboard.Call()
return err
}
}
r, _, err = procSetClipboardData.Call(cfUnicodetext, h)
if r == 0 {
_, _, _ = procCloseClipboard.Call()
return err
}
h = 0 // suppress deferred cleanup
closed, _, err := procCloseClipboard.Call()
if closed == 0 {
return err
}
return nil
}

112
v3/internal/w32/comctl32.go Normal file
View File

@ -0,0 +1,112 @@
//go:build windows
/*
* Copyright (C) 2019 The Winc Authors. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
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
}

View File

@ -0,0 +1,40 @@
//go:build windows
/*
* Copyright (C) 2019 The Winc Authors. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
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

83
v3/internal/w32/consts.go Normal file
View File

@ -0,0 +1,83 @@
//go:build windows
package w32
import (
"golang.org/x/sys/windows/registry"
"strconv"
"syscall"
)
var (
modwingdi = syscall.NewLazyDLL("gdi32.dll")
procCreateSolidBrush = modwingdi.NewProc("CreateSolidBrush")
)
var (
kernel32 = syscall.NewLazyDLL("kernel32")
kernelGlobalAlloc = kernel32.NewProc("GlobalAlloc")
kernelGlobalFree = kernel32.NewProc("GlobalFree")
kernelGlobalLock = kernel32.NewProc("GlobalLock")
kernelGlobalUnlock = kernel32.NewProc("GlobalUnlock")
kernelLstrcpy = kernel32.NewProc("lstrcpyW")
)
var windowsVersion, _ = getWindowsVersionInfo()
func IsWindowsVersionAtLeast(major, minor, buildNumber int) bool {
return windowsVersion.Major >= major &&
windowsVersion.Minor >= minor &&
windowsVersion.Build >= buildNumber
}
type WindowsVersionInfo struct {
Major int
Minor int
Build int
DisplayVersion string
}
func (w *WindowsVersionInfo) IsWindowsVersionAtLeast(major, minor, buildNumber int) bool {
return w.Major >= major && w.Minor >= minor && w.Build >= buildNumber
}
func getWindowsVersionInfo() (*WindowsVersionInfo, error) {
key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
if err != nil {
return nil, err
}
return &WindowsVersionInfo{
Major: regDWORDKeyAsInt(key, "CurrentMajorVersionNumber"),
Minor: regDWORDKeyAsInt(key, "CurrentMinorVersionNumber"),
Build: regStringKeyAsInt(key, "CurrentBuildNumber"),
DisplayVersion: regKeyAsString(key, "DisplayVersion"),
}, nil
}
func regDWORDKeyAsInt(key registry.Key, name string) int {
result, _, err := key.GetIntegerValue(name)
if err != nil {
return -1
}
return int(result)
}
func regStringKeyAsInt(key registry.Key, name string) int {
resultStr, _, err := key.GetStringValue(name)
if err != nil {
return -1
}
result, err := strconv.Atoi(resultStr)
if err != nil {
return -1
}
return result
}
func regKeyAsString(key registry.Key, name string) string {
resultStr, _, err := key.GetStringValue(name)
if err != nil {
return ""
}
return resultStr
}

36
v3/internal/w32/dwmapi.go Normal file
View File

@ -0,0 +1,36 @@
//go:build windows
package w32
import (
"syscall"
"unsafe"
)
var (
moddwmapi = syscall.NewLazyDLL("dwmapi.dll")
procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute")
procDwmExtendFrameIntoClientArea = moddwmapi.NewProc("DwmExtendFrameIntoClientArea")
)
func DwmSetWindowAttribute(hwnd HWND, dwAttribute DWMWINDOWATTRIBUTE, pvAttribute LPCVOID, cbAttribute uint32) HRESULT {
ret, _, _ := procDwmSetWindowAttribute.Call(
hwnd,
uintptr(dwAttribute),
uintptr(pvAttribute),
uintptr(cbAttribute))
return HRESULT(ret)
}
func dwmExtendFrameIntoClientArea(hwnd uintptr, margins *MARGINS) error {
ret, _, _ := procDwmExtendFrameIntoClientArea.Call(
hwnd,
uintptr(unsafe.Pointer(margins)))
if ret != 0 {
return syscall.GetLastError()
}
return nil
}

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +0,0 @@
package w32
// MenuItemFromPoint determines which menu item, if any, is at the specified
// location.
func MenuItemFromPoint(w HWND, m HMENU, screen POINT) int {
ret, _, _ := menuItemFromPoint.Call(
uintptr(w),
uintptr(m),
uintptr(screen.X),
uintptr(screen.Y),
)
return int(ret)
}
func GetClassLongPtr(w HWND, index int) uintptr {
return uintptr(GetClassLong(w, index))
}
func SetClassLongPtr(w HWND, index int, value uintptr) uintptr {
return uintptr(SetClassLong(w, index, int32(value)))
}
func GetWindowLongPtr(hwnd HWND, index int) uintptr {
return uintptr(GetWindowLong(hwnd, index))
}
func SetWindowLongPtr(hwnd HWND, index int, value uintptr) uintptr {
return uintptr(SetWindowLong(hwnd, index, int32(value)))
}

View File

@ -1,43 +0,0 @@
package w32
// MenuItemFromPoint determines which menu item, if any, is at the specified
// location.
func MenuItemFromPoint(w HWND, m HMENU, screen POINT) int {
ret, _, _ := menuItemFromPoint.Call(
uintptr(w),
uintptr(m),
uintptr(uint64(screen.X)<<32|uint64(screen.Y)),
)
return int(ret)
}
func GetClassLongPtr(w HWND, index int) uintptr {
ret, _, _ := getClassLongPtr.Call(uintptr(w), uintptr(index))
return ret
}
func SetClassLongPtr(w HWND, index int, value uintptr) uintptr {
ret, _, _ := setClassLongPtr.Call(
uintptr(w),
uintptr(index),
value,
)
return ret
}
func GetWindowLongPtr(hwnd HWND, index int) uintptr {
ret, _, _ := getWindowLongPtr.Call(
uintptr(hwnd),
uintptr(index),
)
return ret
}
func SetWindowLongPtr(hwnd HWND, index int, value uintptr) uintptr {
ret, _, _ := setWindowLongPtr.Call(
uintptr(hwnd),
uintptr(index),
value,
)
return ret
}

View File

@ -1,43 +0,0 @@
package w32
// MenuItemFromPoint determines which menu item, if any, is at the specified
// location.
func MenuItemFromPoint(w HWND, m HMENU, screen POINT) int {
ret, _, _ := menuItemFromPoint.Call(
uintptr(w),
uintptr(m),
uintptr(uint64(screen.X)<<32|uint64(screen.Y)),
)
return int(ret)
}
func GetClassLongPtr(w HWND, index int) uintptr {
ret, _, _ := getClassLongPtr.Call(uintptr(w), uintptr(index))
return ret
}
func SetClassLongPtr(w HWND, index int, value uintptr) uintptr {
ret, _, _ := setClassLongPtr.Call(
uintptr(w),
uintptr(index),
value,
)
return ret
}
func GetWindowLongPtr(hwnd HWND, index int) uintptr {
ret, _, _ := getWindowLongPtr.Call(
uintptr(hwnd),
uintptr(index),
)
return ret
}
func SetWindowLongPtr(hwnd HWND, index int, value uintptr) uintptr {
ret, _, _ := setWindowLongPtr.Call(
uintptr(hwnd),
uintptr(index),
value,
)
return ret
}

526
v3/internal/w32/gdi32.go Normal file
View File

@ -0,0 +1,526 @@
//go:build windows
/*
* Copyright (C) 2019 The Winc Authors. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
package w32
import (
"syscall"
"unsafe"
)
var (
modgdi32 = syscall.NewLazyDLL("gdi32.dll")
procGetDeviceCaps = modgdi32.NewProc("GetDeviceCaps")
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")
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 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 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 int32) 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, _, _ := procGetDeviceCaps.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 int32) 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 int32) 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
}

177
v3/internal/w32/gdiplus.go Normal file
View File

@ -0,0 +1,177 @@
//go:build windows
/*
* Copyright (C) 2019 The Winc Authors. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
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)))
}
}

View File

@ -0,0 +1,45 @@
//go:build windows
/*
* Copyright (C) 2019 The Winc Authors. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
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...)
}

View File

@ -0,0 +1,33 @@
//go:build windows
/*
* Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
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)))
}

View File

@ -0,0 +1,29 @@
//go:build windows
/*
* Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
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)
}

332
v3/internal/w32/kernel32.go Normal file
View File

@ -0,0 +1,332 @@
//go:build windows
/*
* Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
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")
procGetCurrentThreadId = modkernel32.NewProc("GetCurrentThreadId")
procGetLogicalDrives = modkernel32.NewProc("GetLogicalDrives")
procGetLogicalDriveStrings = modkernel32.NewProc("GetLogicalDriveStringsW")
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")
)
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 GetCurrentThreadId() HANDLE {
ret, _, _ := procGetCurrentThreadId.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 GetLogicalDriveStrings(nBufferLength uint32, lpBuffer *uint16) uint32 {
ret, _, _ := procGetLogicalDriveStrings.Call(
uintptr(nBufferLength),
uintptr(unsafe.Pointer(lpBuffer)),
0)
return uint32(ret)
}

65
v3/internal/w32/ole32.go Normal file
View File

@ -0,0 +1,65 @@
//go:build windows
/*
* Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
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
}

View File

@ -0,0 +1,50 @@
//go:build windows
/*
* Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
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)
}

29
v3/internal/w32/shcore.go Normal file
View File

@ -0,0 +1,29 @@
//go:build windows
package w32
import (
"syscall"
"unsafe"
)
var (
modshcore = syscall.NewLazyDLL("shcore.dll")
procGetDpiForMonitor = modshcore.NewProc("GetDpiForMonitor")
)
func HasGetDPIForMonitorFunc() bool {
err := procGetDpiForMonitor.Find()
return err == nil
}
func GetDPIForMonitor(hmonitor HMONITOR, dpiType MONITOR_DPI_TYPE, dpiX *UINT, dpiY *UINT) uintptr {
ret, _, _ := procGetDpiForMonitor.Call(
hmonitor,
uintptr(dpiType),
uintptr(unsafe.Pointer(dpiX)),
uintptr(unsafe.Pointer(dpiY)))
return ret
}

235
v3/internal/w32/shell32.go Normal file
View File

@ -0,0 +1,235 @@
//go:build windows
/*
* Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
package w32
import (
"errors"
"fmt"
"syscall"
"unsafe"
)
type CSIDL uint32
const (
CSIDL_DESKTOP = 0x00
CSIDL_INTERNET = 0x01
CSIDL_PROGRAMS = 0x02
CSIDL_CONTROLS = 0x03
CSIDL_PRINTERS = 0x04
CSIDL_PERSONAL = 0x05
CSIDL_FAVORITES = 0x06
CSIDL_STARTUP = 0x07
CSIDL_RECENT = 0x08
CSIDL_SENDTO = 0x09
CSIDL_BITBUCKET = 0x0A
CSIDL_STARTMENU = 0x0B
CSIDL_MYDOCUMENTS = 0x0C
CSIDL_MYMUSIC = 0x0D
CSIDL_MYVIDEO = 0x0E
CSIDL_DESKTOPDIRECTORY = 0x10
CSIDL_DRIVES = 0x11
CSIDL_NETWORK = 0x12
CSIDL_NETHOOD = 0x13
CSIDL_FONTS = 0x14
CSIDL_TEMPLATES = 0x15
CSIDL_COMMON_STARTMENU = 0x16
CSIDL_COMMON_PROGRAMS = 0x17
CSIDL_COMMON_STARTUP = 0x18
CSIDL_COMMON_DESKTOPDIRECTORY = 0x19
CSIDL_APPDATA = 0x1A
CSIDL_PRINTHOOD = 0x1B
CSIDL_LOCAL_APPDATA = 0x1C
CSIDL_ALTSTARTUP = 0x1D
CSIDL_COMMON_ALTSTARTUP = 0x1E
CSIDL_COMMON_FAVORITES = 0x1F
CSIDL_INTERNET_CACHE = 0x20
CSIDL_COOKIES = 0x21
CSIDL_HISTORY = 0x22
CSIDL_COMMON_APPDATA = 0x23
CSIDL_WINDOWS = 0x24
CSIDL_SYSTEM = 0x25
CSIDL_PROGRAM_FILES = 0x26
CSIDL_MYPICTURES = 0x27
CSIDL_PROFILE = 0x28
CSIDL_SYSTEMX86 = 0x29
CSIDL_PROGRAM_FILESX86 = 0x2A
CSIDL_PROGRAM_FILES_COMMON = 0x2B
CSIDL_PROGRAM_FILES_COMMONX86 = 0x2C
CSIDL_COMMON_TEMPLATES = 0x2D
CSIDL_COMMON_DOCUMENTS = 0x2E
CSIDL_COMMON_ADMINTOOLS = 0x2F
CSIDL_ADMINTOOLS = 0x30
CSIDL_CONNECTIONS = 0x31
CSIDL_COMMON_MUSIC = 0x35
CSIDL_COMMON_PICTURES = 0x36
CSIDL_COMMON_VIDEO = 0x37
CSIDL_RESOURCES = 0x38
CSIDL_RESOURCES_LOCALIZED = 0x39
CSIDL_COMMON_OEM_LINKS = 0x3A
CSIDL_CDBURN_AREA = 0x3B
CSIDL_COMPUTERSNEARME = 0x3D
CSIDL_FLAG_CREATE = 0x8000
CSIDL_FLAG_DONT_VERIFY = 0x4000
CSIDL_FLAG_NO_ALIAS = 0x1000
CSIDL_FLAG_PER_USER_INIT = 0x8000
CSIDL_FLAG_MASK = 0xFF00
)
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")
procGetSpecialFolderPath = modshell32.NewProc("SHGetSpecialFolderPathW")
)
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)
}
func SHGetSpecialFolderPath(hwndOwner HWND, lpszPath *uint16, csidl CSIDL, fCreate bool) bool {
ret, _, _ := procGetSpecialFolderPath.Call(
uintptr(hwndOwner),
uintptr(unsafe.Pointer(lpszPath)),
uintptr(csidl),
uintptr(BoolToBOOL(fCreate)),
0,
0)
return ret != 0
}

View File

@ -0,0 +1,26 @@
//go:build windows
package w32
import (
"syscall"
"unsafe"
)
var (
modshlwapi = syscall.NewLazyDLL("shlwapi.dll")
procSHCreateMemStream = modshlwapi.NewProc("SHCreateMemStream")
)
func SHCreateMemStream(data []byte) (uintptr, error) {
ret, _, err := procSHCreateMemStream.Call(
uintptr(unsafe.Pointer(&data[0])),
uintptr(len(data)),
)
if ret == 0 {
return 0, err
}
return ret, nil
}

119
v3/internal/w32/theme.go Normal file
View File

@ -0,0 +1,119 @@
//go:build windows
package w32
import (
"unsafe"
"golang.org/x/sys/windows/registry"
)
type DWMWINDOWATTRIBUTE int32
const DwmwaUseImmersiveDarkModeBefore20h1 DWMWINDOWATTRIBUTE = 19
const DwmwaUseImmersiveDarkMode DWMWINDOWATTRIBUTE = 20
const DwmwaBorderColor DWMWINDOWATTRIBUTE = 34
const DwmwaCaptionColor DWMWINDOWATTRIBUTE = 35
const DwmwaTextColor DWMWINDOWATTRIBUTE = 36
const DwmwaSystemBackdropType DWMWINDOWATTRIBUTE = 38
const SPI_GETHIGHCONTRAST = 0x0042
const HCF_HIGHCONTRASTON = 0x00000001
// BackdropType defines the type of translucency we wish to use
type BackdropType int32
func dwmSetWindowAttribute(hwnd uintptr, dwAttribute DWMWINDOWATTRIBUTE, pvAttribute unsafe.Pointer, cbAttribute uintptr) {
ret, _, err := procDwmSetWindowAttribute.Call(
hwnd,
uintptr(dwAttribute),
uintptr(pvAttribute),
cbAttribute)
if ret != 0 {
_ = err
// println(err.Error())
}
}
func SupportsThemes() bool {
// We can't support Windows versions before 17763
return IsWindowsVersionAtLeast(10, 0, 17763)
}
func SupportsCustomThemes() bool {
return IsWindowsVersionAtLeast(10, 0, 17763)
}
func SupportsBackdropTypes() bool {
return IsWindowsVersionAtLeast(10, 0, 22621)
}
func SupportsImmersiveDarkMode() bool {
return IsWindowsVersionAtLeast(10, 0, 18985)
}
func SetTheme(hwnd uintptr, useDarkMode bool) {
if SupportsThemes() {
attr := DwmwaUseImmersiveDarkModeBefore20h1
if SupportsImmersiveDarkMode() {
attr = DwmwaUseImmersiveDarkMode
}
var winDark int32
if useDarkMode {
winDark = 1
}
dwmSetWindowAttribute(hwnd, attr, unsafe.Pointer(&winDark), unsafe.Sizeof(winDark))
}
}
func EnableTranslucency(hwnd uintptr, backdrop BackdropType) {
if SupportsBackdropTypes() {
dwmSetWindowAttribute(hwnd, DwmwaSystemBackdropType, unsafe.Pointer(&backdrop), unsafe.Sizeof(backdrop))
} else {
println("Warning: Translucency type unavailable on Windows < 22621")
}
}
func SetTitleBarColour(hwnd uintptr, titleBarColour int32) {
dwmSetWindowAttribute(hwnd, DwmwaCaptionColor, unsafe.Pointer(&titleBarColour), unsafe.Sizeof(titleBarColour))
}
func SetTitleTextColour(hwnd uintptr, titleTextColour int32) {
dwmSetWindowAttribute(hwnd, DwmwaTextColor, unsafe.Pointer(&titleTextColour), unsafe.Sizeof(titleTextColour))
}
func SetBorderColour(hwnd uintptr, titleBorderColour int32) {
dwmSetWindowAttribute(hwnd, DwmwaBorderColor, unsafe.Pointer(&titleBorderColour), unsafe.Sizeof(titleBorderColour))
}
func IsCurrentlyDarkMode() bool {
key, err := registry.OpenKey(registry.CURRENT_USER, `SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize`, registry.QUERY_VALUE)
if err != nil {
return false
}
defer key.Close()
AppsUseLightTheme, _, err := key.GetIntegerValue("AppsUseLightTheme")
if err != nil {
return false
}
return AppsUseLightTheme == 0
}
type highContrast struct {
CbSize uint32
DwFlags uint32
LpszDefaultScheme *int16
}
func IsCurrentlyHighContrastMode() bool {
var result highContrast
result.CbSize = uint32(unsafe.Sizeof(result))
res, _, err := procSystemParametersInfo.Call(SPI_GETHIGHCONTRAST, uintptr(result.CbSize), uintptr(unsafe.Pointer(&result)), 0)
if res == 0 {
_ = err
return false
}
r := result.DwFlags&HCF_HIGHCONTRASTON == HCF_HIGHCONTRASTON
return r
}

216
v3/internal/w32/toolbar.go Normal file
View File

@ -0,0 +1,216 @@
//go:build windows
/*
* Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
package w32
// ToolBar messages
const (
TB_ENABLEBUTTON = WM_USER + 1
TB_CHECKBUTTON = WM_USER + 2
TB_PRESSBUTTON = WM_USER + 3
TB_HIDEBUTTON = WM_USER + 4
TB_INDETERMINATE = WM_USER + 5
TB_MARKBUTTON = WM_USER + 6
TB_ISBUTTONENABLED = WM_USER + 9
TB_ISBUTTONCHECKED = WM_USER + 10
TB_ISBUTTONPRESSED = WM_USER + 11
TB_ISBUTTONHIDDEN = WM_USER + 12
TB_ISBUTTONINDETERMINATE = WM_USER + 13
TB_ISBUTTONHIGHLIGHTED = WM_USER + 14
TB_SETSTATE = WM_USER + 17
TB_GETSTATE = WM_USER + 18
TB_ADDBITMAP = WM_USER + 19
TB_DELETEBUTTON = WM_USER + 22
TB_GETBUTTON = WM_USER + 23
TB_BUTTONCOUNT = WM_USER + 24
TB_COMMANDTOINDEX = WM_USER + 25
TB_SAVERESTORE = WM_USER + 76
TB_CUSTOMIZE = WM_USER + 27
TB_ADDSTRING = WM_USER + 77
TB_GETITEMRECT = WM_USER + 29
TB_BUTTONSTRUCTSIZE = WM_USER + 30
TB_SETBUTTONSIZE = WM_USER + 31
TB_SETBITMAPSIZE = WM_USER + 32
TB_AUTOSIZE = WM_USER + 33
TB_GETTOOLTIPS = WM_USER + 35
TB_SETTOOLTIPS = WM_USER + 36
TB_SETPARENT = WM_USER + 37
TB_SETROWS = WM_USER + 39
TB_GETROWS = WM_USER + 40
TB_GETBITMAPFLAGS = WM_USER + 41
TB_SETCMDID = WM_USER + 42
TB_CHANGEBITMAP = WM_USER + 43
TB_GETBITMAP = WM_USER + 44
TB_GETBUTTONTEXT = WM_USER + 75
TB_REPLACEBITMAP = WM_USER + 46
TB_GETBUTTONSIZE = WM_USER + 58
TB_SETBUTTONWIDTH = WM_USER + 59
TB_SETINDENT = WM_USER + 47
TB_SETIMAGELIST = WM_USER + 48
TB_GETIMAGELIST = WM_USER + 49
TB_LOADIMAGES = WM_USER + 50
TB_GETRECT = WM_USER + 51
TB_SETHOTIMAGELIST = WM_USER + 52
TB_GETHOTIMAGELIST = WM_USER + 53
TB_SETDISABLEDIMAGELIST = WM_USER + 54
TB_GETDISABLEDIMAGELIST = WM_USER + 55
TB_SETSTYLE = WM_USER + 56
TB_GETSTYLE = WM_USER + 57
TB_SETMAXTEXTROWS = WM_USER + 60
TB_GETTEXTROWS = WM_USER + 61
TB_GETOBJECT = WM_USER + 62
TB_GETBUTTONINFO = WM_USER + 63
TB_SETBUTTONINFO = WM_USER + 64
TB_INSERTBUTTON = WM_USER + 67
TB_ADDBUTTONS = WM_USER + 68
TB_HITTEST = WM_USER + 69
TB_SETDRAWTEXTFLAGS = WM_USER + 70
TB_GETHOTITEM = WM_USER + 71
TB_SETHOTITEM = WM_USER + 72
TB_SETANCHORHIGHLIGHT = WM_USER + 73
TB_GETANCHORHIGHLIGHT = WM_USER + 74
TB_GETINSERTMARK = WM_USER + 79
TB_SETINSERTMARK = WM_USER + 80
TB_INSERTMARKHITTEST = WM_USER + 81
TB_MOVEBUTTON = WM_USER + 82
TB_GETMAXSIZE = WM_USER + 83
TB_SETEXTENDEDSTYLE = WM_USER + 84
TB_GETEXTENDEDSTYLE = WM_USER + 85
TB_GETPADDING = WM_USER + 86
TB_SETPADDING = WM_USER + 87
TB_SETINSERTMARKCOLOR = WM_USER + 88
TB_GETINSERTMARKCOLOR = WM_USER + 89
TB_MAPACCELERATOR = WM_USER + 90
TB_GETSTRING = WM_USER + 91
TB_SETCOLORSCHEME = CCM_SETCOLORSCHEME
TB_GETCOLORSCHEME = CCM_GETCOLORSCHEME
TB_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT
TB_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT
)
// ToolBar notifications
const (
TBN_FIRST = -700
TBN_DROPDOWN = TBN_FIRST - 10
)
// TBN_DROPDOWN return codes
const (
TBDDRET_DEFAULT = 0
TBDDRET_NODEFAULT = 1
TBDDRET_TREATPRESSED = 2
)
// ToolBar state constants
const (
TBSTATE_CHECKED = 1
TBSTATE_PRESSED = 2
TBSTATE_ENABLED = 4
TBSTATE_HIDDEN = 8
TBSTATE_INDETERMINATE = 16
TBSTATE_WRAP = 32
TBSTATE_ELLIPSES = 0x40
TBSTATE_MARKED = 0x0080
)
// ToolBar style constants
const (
TBSTYLE_BUTTON = 0
TBSTYLE_SEP = 1
TBSTYLE_CHECK = 2
TBSTYLE_GROUP = 4
TBSTYLE_CHECKGROUP = TBSTYLE_GROUP | TBSTYLE_CHECK
TBSTYLE_DROPDOWN = 8
TBSTYLE_AUTOSIZE = 16
TBSTYLE_NOPREFIX = 32
TBSTYLE_TOOLTIPS = 256
TBSTYLE_WRAPABLE = 512
TBSTYLE_ALTDRAG = 1024
TBSTYLE_FLAT = 2048
TBSTYLE_LIST = 4096
TBSTYLE_CUSTOMERASE = 8192
TBSTYLE_REGISTERDROP = 0x4000
TBSTYLE_TRANSPARENT = 0x8000
)
// ToolBar extended style constants
const (
TBSTYLE_EX_DRAWDDARROWS = 0x00000001
TBSTYLE_EX_MIXEDBUTTONS = 8
TBSTYLE_EX_HIDECLIPPEDBUTTONS = 16
TBSTYLE_EX_DOUBLEBUFFER = 0x80
)
// ToolBar button style constants
const (
BTNS_BUTTON = TBSTYLE_BUTTON
BTNS_SEP = TBSTYLE_SEP
BTNS_CHECK = TBSTYLE_CHECK
BTNS_GROUP = TBSTYLE_GROUP
BTNS_CHECKGROUP = TBSTYLE_CHECKGROUP
BTNS_DROPDOWN = TBSTYLE_DROPDOWN
BTNS_AUTOSIZE = TBSTYLE_AUTOSIZE
BTNS_NOPREFIX = TBSTYLE_NOPREFIX
BTNS_WHOLEDROPDOWN = 0x0080
BTNS_SHOWTEXT = 0x0040
)
// TBBUTTONINFO mask flags
const (
TBIF_IMAGE = 0x00000001
TBIF_TEXT = 0x00000002
TBIF_STATE = 0x00000004
TBIF_STYLE = 0x00000008
TBIF_LPARAM = 0x00000010
TBIF_COMMAND = 0x00000020
TBIF_SIZE = 0x00000040
TBIF_BYINDEX = 0x80000000
)
type NMMOUSE struct {
Hdr NMHDR
DwItemSpec uintptr
DwItemData uintptr
Pt POINT
DwHitInfo uintptr
}
type NMTOOLBAR struct {
Hdr NMHDR
IItem int32
TbButton TBBUTTON
CchText int32
PszText *uint16
RcButton RECT
}
type TBBUTTON struct {
IBitmap int32
IdCommand int32
FsState byte
FsStyle byte
//#ifdef _WIN64
// BYTE bReserved[6] // padding for alignment
//#elif defined(_WIN32)
BReserved [2]byte // padding for alignment
//#endif
DwData uintptr
IString uintptr
}
type TBBUTTONINFO struct {
CbSize uint32
DwMask uint32
IdCommand int32
IImage int32
FsState byte
FsStyle byte
Cx uint16
LParam uintptr
PszText uintptr
CchText int32
}

File diff suppressed because it is too large Load Diff

1281
v3/internal/w32/user32.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,92 +1,81 @@
//go:build windows
/*
* Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
package w32
import (
"errors"
"syscall"
"unicode/utf16"
"unsafe"
)
type pIUnknownVtbl struct {
queryInterface uintptr
addRef uintptr
release uintptr
func MustLoadLibrary(name string) uintptr {
lib, err := syscall.LoadLibrary(name)
if err != nil {
panic(err)
}
return uintptr(lib)
}
type IUnknown struct {
lpVtbl *pIUnknownVtbl
func MustGetProcAddress(lib uintptr, name string) uintptr {
addr, err := syscall.GetProcAddress(syscall.Handle(lib), name)
if err != nil {
panic(err)
}
return uintptr(addr)
}
func (u *IUnknown) QueryInterface(id *GUID) (*IDispatch, HRESULT) {
return ComQueryInterface(u, id)
func SUCCEEDED(hr HRESULT) bool {
return hr >= 0
}
func (u *IUnknown) AddRef() int32 {
return ComAddRef(u)
func FAILED(hr HRESULT) bool {
return hr < 0
}
func (u *IUnknown) Release() int32 {
return ComRelease(u)
func LOWORD(dw uint32) uint16 {
return uint16(dw)
}
type pIDispatchVtbl struct {
queryInterface uintptr
addRef uintptr
release uintptr
getTypeInfoCount uintptr
getTypeInfo uintptr
getIDsOfNames uintptr
invoke uintptr
func HIWORD(dw uint32) uint16 {
return uint16(dw >> 16 & 0xffff)
}
type IDispatch struct {
lpVtbl *pIDispatchVtbl
func MAKELONG(lo, hi uint16) uint32 {
return uint32(uint32(lo) | ((uint32(hi)) << 16))
}
func (d *IDispatch) QueryInterface(id *GUID) (*IDispatch, HRESULT) {
return ComQueryInterface((*IUnknown)(unsafe.Pointer(d)), id)
func BoolToBOOL(value bool) BOOL {
if value {
return 1
}
return 0
}
func (d *IDispatch) AddRef() int32 {
return ComAddRef((*IUnknown)(unsafe.Pointer(d)))
}
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)
}
}
func (d *IDispatch) Release() int32 {
return ComRelease((*IUnknown)(unsafe.Pointer(d)))
}
func (d *IDispatch) GetIDsOfName(names []string) ([]int32, HRESULT) {
return ComGetIDsOfName(d, names)
}
func (d *IDispatch) Invoke(dispid int32, dispatch int16, params ...interface{}) (*VARIANT, error) {
return ComInvoke(d, dispid, dispatch, params...)
}
type pIStreamVtbl struct {
qeryInterface uintptr
addRef uintptr
release uintptr
}
type IStream struct {
lpVtbl *pIStreamVtbl
}
func (s *IStream) QueryInterface(id *GUID) (*IDispatch, HRESULT) {
return ComQueryInterface((*IUnknown)(unsafe.Pointer(s)), id)
}
func (s *IStream) AddRef() int32 {
return ComAddRef((*IUnknown)(unsafe.Pointer(s)))
}
func (s *IStream) Release() int32 {
return ComRelease((*IUnknown)(unsafe.Pointer(s)))
return ""
}
func ComAddRef(unknown *IUnknown) int32 {
ret, _, _ := syscall.Syscall(unknown.lpVtbl.addRef, 1,
ret, _, _ := syscall.Syscall(unknown.lpVtbl.pAddRef, 1,
uintptr(unsafe.Pointer(unknown)),
0,
0)
@ -94,41 +83,45 @@ func ComAddRef(unknown *IUnknown) int32 {
}
func ComRelease(unknown *IUnknown) int32 {
ret, _, _ := syscall.Syscall(unknown.lpVtbl.release, 1,
ret, _, _ := syscall.Syscall(unknown.lpVtbl.pRelease, 1,
uintptr(unsafe.Pointer(unknown)),
0,
0)
return int32(ret)
}
func ComQueryInterface(unknown *IUnknown, id *GUID) (*IDispatch, HRESULT) {
func ComQueryInterface(unknown *IUnknown, id *GUID) *IDispatch {
var disp *IDispatch
hr, _, _ := syscall.Syscall(unknown.lpVtbl.queryInterface, 3,
hr, _, _ := syscall.Syscall(unknown.lpVtbl.pQueryInterface, 3,
uintptr(unsafe.Pointer(unknown)),
uintptr(unsafe.Pointer(id)),
uintptr(unsafe.Pointer(&disp)),
)
return disp, HRESULT(hr)
uintptr(unsafe.Pointer(&disp)))
if hr != 0 {
panic("Invoke QieryInterface error.")
}
return disp
}
func ComGetIDsOfName(disp *IDispatch, names []string) ([]int32, HRESULT) {
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.getIDsOfNames, 6,
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])),
)
return dispid, HRESULT(hr)
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, err error) {
func ComInvoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{}) (result *VARIANT) {
var dispparams DISPPARAMS
if dispatch&DISPATCH_PROPERTYPUT != 0 {
@ -140,6 +133,7 @@ func ComInvoke(disp *IDispatch, dispid int32, dispatch int16, params ...interfac
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) {
@ -200,7 +194,7 @@ func ComInvoke(disp *IDispatch, dispid int32, dispatch int16, params ...interfac
case *VARIANT:
vargs[n] = VARIANT{VT_VARIANT | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*VARIANT))))}
default:
return nil, errors.New("w32.ComInvoke: unknown variant type")
panic("unknown type")
}
}
dispparams.Rgvarg = uintptr(unsafe.Pointer(&vargs[0]))
@ -210,7 +204,7 @@ func ComInvoke(disp *IDispatch, dispid int32, dispatch int16, params ...interfac
var ret VARIANT
var excepInfo EXCEPINFO
VariantInit(&ret)
hr, _, _ := syscall.Syscall9(disp.lpVtbl.invoke, 8,
hr, _, _ := syscall.Syscall9(disp.lpVtbl.pInvoke, 8,
uintptr(unsafe.Pointer(disp)),
uintptr(dispid),
uintptr(unsafe.Pointer(IID_NULL)),
@ -223,7 +217,7 @@ func ComInvoke(disp *IDispatch, dispid int32, dispatch int16, params ...interfac
if hr != 0 {
if excepInfo.BstrDescription != nil {
bs := UTF16PtrToString(excepInfo.BstrDescription)
return nil, errors.New(bs)
panic(bs)
}
}
for _, varg := range vargs {
@ -234,18 +228,3 @@ func ComInvoke(disp *IDispatch, dispid int32, dispatch int16, params ...interfac
result = &ret
return
}
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 ""
}

152
v3/internal/w32/uxtheme.go Normal file
View File

@ -0,0 +1,152 @@
//go:build windows
/*
* Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
package w32
import (
"syscall"
"unsafe"
)
// LISTVIEW parts
const (
LVP_LISTITEM = 1
LVP_LISTGROUP = 2
LVP_LISTDETAIL = 3
LVP_LISTSORTEDDETAIL = 4
LVP_EMPTYTEXT = 5
LVP_GROUPHEADER = 6
LVP_GROUPHEADERLINE = 7
LVP_EXPANDBUTTON = 8
LVP_COLLAPSEBUTTON = 9
LVP_COLUMNDETAIL = 10
)
// LVP_LISTITEM states
const (
LISS_NORMAL = 1
LISS_HOT = 2
LISS_SELECTED = 3
LISS_DISABLED = 4
LISS_SELECTEDNOTFOCUS = 5
LISS_HOTSELECTED = 6
)
// TREEVIEW parts
const (
TVP_TREEITEM = 1
TVP_GLYPH = 2
TVP_BRANCH = 3
TVP_HOTGLYPH = 4
)
// TVP_TREEITEM states
const (
TREIS_NORMAL = 1
TREIS_HOT = 2
TREIS_SELECTED = 3
TREIS_DISABLED = 4
TREIS_SELECTEDNOTFOCUS = 5
TREIS_HOTSELECTED = 6
)
type HTHEME HANDLE
var (
// Library
libuxtheme uintptr
// Functions
closeThemeData uintptr
drawThemeBackground uintptr
drawThemeText uintptr
getThemeTextExtent uintptr
openThemeData uintptr
setWindowTheme uintptr
)
func init() {
// Library
libuxtheme = MustLoadLibrary("uxtheme.dll")
// Functions
closeThemeData = MustGetProcAddress(libuxtheme, "CloseThemeData")
drawThemeBackground = MustGetProcAddress(libuxtheme, "DrawThemeBackground")
drawThemeText = MustGetProcAddress(libuxtheme, "DrawThemeText")
getThemeTextExtent = MustGetProcAddress(libuxtheme, "GetThemeTextExtent")
openThemeData = MustGetProcAddress(libuxtheme, "OpenThemeData")
setWindowTheme = MustGetProcAddress(libuxtheme, "SetWindowTheme")
}
func CloseThemeData(hTheme HTHEME) HRESULT {
ret, _, _ := syscall.Syscall(closeThemeData, 1,
uintptr(hTheme),
0,
0)
return HRESULT(ret)
}
func DrawThemeBackground(hTheme HTHEME, hdc HDC, iPartId, iStateId int32, pRect, pClipRect *RECT) HRESULT {
ret, _, _ := syscall.Syscall6(drawThemeBackground, 6,
uintptr(hTheme),
uintptr(hdc),
uintptr(iPartId),
uintptr(iStateId),
uintptr(unsafe.Pointer(pRect)),
uintptr(unsafe.Pointer(pClipRect)))
return HRESULT(ret)
}
func DrawThemeText(hTheme HTHEME, hdc HDC, iPartId, iStateId int32, pszText *uint16, iCharCount int32, dwTextFlags, dwTextFlags2 uint32, pRect *RECT) HRESULT {
ret, _, _ := syscall.Syscall9(drawThemeText, 9,
uintptr(hTheme),
uintptr(hdc),
uintptr(iPartId),
uintptr(iStateId),
uintptr(unsafe.Pointer(pszText)),
uintptr(iCharCount),
uintptr(dwTextFlags),
uintptr(dwTextFlags2),
uintptr(unsafe.Pointer(pRect)))
return HRESULT(ret)
}
func GetThemeTextExtent(hTheme HTHEME, hdc HDC, iPartId, iStateId int32, pszText *uint16, iCharCount int32, dwTextFlags uint32, pBoundingRect, pExtentRect *RECT) HRESULT {
ret, _, _ := syscall.Syscall9(getThemeTextExtent, 9,
uintptr(hTheme),
uintptr(hdc),
uintptr(iPartId),
uintptr(iStateId),
uintptr(unsafe.Pointer(pszText)),
uintptr(iCharCount),
uintptr(dwTextFlags),
uintptr(unsafe.Pointer(pBoundingRect)),
uintptr(unsafe.Pointer(pExtentRect)))
return HRESULT(ret)
}
func OpenThemeData(hwnd HWND, pszClassList *uint16) HTHEME {
ret, _, _ := syscall.Syscall(openThemeData, 2,
uintptr(hwnd),
uintptr(unsafe.Pointer(pszClassList)),
0)
return HTHEME(ret)
}
func SetWindowTheme(hwnd HWND, pszSubAppName, pszSubIdList *uint16) HRESULT {
ret, _, _ := syscall.Syscall(setWindowTheme, 3,
uintptr(hwnd),
uintptr(unsafe.Pointer(pszSubAppName)),
uintptr(unsafe.Pointer(pszSubIdList)))
return HRESULT(ret)
}

16
v3/internal/w32/vars.go Normal file
View File

@ -0,0 +1,16 @@
//go:build windows
/*
* Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
* Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
*/
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}}
)

137
v3/internal/w32/window.go Normal file
View File

@ -0,0 +1,137 @@
package w32
import (
"fmt"
"log"
"strconv"
"syscall"
"unsafe"
)
const (
GCLP_HBRBACKGROUND int32 = -10
)
func ExtendFrameIntoClientArea(hwnd uintptr, extend bool) {
// -1: Adds the default frame styling (aero shadow and e.g. rounded corners on Windows 11)
// Also shows the caption buttons if transparent ant translucent but they don't work.
// 0: Adds the default frame styling but no aero shadow, does not show the caption buttons.
// 1: Adds the default frame styling (aero shadow and e.g. rounded corners on Windows 11) but no caption buttons
// are shown if transparent ant translucent.
var margins MARGINS
if extend {
margins = MARGINS{1, 1, 1, 1} // Only extend 1 pixel to have the default frame styling but no caption buttons
}
if err := dwmExtendFrameIntoClientArea(hwnd, &margins); err != nil {
log.Fatal(fmt.Errorf("DwmExtendFrameIntoClientArea failed: %s", err))
}
}
func IsVisible(hwnd uintptr) bool {
ret, _, _ := procIsWindowVisible.Call(hwnd)
return ret != 0
}
func IsWindowFullScreen(hwnd uintptr) bool {
wRect := GetWindowRect(hwnd)
m := MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)
var mi MONITORINFO
mi.CbSize = uint32(unsafe.Sizeof(mi))
if !GetMonitorInfo(m, &mi) {
return false
}
return wRect.Left == mi.RcMonitor.Left &&
wRect.Top == mi.RcMonitor.Top &&
wRect.Right == mi.RcMonitor.Right &&
wRect.Bottom == mi.RcMonitor.Bottom
}
func IsWindowMaximised(hwnd uintptr) bool {
style := uint32(getWindowLong(hwnd, GWL_STYLE))
return style&WS_MAXIMIZE != 0
}
func IsWindowMinimised(hwnd uintptr) bool {
style := uint32(getWindowLong(hwnd, GWL_STYLE))
return style&WS_MINIMIZE != 0
}
func RestoreWindow(hwnd uintptr) {
showWindow(hwnd, SW_RESTORE)
}
func ShowWindowMaximised(hwnd uintptr) {
showWindow(hwnd, SW_MAXIMIZE)
}
func ShowWindowMinimised(hwnd uintptr) {
showWindow(hwnd, SW_MINIMIZE)
}
func SetBackgroundColour(hwnd uintptr, r, g, b uint8) {
col := uint32(r) | uint32(g)<<8 | uint32(b)<<16
hbrush, _, _ := procCreateSolidBrush.Call(uintptr(col))
setClassLongPtr(hwnd, GCLP_HBRBACKGROUND, hbrush)
}
func IsWindowNormal(hwnd uintptr) bool {
return !IsWindowMaximised(hwnd) && !IsWindowMinimised(hwnd) && !IsWindowFullScreen(hwnd)
}
func setClassLongPtr(hwnd uintptr, param int32, val uintptr) bool {
proc := procSetClassLongPtr
if strconv.IntSize == 32 {
/*
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setclasslongptrw
Note: To write code that is compatible with both 32-bit and 64-bit Windows, use SetClassLongPtr.
When compiling for 32-bit Windows, SetClassLongPtr is defined as a call to the SetClassLong function
=> We have to do this dynamically when directly calling the DLL procedures
*/
proc = procSetClassLong
}
ret, _, _ := proc.Call(
hwnd,
uintptr(param),
val,
)
return ret != 0
}
func getWindowLong(hwnd uintptr, index int) int32 {
ret, _, _ := procGetWindowLong.Call(
hwnd,
uintptr(index))
return int32(ret)
}
func showWindow(hwnd uintptr, cmdshow int) bool {
ret, _, _ := procShowWindow.Call(
hwnd,
uintptr(cmdshow))
return ret != 0
}
func MustStringToUTF16Ptr(input string) *uint16 {
ret, err := syscall.UTF16PtrFromString(input)
if err != nil {
panic(err)
}
return ret
}
func MustStringToUTF16uintptr(input string) uintptr {
ret, err := syscall.UTF16PtrFromString(input)
if err != nil {
panic(err)
}
return uintptr(unsafe.Pointer(ret))
}
func MustUTF16FromString(input string) []uint16 {
ret, err := syscall.UTF16FromString(input)
if err != nil {
panic(err)
}
return ret
}

View File

@ -17,7 +17,7 @@ var (
)
func init() {
wmInvokeCallback = w32.RegisterWindowMessage("WailsV0.InvokeCallback")
wmInvokeCallback = w32.RegisterWindowMessage(w32.MustStringToUTF16Ptr("WailsV0.InvokeCallback"))
}
// initMainLoop must be called with the same OSThread that is used to call runMainLoop() later.

View File

@ -102,7 +102,7 @@ func (m *MessageProcessor) processWindowMethod(method string, rw http.ResponseWr
m.Error("Invalid SetBackgroundColour Message: 'a' value required")
return
}
window.SetBackgroundColour(&RGBA{
window.SetBackgroundColour(RGBA{
Red: *r,
Green: *g,
Blue: *b,

View File

@ -23,7 +23,8 @@ type WebviewWindowOptions struct {
MaxHeight int
StartState WindowState
Mac MacWindow
BackgroundColour *RGBA
BackgroundType BackgroundType
BackgroundColour RGBA
HTML string
JS string
CSS string
@ -43,8 +44,22 @@ var WebviewWindowDefaults = &WebviewWindowOptions{
Width: 800,
Height: 600,
URL: "",
BackgroundColour: RGBA{
Red: 255,
Green: 255,
Blue: 255,
Alpha: 255,
},
}
type RGBA struct {
Red, Green, Blue, Alpha uint8
}
type BackgroundType int
const (
BackgroundTypeSolid BackgroundType = iota
BackgroundTypeTransparent
BackgroundTypeTranslucent
)

View File

@ -1,5 +1,18 @@
package application
type BackdropType int32
const (
Auto BackdropType = 0
None BackdropType = 1
Mica BackdropType = 2
Acrylic BackdropType = 3
Tabbed BackdropType = 4
)
type WindowsWindow struct {
AlwaysOnTop bool
// Select the type of translucent backdrop. Requires Windows 11 22621 or later.
BackdropType BackdropType
// Disable the icon in the titlebar
DisableIcon bool
}

View File

@ -21,7 +21,7 @@ type (
setMaxSize(width, height int)
execJS(js string)
restore()
setBackgroundColour(color *RGBA)
setBackgroundColour(color RGBA)
run()
center()
size() (int, int)
@ -171,7 +171,7 @@ func (w *WebviewWindow) run() {
func (w *WebviewWindow) SetAlwaysOnTop(b bool) *WebviewWindow {
w.options.AlwaysOnTop = b
if w.impl == nil {
if w.impl != nil {
w.impl.setAlwaysOnTop(b)
}
return w
@ -346,7 +346,7 @@ func (w *WebviewWindow) IsFullscreen() bool {
return w.impl.isFullscreen()
}
func (w *WebviewWindow) SetBackgroundColour(colour *RGBA) *WebviewWindow {
func (w *WebviewWindow) SetBackgroundColour(colour RGBA) *WebviewWindow {
w.options.BackgroundColour = colour
if w.impl != nil {
w.impl.setBackgroundColour(colour)

View File

@ -1147,7 +1147,7 @@ func (w *macosWebviewWindow) run() {
})
}
func (w *macosWebviewWindow) setBackgroundColour(colour *RGBA) {
func (w *macosWebviewWindow) setBackgroundColour(colour RGBA) {
if colour == nil {
return
}

View File

@ -3,11 +3,13 @@
package application
import (
"errors"
"fmt"
"github.com/wailsapp/wails/v3/internal/w32"
"syscall"
"unsafe"
"github.com/samber/lo"
"github.com/wailsapp/wails/v3/internal/w32"
)
var showDevTools = func(window unsafe.Pointer) {}
@ -15,6 +17,7 @@ var showDevTools = func(window unsafe.Pointer) {}
type windowsWebviewWindow struct {
windowImpl unsafe.Pointer
parent *WebviewWindow
hwnd w32.HWND
}
func (w *windowsWebviewWindow) setTitle(title string) {
@ -23,13 +26,18 @@ func (w *windowsWebviewWindow) setTitle(title string) {
}
func (w *windowsWebviewWindow) setSize(width, height int) {
//TODO implement me
panic("implement me")
x, y := w.position()
w32.MoveWindow(w.hwnd, x, y, width, height, true)
}
func (w *windowsWebviewWindow) setAlwaysOnTop(alwaysOnTop bool) {
//TODO implement me
panic("implement me")
globalApplication.dispatchOnMainThread(func() {
position := w32.HWND_NOTOPMOST
if alwaysOnTop {
position = w32.HWND_TOPMOST
}
w32.SetWindowPos(w.hwnd, position, 0, 0, 0, 0, uint(w32.SWP_NOMOVE|w32.SWP_NOSIZE))
})
}
func (w *windowsWebviewWindow) setURL(url string) {
@ -38,8 +46,9 @@ func (w *windowsWebviewWindow) setURL(url string) {
}
func (w *windowsWebviewWindow) setResizable(resizable bool) {
//TODO implement me
panic("implement me")
globalApplication.dispatchOnMainThread(func() {
w.setStyle(resizable, w32.WS_THICKFRAME)
})
}
func (w *windowsWebviewWindow) setMinSize(width, height int) {
@ -62,9 +71,8 @@ func (w *windowsWebviewWindow) restore() {
panic("implement me")
}
func (w *windowsWebviewWindow) setBackgroundColour(color *RGBA) {
//TODO implement me
panic("implement me")
func (w *windowsWebviewWindow) setBackgroundColour(color RGBA) {
w32.SetBackgroundColour(w.hwnd, color.Red, color.Green, color.Blue)
}
func (w *windowsWebviewWindow) run() {
@ -74,22 +82,18 @@ func (w *windowsWebviewWindow) run() {
func (w *windowsWebviewWindow) _run() {
var exStyle uint
options := w.parent.options
windowsOptions := options.Windows
//if windowsOptions != nil {
exStyle = w32.WS_EX_CONTROLPARENT | w32.WS_EX_APPWINDOW
// if windowsOptions.WindowIsTranslucent {
// exStyle |= w32.WS_EX_NOREDIRECTIONBITMAP
// }
//}
if windowsOptions.AlwaysOnTop {
if options.BackgroundType != BackgroundTypeSolid {
exStyle |= w32.WS_EX_NOREDIRECTIONBITMAP
}
if options.AlwaysOnTop {
exStyle |= w32.WS_EX_TOPMOST
}
var hwnd w32.HWND
hwnd = w32.CreateWindowEx(
w.hwnd = w32.CreateWindowEx(
exStyle,
windowClassName,
lo.Must(syscall.UTF16PtrFromString(options.Title)),
w32.WS_OVERLAPPEDWINDOW|w32.WS_VISIBLE,
w32.WS_OVERLAPPEDWINDOW,
w32.CW_USEDEFAULT,
w32.CW_USEDEFAULT,
options.Width,
@ -99,15 +103,38 @@ func (w *windowsWebviewWindow) _run() {
w32.GetModuleHandle(""),
nil)
if hwnd == 0 {
if w.hwnd == 0 {
panic("Unable to create window")
}
if !options.Hidden {
w32.ShowWindow(hwnd, w32.SW_SHOW)
w32.UpdateWindow(hwnd)
if options.DisableResize {
w.setResizable(false)
}
w32.SetForegroundWindow(hwnd)
// Icon
if !options.Windows.DisableIcon {
// App icon ID is 3
icon, err := NewIconFromResource(w32.GetModuleHandle(""), uint16(3))
if err == nil {
w.setIcon(icon)
}
} else {
w.disableIcon()
}
switch options.BackgroundType {
case BackgroundTypeSolid:
w.setBackgroundColour(options.BackgroundColour)
case BackgroundTypeTransparent:
case BackgroundTypeTranslucent:
w.setBackdropType(options.Windows.BackdropType)
}
if !options.Hidden {
w.show()
w.update()
}
w.setForeground()
}
func (w *windowsWebviewWindow) center() {
@ -120,19 +147,27 @@ func (w *windowsWebviewWindow) size() (int, int) {
panic("implement me")
}
func (w *windowsWebviewWindow) setForeground() {
w32.SetForegroundWindow(w.hwnd)
}
func (w *windowsWebviewWindow) update() {
w32.UpdateWindow(w.hwnd)
}
func (w *windowsWebviewWindow) width() int {
//TODO implement me
panic("implement me")
rect := w32.GetWindowRect(w.hwnd)
return int(rect.Right - rect.Left)
}
func (w *windowsWebviewWindow) height() int {
//TODO implement me
panic("implement me")
rect := w32.GetWindowRect(w.hwnd)
return int(rect.Bottom - rect.Top)
}
func (w *windowsWebviewWindow) position() (int, int) {
//TODO implement me
panic("implement me")
rect := w32.GetWindowRect(w.hwnd)
return int(rect.Left), int(rect.Right)
}
func (w *windowsWebviewWindow) destroy() {
@ -261,8 +296,7 @@ func (w *windowsWebviewWindow) setFullscreenButtonEnabled(enabled bool) {
}
func (w *windowsWebviewWindow) show() {
//TODO implement me
panic("implement me")
w32.ShowWindow(w.hwnd, w32.SW_SHOW)
}
func (w *windowsWebviewWindow) hide() {
@ -294,3 +328,76 @@ func (w *windowsWebviewWindow) openContextMenu(menu *Menu, data *ContextMenuData
thisMenu.update()
//C.windowShowMenu(w.nsWindow, thisMenu.nsMenu, C.int(data.X), C.int(data.Y))
}
func (w *windowsWebviewWindow) setStyle(b bool, style int) {
currentStyle := int(w32.GetWindowLongPtr(w.hwnd, w32.GWL_STYLE))
if currentStyle != 0 {
if b {
currentStyle |= style
} else {
currentStyle &^= style
}
w32.SetWindowLongPtr(w.hwnd, w32.GWL_STYLE, uintptr(currentStyle))
}
}
func (w *windowsWebviewWindow) setExStyle(b bool, style int) {
currentStyle := int(w32.GetWindowLongPtr(w.hwnd, w32.GWL_EXSTYLE))
if currentStyle != 0 {
if b {
currentStyle |= style
} else {
currentStyle &^= style
}
w32.SetWindowLongPtr(w.hwnd, w32.GWL_EXSTYLE, uintptr(currentStyle))
}
}
func (w *windowsWebviewWindow) setBackdropType(backdropType BackdropType) {
if !w32.IsWindowsVersionAtLeast(10, 0, 22621) {
var accent = w32.ACCENT_POLICY{
AccentState: w32.ACCENT_ENABLE_BLURBEHIND,
}
var data w32.WINDOWCOMPOSITIONATTRIBDATA
data.Attrib = w32.WCA_ACCENT_POLICY
data.PvData = w32.PVOID(&accent)
data.CbData = w32.SIZE_T(unsafe.Sizeof(accent))
w32.SetWindowCompositionAttribute(w.hwnd, &data)
} else {
backdropValue := backdropType
// We default to None, but in win32 None = 1 and Auto = 0
// So we check if the value given was Auto and set it to 0
if backdropType == Auto {
backdropValue = None
}
w32.DwmSetWindowAttribute(w.hwnd, w32.DwmwaSystemBackdropType, w32.LPCVOID(&backdropValue), uint32(unsafe.Sizeof(backdropValue)))
}
}
func (w *windowsWebviewWindow) setIcon(icon w32.HICON) {
w32.SendMessage(w.hwnd, w32.BM_SETIMAGE, w32.IMAGE_ICON, uintptr(icon))
}
func (w *windowsWebviewWindow) disableIcon() {
// TODO: If frameless, return
exStyle := w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE)
w32.SetWindowLong(w.hwnd, w32.GWL_EXSTYLE, uint32(exStyle|w32.WS_EX_DLGMODALFRAME))
w32.SetWindowPos(w.hwnd, 0, 0, 0, 0, 0,
uint(
w32.SWP_FRAMECHANGED|
w32.SWP_NOMOVE|
w32.SWP_NOSIZE|
w32.SWP_NOZORDER),
)
}
func NewIconFromResource(instance w32.HINSTANCE, resId uint16) (w32.HICON, error) {
var err error
var result w32.HICON
if result = w32.LoadIconWithResourceID(instance, resId); result == 0 {
err = errors.New(fmt.Sprintf("Cannot load icon from resource with id %v", resId))
}
return result, err
}