- 互斥体防多开/ShellExecute/窗口类名与标题查询/顶层窗口目录, 新增依赖 lxn/win - 仅 Windows, 附测试、examples/dll 例程与包 README
131 lines
3.5 KiB
Go
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
|
|
}
|