Freigeben über


Benachrichtigungskanal

Dieser Abschnitt enthält Informationen zur Funktion CreatePrintAsyncNotifyChannel und zur IPrintAsyncNotifyChannel-Schnittstelle .

HRESULT
 CreatePrintAsyncNotifyChannel(
    IN LPCWSTR,
    IN PrintAsyncNotificationType*,
    IN PrintAsyncNotifyUserFilter,
    IN PrintAsyncNotifyConversationStyle,
    IN IPrintAsyncNotifyCallback*,
 OUT IPrintAsyncNotifyChannel**
    );

Druckkomponenten rufen die Funktion CreatePrintAsyncNotifyChannel auf, um einen Benachrichtigungskanal zu erstellen. Der Kanal kann drucker- oder serverbezogen sein.

Die Druckkomponente kann einen Benachrichtigungskanal nur öffnen, wenn die Komponente vom Spooler geladen wird. Winspool.drv deaktiviert diese Funktion, wenn der Aufrufer innerhalb von Anwendungen und nicht im spooler-Dienst ausgeführt wird. Wenn die Anwendung beispielsweise den Treiber zum Rendern lädt, schlägt ein Aufruf von CreatePrintAsyncNotifyChannel fehl. Derselbe Aufruf ist jedoch erfolgreich, wenn der Treiber vom Spoolerdienst geladen wird.

Spoolss.lib bietet diese Funktionalität, sodass Portmonitore Kanäle öffnen können. Komponenten, die im Spooler ausgeführt werden und mit Spoolss.lib verknüpft sind, können die Funktion CreatePrintAsyncNotifyChannel aufrufen. Im folgenden Verfahren wird der Zweck der einzelnen Eingabeparameter in einem Aufruf dieser Funktion erläutert. Der erste Schritt in der Prozedur gilt für den ersten Parameter in dieser Funktion, der zweite Schritt für den zweiten Parameter usw.

Um einen Benachrichtigungskanal zu erstellen, geben Sie die folgenden Elemente an:

  1. Der Name des Druckers oder Servers.

  2. Der Benachrichtigungskanaltyp. Der Aufrufer kann den Typ der Benachrichtigungen angeben, die über diesen Kanal gesendet werden sollen.

  3. Der Benutzerfilter. Der Aufrufer kann die Benutzer angeben, die Benachrichtigungen empfangen sollen, entweder derselbe Benutzer wie der Benachrichtigungssender oder alle Benutzer.

  4. Der Unterhaltungsfilter. Der Aufrufer muss angeben, ob es sich um einen unidirektionalen oder bidirektionalen Kanal handelt. Um den Kanal als unidirektional zu markieren, legen Sie den letzten Parameter (vom Typ IPrintAsyncNotifyChannel**) von CreatePrintAsyncNotifyChannel auf NULL fest.

  5. Die IPrintAsyncNotifyCallback-Schnittstelle , die aufgerufen werden soll, wenn eine Benachrichtigung vom anderen Ende des Kanals zurückkommt. Dies kann NULL sein, wenn der Aufrufer nicht am Empfangen von Antworten interessiert ist.

Wenn CreatePrintAsyncNotifyChannel zurückgibt, zeigt der sechste Parameter (vom Typ IPrintAsyncNotifyChannel**) auf einen Speicherspeicherort, der die Adresse eines IPrintAsyncNotifyChannel-Objekts enthält. Dieses Objekt identifiziert den Kanal und wird zum Senden von Benachrichtigungen und zum Schließen des Kanals verwendet.

IPrintAsyncNotifyChannel-Schnittstelle

Die IPrintAsyncNotifyChannel-Schnittstelle identifiziert einen Kanal und wird zum Senden von Benachrichtigungen und zum Schließen des Kanals verwendet. Wenn eine Druckkomponente die CreatePrintAsyncNotifyChannel-Funktion aufruft, um einen Benachrichtigungskanal zu erstellen, antwortet der Spoolerdienst, indem er ein Objekt bereitstellt, das die IPrintAsyncNotifyChannel-Schnittstelle verfügbar macht.

Diese Schnittstelle erbt von der IUnknown-Schnittstelle , sodass die Clients des Spoolerbenachrichtigungsmechanismus entweder ein COM- oder ein C++-Objekt implementieren können. Die Schnittstellendeklaration im folgenden Codebeispiel zeigt diese Vererbung:

#define INTERFACE IPrintAsyncNotifyChannel
DECLARE_INTERFACE_(IPrintAsyncNotifyChannel, IUnknown)
{
    STDMETHOD(QueryInterface)(
        THIS_
        REFIID riid,
        void** ppvObj
        ) PURE;

    STDMETHOD_(ULONG, AddRef)(
        THIS
        ) PURE;

    STDMETHOD_(ULONG, Release)(
        THIS
        ) PURE;

    STDMETHOD(SendNotification)(
         THIS_
         IN IPrintAsyncNotifyDataObject*
         ) PURE;

    STDMETHOD(CloseChannel)(
         THIS_
         IN IPrintAsyncNotifyDataObject*
         ) PURE;
};

