次の方法で共有


印刷フィルターの非同期通知

重要

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 インターフェイス実装へのポインターです。

双方向通知チャンネルの使用が完了したら、そのチャンネルを解放する必要がある場合があります。 これを行うには、IPrintAsyncNotifyChannelRelease メソッドを呼び出します。 チャンネルを解放するタイミングについては、「通知チャンネル」を参照してください。

偽装と通知

フィルターは、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...
}