C++ Windows-Events hooken

te one

Lt. Commander
Registriert
Apr. 2009
Beiträge
1.255
Hallo,

ich möchte bei bestimmten Betriebssystem-Events (Windows, dafür gibts eine eigene API) in C++ gecallt werden. Ich habe soetwas in der Richtung mal recht easy in C# gemacht. In C++ stehe ich mit tausend Fragezeichen vor dem Problem.
Selbst Google half mir nicht wirklich weiter (habe aber auch noch nie eine DLL geschrieben... bin C++-Neuling). Geht das überhaupt in C++? Wenn ja, hat einer (gut erklärte!) Links bzw. ein Beispiel?

Danke & Gruß
 
Zuletzt bearbeitet:
windows.h enthält alles um über die Windows-API mit Windows zu interagieren.
Hier findest du Microsofts Dokumentation:
https://docs.microsoft.com/en-us/windows/win32/

Gegen die Windows-API zu programmieren ist anstrengend und mit viel Recherche und trail&error verbunden.
Aber lass dich nicht entmutigen :D
Gut möglich, dass es für deinen Fall auch schon jemand in einer entsprechenden Bibliothek gekapselt hat.
Würde zumindest dein Leben einfacher machen.
 
Okay, da habe ich wieder gut was zu lesen.
Noch eine Frage zur Entwicklung: Wenn ich die Hooks nicht wieder lösche (weil Programm abschmiert o.Ä.): Werden die durch einen Reboot entfernt oder schrotte ich dauerhaft mein Windows?
 
Dein Windows schrotten wirst garantiert nicht.

Und, wenn etwas abschmirrt, wird in C++ i.d.R. der Destruktor aufgerufen, der alles notwendige rückgängig machen dürfte. Aber ich denke nicht, dass du da Probleme bekommst, wenn du sie nicht gerade aktiv provozierst.
Sollte sowas möglich sein, würde zu hoher Wahrscheinlichkeit eine Warnung dabei stehen.
 
Ich bin mir unsicher, ob wir vom gleichen reden:
Ich möchte, zB:
  • dass ich bei jedem beliebigen Klick irgendwo in Windows (egal welches Fenster gerade im Fokus ist)
  • dass ich jeden Fokuswechsel (aktives Fenster wird gewechselt)
gecallt werde. Und wenn ich mich so in Windows hänge und nicht mehr aushänge... Wer sagt mir, dass Windows nicht dauerhaft bei jedem Klick versucht etwas aufzurufen was es nicht gibt?
 
te one schrieb:
Wer sagt mir, dass Windows nicht dauerhaft bei jedem Klick versucht etwas aufzurufen was es nicht gibt?
Dokumentation oder Verstand: Wär schon ziemlich doof ständig das Risiko zu haben, dass Windows geschrottet werden würde, wenn man Events nutzt.


Es folgt Spekulation, weil ich es tatsächlich noch nicht ausprobiert habe, aber es erscheint mir sinnvoll. Wenn man Gewissheit haben möchte: Ausprobieren oder recherchieren.

C++:
// Register
event_token KeyDown(KeyEventHandler const& handler) const;
Wie du siehst, wenn du einen Handler registrierst, bekommst du ein event_token.
Ich geh mal stark davon aus, dass event_token im Destruktor dafür sorgt, dass der Handler nicht mehr registriert ist. Und wie wir wissen, werden die Destruktoren aufgerufen, wenn man den Scope verlässt/das Programm beendet wird.
 
Zuletzt bearbeitet:
Meiner Erfahung nach ist da Windows recht gründlich und "räumt dir hinterher".
Es weiß ja, dass dein Programm beendet wurde, egal wie oder warum und es weiß ja auch, mit was dein Programm interagiert hat.
Mir ist es jedenfalls noch nicht passiert, dass ich nach dem Killen einer meiner Anwendungen irgendwelche Artefakterscheinungen hatte, weil das Programm keine Chance hatte Abonnements rückgängig zu machen oder Handles wieder freizugeben.
Das ist aus Sicht des Betriebsystems einfach ein zu einfacher "Bug", dass das schon von Anbeginn der Möglichkeit sich an Events zu hängen aufgefallen und behandet werden müsste. Was anderes kann ich mir kaum vorstellen.
Sonst würds ja überall knallen, wie in den "guten alten Zeiten", als Grafiktreiber noch im Kernel liefen...

Was ich mir maximal vorstellen könnte wären Begleiterscheinungen, wie sie es bei Message Posting gibt.
Wenn du ein Window-Handle beziehst, eine Ewigkeit wartest, sodass das zugehörige Fesnter schon nicht mehr existiert, das ehemalige Window-Handle aber wieder vergeben wurde, so erreicht eine Message die du zu diesem Handle schickst das neue Fenster.
https://stackoverflow.com/questions/17096073/postmessage-to-an-invalid-hwnd

Aber auch das halte ich für unwahrscheinlich, weil da die Rollen ja im Endeffekt vertauscht sind: Nicht das Betriebsystem schickt etwas, sondern du übers Betriebsystem und wenn das Nonsens is, bist halt auch selber schuld.
 
