This section contains information about the CreatePrintAsyncNotifyChannel function and the IPrintAsyncNotifyChannel interface.
HRESULT
CreatePrintAsyncNotifyChannel(
IN LPCWSTR,
IN PrintAsyncNotificationType*,
IN PrintAsyncNotifyUserFilter,
IN PrintAsyncNotifyConversationStyle,
IN IPrintAsyncNotifyCallback*,
OUT IPrintAsyncNotifyChannel**
);
Printing components call the CreatePrintAsyncNotifyChannel function to create a notification channel. 通道可以是每個印表機或每個伺服器。
只有在多任務緩衝處理程式載入元件時,列印元件才能開啟通知通道。 Winspool.drv 如果呼叫端在應用程式內執行,而不是在多任務緩衝處理程式服務中執行,則會停用這項功能。 For example, when the application loads the driver to perform rendering, a call to CreatePrintAsyncNotifyChannel fails. 不過,如果多任務緩衝處理程式服務載入驅動程式,則相同的呼叫會成功。
Spoolss.lib 提供此功能,讓埠監視器可以開啟通道。 Components that run inside the spooler and that are linked to Spoolss.lib can call the CreatePrintAsyncNotifyChannel function. 下列程式說明呼叫此函式中每個輸入參數的用途。 程序中的第一個步驟會套用至此函式中的第一個參數,第二個步驟會套用至第二個參數,依此類推。
若要建立通知通道,請指定下列項目:
印表機或伺服器的名稱。
通知通道類型。 呼叫端可以指定要透過此通道傳送的通知類型。
使用者篩選器。 呼叫端可以指定接收通知的使用者、與通知傳送者相同的使用者或所有使用者。
對話過濾器。 呼叫端必須指定這是單向還是雙向通道。 To mark the channel as unidirectional, set the last parameter (of type IPrintAsyncNotifyChannel**) of CreatePrintAsyncNotifyChannel to NULL.
The IPrintAsyncNotifyCallback interface to be called when a notification comes back from the other end of the channel. This can be NULL, if the caller is not interested in receiving responses.
When CreatePrintAsyncNotifyChannel returns, the sixth parameter (of type IPrintAsyncNotifyChannel**) points to a memory location that contains the address of an IPrintAsyncNotifyChannel object. 此物件會識別通道,並用來傳送通知及關閉通道。
IPrintAsyncNotifyChannel Interface
The IPrintAsyncNotifyChannel interface identifies a channel and is used to send notifications and to close the channel. When a printing component calls the CreatePrintAsyncNotifyChannel function to create a notification channel, the spooler service responds by providing an object that exposes the IPrintAsyncNotifyChannel interface.
This interface inherits from the IUnknown interface so that the clients of the spooler notification mechanism can implement either a COM or a C++ object. 下列程式碼範例中的介面宣告顯示了此繼承:
#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;
};
To send a notification, the sender calls the IPrintAsyncNotifyChannel::SendNotification method. 傳送者可以是開啟通道並傳送通知的列印元件,也可以是必須回應通知時的接聽用戶端。 這個方法會以非同步方式運作。 當方法傳回成功碼時,多任務緩衝處理程式會嘗試將通知傳送給接聽程式。 但不能保證任何接聽程式都會收到通知。
To close the channel, the sender or a listener can call the IPrintAsyncNotifyChannel::CloseChannel method. The caller can pass in a notification that gives the reason for closing the channel or can pass a NULL pointer. 關閉通道時,會捨棄所有佇列的通知。
You must be careful in calling Release on a channel object, because it does not follow all the general COM programming invariants. You should call Release on IPrintAsyncNotifyChannel only if the following conditions occur:
If you called AddRef explicitly, and you must match it with a call to Release.
If you created the channel as unidirectional, and you must call Release one time on the pointer that you received as an output parameter. You should call Release after you have sent the desired notifications and closed the channel.
If you created the channel as bidirectional, you might have to call Release one time on the pointer that you received as an output parameter. You should call Release only if you do one or more of the following:
Before you call Release for a bidirectional channel, you must always call CloseChannel and receive a success result. You must not call Release if the call to CloseChannel fails, because the channel might have already been released on your behalf.
You must not call Release while entering the ChannelClosed event. To avoid this situation, check for a call to CloseChannel that has failed with the error CHANNEL_ALREADY_CLOSED. You do not have to call Release in this case, because the channel has already been released on your behalf.
You must not call CloseChannel, Release, or any other member function on the channel if your ChannelClosed callback function has finished running. 在此情況下,通道已釋放,因此任何進一步的呼叫都可能導致未定義的行為。 此限制可能需要前景執行緒與回呼物件之間的協調。
You must make sure that your foreground thread and callback object coordinate the call to CloseChannel and Release. Your foreground thread and your callback object cannot begin a call to CloseChannel if the other is about to call or has completed calling Release. You can implement this restriction by using the InterlockedCompareExchange routine. If you do not use InterlockedCompareExchange, you might cause undefined behavior.
If you registered as a listener on the channel, you can call CloseChannel and then call Release in your IPrintAsyncNotifyCallback::OnEventNotify callback function to end the bidirectional communication. However, you must not call CloseChannel or Release in your ChannelClosed callback.
If you meet one of these conditions, you must call Release. If you do not meet one of these conditions, you must not call Release.
Note
Calling Release under any of the preceding conditions but the first, in which you call AddRef explicitly, is an exception to general COM programming patterns. IPrintAsyncNotifyChannel differs from standard COM practice in this situation.