Compartilhar via


Notificações assíncronas em filtros de impressão

Importante

A plataforma de impressão moderna é o meio preferido do Windows para se comunicar com as impressoras. Recomendamos que você use o driver de classe de caixa de entrada IPP da Microsoft juntamente com PSA (Aplicativos de Suporte à Impressão) para personalizar a experiência de impressão no Windows 10 e 11 para o desenvolvimento de dispositivos de impressora.

Para obter mais informações, consulte Plataformade impressão moderna e o Guia de design do aplicativo de suporte de impressão.

O pipeline de filtro de impressão tem um recurso de notificação assíncrona que é muito semelhante à notificação assíncrona com suporte no spooler de impressão para aplicativos. A função RouterCreatePrintAsyncNotificationChannel que está disponível no spooler de impressão não está disponível para filtros de impressão. Os filtros de impressão devem usar a interface IPrintClassObjectFactory para criar objetos IPrintAsyncNotify.

Este tópico descreve como usar o recurso de notificação assíncrona em um filtro de impressão.

Não há suporte para a geração de notificações assíncronas de um filtro de impressão no modelo de driver de impressão v4.

IPrintClassObjectFactory

A interface IPrintClassObjectFactory fornece acesso às interfaces de notificação. O exemplo de código a seguir ilustra como um filtro pode obter essa interface do recipiente de propriedades.

// 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));
}

Canal de notificação

Com a interface IPrintClassObjectFactory , o filtro pode criar um canal de notificação unidirecional ou bidirecional, dependendo das necessidades do filtro. O exemplo de código a seguir continua a partir do exemplo anterior e mostra como um filtro estabelece um canal de notificação unidirecional.

// 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...
}

Para criar um canal de notificação bidirecional, você usaria o exemplo de código a seguir no lugar do exemplo anterior.

// 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...
}

No exemplo de código anterior, a variável pIAsyncCallback é um ponteiro para a implementação do chamador da interface IPrintAsyncNotifyCallback.

Em alguns casos, você deve liberar o canal de notificação bidirecional quando terminar. Para fazer isso, chame o método Release em IPrintAsyncNotifyChannel. Para obter informações sobre quando liberar um canal, consulte Canal de Notificação.

Representação e notificação

O filtro não deve representar a conta de usuário quando chama o método IPrintAsyncNotify::CreatePrintAsyncNotifyChannel . O mecanismo de autorização no spooler de impressão requer que ele seja chamado da conta do Serviço Local. Se o filtro precisar representar a conta do usuário que enviou o trabalho, o filtro deverá reverter para si mesmo antes de chamar CreatePrintAsyncNotifyChannel. Depois que a chamada retornar, o filtro poderá reverter para a conta de usuário, se necessário.

Mesmo que a chamada de notificação seja feita no contexto do Serviço Local, as notificações kPerUser ainda são enviadas ao usuário que enviou o trabalho com base na associação de usuário da ID do trabalho.

Adaptando o código de exemplo do WDK

Você pode adaptar o exemplo de notificação do código de exemplo do WDK para funcionar em um filtro de impressão substituindo a chamada RouterCreatePrintAsyncNotificationChannel pelo exemplo de código a seguir.

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...
}