Ich muss diesen Post hier nochmal aufwärmen...
Hat jemand einen Beispiel-Codeschnipsel wo man in C++ zB jedes mal gecallt wird, wenn das aktive Windows-Fenster gewechselt wird (C++/WinRT). Als Anfänger komme ich da garnicht klar... Frage mich noch immer, ob das damit überhaupt funktioniert.
 
Also, wenn du bei aktiven Fenstern auch fremde Fenster meinst, weiß ich nicht, ob das über die Windows Runtime angeboten wird - jedenfalls finde ich nichts, was durchaus daran liegen kann, dass es noch nicht so alt ist.

WIe auch immer, via Win32, findet man bei StackOverflow schnell Beispiele:
https://stackoverflow.com/questions...ect-when-i-change-the-active-window-on-screen

Ggf. kannst ja mal auf SO fragen, ob das auch via WinRT möglich ist, ansonsten hier einfach Win32 nutzen (schließt sich ja nicht aus).
 
@new Account() Ja, es geht mir um fremde Fenster. Ich glaube da brauche ich wirklich Win32. Die Funktion SetWinEventHook bringt mich wohl weiter.
Ich suche nun allerdings schon wieder eine Stunde lang einfach mal ein Beispiel, das läuft... Bisher kommt bei jedem Code irgendeine andere kryptische Meldung (hier ist zB C++ Code: http://www.jose.it-berater.org/oleacc/functions/setwineventhook.htm) :/ Man muss das ganze wohl auch als DLL erstellen?!
 
edit: Hier stand Mist - bin eben nochmal am testen^^
Ergänzung ()

So, nun aber. Mein Code compiled mittlerweile erfolgreich - leider werde ich nicht gecallt, wenn das aktive Fenster wechselt (müsste dann einen Sound abspielen).
Ich hoffe, dass die Funktion "SetWinEventHook()" die richtige ist. Mir ist unklar, ob sich das nur auf eigene Fenster, oder global auf alle offenen Windows-Anwendungen bezieht. (Namensgebung Fenster = Windows = Betriebssystem ist hier total irreführend). Ich möchte das ganze ja global für das Windows-Betriebssystem haben.
(Code adaptiert von http://www.jose.it-berater.org/oleacc/functions/setwineventhook.htm )

edit: Ahhh, man braucht noch eine Message-Loop (Hilfe sagt: "The client thread that calls SetWinEventHook must have a message loop in order to receive events.").
Nun wäre ich lediglich noch für einen Tipp dankbar wie ich das ganze schön designe.
Ich möchte beim Start meinen Konsolen-App eine Config einlesen. In dieser Config steht, was passieren soll, wenn ein bestimmtes Fenster längere Zeit nicht im Fokus war (das heißt ich speichere mir alle zuletzt geöffneten Fenster + Zeitstempel und ich müsste in festen Intervallen prüfen, ob das einen nun längere Zeit nicht im Fokus war. Wie verpacke ich das schön mit der Message-Loop?

C++:
#include <iostream>
#include <Windows.h>
#include <oleacc.h>


// Global variable.
HWINEVENTHOOK g_hook;


// Callback function that handles events.
void CALLBACK HandleWinEvent(HWINEVENTHOOK hook,
    DWORD event, HWND hwnd,
    LONG idObject, LONG idChild,
    DWORD dwEventThread, DWORD dwmsEventTime)
{
    IAccessible* pAcc = NULL;
    VARIANT varChild;
    //std::cout << "CALLED!";
    MessageBeep(MB_ICONERROR);
    /*HRESULT hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &pAcc , &varChild);
    if ((hr == S_OK) && (pAcc != NULL)) {
        BSTR bstrName;
        pAcc->get_accName(varChild, &bstrName);
        if (event == EVENT_SYSTEM_MENUSTART)
        {
            printf("Begin: ");
        }
        else if (event == EVENT_SYSTEM_MENUEND)
        {
            printf("End:   ");
        }
        printf("%S\n", bstrName);
        SysFreeString(bstrName);
        pAcc->Release();
    }*/
}


// Initializes COM and sets up the event hook.
void InitializeMSAA()
{
    CoInitialize(NULL);
    g_hook = SetWinEventHook(
        EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_MENUEND,  // Range of events (4 to 5).
        NULL,                                          // Handle to DLL.
        HandleWinEvent,                                // The callback.
        0, 0,              // Process and thread IDs of interest (0 = all)
        WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); // Flags.
}

// Unhooks the event and shuts down COM.
void ShutdownMSAA()
{
    UnhookWinEvent(g_hook);
    CoUninitialize();
}

int main()
{
    std::cout << "Hello World!\n";
    InitializeMSAA();
    MessageBeep(MB_ICONERROR);
    system("pause");
    std::cout << "Test";
    ShutdownMSAA();
}
 
Zuletzt bearbeitet:
Zurück
Oben