Canale di notifica

Questa sezione contiene informazioni sulla funzione CreatePrintAsyncNotifyChannel e sull'interfaccia IPrintAsyncNotifyChannel .

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

I componenti di stampa chiamano la funzione CreatePrintAsyncNotifyChannel per creare un canale di notifica. Il canale può essere per stampante o per server.

Il componente di stampa può aprire un canale di notifica solo se il componente viene caricato dallo spooler. Winspool.drv disabilita questa funzionalità se il chiamante viene eseguito all'interno delle applicazioni e non nel servizio spooler. Ad esempio, quando l'applicazione carica il driver per eseguire il rendering, una chiamata a CreatePrintAsyncNotifyChannel ha esito negativo. Tuttavia, la stessa chiamata ha esito positivo se il driver viene caricato dal servizio spooler.

Spoolss.lib fornisce questa funzionalità in modo che i monitoraggi delle porte possano aprire canali. I componenti eseguiti all'interno dello spooler e collegati a Spoolss.lib possono chiamare la funzione CreatePrintAsyncNotifyChannel . La procedura seguente illustra lo scopo di ogni parametro di input in una chiamata a questa funzione. Il primo passaggio della procedura si applica al primo parametro in questa funzione, il secondo passaggio si applica al secondo parametro e così via.

Per creare un canale di notifica, specificare gli elementi seguenti:

  1. Nome della stampante o del server.

  2. Tipo di canale di notifica. Il chiamante può specificare il tipo di notifiche che devono essere inviate tramite questo canale.

  3. Filtro utente. Il chiamante può specificare gli utenti che devono ricevere notifiche, lo stesso utente del mittente della notifica o tutti gli utenti.

  4. Filtro di conversazione. Il chiamante deve specificare se si tratta di un canale unidirezionale o bidirezionale. Per contrassegnare il canale come unidirezionale, impostare l'ultimo parametro (di tipo IPrintAsyncNotifyChannel**) di CreatePrintAsyncNotifyChannel su NULL.

  5. Interfaccia IPrintAsyncNotifyCallback da chiamare quando viene restituita una notifica dall'altra estremità del canale. Può essere NULL, se il chiamante non è interessato a ricevere risposte.

Quando CreatePrintAsyncNotifyChannel restituisce il sesto parametro (di tipo IPrintAsyncNotifyChannel**) punta a un percorso di memoria che contiene l'indirizzo di un oggetto IPrintAsyncNotifyChannel . Questo oggetto identifica il canale e viene usato per inviare notifiche e chiudere il canale.

Interfaccia IPrintAsyncNotifyChannel

L'interfaccia IPrintAsyncNotifyChannel identifica un canale e viene usato per inviare notifiche e chiudere il canale. Quando un componente di stampa chiama la funzione CreatePrintAsyncNotifyChannel per creare un canale di notifica, il servizio spooler risponde fornendo un oggetto che espone l'interfaccia IPrintAsyncNotifyChannel .

Questa interfaccia eredita dall'interfaccia IUnknown in modo che i client del meccanismo di notifica dello spooler possano implementare un oggetto COM o C++. La dichiarazione di interfaccia nell'esempio di codice seguente mostra questa ereditarietà:

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

Per inviare una notifica, il mittente chiama il metodo IPrintAsyncNotifyChannel::SendNotification . Il mittente può essere il componente di stampa che apre il canale e invia notifiche o un client in ascolto quando deve rispondere a una notifica. Questo metodo si comporta in modo asincrono. Quando il metodo restituisce un codice di operazione riuscita, lo spooler tenta di inviare la notifica ai listener. Tuttavia, non esiste alcuna garanzia che tutti i listener ricevano la notifica.

Per chiudere il canale, il mittente o un listener può chiamare il metodo IPrintAsyncNotifyChannel::CloseChannel . Il chiamante può passare una notifica che indica il motivo della chiusura del canale o può passare un puntatore NULL . Quando il canale viene chiuso, tutte le notifiche in coda vengono eliminate.

È necessario prestare attenzione a chiamare Release su un oggetto canale, perché non segue tutte le invarianti di programmazione COM generali. È consigliabile chiamare Release su IPrintAsyncNotifyChannel solo se si verificano le condizioni seguenti:

  • Se è stato chiamato AddRef in modo esplicito ed è necessario associarlo a una chiamata a Release.

  • Se il canale è stato creato come unidirezionale ed è necessario chiamare Release una volta sul puntatore ricevuto come parametro di output. È necessario chiamare Release dopo aver inviato le notifiche desiderate e chiuso il canale.

  • Se il canale è stato creato come bidirezionale, potrebbe essere necessario chiamare Release una volta sul puntatore ricevuto come parametro di output. È consigliabile chiamare Release solo se si esegue una o più delle operazioni seguenti:

    • Prima di chiamare Release per un canale bidirezionale, è necessario chiamare sempre CloseChannel e ricevere un risultato positivo. Non è necessario chiamare Release se la chiamata a CloseChannel ha esito negativo, perché il canale potrebbe essere già stato rilasciato per conto dell'utente.

    • Non è necessario chiamare Release durante l'immissione dell'evento ChannelClosed . Per evitare questa situazione, verificare la presenza di una chiamata a CloseChannel non riuscita con l'errore CHANNEL_ALREADY_CLOSED. Non è necessario chiamare Release in questo caso, perché il canale è già stato rilasciato per conto dell'utente.

    • Non è necessario chiamare CloseChannel, Release o qualsiasi altra funzione membro nel canale se la funzione di callback ChannelClosed è stata completata. In questo caso, il canale è già stato rilasciato, pertanto qualsiasi altra chiamata potrebbe causare un comportamento indefinito. Questa restrizione potrebbe richiedere il coordinamento tra il thread in primo piano e l'oggetto callback.

    • È necessario assicurarsi che il thread in primo piano e l'oggetto callback coordinano la chiamata a CloseChannel e Release. Il thread in primo piano e l'oggetto di callback non possono avviare una chiamata a CloseChannel se l'altro sta per chiamare o ha completato la chiamata a Release. È possibile implementare questa restrizione utilizzando la routine InterlockedCompareExchange . Se non si utilizza InterlockedCompareExchange, è possibile che si verifichi un comportamento non definito.

  • Se è stato registrato come listener nel canale, è possibile chiamare CloseChannel e quindi chiamare Release nella funzione di callback IPrintAsyncNotifyCallback::OnEventNotify per terminare la comunicazione bidirezionale. Tuttavia, non è necessario chiamare CloseChannel o Release nel callback ChannelClosed .

Se si soddisfa una di queste condizioni, è necessario chiamare Release. Se non si soddisfa una di queste condizioni, non è necessario chiamare Release.

Nota

La chiamata a Release in una qualsiasi delle condizioni precedenti, ma la prima, in cui si chiama AddRef in modo esplicito, è un'eccezione ai modelli di programmazione COM generali. IPrintAsyncNotifyChannel differisce dalla pratica COM standard in questa situazione.