印刷フィルターの非同期通知
重要
Windows でプリンターとの通信手段として推奨されるのは、最新の印刷プラットフォームです。 プリンターデバイス開発におけるWindows 10および11での印刷体験をカスタマイズするために、MicrosoftのIPPインボックスクラスドライバーとPrint Support Apps (PSA)の使用を推奨します。
詳細については、最新の印刷プラットフォームに関する記事および「印刷サポート アプリの設計ガイド」を参照してください 。
印刷フィルター パイプラインには、アプリケーションの印刷スプーラーでサポートされている非同期通知によく似た非同期通知機能があります。 印刷スプーラーで使用できる RouterCreatePrintAsyncNotificationChannel 関数は、印刷フィルターでは使用できません。 IPrintAsyncNotify オブジェクトを作成するには、印刷フィルターで IPrintClassObjectFactory インターフェイスを使用する必要があります。
このトピックでは、印刷フィルターで非同期通知機能を使用する方法について説明します。
v4 印刷ドライバー モデルでは、印刷フィルターからの非同期通知のスローはサポートされていません。
IPrintClassObjectFactory
IPrintClassObjectFactory インターフェイスは、通知インターフェイスへのアクセスを提供します。 次のコード例は、フィルターがプロパティ バッグからこのインターフェイスを取得する方法を示しています。
// 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));
}
通知チャンネル
IPrintClassObjectFactory インターフェイスを使用すると、フィルターのニーズに応じて、一方向または双方向の通知チャンネルを作成できます。 次のコード例は、前の例の続きであり、フィルターが一方向の通知チャンネルを確立する方法を示しています。
// 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...
}
双方向通知チャンネルを作成するには、前の例の代わりに次のコード例を使用します。
// 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...
}
前のコード例では、変数 pIAsyncCallback
は、呼び出し元の IPrintAsyncNotifyCallback インターフェイス実装へのポインターです。
双方向通知チャンネルの使用が完了したら、そのチャンネルを解放する必要がある場合があります。 これを行うには、IPrintAsyncNotifyChannel で Release メソッドを呼び出します。 チャンネルを解放するタイミングについては、「通知チャンネル」を参照してください。
偽装と通知
フィルターは、IPrintAsyncNotify::CreatePrintAsyncNotifyChannel メソッドを呼び出すときに、ユーザー アカウントを偽装してはなりません。 印刷スプーラーの承認メカニズムでは、ローカル サービス アカウントから呼び出す必要があります。 フィルターがジョブを送信したユーザーのアカウントを偽装する必要がある場合は、CreatePrintAsyncNotifyChannel を呼び出す前にフィルターを元に戻す必要があります。 呼び出しが戻ったら、必要に応じて、フィルターをユーザー アカウントに戻すことができます。
ローカル サービス コンテキストで通知呼び出しが行われる場合でも、kPerUser 通知は、ジョブ ID のユーザー関連付けに基づいてジョブを送信したユーザーに送信されます。
WDK サンプル コードの適用
RouterCreatePrintAsyncNotificationChannel 呼び出しを次のコード例に置き換えることで、WDK サンプル コードの通知サンプルを印刷フィルターで動作するように適用できます。
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...
}