Асинхронные уведомления в фильтрах печати
Внимание
Современная платформа печати — это предпочтительный способ взаимодействия с принтерами Windows. Рекомендуется использовать драйвер класса "Входящие" Microsoft IPP вместе с приложениями поддержки печати (PSA), чтобы настроить возможности печати в Windows 10 и 11 для разработки устройств принтера.
Дополнительные сведения см. в статье "Современная платформа печати" и руководство по проектированию приложений поддержки печати.
Конвейер фильтра печати имеет функцию асинхронного уведомления, которая очень похожа на асинхронное уведомление, поддерживаемое в spooler печати для приложений. Функция RouterCreatePrintAsyncNotificationChannel , доступная в spooler печати, недоступна для печати фильтров. Фильтры печати должны использовать интерфейс IPrintClassObjectFactory для создания объектов IPrintAsyncNotify .
В этом разделе описывается, как использовать функцию асинхронного уведомления в фильтре печати.
Создание асинхронных уведомлений из фильтра печати не поддерживается в модели драйвера печати версии 4.
IPrintClassObjectFactory
Интерфейс IPrintClassObjectFactory предоставляет доступ к интерфейсам уведомлений. В следующем примере кода показано, как фильтр может получить этот интерфейс из контейнера свойств.
// This interface is defined as a private member variable in the filter class
IPrintClassObjectFactory *m_pPrintClassFactory;
// The following code goes in the IntializeFilter method of the filter
VARIANT var;
VariantInit(&var);
HRESULT hr = pIPropertyBag->GetProperty(
XPS_FP_PRINT_CLASS_FACTORY,
&var);
if (SUCCEEDED(hr))
{
hr = V_UNKNOWN(&var)->QueryInterface(
IID_IPrintClassObjectFactory,
reinterpret_cast<void **>(&m_pPrintClassFactory));
}
Канал уведомления
С помощью интерфейса IPrintClassObjectFactory фильтр может создать однонаправленный или двунаправленный канал уведомлений в зависимости от потребностей фильтра. В следующем примере кода показано, как фильтр устанавливает однонаправленный канал уведомлений.
// Create a unidirectional notification channel
IPrintAsyncNotifyChannel *pIAsyncNotifyChannel;
IPrintAsyncNotify *pIAsyncNotify;
HRESULT hr = m_pPrintClassFactory->GetPrintClassObject(
m_bstrPrinter, // The printer name that was read from the property bag
IID_IPrintAsyncNotify,
reinterpret_cast<void**>(&pIAsyncNotify)));
if (SUCCEEDED(hr))
{
hr = pIAsyncNotify->CreatePrintAsyncNotifyChannel(
m_jobId,
const_cast<GUID*>(&MS_ASYNCNOTIFY_UI),
kPerUser,
kUniDirectional,
NULL,
&pIAsyncNotifyChannel));
// etc...
}
Чтобы создать двунаправленный канал уведомлений, следует использовать следующий пример кода вместо предыдущего примера.
// Create a bidirectional notification channel
IPrintAsyncNotifyChannel *pIAsyncNotifyChannel;
IPrintAsyncNotify *pIAsyncNotify;
HRESULT hr = m_pPrintClassFactory->GetPrintClassObject(
m_bstrPrinterName, // The printer name that was read from the property bag
IID_IPrintAsyncNotify,
reinterpret_cast<void**>(&pIAsyncNotify)));
if (SUCCEEDED(hr))
{
hr = pIAsyncNotify->CreatePrintAsyncNotifyChannel(
m_jobId,
const_cast<GUID*>(& SAMPLE_ASYNCNOTIFY_UI),
kPerUser,
kBiDirectional,
pIAsyncCallback,
&pIAsyncNotifyChannel));
// etc...
}
В предыдущем примере кода переменная pIAsyncCallback
является указателем на реализацию вызывающего интерфейса IPrintAsyncNotifyCallback .
В некоторых случаях вы должны освободить двунаправленный канал уведомлений при завершении работы с ним. Для этого вызовите метод Release в IPrintAsyncNotifyChannel. Сведения о выпуске канала см. в разделе "Канал уведомлений".
Олицетворение и уведомление
Фильтр не должен олицетворить учетную запись пользователя при вызове метода IPrintAsyncNotify::CreatePrintAsyncNotifyChannel. Механизм авторизации в spooler печати требует, чтобы он вызывался из учетной записи локальной службы. Если фильтр должен олицетворить учетную запись пользователя, отправившего задание, фильтр должен вернуться к себе перед вызовом CreatePrintAsyncNotifyChannel. После возвращения вызова фильтр может вернуться к учетной записи пользователя при необходимости.
Несмотря на то, что вызов уведомления выполняется в контексте локальной службы, уведомления kPerUser по-прежнему отправляются пользователю, отправившему задание на основе связи пользователя с идентификатором задания.
Адаптация примера кода WDK
Пример уведомления можно адаптировать из примера кода WDK для работы в фильтре печати, заменив вызов RouterCreatePrintAsyncNotificationChannel следующим примером кода.
IPrintAsyncNotify *pIAsyncNotify;
HRESULT hr = m_pPrintClassFactory->GetPrintClassObject(
m_bstrPrinterName, // get it from the property bag
IID_IPrintAsyncNotify,
reinterpret_cast<void**>(&pIAsyncNotify)));
if (SUCCEEDED(hr))
{
hr = pIAsyncNotify->CreatePrintAsyncNotifyChannel(
// the same arguments as for
// RouterCreatePrintAsyncNotificationChannel
);
// etc...
}