Compartilhar via


Canal de notificação

Esta seção contém informações sobre a função CreatePrintAsyncNotifyChannel e a interface IPrintAsyncNotifyChannel .

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

Os componentes de impressão chamam a função CreatePrintAsyncNotifyChannel para criar um canal de notificação. O canal pode ser por impressora ou por servidor.

O componente de impressão só poderá abrir um canal de notificação se o componente for carregado pelo spooler. Winspool.drv desabilita essa funcionalidade se o chamador for executado dentro de aplicativos e não no serviço spooler. Por exemplo, quando o aplicativo carrega o driver para executar a renderização, uma chamada para CreatePrintAsyncNotifyChannel falha. No entanto, a mesma chamada terá êxito se o driver for carregado pelo serviço spooler.

Spoolss.lib fornece essa funcionalidade para que os monitores de porta possam abrir canais. Os componentes executados dentro do spooler e vinculados a Spoolss.lib podem chamar a função CreatePrintAsyncNotifyChannel . O procedimento a seguir explica a finalidade de cada parâmetro de entrada em uma chamada para essa função. A primeira etapa do procedimento se aplica ao primeiro parâmetro nessa função, a segunda etapa se aplica ao segundo parâmetro e assim por diante.

Para criar um canal de notificação, especifique os seguintes itens:

  1. O nome da impressora ou do servidor.

  2. O tipo de canal de notificação. O chamador pode especificar o tipo de notificações que devem ser enviadas por este canal.

  3. O filtro do usuário. O chamador pode especificar os usuários que devem receber notificações, seja o mesmo usuário que o remetente de notificação ou todos os usuários.

  4. O filtro de conversa. O chamador deve especificar se este é um canal unidirecional ou bidirecional. Para marcar o canal como unidirecional, defina o último parâmetro (do tipo IPrintAsyncNotifyChannel**) de CreatePrintAsyncNotifyChannel como NULL.

  5. A interface IPrintAsyncNotifyCallback a ser chamada quando uma notificação voltar do outro lado do canal. Isso pode ser NULL, se o chamador não estiver interessado em receber respostas.

Quando CreatePrintAsyncNotifyChannel retorna, o sexto parâmetro (do tipo IPrintAsyncNotifyChannel**) aponta para um local de memória que contém o endereço de um objeto IPrintAsyncNotifyChannel . Esse objeto identifica o canal e é usado para enviar notificações e fechar o canal.

IPrintAsyncNotifyChannel Interface

A interface IPrintAsyncNotifyChannel identifica um canal e é usada para enviar notificações e fechar o canal. Quando um componente de impressão chama a função CreatePrintAsyncNotifyChannel para criar um canal de notificação, o serviço spooler responde fornecendo um objeto que expõe a interface IPrintAsyncNotifyChannel .

Essa interface herda da interface IUnknown para que os clientes do mecanismo de notificação do spooler possam implementar um objeto COM ou C++. A declaração de interface no exemplo de código a seguir mostra essa herança:

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

Para enviar uma notificação, o remetente chama o método IPrintAsyncNotifyChannel::SendNotification . O remetente pode ser o componente de impressão que abre o canal e envia notificações ou um cliente ouvinte quando precisa responder a uma notificação. Esse método se comporta de forma assíncrona. Quando o método retorna um código de êxito, o spooler tenta enviar a notificação aos ouvintes. Mas não há nenhuma garantia de que os ouvintes recebam a notificação.

Para fechar o canal, o remetente ou um ouvinte pode chamar o método IPrintAsyncNotifyChannel::CloseChannel . O chamador pode passar uma notificação que fornece o motivo para fechar o canal ou pode passar um ponteiro NULL . Quando o canal é fechado, todas as notificações enfileiradas são descartadas.

Você deve ter cuidado ao chamar Release em um objeto de canal, pois ele não segue todas as invariáveis gerais de programação COM. Você deve chamar Release em IPrintAsyncNotifyChannel somente se as seguintes condições ocorrerem:

  • Se você chamou AddRef explicitamente e deve combiná-lo com uma chamada para Release.

  • Se você criou o canal como unidirecional e deve chamar Release uma vez no ponteiro recebido como um parâmetro de saída. Você deve chamar Release depois de enviar as notificações desejadas e fechar o canal.

  • Se você criou o canal como bidirecional, talvez seja necessário chamar Release uma vez no ponteiro recebido como um parâmetro de saída. Você deve chamar Release somente se fizer um ou mais dos seguintes procedimentos:

    • Antes de chamar Release para um canal bidirecional, você sempre deve chamar CloseChannel e receber um resultado de êxito. Você não deve chamar Release se a chamada para CloseChannel falhar, pois o canal pode já ter sido liberado em seu nome.

    • Você não deve chamar Release ao inserir o evento ChannelClosed . Para evitar essa situação, marcar uma chamada para CloseChannel que falhou com o erro CHANNEL_ALREADY_CLOSED. Você não precisa chamar Release nesse caso, pois o canal já foi liberado em seu nome.

    • Você não deve chamar CloseChannel, Release ou qualquer outra função membro no canal se a função de retorno de chamada ChannelClosed tiver terminado de ser executada. Nesse caso, o canal já foi liberado, portanto, qualquer chamada adicional pode causar um comportamento indefinido. Essa restrição pode exigir coordenação entre o thread em primeiro plano e o objeto de retorno de chamada.

    • Você deve verificar se o thread de primeiro plano e o objeto de retorno de chamada coordenam a chamada para CloseChannel e Release. O thread em primeiro plano e o objeto de retorno de chamada não poderão iniciar uma chamada para CloseChannel se o outro estiver prestes a chamar ou tiver concluído a chamada Release. Você pode implementar essa restrição usando a rotina InterlockedCompareExchange . Se você não usar InterlockedCompareExchange, poderá causar um comportamento indefinido.

  • Se você se registrou como ouvinte no canal, pode chamar CloseChannel e, em seguida, chamar Release na função de retorno de chamada IPrintAsyncNotifyCallback::OnEventNotify para encerrar a comunicação bidirecional. No entanto, você não deve chamar CloseChannel ou Release em seu retorno de chamada ChannelClosed .

Se você atender a uma dessas condições, deverá chamar Release. Se você não atender a uma dessas condições, não deverá chamar Release.

Observação

Chamar Release em qualquer uma das condições anteriores, mas a primeira, na qual você chama AddRef explicitamente, é uma exceção aos padrões gerais de programação COM. IPrintAsyncNotifyChannel difere da prática COM padrão nessa situação.