Condividi tramite


Notifiche asincrone nei filtri di stampa

Importante

La piattaforma di stampa moderna è il mezzo preferito di Windows per comunicare con le stampanti. Ti consigliamo di usare il driver di classe IPP di Microsoft, insieme a Print Support Apps (PSA), per personalizzare l'esperienza di stampa in Windows 10 e 11 per lo sviluppo di dispositivi per stampanti.

Per altre informazioni, vedere Piattaforma di stampa moderna e guida alla progettazione dell'app di supporto per la stampa.

La pipeline del filtro di stampa ha una funzionalità di notifica asincrona molto simile alla notifica asincrona supportata nello spooler di stampa per le applicazioni. La funzione RouterCreatePrintAsyncNotificationChannel disponibile nello spooler di stampa non è disponibile per i filtri di stampa. I filtri di stampa devono usare l'interfaccia IPrintClassObjectFactory per creare oggetti IPrintAsyncNotify.

In questo argomento viene descritto come utilizzare la funzionalità di notifica asincrona in un filtro di stampa.

La creazione di notifiche asincrone da un filtro di stampa non è supportata nel modello di driver di stampa v4.

IPrintClassObjectFactory

L'interfaccia IPrintClassObjectFactory consente di accedere alle interfacce di notifica. Nell'esempio di codice seguente viene illustrato come un filtro può ottenere questa interfaccia dal contenitore delle proprietà.

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

Canale di notifica

Con l'interfaccia IPrintClassObjectFactory, il filtro può creare un canale di notifica unidirezionale o bidirezionale, a seconda delle esigenze del filtro. L'esempio di codice seguente continua dall'esempio precedente e mostra come un filtro stabilisce un canale di notifica unidirezionale.

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

Per creare un canale di notifica bidirezionale, usare l'esempio di codice seguente al posto dell'esempio precedente.

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

Nell'esempio di codice precedente, la variabile è un puntatore all'implementazione pIAsyncCallback del chiamante dell'interfaccia IPrintAsyncNotifyCallback .

In alcuni casi, è necessario rilasciare il canale di notifica bidirezionale al termine dell'operazione. A tale scopo, chiamare il metodo Release in IPrintAsyncNotifyChannel. Per informazioni su quando rilasciare un canale, vedere Canale di notifica.

Rappresentazione e notifica

Il filtro non deve rappresentare l'account utente quando chiama il metodo IPrintAsyncNotify::CreatePrintAsyncNotifyChannel. Il meccanismo di autorizzazione nello spooler di stampa richiede che venga chiamato dall'account del servizio locale. Se il filtro deve rappresentare l'account dell'utente che ha inviato il processo, il filtro deve ripristinare se stesso prima di chiamare CreatePrintAsyncNotifyChannel. Al termine della chiamata, il filtro può ripristinare l'account utente, se necessario.

Anche se la chiamata di notifica viene effettuata nel contesto del servizio locale, le notifiche kPerUser vengono comunque inviate all'utente che ha inviato il processo in base all'associazione utente dell'ID processo.

Adattamento del codice di esempio WDK

È possibile adattare l'esempio di notifica dal codice di esempio WDK per lavorare in un filtro di stampa sostituendo la chiamata RouterCreatePrintAsyncNotificationChannel con l'esempio di codice seguente.

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