Files
zogo/dll/user32.go
T
4566704 ef7cd3e3c4 feat(dll): 自 go-hua 迁入 Windows 系统 API 封装
- 互斥体防多开/ShellExecute/窗口类名与标题查询/顶层窗口目录, 新增依赖 lxn/win
- 仅 Windows, 附测试、examples/dll 例程与包 README
2026-09-20 12:29:36 +08:00

131 lines
3.5 KiB
Go

//go:build (windows && amd64) || (windows && 386)
package dll
import (
"github.com/lxn/win"
"syscall"
"unsafe"
)
var (
user32Dll *syscall.DLL
procGetWindowTextW *syscall.Proc
procGetWindowClassW *syscall.Proc
procFindWindowExW *syscall.Proc
)
func init() {
user32Dll = syscall.MustLoadDLL("user32.dll")
procGetWindowTextW = user32Dll.MustFindProc("GetWindowTextW")
procGetWindowClassW = user32Dll.MustFindProc("GetClassNameW")
procFindWindowExW = user32Dll.MustFindProc("FindWindowExW")
}
// GetWindowText 获取窗口标题(user32 GetWindowTextW 原生调用)
func GetWindowText(hWnd win.HWND, str *uint16, maxCount int32) (len int32, err error) {
//r0, _, e1 := procGetWindowTextW.Call(uintptr(hWnd), uintptr(unsafe.Pointer(str)), uintptr(maxCount))
r0, _, e1 := syscall.Syscall(procGetWindowTextW.Addr(), 3, uintptr(hWnd), uintptr(unsafe.Pointer(str)), uintptr(maxCount))
len = int32(r0)
if len == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
// GetWindowTextString 获取窗口标题并转为 string
func GetWindowTextString(hWnd win.HWND) (string, error) {
buf := make([]uint16, 255)
_, err := GetWindowText(hWnd, &buf[0], int32(len(buf)))
if err != nil {
return "", err
}
windowsTitle := syscall.UTF16ToString(buf)
return windowsTitle, nil
}
// GetTopFolderPath 获取资源管理器当前打开的顶层路径
func GetTopFolderPath() (string, error) {
//lName := uint16(0)
hWnd := win.FindWindow(syscall.StringToUTF16Ptr("CabinetWClass"), nil)
if hWnd == 0 {
return "", nil
}
hWnd = GetWindowFromClassName(hWnd, "Breadcrumb Parent")
if hWnd == 0 {
return "", nil
}
hWnd = FindWindowExW(hWnd, 0, syscall.StringToUTF16Ptr("ToolbarWindow32"), nil)
if hWnd == 0 {
return "", nil
}
buf := make([]uint16, 255)
_, err := GetWindowText(hWnd, &buf[0], int32(len(buf)))
if err != nil {
return "", err
}
title := syscall.UTF16ToString(buf)
return title, nil
}
// FindWindowExW 查找子窗口(user32 FindWindowExW 原生调用)
func FindWindowExW(parent win.HWND, child win.HWND, lpClassName, lpWindowName *uint16) win.HWND {
ret, _, _ := procFindWindowExW.Call(uintptr(parent), uintptr(child),
uintptr(unsafe.Pointer(lpClassName)),
uintptr(unsafe.Pointer(lpWindowName)),
0)
return win.HWND(ret)
}
// GetWindowFromClassName 使用类名获取窗口句柄 递归
func GetWindowFromClassName(parentWnd win.HWND, className string) win.HWND {
// 寻找顶层窗口
hWnd := FindWindowExW(parentWnd, 0, nil, nil)
for hWnd != 0 {
// 获取窗口类名
name, _ := GetWindowClassString(hWnd)
if name == className {
return hWnd
}
// 递归查找
phWnd := GetWindowFromClassName(hWnd, className)
if phWnd != 0 {
return phWnd
}
// 查找下一子窗口
hWnd = FindWindowExW(parentWnd, hWnd, nil, nil)
}
return 0
}
// GetWindowClassString 取窗口类名 string
func GetWindowClassString(hWnd win.HWND) (string, error) {
buf := make([]uint16, 255)
_, err := GetWindowClass(hWnd, &buf[0], int32(len(buf)))
if err != nil {
return "", err
}
return syscall.UTF16ToString(buf), nil
}
// GetWindowClass 取窗口类名 API
func GetWindowClass(hWnd win.HWND, str *uint16, maxCount int32) (len int32, err error) {
//r0, _, e1 := procGetWindowTextW.Call(uintptr(hWnd), uintptr(unsafe.Pointer(str)), uintptr(maxCount))
r0, _, e1 := syscall.Syscall(procGetWindowClassW.Addr(), 3, uintptr(hWnd), uintptr(unsafe.Pointer(str)), uintptr(maxCount))
len = int32(r0)
if len == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}