Canal de notification
Cette section contient des informations sur la fonction CreatePrintAsyncNotifyChannel et l’interface IPrintAsyncNotifyChannel .
HRESULT
CreatePrintAsyncNotifyChannel(
IN LPCWSTR,
IN PrintAsyncNotificationType*,
IN PrintAsyncNotifyUserFilter,
IN PrintAsyncNotifyConversationStyle,
IN IPrintAsyncNotifyCallback*,
OUT IPrintAsyncNotifyChannel**
);
Les composants d’impression appellent la fonction CreatePrintAsyncNotifyChannel pour créer un canal de notification. Le canal peut être par imprimante ou par serveur.
Le composant d’impression peut ouvrir un canal de notification uniquement si le composant est chargé par le spouleur. Winspool.drv désactive cette fonctionnalité si l’appelant s’exécute à l’intérieur des applications, et non dans le service spouleur. Par exemple, lorsque l’application charge le pilote pour effectuer le rendu, un appel à CreatePrintAsyncNotifyChannel échoue. Toutefois, le même appel réussit si le pilote est chargé par le service de spouleur.
Spoolss.lib fournit cette fonctionnalité afin que les moniteurs de port puissent ouvrir des canaux. Les composants qui s’exécutent à l’intérieur du spouleur et qui sont liés à Spoolss.lib peuvent appeler la fonction CreatePrintAsyncNotifyChannel . La procédure suivante explique l’objectif de chaque paramètre d’entrée dans un appel à cette fonction. La première étape de la procédure s’applique au premier paramètre de cette fonction, la deuxième étape s’applique au deuxième paramètre, et ainsi de suite.
Pour créer un canal de notification, spécifiez les éléments suivants :
Nom de l’imprimante ou du serveur.
Type de canal de notification. L’appelant peut spécifier le type de notifications qui doivent être envoyées via ce canal.
Filtre utilisateur. L’appelant peut spécifier les utilisateurs qui doivent recevoir des notifications, soit le même utilisateur que l’expéditeur de la notification, soit tous les utilisateurs.
Filtre de conversation. L’appelant doit spécifier s’il s’agit d’un canal unidirectionnel ou bidirectionnel. Pour marquer le canal comme unidirectionnel, définissez le dernier paramètre (de type IPrintAsyncNotifyChannel**) de CreatePrintAsyncNotifyChannel sur NULL.
Interface IPrintAsyncNotifyCallback à appeler lorsqu’une notification revient de l’autre extrémité du canal. Cela peut être NULL si l’appelant n’est pas intéressé par la réception des réponses.
Lorsque CreatePrintAsyncNotifyChannel retourne, le sixième paramètre (de type IPrintAsyncNotifyChannel**) pointe vers un emplacement mémoire qui contient l’adresse d’un objet IPrintAsyncNotifyChannel . Cet objet identifie le canal et est utilisé pour envoyer des notifications et fermer le canal.
IPrintAsyncNotifyChannel, interface
L’interface IPrintAsyncNotifyChannel identifie un canal et est utilisée pour envoyer des notifications et fermer le canal. Lorsqu’un composant d’impression appelle la fonction CreatePrintAsyncNotifyChannel pour créer un canal de notification, le service spouleur répond en fournissant un objet qui expose l’interface IPrintAsyncNotifyChannel .
Cette interface hérite de l’interface IUnknown afin que les clients du mécanisme de notification du spouleur puissent implémenter un objet COM ou C++. La déclaration d’interface dans l’exemple de code suivant montre cet héritage :
#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;
};
Pour envoyer une notification, l’expéditeur appelle la méthode IPrintAsyncNotifyChannel::SendNotification . L’expéditeur peut être le composant d’impression qui ouvre le canal et envoie des notifications ou un client à l’écoute lorsqu’il doit répondre à une notification. Cette méthode se comporte de manière asynchrone. Lorsque la méthode retourne un code de réussite, le spouleur tente d’envoyer la notification aux écouteurs. Mais il n’y a aucune garantie que les écouteurs reçoivent la notification.
Pour fermer le canal, l’expéditeur ou un écouteur peut appeler la méthode IPrintAsyncNotifyChannel::CloseChannel . L’appelant peut transmettre une notification qui indique la raison de la fermeture du canal ou peut passer un pointeur NULL . Lorsque le canal est fermé, toutes les notifications en file d’attente sont ignorées.
Vous devez être prudent lors de l’appel de Release sur un objet de canal, car il ne suit pas tous les invariants de programmation COM généraux. Vous devez appeler Release sur IPrintAsyncNotifyChannel uniquement si les conditions suivantes se produisent :
Si vous avez appelé AddRef explicitement et que vous devez le faire correspondre à un appel à Release.
Si vous avez créé le canal en tant que canal unidirectionnel et que vous devez appeler Release une fois sur le pointeur que vous avez reçu en tant que paramètre de sortie. Vous devez appeler Release après avoir envoyé les notifications souhaitées et fermé le canal.
Si vous avez créé le canal en tant que bidirectionnel, vous devrez peut-être appeler Release une fois sur le pointeur que vous avez reçu en tant que paramètre de sortie. Vous devez appeler Release uniquement si vous effectuez une ou plusieurs des opérations suivantes :
Avant d’appeler Release pour un canal bidirectionnel, vous devez toujours appeler CloseChannel et recevoir un résultat de réussite. Vous ne devez pas appeler Release si l’appel à CloseChannel échoue, car le canal a peut-être déjà été libéré en votre nom.
Vous ne devez pas appeler Release lors de l’entrée de l’événement ChannelClosed . Pour éviter cette situation, case activée pour un appel à CloseChannel qui a échoué avec l’erreur CHANNEL_ALREADY_CLOSED. Dans ce cas, vous n’avez pas besoin d’appeler Release , car le canal a déjà été libéré en votre nom.
Vous ne devez pas appeler CloseChannel, Release ou toute autre fonction membre sur le canal si votre fonction de rappel ChannelClosed a terminé son exécution. Dans ce cas, le canal a déjà été libéré, donc tous les appels supplémentaires peuvent entraîner un comportement non défini. Cette restriction peut nécessiter une coordination entre votre thread de premier plan et l’objet de rappel.
Vous devez vous assurer que votre thread de premier plan et votre objet de rappel coordonnent l’appel à CloseChannel et Release. Votre thread de premier plan et votre objet de rappel ne peuvent pas commencer un appel à CloseChannel si l’autre est sur le point d’appeler ou a terminé l’appel de Release. Vous pouvez implémenter cette restriction à l’aide de la routine InterlockedCompareExchange . Si vous n’utilisez pas InterlockedCompareExchange, vous risquez d’entraîner un comportement non défini.
Si vous vous êtes inscrit en tant qu’écouteur sur le canal, vous pouvez appeler CloseChannel , puis appeler Release dans votre fonction de rappel IPrintAsyncNotifyCallback::OnEventNotify pour mettre fin à la communication bidirectionnelle. Toutefois, vous ne devez pas appeler CloseChannel ou Release dans votre rappel ChannelClosed .
Si vous remplissez l’une de ces conditions, vous devez appeler Release. Si vous ne remplissez pas l’une de ces conditions, vous ne devez pas appeler Release.
Notes
L’appel de Release dans l’une des conditions précédentes, mais la première, dans laquelle vous appelez AddRef explicitement, est une exception aux modèles de programmation COM généraux. IPrintAsyncNotifyChannel diffère de la pratique COM standard dans cette situation.