Поделиться через


Асинхронные уведомления в фильтрах печати

Внимание

Современная платформа печати — это предпочтительный способ взаимодействия с принтерами 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...
}