Zum Senden einer Benachrichtigung ruft der Absender die IPrintAsyncNotifyChannel::SendNotification-Methode auf. Der Absender kann entweder die Druckkomponente sein, die den Kanal öffnet und Benachrichtigungen sendet, oder ein lauschender Client, wenn er auf eine Benachrichtigung reagieren muss. Diese Methode verhält sich asynchron. Wenn die Methode einen Erfolgscode zurückgibt, versucht der Spooler, die Benachrichtigung an Listener zu senden. Es gibt jedoch keine Garantie, dass Listener die Benachrichtigung erhalten.

Zum Schließen des Kanals kann der Absender oder ein Listener die IPrintAsyncNotifyChannel::CloseChannel-Methode aufrufen. Der Aufrufer kann eine Benachrichtigung übergeben, die den Grund für das Schließen des Kanals angibt, oder einen NULL-Zeiger übergeben. Wenn der Kanal geschlossen wird, werden alle Benachrichtigungen in der Warteschlange verworfen.

Sie müssen beim Aufrufen von Release für ein Kanalobjekt vorsichtig sein, da es nicht allen allgemeinen COM-Programmierinvarianten folgt. Sie sollten Release on IPrintAsyncNotifyChannel nur aufrufen, wenn die folgenden Bedingungen auftreten:

  • Wenn Sie AddRef explizit aufgerufen haben und sie mit einem Aufruf von Release abgleichen müssen.

  • Wenn Sie den Kanal als unidirektional erstellt haben, und Sie für den Zeiger, den Sie als Ausgabeparameter empfangen haben, einmal Release aufrufen müssen. Sie sollten Release aufrufen, nachdem Sie die gewünschten Benachrichtigungen gesendet und den Kanal geschlossen haben.

  • Wenn Sie den Kanal als bidirektional erstellt haben, müssen Sie möglicherweise einmal Release auf dem Zeiger aufrufen, den Sie als Ausgabeparameter erhalten haben. Sie sollten Release nur aufrufen, wenn Sie mindestens eine der folgenden Aktionen ausführen:

    • Bevor Sie Release für einen bidirektionalen Kanal aufrufen, müssen Sie immer CloseChannel aufrufen und ein Erfolgsergebnis erhalten. Sie dürfen Release nicht aufrufen, wenn der Aufruf von CloseChannel fehlschlägt, da der Kanal möglicherweise bereits in Ihrem Namen freigegeben wurde.

    • Sie dürfen Release nicht aufrufen, während Sie das ChannelClosed-Ereignis eingeben. Um diese Situation zu vermeiden, suchen Sie nach einem Aufruf von CloseChannel , der mit dem Fehler CHANNEL_ALREADY_CLOSED fehlgeschlagen ist. In diesem Fall müssen Sie Release nicht aufrufen, da der Kanal bereits in Ihrem Namen freigegeben wurde.

    • Sie dürfen CloseChannel, Release oder eine andere Memberfunktion im Kanal nicht aufrufen, wenn die ChannelClosed-Rückruffunktion die Ausführung beendet hat. In diesem Fall wurde der Kanal bereits freigegeben, sodass alle weiteren Aufrufe zu nicht definiertem Verhalten führen können. Diese Einschränkung erfordert möglicherweise eine Koordination zwischen Ihrem Vordergrundthread und dem Rückrufobjekt.

    • Sie müssen sicherstellen, dass Ihr Vordergrundthread und das Rückrufobjekt den Aufruf von CloseChannel und Release koordinieren. Ihr Vordergrundthread und Ihr Rückrufobjekt können keinen Aufruf von CloseChannel starten, wenn der andere den Aufruf von Release abgeschlossen hat. Sie können diese Einschränkung mithilfe der InterlockedCompareExchange-Routine implementieren. Wenn Sie InterlockedCompareExchange nicht verwenden, können Sie nicht definiertes Verhalten verursachen.

  • Wenn Sie sich als Listener auf dem Kanal registriert haben, können Sie CloseChannel aufrufen und dann Release in Ihrer IPrintAsyncNotifyCallback::OnEventNotify-Rückruffunktion aufrufen, um die bidirektionale Kommunikation zu beenden. Sie dürfen jedoch closeChannel oder Release nicht in Ihrem ChannelClosed-Rückruf aufrufen.

Wenn Sie eine dieser Bedingungen erfüllen, müssen Sie Release aufrufen. Wenn Sie eine dieser Bedingungen nicht erfüllen, dürfen Sie release nicht aufrufen.

Hinweis

Das Aufrufen von Release unter einer der vorherigen Bedingungen, aber die erste, in der Sie AddRef explizit aufrufen, ist eine Ausnahme von allgemeinen COM-Programmiermustern. IPrintAsyncNotifyChannel unterscheidet sich in dieser Situation von der COM-Standardpraxis.