2

添加信息:
当我在 Windows 7 中使用我的 .exe 文件时,一切正常。它在 Windows 10 中不起作用。我不知道为什么。

原帖:
可能我只是需要更多的咖啡......但我正在尝试编写一个小程序来监听 Alt+Tab 事件。所以我添加了SetWinEventHook来监听EVENT_SYSTEM_SWITCHSTARTEVENT_SYSTEM_SWITCHEND。因为这就是我认为根据 MSDN 的方法:SetWinEventHookWinEventProc callbackEvent constants

出于某种原因,这些事件似乎永远不会触发。但更有可能我错过了一些东西。

当我没有让它在我的真实应用程序中工作时,我创建了这个小应用程序来测试它。它也不能在那里工作。但其他事件确实有效。EVENT_SYSTEM_FOREGROUNDEVENT_OBJECT_CREATEEVENT_OBJECT_DESTROY一直在发生。

我的小型测试应用程序的代码:

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

namespace
{
    HWINEVENTHOOK sTabHook;
    HWINEVENTHOOK sFocusHook;
    HWINEVENTHOOK sCreateHook;
}

void CALLBACK tabEventProc(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
    printf("Never happens!");
    if (EVENT_SYSTEM_SWITCHSTART == event)
    {
        printf("Tab start\n");
    }
    else if (EVENT_SYSTEM_SWITCHEND == event)
    {
        printf("Tab end\n");
    }
}

void CALLBACK focusEventProc(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
    printf("Window focused\n");
}

void CALLBACK createEventProc(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
    if (EVENT_OBJECT_CREATE == event)
    {
        printf("Object created\n");
    }
    else if (EVENT_OBJECT_DESTROY == event)
    {
        printf("Object destroyed\n");
    }
}

DWORD WINAPI threadProc()
{
    sTabHook = SetWinEventHook(EVENT_SYSTEM_SWITCHSTART, EVENT_SYSTEM_SWITCHEND, nullptr, tabEventProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); //no ice, no napkins, no soda, no salt, no pepper... no quaso, NOTHING!
    sFocusHook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, nullptr, focusEventProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
    sCreateHook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_DESTROY, nullptr, createEventProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);

    MSG message;
    while (GetMessage(&message, nullptr, 0, 0)) {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }

    UnhookWinEvent(sTabHook);
    UnhookWinEvent(sFocusHook);
    UnhookWinEvent(sCreateHook);

    return 0;
}

int main()
{
    HANDLE threadHandle;
    DWORD thread;

    threadHandle = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)threadProc, 0, 0, &thread);
    if (threadHandle)
    {
        return WaitForSingleObject(threadHandle, INFINITE);
    }
    else
    {
        return 1;
    }

    return 0;
}

在单击窗口和打开/关闭窗口时,我从focusEventProccreateEventProc方法中得到了很多打印输出。但是当 alt+tab 切换到其他应用程序时, tabEventProc没有打印输出。

如果我在方法中放置断点也是一样的。它永远不会在tabEventProc内部中断,但一直在其他两种方法中。

有人可以告诉我我做错了什么吗?因为 Google Wan Kenobi 无法帮助我。我真的很困惑。

我正在使用 Windows 10 和 Visual Studio 2017 社区版。该项目是从 Visual Studios“创建新项目”模板创建的标准 C++ 控制台项目。

4

1 回答 1

2

好的。所以我想你必须遵守丑陋的黑客才能使 Alt-Tab 检测在 Windows 10 上工作。

这是我最终得到的丑陋解决方案:

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <string>

namespace
{
    HINSTANCE sInstance = GetModuleHandle(nullptr);
    HHOOK sTabHook;
    HWINEVENTHOOK sFocusHook;
    bool sAltTabHappend = false;
}

LRESULT CALLBACK tabEventProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    auto kbdLlHookStruct = (KBDLLHOOKSTRUCT*)lParam;

    switch (nCode)
    {
        case HC_ACTION:
        {
            if (kbdLlHookStruct->vkCode == VK_TAB && kbdLlHookStruct->flags & LLKHF_ALTDOWN)
            {
                printf("Alt-Tab\n");
                sAltTabHappend = true;
            }
        }
    }


    return CallNextHookEx(sTabHook, nCode, wParam, lParam);
}

void CALLBACK focusEventProc(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
    if (!sAltTabHappend)
    {
        return;
    }

    char windowTitleOut[256];
    GetWindowTextA(hwnd, windowTitleOut, sizeof(windowTitleOut));
    std::string windowTitle(windowTitleOut);

    if (windowTitle.empty() || 0 == windowTitle.compare("Task Switching"))
    {
        return;
    }

    printf("You just canged to %s by Alt-tabbing... yeah...\n", windowTitleOut);
    sAltTabHappend = false;
}

DWORD WINAPI threadProc()
{
    sTabHook = SetWindowsHookEx(WH_KEYBOARD_LL, tabEventProc, sInstance, 0);
    sFocusHook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, nullptr, focusEventProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);

    MSG message;
    while (GetMessage(&message, nullptr, 0, 0)) {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }

    UnhookWindowsHookEx(sTabHook);
    UnhookWinEvent(sFocusHook);

    return 0;
}

int main()
{
    HANDLE threadHandle;
    DWORD thread;

    threadHandle = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)threadProc, 0, 0, &thread);
    if (threadHandle)
    {
        return WaitForSingleObject(threadHandle, INFINITE);
    }
    else
    {
        return 1;
    }

    return 0;
}

因此,我没有连接到EVENT_SYSTEM_SWITCHSTARTEVENT_SYSTEM_SWITCHEND ,而是使用SetWindowsHookEx连接到WH_KEYBOARD_LL。然后我检查 Alt+Tab 按键组合。如果发生这种情况,我将其保存到一个静态变量中,并在EVENT_SYSTEM_FOREGROUND我检查之前是否发生过 Alt+Tab,然后假设我们 Alt+Tab 切换到该窗口。

我真的很讨厌这个解决方案,因为它不能保证焦点窗口就是我们切换到的那个。必须有更好的方法。

它并没有回答为什么EVENT_SYSTEM_SWITCHSTARTEVENT_SYSTEM_SWITCHEND在 Windows 10 上不起作用的问题。

于 2018-04-01T11:53:05.363 回答