Files
u-desktop/win32.go

149 lines
4.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"log"
"unsafe"
"github.com/jchv/go-webview2"
"golang.org/x/sys/windows"
)
var (
user32 = windows.NewLazySystemDLL("user32.dll")
procFindWindowW = user32.NewProc("FindWindowW")
procFindWindowExW = user32.NewProc("FindWindowExW")
procSendMessageTimeoutW = user32.NewProc("SendMessageTimeoutW")
procSetParent = user32.NewProc("SetParent")
procGetForegroundWindow = user32.NewProc("GetForegroundWindow")
procGetWindowRect = user32.NewProc("GetWindowRect")
procGetSystemMetrics = user32.NewProc("GetSystemMetrics")
procMoveWindow = user32.NewProc("MoveWindow")
procShowWindow = user32.NewProc("ShowWindow")
procSetProcessDPIAware = user32.NewProc("SetProcessDPIAware")
procSetWindowLongPtrW = user32.NewProc("SetWindowLongPtrW")
procGetWindowLongPtrW = user32.NewProc("GetWindowLongPtrW")
procGetDpiForWindow = user32.NewProc("GetDpiForWindow")
procGetClientRect = user32.NewProc("GetClientRect")
procMessageBoxW = user32.NewProc("MessageBoxW")
procGetMessageW = user32.NewProc("GetMessageW")
procPostMessageW = user32.NewProc("PostMessageW")
procTranslateMessage = user32.NewProc("TranslateMessage")
procDispatchMessageW = user32.NewProc("DispatchMessageW")
)
var wv webview2.WebView
var wvHwnd uintptr
var jsQueue = make(chan string, 64)
var paused int32
const (
wmEvalJS = 0x0401
wmSetHtml = 0x0402
)
const (
gwlStyle = uintptr(0xFFFFFFF0) // GWL_STYLE = -16
wsPopup = uintptr(0x80000000)
wsVisible = uintptr(0x10000000)
wsChild = uintptr(0x02000000)
wsSizebox = uintptr(0x00040000)
wsMaxbox = uintptr(0x00010000)
)
var htmlQueue = make(chan string, 1)
var (
classProgman = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr("Progman")))
classShellDefView = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr("SHELLDLL_DefView")))
classWorkerW = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr("WorkerW")))
)
func evalJS(js string) {
select {
case jsQueue <- js:
log.Println("evalJS queued:", js[:min(len(js), 60)])
default:
log.Println("jsQueue full, dropping eval")
}
if wvHwnd != 0 {
procPostMessageW.Call(wvHwnd, wmEvalJS, 0, 0)
}
}
func findWorkerW() uintptr {
progman, _, _ := procFindWindowW.Call(
classProgman, 0)
if progman == 0 {
log.Println("findWorkerW: Progman not found")
return 0
}
// 发送 0x052C 触发 Progman 创建 WorkerW
var result uintptr
procSendMessageTimeoutW.Call(progman, 0x052C, 0, 0, 0x0000, 1000, uintptr(unsafe.Pointer(&result)))
// 方法1: Progman 下找 SHELLDLL_DefView再找其后的 WorkerW
shellDefView, _, _ := procFindWindowExW.Call(progman, 0, classShellDefView, 0)
if shellDefView != 0 {
ww, _, _ := procFindWindowExW.Call(progman, shellDefView, classWorkerW, 0)
if ww != 0 {
log.Printf("findWorkerW: 方法1成功, WorkerW=0x%x", ww)
return ww
}
}
// 方法2: 遍历顶层 WorkerW找到含 SHELLDLL_DefView 的那个,取它后面的 WorkerW
var prev uintptr
for {
ww, _, _ := procFindWindowExW.Call(0, prev, classWorkerW, 0)
if ww == 0 {
break
}
child, _, _ := procFindWindowExW.Call(ww, 0, classShellDefView, 0)
if child != 0 {
// 这个 WorkerW 包含 SHELLDLL_DefView找它后面的 WorkerW
next, _, _ := procFindWindowExW.Call(0, ww, classWorkerW, 0)
if next != 0 {
log.Printf("findWorkerW: 方法2成功, WorkerW=0x%x (after 0x%x)", next, ww)
return next
}
}
prev = ww
}
// 方法3: 遍历顶层 WorkerW找任意不含 SHELLDLL_DefView 的可见 WorkerW
prev = 0
for {
ww, _, _ := procFindWindowExW.Call(0, prev, classWorkerW, 0)
if ww == 0 {
break
}
child, _, _ := procFindWindowExW.Call(ww, 0, classShellDefView, 0)
if child == 0 {
log.Printf("findWorkerW: 方法3成功, WorkerW=0x%x", ww)
return ww
}
prev = ww
}
// 方法4: 兜底Progman 下的第一个 WorkerW
ww, _, _ := procFindWindowExW.Call(progman, 0, classWorkerW, 0)
if ww != 0 {
log.Printf("findWorkerW: 方法4(兜底), WorkerW=0x%x", ww)
}
return ww
}
func getDPI(hwnd uintptr) int {
dpi, _, _ := procGetDpiForWindow.Call(hwnd)
if dpi == 0 {
return 96
}
return int(dpi)
}
func getScreenSize() (int32, int32) {
w, _, _ := procGetSystemMetrics.Call(0)
h, _, _ := procGetSystemMetrics.Call(1)
return int32(w), int32(h)
}