Notificaciones asincrónicas en filtros de impresión
Importante
La plataforma de impresión moderna es el medio preferido de Windows para comunicarse con impresoras. Se recomienda usar el controlador de clase de bandeja de entrada IPP de Microsoft, junto con aplicaciones de soporte técnico de impresión (PSA), para personalizar la experiencia de impresión en Windows 10 y 11 para el desarrollo de dispositivos de impresora.
Para obtener más información, consulte Plataforma de impresión moderna y la Guía de diseño de aplicaciones para compatibilidad con impresión.
La canalización de filtro de impresión tiene una característica de notificación asincrónica muy similar a la notificación asincrónica que se admite en el administrador de trabajos de impresión para aplicaciones. La función RouterCreatePrintAsyncNotificationChannel que está disponible en el administrador de trabajos de impresión no está disponible para filtros de impresión. Los filtros de impresión deben usar la interfaz IPrintClassObjectFactory para crear objetos IPrintAsyncNotify.
En este tema se describe cómo usar la característica de notificación asincrónica en un filtro de impresión.
No se admite la generación de notificaciones asincrónicas desde un filtro de impresión en el modelo de controlador de impresión v4.
IPrintClassObjectFactory
La interfaz IPrintClassObjectFactory proporciona acceso a las interfaces de notificación. En el ejemplo de código siguiente se muestra cómo un filtro puede obtener esta interfaz del contenedor de propiedades.
// 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 notificación
Con la interfaz IPrintClassObjectFactory, el filtro puede crear un canal de notificación unidireccional o bidireccional, en función de las necesidades del filtro. El ejemplo de código siguiente continúa desde el ejemplo anterior y muestra cómo un filtro establece un canal de notificación unidireccional.
// 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 crear un canal de notificación bidireccional, usaría el siguiente ejemplo de código en lugar del ejemplo 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...
}
En el ejemplo de código anterior, la variable pIAsyncCallback
es un puntero a la implementación del llamador de la interfaz IPrintAsyncNotifyCallback.
En algunos casos, debe liberar el canal de notificación bidireccional cuando haya terminado con él. Para ello, llame al método Release en IPrintAsyncNotifyChannel. Para obtener información sobre cuándo liberar un canal, consulte Canal de notificación.
Suplantación y notificación
El filtro no debe suplantar a la cuenta de usuario cuando llama al método IPrintAsyncNotify::CreatePrintAsyncNotifyChannel. El mecanismo de autorización en el administrador de trabajos de impresión requiere que se llame desde la cuenta de servicio local. Si el filtro debe suplantar la cuenta del usuario que envió el trabajo, el filtro debe revertirse a sí mismo antes de llamar a CreatePrintAsyncNotifyChannel. Después de que se devuelva la llamada, el filtro puede volver a la cuenta de usuario, si es necesario.
Aunque la llamada de notificación se realiza mientras se encuentra en el contexto del servicio local, las notificaciones kPerUser se siguen enviando al usuario que envió el trabajo en función de la asociación de usuario del identificador de trabajo.
Adaptación del código de ejemplo de WDK
Puede adaptar el ejemplo de notificación del código de ejemplo de WDK para que funcione en un filtro de impresión reemplazando la llamada RouterCreatePrintAsyncNotificationChannel por el ejemplo de código siguiente.
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...
}