mirror of
https://github.com/black-ant/Ant-Browser.git
synced 2026-07-14 18:48:55 +08:00
142 lines
4.1 KiB
Go
142 lines
4.1 KiB
Go
//go:build windows
|
|
|
|
package main
|
|
|
|
import (
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
const (
|
|
swShow = 5
|
|
swRestore = 9
|
|
)
|
|
|
|
var (
|
|
user32Activate = windows.NewLazySystemDLL("user32.dll")
|
|
procAllowSetForegroundWindow = user32Activate.NewProc("AllowSetForegroundWindow")
|
|
procAttachThreadInput = user32Activate.NewProc("AttachThreadInput")
|
|
procEnumWindows = user32Activate.NewProc("EnumWindows")
|
|
procGetForegroundWindow = user32Activate.NewProc("GetForegroundWindow")
|
|
procGetWindow = user32Activate.NewProc("GetWindow")
|
|
procGetWindowTextLengthW = user32Activate.NewProc("GetWindowTextLengthW")
|
|
procGetWindowThreadProcessID = user32Activate.NewProc("GetWindowThreadProcessId")
|
|
procIsIconic = user32Activate.NewProc("IsIconic")
|
|
procIsWindowVisible = user32Activate.NewProc("IsWindowVisible")
|
|
procShowWindow = user32Activate.NewProc("ShowWindow")
|
|
procSetForegroundWindow = user32Activate.NewProc("SetForegroundWindow")
|
|
procSetWindowPos = user32Activate.NewProc("SetWindowPos")
|
|
)
|
|
|
|
const (
|
|
gwOwner = 4
|
|
hwndTopmost = ^uintptr(0)
|
|
hwndNotopmost = ^uintptr(1)
|
|
swpNoMove = 0x0002
|
|
swpNoSize = 0x0001
|
|
swpShowWindow = 0x0040
|
|
)
|
|
|
|
func grantExistingSingleInstanceForeground(pid int) {
|
|
if pid > 0 {
|
|
procAllowSetForegroundWindow.Call(uintptr(pid))
|
|
}
|
|
}
|
|
|
|
func activateExistingSingleInstanceWindow(pid int) {
|
|
if pid <= 0 {
|
|
return
|
|
}
|
|
grantExistingSingleInstanceForeground(pid)
|
|
if hwnd := findTopLevelWindowByPID(uint32(pid)); hwnd != 0 {
|
|
procShowWindow.Call(hwnd, swRestore)
|
|
procShowWindow.Call(hwnd, swShow)
|
|
if ok, _, _ := procSetForegroundWindow.Call(hwnd); ok == 0 {
|
|
attachForegroundThreadInput(hwnd, func() {
|
|
procSetForegroundWindow.Call(hwnd)
|
|
})
|
|
}
|
|
if ok, _, _ := procSetForegroundWindow.Call(hwnd); ok == 0 {
|
|
procSetWindowPos.Call(hwnd, hwndTopmost, 0, 0, 0, 0, swpNoMove|swpNoSize|swpShowWindow)
|
|
procSetWindowPos.Call(hwnd, hwndNotopmost, 0, 0, 0, 0, swpNoMove|swpNoSize|swpShowWindow)
|
|
procSetForegroundWindow.Call(hwnd)
|
|
}
|
|
}
|
|
}
|
|
|
|
func attachForegroundThreadInput(hwnd uintptr, fn func()) {
|
|
foreground, _, _ := procGetForegroundWindow.Call()
|
|
if foreground == 0 || hwnd == 0 {
|
|
fn()
|
|
return
|
|
}
|
|
|
|
var foregroundPID uint32
|
|
foregroundThread, _, _ := procGetWindowThreadProcessID.Call(foreground, uintptr(unsafe.Pointer(&foregroundPID)))
|
|
var targetPID uint32
|
|
targetThread, _, _ := procGetWindowThreadProcessID.Call(hwnd, uintptr(unsafe.Pointer(&targetPID)))
|
|
if foregroundThread == 0 || targetThread == 0 || foregroundThread == targetThread {
|
|
fn()
|
|
return
|
|
}
|
|
|
|
procAttachThreadInput.Call(foregroundThread, targetThread, 1)
|
|
defer procAttachThreadInput.Call(foregroundThread, targetThread, 0)
|
|
fn()
|
|
}
|
|
|
|
func findTopLevelWindowByPID(pid uint32) uintptr {
|
|
type candidateWindow struct {
|
|
hwnd uintptr
|
|
visible bool
|
|
titled bool
|
|
owned bool
|
|
minimized bool
|
|
}
|
|
var candidates []candidateWindow
|
|
callback := windows.NewCallback(func(hwnd uintptr, lparam uintptr) uintptr {
|
|
var windowPID uint32
|
|
procGetWindowThreadProcessID.Call(hwnd, uintptr(unsafe.Pointer(&windowPID)))
|
|
if windowPID == pid {
|
|
visible, _, _ := procIsWindowVisible.Call(hwnd)
|
|
titleLength, _, _ := procGetWindowTextLengthW.Call(hwnd)
|
|
owner, _, _ := procGetWindow.Call(hwnd, gwOwner)
|
|
minimized, _, _ := procIsIconic.Call(hwnd)
|
|
candidates = append(candidates, candidateWindow{
|
|
hwnd: hwnd,
|
|
visible: visible != 0,
|
|
titled: titleLength > 0,
|
|
owned: owner != 0,
|
|
minimized: minimized != 0,
|
|
})
|
|
}
|
|
return 1
|
|
})
|
|
procEnumWindows.Call(callback, 0)
|
|
if len(candidates) == 0 {
|
|
return 0
|
|
}
|
|
for _, candidate := range candidates {
|
|
if candidate.visible && candidate.titled && !candidate.owned {
|
|
return candidate.hwnd
|
|
}
|
|
}
|
|
for _, candidate := range candidates {
|
|
if candidate.titled && !candidate.owned {
|
|
return candidate.hwnd
|
|
}
|
|
}
|
|
for _, candidate := range candidates {
|
|
if candidate.visible && !candidate.owned {
|
|
return candidate.hwnd
|
|
}
|
|
}
|
|
for _, candidate := range candidates {
|
|
if candidate.minimized && !candidate.owned {
|
|
return candidate.hwnd
|
|
}
|
|
}
|
|
return candidates[0].hwnd
|
|
}
|