Канал уведомления
Этот раздел содержит сведения о функции CreatePrintAsyncNotifyChannel и интерфейсе IPrintAsyncNotifyChannel .
HRESULT
CreatePrintAsyncNotifyChannel(
IN LPCWSTR,
IN PrintAsyncNotificationType*,
IN PrintAsyncNotifyUserFilter,
IN PrintAsyncNotifyConversationStyle,
IN IPrintAsyncNotifyCallback*,
OUT IPrintAsyncNotifyChannel**
);
Компоненты печати вызывают функцию CreatePrintAsyncNotifyChannel для создания канала уведомлений. Канал может быть для каждого принтера или сервера.
Компонент печати может открыть канал уведомлений только в том случае, если компонент загружен диспетчером очереди. Winspool.drv отключает эту возможность, если вызывающий объект выполняется внутри приложений, а не в службе очереди очереди. Например, когда приложение загружает драйвер для отрисовки, вызов CreatePrintAsyncNotifyChannel завершается ошибкой . Однако тот же вызов выполняется успешно, если драйвер загружен службой очереди очереди.
Spoolss.lib предоставляет эту функцию, чтобы мониторы портов могли открывать каналы. Компоненты, которые выполняются внутри очереди очереди и связаны с Spoolss.lib, могут вызывать функцию CreatePrintAsyncNotifyChannel . В следующей процедуре объясняется назначение каждого входного параметра в вызове этой функции. Первый шаг процедуры применяется к первому параметру в этой функции, второй шаг применяется ко второму параметру и т. д.
Чтобы создать канал уведомлений, укажите следующие элементы:
Имя принтера или сервера.
Тип канала уведомлений. Вызывающий объект может указать тип уведомлений, которые будут отправляться через этот канал.
Фильтр пользователя. Вызывающий объект может указать пользователей, которые будут получать уведомления, либо того же пользователя, что и отправитель уведомления, либо всех пользователей.
Фильтр беседы. Вызывающий объект должен указать, является ли это однонаправленным или двунаправленным каналом. Чтобы пометить канал как однонаправленный, задайте для последнего параметра (типа IPrintAsyncNotifyChannel**) параметра CreatePrintAsyncNotifyChannelзначение NULL.
Интерфейс IPrintAsyncNotifyCallback , который вызывается при возврате уведомления с другого конца канала. Это значение может иметь значение NULL, если вызывающий объект не заинтересован в получении ответов.
Когда функция CreatePrintAsyncNotifyChannel возвращает значение , шестой параметр (типа IPrintAsyncNotifyChannel**) указывает на расположение памяти, содержащее адрес объекта IPrintAsyncNotifyChannel . Этот объект идентифицирует канал и используется для отправки уведомлений и закрытия канала.
Интерфейс IPrintAsyncNotifyChannel
Интерфейс IPrintAsyncNotifyChannel определяет канал и используется для отправки уведомлений и закрытия канала. Когда компонент печати вызывает функцию CreatePrintAsyncNotifyChannel для создания канала уведомлений, служба очереди очереди отвечает, предоставляя объект, предоставляющий интерфейс IPrintAsyncNotifyChannel .
Этот интерфейс наследуется от интерфейса IUnknown , чтобы клиенты механизма уведомлений очереди могли реализовать объект COM или C++. Объявление интерфейса в следующем примере кода показывает это наследование:
#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;
};
Чтобы отправить уведомление, отправитель вызывает метод IPrintAsyncNotifyChannel::SendNotification . Отправитель может быть либо компонентом печати, который открывает канал и отправляет уведомления, либо прослушивающим клиентом, когда ему нужно ответить на уведомление. Этот метод ведет себя асинхронно. Когда метод возвращает код успешного выполнения, диспетчер очереди пытается отправить уведомление прослушивателям. Но нет никакой гарантии, что прослушиватели получат уведомление.
Чтобы закрыть канал, отправитель или прослушиватель может вызвать метод IPrintAsyncNotifyChannel::CloseChannel . Вызывающий объект может передать уведомление, указывающее причину закрытия канала, или передать указатель NULL . При закрытии канала все уведомления в очереди удаляются.
Необходимо соблюдать осторожность при вызове release для объекта канала, так как он не соответствует всем общим инвариантам com-программирования. Вы должны вызывать Release для IPrintAsyncNotifyChannel только в том случае, если возникают следующие условия:
Если вы явно вызвали AddRef и необходимо сопоставить его с вызовом Release.
Если вы создали канал как однонаправленный и необходимо вызвать Release один раз для указателя, полученного в качестве выходного параметра. После отправки нужных уведомлений и закрытия канала следует вызвать функцию Release .
Если вы создали канал как двунаправленный, может потребоваться один раз вызвать Release для указателя, полученного в качестве выходного параметра. Вы должны вызывать Release только в том случае, если вы выполняете одно или несколько из следующих действий:
Прежде чем вызывать release для двунаправленного канала, необходимо всегда вызывать CloseChannel и получать результат успешного выполнения. Вы не должны вызывать Release , если вызов CloseChannel завершается сбоем, так как канал, возможно, уже был освобожден от вашего имени.
Не следует вызывать Release при вводе события ChannelClosed . Чтобы избежать этой ситуации, проверка для вызова CloseChannel, который завершился сбоем с ошибкой CHANNEL_ALREADY_CLOSED. В этом случае не нужно вызывать Release , так как канал уже был освобожден от вашего имени.
Вы не должны вызывать CloseChannel, Release или любую другую функцию-член в канале, если функция обратного вызова ChannelClosed завершена. В этом случае канал уже освобожден, поэтому любые дальнейшие вызовы могут привести к неопределенному поведению. Для этого ограничения может потребоваться координация между потоком переднего плана и объектом обратного вызова.
Необходимо убедиться, что поток переднего плана и объект обратного вызова координируют вызов CloseChannel и Release. Поток переднего плана и объект обратного вызова не могут начать вызов CloseChannel , если другой объект должен вызвать или завершил вызов Release. Это ограничение можно реализовать с помощью подпрограммы InterlockedCompareExchange . Если вы не используете InterlockedCompareExchange, это может привести к неопределенному поведению.
Если вы зарегистрировались в качестве прослушивателя в канале, вы можете вызвать CloseChannel , а затем вызвать Release в функции обратного вызова IPrintAsyncNotifyCallback::OnEventNotify , чтобы завершить двунаправленную связь. Однако не следует вызывать CloseChannel или Release в обратном вызове ChannelClosed .
Если вы соответствуете одному из этих условий, необходимо вызвать release. Если вы не соответствуете одному из этих условий, не следует вызывать Release.
Примечание
Вызов Release при любом из предыдущих условий, кроме первого, в котором вы явно вызываете AddRef , является исключением из общих шаблонов программирования COM. В этой ситуации IPrintAsyncNotifyChannel отличается от стандартной практики COM.