The system events EVENT_SYSTEM_SWITCHSTART and EVENT_SYSTEM_SWITCHEND works in Windows 7 but not in Windows 10
Asked Answered
S

1

5

Added info:
When I use my .exe file in Windows 7 everything works as it should. It does not work in Windows 10. And I can't figure out why.

Original post:
Probably I just need more coffee... ... but I'm trying to write a small program that is going to listen to Alt+Tab events. So I added the SetWinEventHook to listen for EVENT_SYSTEM_SWITCHSTART and EVENT_SYSTEM_SWITCHEND. Since that is what I figured is the way to do it according to MSDN: SetWinEventHook, WinEventProc callback, Event constants

For some reason, these events never seem to fire. But more likely I'm missing something.

When I didn't get it to work in my real application, I created this small application to test it in. And it does not work there either. But other events do work. EVENT_SYSTEM_FOREGROUND, EVENT_OBJECT_CREATE and EVENT_OBJECT_DESTROY happens all the time.

The code to my small test application:

#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;
}

I get a lot of printouts from the focusEventProc and createEventProc methods when clicking on windows and opening/closing windows. But no printouts from tabEventProc when alt+tabbing to other applications.

Same thing if I put breakpoints in the methods. It never breaks inside tabEventProc, but all the time in the two other methods.

Can someone please tell me what I'm doing wrong? Cause Google Wan Kenobi haven't been able to help me. And I'm really baffled.

I'm using Windows 10 and Visual Studio 2017 Community edition. The project is a standard C++ console project created from the Visual Studios "create new project" template.

Sennet answered 31/3, 2018 at 13:45 Comment(2)
... so... I tested to create the same application on Windows 7 in Visual Studio 2015... And it works! sigh That is truly horrific. Have Microsoft changed the API or something? I don't get it!Sennet
Tried transferring the .exe file from the Win7 system to the Win10 system. No printouts from EVENT_SYSTEM_SWITCHSTART/END events. So I guess they've changed the events in Win10? Can't find any documentation about that, though...Sennet
S
6

Ok. So I guess you have to conform to ugly hacks to make Alt-Tab detection work on Windows 10.

This is the ugly solution I ended up with:

#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;
}

So instead of hooking up to the EVENT_SYSTEM_SWITCHSTART and EVENT_SYSTEM_SWITCHEND I hook up to the WH_KEYBOARD_LL with SetWindowsHookEx. Then I check for Alt+Tab keypress combinations. If one happens I save that to a static variable and at EVENT_SYSTEM_FOREGROUND I check if a Alt+Tab has happened before and then assume that we Alt+Tab switched to that window.

I really hate this solution since it does not guarantee that the focused window is the one we switched to. There have to be a better way.

And it does not answer the question why EVENT_SYSTEM_SWITCHSTART and EVENT_SYSTEM_SWITCHEND doesn't work on Windows 10.

Sennet answered 1/4, 2018 at 11:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.