Asynchrone Benachrichtigungen in Druckfiltern
Wichtig
Die moderne Druckplattform ist die bevorzugte Methode von Windows für die Kommunikation mit Druckern. Wir empfehlen die Verwendung des Microsoft IPP-Treibers für die Posteingangsklasse zusammen mit Print Support Apps (PSA), um das Druckverhalten in Windows 10 und 11 für die Entwicklung von Druckergeräten anzupassen.
Weitere Informationen finden Sie unter Moderne Druckplattform und im Designhandbuch für die Drucksupport-App.
Die Druckfilterpipeline verfügt über ein asynchrones Benachrichtigungsfeature, das der asynchronen Benachrichtigung ähnelt, die im Druckspooler für Anwendungen unterstützt wird. Die RouterCreatePrintAsyncNotificationChannel-Funktion, die im Druckspooler verfügbar ist, steht nicht zum Drucken von Filtern zur Verfügung. Druckfilter müssen die IPrintClassObjectFactory-Schnittstelle verwenden, um IPrintAsyncNotify-Objekte zu erstellen.
In diesem Thema wird die Verwendung des asynchronen Benachrichtigungsfeatures in einem Druckfilter beschrieben.
Das Auslösen asynchroner Benachrichtigungen von einem Druckfilter wird im v4-Drucktreibermodell nicht unterstützt.
IPrintClassObjectFactory
Die IPrintClassObjectFactory-Schnittstelle bietet Zugriff auf die Benachrichtigungsschnittstellen. Im folgenden Codebeispiel wird veranschaulicht, wie ein Filter diese Schnittstelle aus dem Eigenschaftsbehälter abrufen kann.
// 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));
}
Benachrichtigungskanal
Mit der IPrintClassObjectFactory-Schnittstelle kann der Filter abhängig von den Anforderungen des Filters einen unidirektionalen oder bidirektionalen Benachrichtigungskanal erstellen. Das folgende Codebeispiel setzt sich aus dem vorherigen Beispiel fort und zeigt, wie ein Filter einen unidirektionalen Benachrichtigungskanal einfügt.
// 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...
}
Um einen bidirektionalen Benachrichtigungskanal zu erstellen, verwenden Sie anstelle des vorherigen Beispiels das folgende Codebeispiel.
// 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...
}
Im vorherigen Codebeispiel ist die Variable pIAsyncCallback
ein Zeiger auf die Implementierung der IPrintAsyncNotifyCallback-Schnittstelle des Aufrufers.
In einigen Fällen müssen Sie den bidirektionalen Benachrichtigungskanal freigeben, wenn Sie damit fertig sind. Rufen Sie dazu die Release-Methode auf IPrintAsyncNotifyChannel auf. Informationen zum Freigeben eines Kanals finden Sie unter Benachrichtigungskanal.
Identitätswechsel und Benachrichtigung
Der Filter darf die Identität des Benutzerkontos nicht annehmen, wenn er die IPrintAsyncNotify::CreatePrintAsyncNotifyChannel-Methode aufruft. Der Autorisierungsmechanismus im Druckspooler erfordert, dass er aus dem „Lokalen Dienstkonto” aufgerufen wird. Wenn der Filter die Identität des Kontos des Benutzers annehmen muss, der den Auftrag übermittelt hat, muss der Filter auf sich selbst zurückgesetzt werden, bevor er CreatePrintAsyncNotifyChannel aufruft. Nachdem der Aufruf zurückgegeben wurde, kann der Filter bei Bedarf wieder auf das Benutzerkonto zurückgesetzt werden.
Obwohl der Benachrichtigungsaufruf im Kontext des lokalen Diensts erfolgt, werden kPerUser-Benachrichtigungen weiterhin an den Benutzer gesendet, der den Auftrag basierend auf der Benutzerzuordnung der Auftrags-ID übermittelt hat.
Anpassen des WDK-Beispielcodes
Sie können das Benachrichtigungsbeispiel aus dem WDK-Beispielcode anpassen, um in einem Druckfilter zu arbeiten, indem Sie den RouterCreatePrintAsyncNotificationChannel-Aufruf durch das folgende Codebeispiel ersetzen.
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...
}