获取最后激活窗口的句柄。

5
我正在开发一个应用程序,它位于系统托盘中,并可以对活动窗口执行操作。但是当单击系统托盘中的图标时,GetForegroundWindow()返回任务栏。我需要获取在任务栏之前处于活动状态的窗口。
我尝试使用EnumWindowsGetWindow枚举桌面窗口,但这通常会出现桌面小部件和其他最上层项目,而不是上次活动的窗口。这是否可能,或者窗口停用时信息完全丢失?
2个回答

2

我认为获取这些信息的唯一方法是在WH_CALLWNDPROC上安装系统范围的钩子(SetWindowsHookEx),并捕获所有WM_ACTIVATEAPP。这甚至可以让您跟踪窗口活动时的完整历史记录。


这个程序很好用。然而,我有一个问题:某些应用程序没有受到影响,因为它们是64位的(或者如果我编译为64位,则为32位)。你有什么想法? - Nick Whaley
我可以与32位和64位DLL进行钩子,并在两者之间使用某种进程间通信,但看起来非常混乱。 - Nick Whaley
很不幸,我认为没有一种简洁的方法来完成它,所以使用两个DLL和一些IPC是目前唯一的选择。 - Andreas Magnusson
替代 WH_CALLWNDPROC,使用 WH_CBT,并查找 HCBT_ACTIVATE。 - Remy Lebeau

0

您可以使用GetTopWindow(NULL)GetNextWindow(hwnd)按Z顺序列出所有窗口。 接下来,跳过所有属于exeplorer.exe的窗口,第一个找到的窗口将是最顶部的用户窗口。

我注意到唯一的问题是当有人使用“始终置顶”选项时。例如,Winamp就有这样的选项。但这是相当不寻常的情况。

#include <Windows.h>
#include <Tlhelp32.h> /// for CreateToolhelp32Snapshot()
#include <assert.h>

HWND getLastActiveWindow(){
    /// find process ID of first explorer.exe
    /// normaly there will be only 1 anyway.
    static DWORD explorerProcessId= 0; /// we can cache it, since it shoudn't change
    if(!explorerProcessId){
        PROCESSENTRY32 entry= {0};
        entry.dwSize= sizeof(PROCESSENTRY32);
        HANDLE snap= CreateToolhelp32Snapshot( TH32CS_SNAPALL, 0 );
        if( Process32First( snap, &entry ) ){
            do{
                if( strcmp(entry.szExeFile,"explorer.exe")==0 ){ /// we are searching for explorer.exe
                    explorerProcessId= entry.th32ProcessID;
                    break;
                }
            }while( Process32Next(snap,&entry) );
        }
        CloseHandle( snap );
    }
    assert( explorerProcessId );

    /// list of all windows sorted in Z-Order
    {
        HWND hwnd= GetTopWindow( NULL ); /// get window with highest Z
        while( hwnd ){
            if( IsWindowVisible(hwnd) ){ /// we care only about visible windows
                DWORD procId;
                GetWindowThreadProcessId( hwnd, &procId ); /// get process ID of hwnd
                if( procId != explorerProcessId ){ /// we don't care about window owned by explorer.exe
                    return hwnd; /// return top most window
                }
            }
            hwnd= GetNextWindow( hwnd, GW_HWNDNEXT ); /// get next windows in Z order
        }
    }

    /// No window found.
    /// It may happen if there are no window opened, so handle that case somehow, depending on your application
    return NULL;
}

1
小心处理这个问题。在文档中提到了一个关于z-order的重大缺陷:所有最顶层的窗口都会在非最顶层窗口之前显示在z-order中。问题是:一个窗口可以是最顶层的,但通过将其放置在监视器区域之外来对用户隐藏。现在,为什么有人想要创建一个最顶层的窗口,然后以这种恶劣的方式隐藏它呢?为什么不去问Inkscape的开发者呢?我刚刚发现,无论我做什么,Inkscape始终处于z-order的顶部,因为它有一些被标记为最顶层的窗口,但移动到了可见区域之外。 - itachi
1
小心处理这个问题。在文档中提到了一个关于z-order的重大缺陷:所有最顶层的窗口在非最顶层窗口之前显示在z-order中。问题在于:一个窗口可以是最顶层的,但通过将其放置在显示器区域之外来对用户隐藏。现在,为什么有人会想要创建一个最顶层的窗口,然后以这种恶劣的方式隐藏它呢?为什么不去问问Inkscape的开发人员呢?我刚刚发现,无论我做什么,Inkscape始终在z-order的顶部,因为它有一些被标记为最顶层的窗口,但是移动到了可见区域之外。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接