通知チャンネル
このセクションには、CreatePrintAsyncNotifyChannel 関数と IPrintAsyncNotifyChannel インターフェイスに関する情報が含まれています。
HRESULT
CreatePrintAsyncNotifyChannel(
IN LPCWSTR,
IN PrintAsyncNotificationType*,
IN PrintAsyncNotifyUserFilter,
IN PrintAsyncNotifyConversationStyle,
IN IPrintAsyncNotifyCallback*,
OUT IPrintAsyncNotifyChannel**
);
印刷コンポーネントは、 CreatePrintAsyncNotifyChannel 関数を呼び出して通知チャネルを作成します。 チャネルはプリンターごとでもサーバー単位でもかまいません。
印刷コンポーネントは、スプーラーによってコンポーネントが読み込まれている場合にのみ、通知チャネルを開くことができます。 Winspool.drv は、呼び出し元がスプーラー サービスではなく、アプリケーション内で実行されている場合に、この機能を無効にします。 たとえば、アプリケーションがドライバーを読み込んでレンダリングを実行すると、CreatePrintAsyncNotifyChannel の呼び出しが失敗します。 ただし、スプーラー サービスによってドライバーが読み込まれる場合は、同じ呼び出しが成功します。
Spoolss.lib は、ポート モニターがチャネルを開くことができるように、この機能を提供します。 スプーラー内で実行され、Spoolss.lib にリンクされているコンポーネントは、CreatePrintAsyncNotifyChannel 関数を呼び出すことができます。 次の手順では、この関数の呼び出しにおける各入力パラメーターの目的について説明します。 プロシージャの最初のステップは、この関数の最初のパラメーターに適用され、2 番目のステップは 2 番目のパラメーターに適用されます。
通知チャネルを作成するには、次の項目を指定します。
プリンターまたはサーバーの名前。
通知チャンネルの種類 呼び出し元は、このチャネルを通じて送信する通知の種類を指定できます。
ユーザー フィルター。 呼び出し元は、通知を受信するユーザー、通知送信者と同じユーザー、またはすべてのユーザーを指定できます。
会話フィルター。 呼び出し元は、これが一方向チャネルか双方向チャネルかを指定する必要があります。 チャネルを一方向としてマークするには、CreatePrintAsyncNotifyChannel の最後のパラメーター (IPrintAsyncNotifyChannel**) を NULL に設定します。
通知がチャネルの もう一方の端から戻ったときに呼び出される IPrintAsyncNotifyCallback インターフェイス。 呼び出し元が 応答の受信に関心がない場合は、NULL を指定できます。
CreatePrintAsyncNotifyChannel が返されると、6 番目のパラメーター (IPrintAsyncNotifyChannel**型) は、IPrintAsyncNotifyChannel オブジェクトのアドレスを含むメモリの場所を指します。 このオブジェクトはチャネルを識別し、通知の送信とチャネルの終了に使用されます。
IPrintAsyncNotifyChannel インターフェイス
IPrintAsyncNotifyChannel インターフェイスはチャネルを識別し、通知の送信とチャネルの終了に使用されます。 印刷コンポーネントが CreatePrintAsyncNotifyChannel 関数を呼び出して通知チャネルを作成すると、スプーラー サービスは IPrintAsyncNotifyChannel インターフェイスを公開するオブジェクトを提供することで応答します。
このインターフェイスは、スプーラー通知メカニズムのクライアントが COM または C++ オブジェクトを実装できるように、IUnknown インターフェイスから継承します。 次のコード例のインターフェイス宣言は、この継承を示しています。
#define INTERFACE IPrintAsyncNotifyChannel
DECLARE_INTERFACE_(IPrintAsyncNotifyChannel, IUnknown)
{
STDMETHOD(QueryInterface)(
THIS_
REFIID riid,
void** ppvObj
) PURE;
STDMETHOD_(ULONG, AddRef)(
THIS
) PURE;
STDMETHOD_(ULONG, Release)(
THIS
) PURE;
STDMETHOD(SendNotification)(
THIS_
IN IPrintAsyncNotifyDataObject*
) PURE;
STDMETHOD(CloseChannel)(
THIS_
IN IPrintAsyncNotifyDataObject*
) PURE;
};
通知を送信するために、送信者は IPrintAsyncNotifyChannel::SendNotification メソッドを呼び出します。 送信者は、チャネルを開いて通知を送信する印刷コンポーネントか、通知に応答する必要があるときにリスニングしているクライアントのいずれかになります。 このメソッドは非同期的に動作します。 メソッドが成功コードを返すと、スプーラーはリスナーに通知を送信しようとします。 ただし、リスナーが通知を受け取る保証はありません。
チャネルを閉じるには、送信者またはリスナーが IPrintAsyncNotifyChannel::CloseChannel メソッドを呼び出すことができます。 呼び出し元は、チャネルを閉じる理由を示す通知を渡すか、NULL ポインターを渡すことができます。 チャネルが閉じられると、キューに登録されているすべての通知が破棄されます。
チャネル オブジェクトに対して「リリース」を呼び出す際には注意が必要です。これは、一般的な COM プログラミング インバリアントのすべてに従うわけではないためです。 次の条件が発生した場合にのみ、IPrintAsyncNotifyChannel で「リリース」を呼び出す必要があります。
AddRef を明示的に呼び出し「リリース」の呼び出しと一致させる必要がある場合。
チャネルを一方向として作成し、出力パラメーターとして受け取ったポインターで「リリース」を 1 回呼び出す必要がある場合。 目的の通知を送信し、チャネルを閉じた後「リリース」を呼び出す必要があります。
チャネルを双方向として作成し、出力パラメーターとして受け取ったポインターで「リリース」を 1 回呼び出さなければならない場合があります。 「リリース」は、次のいずれかの操作を行う場合にのみ呼び出す必要があります。
双方向チャネルに対して「リリース」を呼び出す前に、必ず CloseChannel を呼び出し、成功の結果を受け取る必要があります。 チャネルが既にユーザーに代わって解放されている可能性があるため、CloseChannel の呼び出しが失敗した場合は「リリース」を呼び出す必要はありません。
ChannelClosed イベントの入力中に「リリース」を呼び出してはなりません。 このような状況を回避するには、エラー CHANNEL_ALREADY_CLOSED で失敗した CloseChannel の呼び出しをチェックします。 チャネルは既にユーザーに代わってリリースされているため、この場合は「リリース」を呼び出す必要はありません。
ChannelClosed コールバック関数の実行が完了した場合は、チャネルで CloseChannel、「リリース」またはその他のメンバー関数を呼び出してはなりません。 この場合、チャネルは既にリリースされているため、それ以上呼び出すと未定義の動作が発生する可能性があります。 この制限には、フォアグラウンド スレッドとコールバック オブジェクト間の調整が必要な場合があります。
フォアグラウンド スレッドとコールバック オブジェクトが CloseChannel および「リリース」の呼び出しを調整していることを確認する必要があります。 フォアグラウンド スレッドとコールバック オブジェクトは、もう一方が呼び出しを開始しようとしている場合、または「リリース」の呼び出しを完了している場合は、CloseChannel の呼び出しを開始できません。 InterlockedCompareExchange ルーチンを使用して、この制限を実装できます。 InterlockedCompareExchange を使用しない場合は、未定義の動作が発生する可能性があります。
チャネルでリスナーとして登録した場合は、CloseChannel を呼び出し、IPrintAsyncNotifyCallback::OnEventNotify コールバック関数で「リリース」を呼び出して双方向通信を終了できます。 ただし、ChannelClosed コールバックで CloseChannel または リリース を呼び出してはなりません。
これらの条件のいずれかを満たしている場合は「リリース」を呼び出す必要があります。 これらの条件のいずれかを満たしていない場合は「リリース」を呼び出さないでください。
Note
上記のいずれかの条件で「リリース」を呼び出しますが、最初に AddRef を明示的に呼び出すことは、一般的な COM プログラミング パターンの例外です。 IPrintAsyncNotifyChannel は 、この状況では標準の COM プラクティスとは異なります。