Canal de notificación
Esta sección contiene información sobre la función CreatePrintAsyncNotifyChannel y la interfaz IPrintAsyncNotifyChannel .
HRESULT
CreatePrintAsyncNotifyChannel(
IN LPCWSTR,
IN PrintAsyncNotificationType*,
IN PrintAsyncNotifyUserFilter,
IN PrintAsyncNotifyConversationStyle,
IN IPrintAsyncNotifyCallback*,
OUT IPrintAsyncNotifyChannel**
);
Los componentes de impresión llaman a la función CreatePrintAsyncNotifyChannel para crear un canal de notificación. El canal puede ser por impresora o por servidor.
El componente de impresión solo puede abrir un canal de notificación si el administrador de colas carga el componente. Winspool.drv deshabilita esta funcionalidad si el autor de la llamada se ejecuta dentro de las aplicaciones y no en el servicio de cola. Por ejemplo, cuando la aplicación carga el controlador para realizar la representación, se produce un error en una llamada a CreatePrintAsyncNotifyChannel . Sin embargo, la misma llamada se realiza correctamente si el servicio de cola carga el controlador.
Spoolss.lib proporciona esta funcionalidad para que los monitores de puerto puedan abrir canales. Los componentes que se ejecutan dentro del administrador de trabajos de cola y que están vinculados a Spoolss.lib pueden llamar a la función CreatePrintAsyncNotifyChannel . En el procedimiento siguiente se explica el propósito de cada parámetro de entrada en una llamada a esta función. El primer paso del procedimiento se aplica al primer parámetro de esta función, el segundo paso se aplica al segundo parámetro, etc.
Para crear un canal de notificación, especifique los siguientes elementos:
Nombre de la impresora o servidor.
Tipo de canal de notificación. El autor de la llamada puede especificar el tipo de notificaciones que se van a enviar a través de este canal.
Filtro de usuario. El autor de la llamada puede especificar los usuarios que van a recibir notificaciones, ya sea el mismo usuario que el remitente de la notificación o todos los usuarios.
Filtro de conversación. El autor de la llamada debe especificar si se trata de un canal unidireccional o bidireccional. Para marcar el canal como unidireccional, establezca el último parámetro (de tipo IPrintAsyncNotifyChannel**) de CreatePrintAsyncNotifyChannel en NULL.
Se llamará a la interfaz IPrintAsyncNotifyCallback cuando una notificación vuelva del otro extremo del canal. Esto puede ser NULL, si el autor de la llamada no está interesado en recibir respuestas.
Cuando se devuelve CreatePrintAsyncNotifyChannel , el sexto parámetro (de tipo IPrintAsyncNotifyChannel**) apunta a una ubicación de memoria que contiene la dirección de un objeto IPrintAsyncNotifyChannel . Este objeto identifica el canal y se usa para enviar notificaciones y cerrar el canal.
IPrintAsyncNotifyChannel (Interfaz)
La interfaz IPrintAsyncNotifyChannel identifica un canal y se usa para enviar notificaciones y cerrar el canal. Cuando un componente de impresión llama a la función CreatePrintAsyncNotifyChannel para crear un canal de notificación, el servicio de cola responde proporcionando un objeto que expone la interfaz IPrintAsyncNotifyChannel .
Esta interfaz hereda de la interfaz IUnknown para que los clientes del mecanismo de notificación del administrador de colas puedan implementar un objeto COM o C++. La declaración de interfaz en el ejemplo de código siguiente muestra esta herencia:
#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 una notificación, el remitente llama al método IPrintAsyncNotifyChannel::SendNotification . El remitente puede ser el componente de impresión que abre el canal y envía notificaciones o un cliente de escucha cuando tiene que responder a una notificación. Este método se comporta de forma asincrónica. Cuando el método devuelve un código correcto, el administrador de colas intenta enviar la notificación a los agentes de escucha. Pero no hay ninguna garantía de que los agentes de escucha reciban la notificación.
Para cerrar el canal, el remitente o un agente de escucha pueden llamar al método IPrintAsyncNotifyChannel::CloseChannel . El autor de la llamada puede pasar una notificación que proporcione el motivo para cerrar el canal o puede pasar un puntero NULL . Cuando se cierra el canal, se descartan todas las notificaciones en cola.
Debe tener cuidado al llamar a Release en un objeto de canal, ya que no sigue todos los invariantes generales de programación COM. Debe llamar a Release en IPrintAsyncNotifyChannel solo si se producen las condiciones siguientes:
Si llamó explícitamente a AddRef y debe coincidir con una llamada a Release.
Si creó el canal como unidireccional y debe llamar a Release una vez en el puntero que recibió como parámetro de salida. Debe llamar a Release después de enviar las notificaciones deseadas y cerrar el canal.
Si creó el canal como bidireccional, es posible que tenga que llamar a Release una vez en el puntero que recibió como parámetro de salida. Solo debe llamar a Release si realiza una o varias de las siguientes acciones:
Antes de llamar a Release para un canal bidireccional, siempre debe llamar a CloseChannel y recibir un resultado correcto. No debe llamar a Release si se produce un error en la llamada a CloseChannel , ya que es posible que el canal ya se haya publicado en su nombre.
No debe llamar a Release mientras escribe el evento ChannelClosed . Para evitar esta situación, compruebe si hay una llamada a CloseChannel que ha producido un error con el error CHANNEL_ALREADY_CLOSED. No es necesario llamar a Release en este caso, porque el canal ya se ha publicado en su nombre.
No debe llamar a CloseChannel, Release ni a ninguna otra función miembro en el canal si la función de devolución de llamada ChannelClosed ha terminado de ejecutarse. En este caso, el canal ya se ha liberado, por lo que cualquier otra llamada puede provocar un comportamiento indefinido. Esta restricción puede requerir la coordinación entre el subproceso en primer plano y el objeto de devolución de llamada.
Debe asegurarse de que el subproceso en primer plano y el objeto de devolución de llamada coordinan la llamada a CloseChannel y Release. El subproceso en primer plano y el objeto de devolución de llamada no pueden iniciar una llamada a CloseChannel si el otro está a punto de llamar a o ha completado la llamada Release. Puede implementar esta restricción mediante la rutina InterlockedCompareExchange . Si no usa InterlockedCompareExchange, puede provocar un comportamiento indefinido.
Si se registró como agente de escucha en el canal, puede llamar a CloseChannel y, a continuación, llamar a Release en la función de devolución de llamada IPrintAsyncNotifyCallback::OnEventNotify para finalizar la comunicación bidireccional. Sin embargo, no debe llamar a CloseChannel ni Release en la devolución de llamada ChannelClosed .
Si cumple una de estas condiciones, debe llamar a Release. Si no cumple una de estas condiciones, no debe llamar a Release.
Nota
Llamar a Release en cualquiera de las condiciones anteriores, pero la primera, en la que se llama explícitamente a AddRef , es una excepción a los patrones de programación COM generales. IPrintAsyncNotifyChannel difiere de la práctica COM estándar en esta situación.