如何通过Window任务栏按钮获取窗口句柄?

GPT-4 在这个问题上简直是智障,浪费了好长时间。AutoHotkey 可能通过 acc 库获取任务栏按钮的文本,也就是所指向窗口的标题,但没有方法直接获取这个窗口的句柄。

谁知道有什么方法可能通过 Window 任务栏按钮获取窗口句柄吗?

图片

softcnkiller你值得拥有
原帖CSDN

1 个赞

winget了解一下WinGet | AutoHotkey (wyagd001.github.io)

WinGet, OutputVar, ID , WinTitle, WinText, ExcludeTitle, ExcludeText

类似这种问题还是查看中文说明比较快,你直接在中文说明中文搜 窗口句柄 也能很快得到解答

谢谢提醒,我想起来我也有个删除托盘图标的库,应该从中找到相应的API。

文档里确实有窗口句柄字符,但"通过任务栏按钮获取"这个前提如何实现?

你说的任务栏按钮是指
A 固定在任务栏左侧的快捷方式
B 某软件被打开时,在任务栏显示的一段bar,可以用来点击击切换激活窗口
C 任务栏右侧的托盘小图标按钮,表示某软件在后台运行。

所以咱们的讨论前提是区分 快捷方式/任务栏按钮/托盘图标 吗?

我只是看你突然又提到托盘图标

怕我理解错你的意思了。

===
回归正题,
已知 你已经获取到了窗口标题

那么只需要

wintitle := "你获取到的窗口标题"
WinGet, IDname, ID , wintitle
msgbox, % IDname

因为我隐约记得写那个托盘库的时候有个没利用到的任务栏窗口列表。
通过我能够使用 acc() 库应该能表明我不是不知道AutoHotkey函数作用的新手。既然我在得到窗口标题的情况下仍旧寻问如何获取句柄,显然是有其他问题。比如有多个相同标题的窗口。

奥奥 原来是这个意思。
我说怎么这么奇怪。

Window系统的进程 PID,是会被系统回收重复使用的。所以它的值大小没有意义。
窗口标题的方法是不准确的,抛开拖动按钮或者重启 explorer.exe 引发的失序不谈,那些频繁变更窗口标题的窗口是无法解决的问题。

额,试了下还真是,进程不是越来越大。

dog大佬,想请问一下windows alt+tab时的任务预览窗口,以及此状态下当指针光标移动到每个预览窗口的任务缩略图对应的title、class之类信息能获取到吗?

尝试了window spy,显示暂停状态无法获取到信息

之所有这样的需求是因为qttabbar的一个小bug,在任务预览窗口的状态无法使用鼠标中键或者点击缩略图右上角的×关闭资源管理器,已经习惯了通过这样的方式关闭程序了,就想着能否通过ahk来

卧槽,试了下还真是。

然后我试了下uia方式获取信息,
可以获取到title。
进而通过winget,可以获取class id之类信息(不存在重名title的情况下)。

如果存在重名title,那就没办法分辨啦,毕竟那不是个真实窗口,只是绘制了个ui

1 个赞

我已经习惯了用dpi键(改中键)来关闭窗口了,所以这个bug我第一次用就发现了,后面试了国内的版本可以关,但感觉没有原版好用,然后又发现win+tab和alt+ctrl+tab也能关,就是alt+tab关不了,谢谢提示

更加卧槽了,alt + tab 和 alt+ctrl+tab 有啥区别?我实在是想象不出来

可能是和按住了alt键有关?

试了下果然,看来是alt+中键、左键被注册成其他功能了。

在论坛找了个旧函数,但不知道为啥就是修改不出来。
没仔细看,原来这方法在WIN7就失效了。

GetMouseTaskButton(ByRef hwnd)
{
    MouseGetPos, x, y, win, ctl, 2
    ; Check if hovering over taskbar.
    WinGetClass, cl, ahk_id %win%
    if (cl != "Shell_TrayWnd")
        return
    ; Check if hovering over a Toolbar.
    WinGetClass, cl, ahk_id %ctl%
    if (cl = "MSTaskListWClass"  ; Windows 7: the methods used below won't work.
        || A_PtrSize=8  ; Script not compatible with 64-bit AutoHotkey.exe.
        || DllCall("IsWow64Process", "Uint", DllCall("GetCurrentProcess")
            , "intP", iswow64) && iswow64)  ; OS/taskbar is 64-bit - not compatible.
    {   
        hwnd := 0
        return 1
    }
    if (cl != "ToolbarWindow32")
        return
    ; Check if hovering over task-switching buttons (specific toolbar).
    hParent := DllCall("GetParent", "Uint", ctl)
    WinGetClass, cl, ahk_id %hParent%
    if (cl != "MSTaskSwWClass")
        return
   
    WinGet, pidTaskbar, PID, ahk_class Shell_TrayWnd

    hProc := DllCall("OpenProcess", "Uint", 0x38, "int", 0, "Uint", pidTaskbar)
    pRB := DllCall("VirtualAllocEx", "Uint", hProc
        , "Uint", 0, "Uint", 20, "Uint", 0x1000, "Uint", 0x4)

    VarSetCapacity(pt, 8, 0)
    NumPut(x, pt, 0, "int")
    NumPut(y, pt, 4, "int")
   
    ; Convert screen coords to toolbar-client-area coords.
    DllCall("ScreenToClient", "uint", ctl, "uint", &pt)
   
    ; Write POINT into explorer.exe.
    DllCall("WriteProcessMemory", "uint", hProc, "uint", pRB+0, "uint", &pt, "uint", 8, "uint", 0)

;     SendMessage, 0x447,,,, ahk_id %ctl%  ; TB_GETHOTITEM
    SendMessage, 0x445, 0, pRB,, ahk_id %ctl%  ; TB_HITTEST
    btn_index := ErrorLevel
    ; Convert btn_index to a signed int, since result may be -1 if no 'hot' item.
    if btn_index > 0x7FFFFFFF
        btn_index := -(~btn_index) - 1
   
   
    if (btn_index > -1)
    {
        ; Get button info.
        SendMessage, 0x417, btn_index, pRB,, ahk_id %ctl%   ; TB_GETBUTTON
   
        VarSetCapacity(btn, 20)
        DllCall("ReadProcessMemory", "Uint", hProc
            , "Uint", pRB, "Uint", &btn, "Uint", 20, "Uint", 0)
   
        state := NumGet(btn, 8, "UChar")  ; fsState
        pdata := NumGet(btn, 12, "UInt")  ; dwData
       
        ret := DllCall("ReadProcessMemory", "Uint", hProc
            , "Uint", pdata, "UintP", hwnd, "Uint", 4, "Uint", 0)
    } else
        hwnd = 0

       
    DllCall("VirtualFreeEx", "Uint", hProc, "Uint", pRB, "Uint", 0, "Uint", 0x8000)
    DllCall("CloseHandle", "Uint", hProc)


    ; Negative values indicate seperator items. (abs(btn_index) is the index)
    return btn_index > -1 ? btn_index+1 : 0
}
1 个赞

换了思路想了下先模拟左键单击,然后在关闭当前窗口就行了 :joy:

#IfWinActive ahk_class MultitaskingViewFrame 
!MButton::
    Click, left
    WinClose, A
    SendInput, {Alt Down}{Tab Down}
    SetTimer, CheckTabKey, -500  ; 
Return

CheckTabKey:
    If !GetKeyState("Tab", "P")  ; 
    {
        SendInput, {Alt Up}
        SetTimer, CheckTabKey, Off
        Return
    }
Return
#IfWinActive