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