通知通道
本節包含 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 函式。 下列程式說明呼叫此函式中每個輸入參數的用途。 程式中的第一個步驟會套用至此函式中的第一個參數,第二個步驟會套用至第二個參數等等。
若要建立通知通道,請指定下列專案:
印表機或伺服器的名稱。
通知通道類型。 呼叫端可以指定要透過此通道傳送的通知類型。
使用者篩選準則。 呼叫端可以指定接收通知的使用者、與通知傳送者相同的使用者,或所有使用者。
交談篩選準則。 呼叫端必須指定這是否為單向通道或雙向通道。 若要將通道標示為單向,請將IPrintAsyncNotifyChannel**類型 (的最後一個參數設定為Null ) CreatePrintAsyncNotifyChannel。
當通知從通道的另一端傳回時,要呼叫的 IPrintAsyncNotifyCallback 介面。 如果呼叫端對接收回應不感興趣,這可以是 Null。
當 CreatePrintAsyncNotifyChannel 傳回時, IPrintAsyncNotifyChannel**類型 (的第六個參數) 指向包含 IPrintAsyncNotifyChannel 物件的位址的記憶體位置。 此物件會識別通道,並用來傳送通知並關閉通道。
IPrintAsyncNotifyChannel 介面
IPrintAsyncNotifyChannel介面會識別通道,並用來傳送通知並關閉通道。 當列印元件呼叫 CreatePrintAsyncNotifyChannel 函式來建立通知通道時,多工緩衝處理常式服務會提供公開 IPrintAsyncNotifyChannel 介面的物件來回應。
這個介面繼承自 IUnknown 介面,讓多工緩衝處理常式通知機制的用戶端可以實作 COM 或 C++ 物件。 下列程式碼範例中的介面宣告會顯示此繼承:
#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 指標。 關閉通道時,會捨棄所有已排入佇列的通知。
您必須小心在通道物件上呼叫 Release ,因為它不會遵循所有一般 COM 程式設計不變數。 只有在發生下列情況時,才應該在IPrintAsyncNotifyChannel上呼叫Release:
如果您明確呼叫 AddRef ,而且您必須與 Release的呼叫相符。
如果您將通道建立為單向通道,則必須在您收到的指標上呼叫 Release 一次作為輸出參數。 您應該在傳送所需的通知並關閉通道之後呼叫 Release 。
如果您將通道建立為雙向,您可能必須在您收到作為輸出參數的指標上呼叫 Release 一次。 只有在執行下列一或多個動作時,才應該呼叫 Release :
呼叫雙向通道的 Release 之前,您一律必須呼叫 CloseChannel 並收到成功結果。 如果CloseChannel的呼叫失敗,您就不得呼叫Release,因為通道可能已代表您發行。
輸入ChannelClosed事件時,您不得呼叫Release。 若要避免這種情況,請檢查已失敗的 CloseChannel 呼叫,並CHANNEL_ALREADY_CLOSED錯誤。 在此情況下,您不需要呼叫 Release ,因為通道已代表您發行。
如果您的ChannelClosed回呼函式已完成執行,您就不得呼叫通道上的CloseChannel、Release或任何其他成員函式。 在此情況下,通道已經釋放,因此任何進一步的呼叫都可能會導致未定義的行為。 此限制可能需要在前景執行緒和回呼物件之間進行協調。
您必須確定前景執行緒和回呼物件會協調 CloseChannel 和 Release的呼叫。 如果另一個執行緒即將呼叫或已完成呼叫Release,則前景執行緒和回呼物件無法開始對CloseChannel的呼叫。 您可以使用 InterlockedCompareExchange 常式來實作此限制。 如果您未使用 InterlockedCompareExchange,可能會造成未定義的行為。
如果您在通道上註冊為接聽程式,您可以呼叫CloseChannel,然後在IPrintAsyncNotifyCallback::OnEventNotify回呼函式中呼叫Release以結束雙向通訊。 不過,您不得在ChannelClosed回呼中呼叫CloseChannel或Release。
如果您符合上述其中一個條件,您必須呼叫 Release。 如果您不符合上述其中一個條件,則不得呼叫 Release。
注意
在任何上述條件下呼叫 Release ,但第一個條件明確呼叫 AddRef ,是一般 COM 程式設計模式的例外狀況。 IPrintAsyncNotifyChannel 與在此情況下的標準 COM 做法不同。