Lernen, wenn ein Ereignis eintritt

[Das dieser Seite zugeordnete Feature DirectShow ist ein Legacyfeature. Es wurde von MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation abgelöst. Diese Features wurden für Windows 10 und Windows 11 optimiert. Microsoft empfiehlt dringend, dass neuer Code mediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation anstelle von DirectShow verwendet, wenn möglich. Microsoft schlägt vor, dass vorhandener Code, der die Legacy-APIs verwendet, so umgeschrieben wird, dass nach Möglichkeit die neuen APIs verwendet werden.]

Um DirectShow-Ereignisse zu verarbeiten, benötigt eine Anwendung eine Möglichkeit, herauszufinden, wann Ereignisse in der Warteschlange warten. Der Filter Graph-Manager bietet hierfür zwei Möglichkeiten:

  • Fensterbenachrichtigung: Der Filter Graph-Manager sendet eine benutzerdefinierte Windows-Nachricht an ein Anwendungsfenster, wenn ein neues Ereignis vorliegt.
  • Ereignissignalisierung: Der Filter Graph Manager signalisiert ein Windows-Ereignis, wenn DirectShow-Ereignisse in der Warteschlange vorhanden sind, und setzt das Ereignis zurück, wenn die Warteschlange leer ist.

Eine Anwendung kann beide Verfahren verwenden. Fensterbenachrichtigungen sind in der Regel einfacher.

Fensterbenachrichtigung

Rufen Sie zum Einrichten der Fensterbenachrichtigung die IMediaEventEx::SetNotifyWindow-Methode auf, und geben Sie eine private Nachricht an. Anwendungen können Nachrichtennummern im Bereich von WM_APP bis 0xBFFF als private Nachrichten verwenden. Wenn der Filter Graph Manager eine neue Ereignisbenachrichtigung in der Warteschlange platziert, sendet er diese Nachricht im angegebenen Fenster. Die Anwendung antwortet auf die Nachricht aus der Meldungsschleife des Fensters.

Im folgenden Codebeispiel wird gezeigt, wie das Benachrichtigungsfenster festgelegt wird.

#define WM_GRAPHNOTIFY WM_APP + 1   // Private message.
pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);

Die Nachricht ist eine normale Windows-Nachricht und wird getrennt von der DirectShow-Ereignisbenachrichtigungswarteschlange bereitgestellt. Der Vorteil dieses Ansatzes besteht darin, dass die meisten Anwendungen bereits eine Nachrichtenschleife implementieren. Daher können Sie die DirectShow-Ereignisbehandlung ohne viel zusätzlichen Aufwand integrieren.

Das folgende Codebeispiel zeigt eine Gliederung, wie auf die Benachrichtigung reagiert wird. Ein vollständiges Beispiel finden Sie unter Reagieren auf Ereignisse.

LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
    switch (msg)
    {
        case WM_GRAPHNOTIFY:
            HandleEvent();  // Application-defined function.
            break;
        // Handle other Windows messages here too.
    }
    return (DefWindowProc(hwnd, msg, wParam, lParam));
}

Da die Ereignisbenachrichtigung und die Nachrichtenschleife asynchron sind, kann die Warteschlange mehr als ein Ereignis enthalten, sobald Ihre Anwendung auf die Nachricht antwortet. Außerdem können Ereignisse manchmal aus der Warteschlange gelöscht werden, wenn sie ungültig werden. Rufen Sie daher in Ihrem Ereignisbehandlungscode IAMMediaEvent::GetEvent auf, bis ein Fehlercode zurückgegeben wird, der angibt, dass die Warteschlange leer ist.

Bevor Sie den IMediaEventEx-Zeiger freigeben, brechen Sie die Ereignisbenachrichtigung ab, indem Sie SetNotifyWindow mit einem NULL-Zeiger aufrufen. Überprüfen Sie in Ihrem Ereignisverarbeitungscode, ob Ihr IMediaEventEx-Zeiger gültig ist, bevor Sie GetEvent aufrufen. Diese Schritte verhindern einen möglichen Fehler, bei dem die Anwendung die Ereignisbenachrichtigung empfängt, nachdem sie den IMediaEventEx-Zeiger freigegeben hat.

Ereignissignal

Der Filter Graph-Manager behält ein manuelles Zurücksetzungsereignis bei, das den Zustand der Ereigniswarteschlange widerspiegelt. Wenn die Warteschlange Benachrichtigungen über ausstehende Ereignisse enthält, signalisiert der Filter Graph Manager das Ereignis für manuelles Zurücksetzen. Wenn die Warteschlange leer ist, wird das Ereignis durch einen Aufruf der IMediaEvent::GetEvent-Methode zurückgesetzt. Eine Anwendung kann dieses Ereignis verwenden, um den Status der Warteschlange zu bestimmen.

Hinweis

Die Terminologie kann hier verwirrend sein. Das Ereignis für manuelles Zurücksetzen ist der Typ des Ereignisses, das von der Windows CreateEvent-Funktion erstellt wurde. es hat nichts mit den von DirectShow definierten Ereignissen zu tun.

 

Rufen Sie die IMediaEvent::GetEventHandle-Methode auf, um ein Handle für das Ereignis zum manuellen Zurücksetzen abzurufen. Warten Sie, bis das Ereignis durch Aufrufen einer Funktion wie WaitForMultipleObjects signalisiert wird. Nachdem das Ereignis signalisiert wurde, rufen Sie IMediaEvent::GetEvent auf, um das DirectShow-Ereignis abzurufen.

Das folgende Codebeispiel veranschaulicht diese Vorgehensweise. Es ruft das Ereignishandle ab und wartet dann in Intervallen von 100 Millisekunden, bis das Ereignis signalisiert wird. Wenn das Ereignis signalisiert wird, ruft es GetEvent auf und gibt den Ereigniscode und die Ereignisparameter im Konsolenfenster aus. Die Schleife wird beendet, wenn das EC_COMPLETE-Ereignis auftritt, was angibt, dass die Wiedergabe abgeschlossen ist.

HANDLE  hEvent; 
long    evCode, param1, param2;
BOOLEAN bDone = FALSE;
HRESULT hr = S_OK;
hr = pEvent->GetEventHandle((OAEVENT*)&hEvent);
if (FAILED(hr))
{
    /* Insert failure-handling code here. */
}

while(!bDone) 
{
    if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 100))
    { 
        while (S_OK == pEvent->GetEvent(&evCode, &param1, &param2, 0)) 
        {
            printf("Event code: %#04x\n Params: %d, %d\n", evCode, param1, param2);
            pEvent->FreeEventParams(evCode, param1, param2);
            bDone = (EC_COMPLETE == evCode);
        }
    }
} 

Da das Filterdiagramm das Ereignis bei Bedarf automatisch festlegt oder zurücksetzt, sollte Ihre Anwendung dies nicht tun. Wenn Sie das Filterdiagramm freigeben, schließt das Filterdiagramm außerdem das Ereignishandle. Verwenden Sie also nach diesem Punkt nicht mehr das Ereignishandle.