Ajout de la prise en charge des événements d’interruption
Pour configurer correctement votre pilote WIA afin de signaler les événements d’interruption, procédez comme suit :
Définissez Capabilities=0x31 dans le fichier INF de l’appareil. (Pour plus d’informations, consultez Fichiers INF pour les appareils WIA .)
Rapportez STI_GENCAP_NOTIFICATIONS et STI_USD_GENCAP_NATIVE_PUSHSUPPORT dans la méthode IStiUSD::GetCapabilities .
Signalez tous les événements pris en charge dans la méthode IWiaMiniDrv::d rvGetCapabilities .
Mettre en cache et utiliser le handle d’événement passé dans la méthode IStiUSD::SetNotificationHandle . Il s’agit de la gestion des événements que l’appareil signale ou que le minidriver WIA signale directement à l’aide de SetEvent (décrit dans la documentation Microsoft Windows SDK). C’est dans cette méthode que vous lancez l’état d’attente de l’appareil WIA.
Signalez la réponse appropriée aux informations sur l’événement dans la méthode IStiUSD::GetNotificationData .
Les deux exemples suivants montrent la configuration de votre appareil pour les interruptions avec des implémentations des méthodes IWiaMiniDrv::d rvGetCapabilities et IStiUSD::SetNotificationHandle .
Note Il est important d’utiliser des appels d’E/S qui se chevauchent avec toutes les activités impliquant les pilotes en mode noyau. Cela permet des délais d’expiration et d’annulation appropriés des demandes d’appareil.
Explication de l’implémentation IWiaMiniDrv::d rvGetCapabilities
Le service WIA appelle la méthode IWiaMiniDrv::d rvGetCapabilities pour obtenir les événements et les commandes pris en charge par l’appareil WIA. Le pilote WIA doit d’abord examiner le paramètre lFlags entrant pour déterminer à quelle requête il doit répondre.
Le pilote WIA doit allouer de la mémoire (à utiliser par le pilote WIA et libérée par celui-ci) pour contenir un tableau de structures WIA_DEV_CAP_DRV . Dans l’appel à IWiaMiniDrv::d rvGetCapabilities, passez un pointeur vers l’emplacement de mémoire qui contient l’adresse de la mémoire allouée au pilote WIA dans le paramètre ppCapabilities .
Note Le service WIA ne libère pas cette mémoire. Il est important que le pilote WIA gère la mémoire allouée.
L’exemple suivant montre une implémentation de la méthode IWiaMiniDrv::d rvGetCapabilities .
HRESULT _stdcall CWIADevice::drvGetCapabilities(
BYTE *pWiasContext,
LONG lFlags,
LONG *pcelt,
WIA_DEV_CAP_DRV **ppCapabilities,
LONG *plDevErrVal)
{
//
// If the caller did not pass in the correct parameters,
// then fail the call and return E_INVALIDARG.
//
if (!pWiasContext) {
//
// The WIA service may pass in a NULL for the pWiasContext.
// This is expected because there is a case where no item
// was created at the time the event was fired.
//
}
if (!plDevErrVal) {
return E_INVALIDARG;
}
if (!pcelt) {
return E_INVALIDARG;
}
if (!ppCapabilities) {
return E_INVALIDARG;
}
*plDevErrVal = 0;
HRESULT hr = S_OK;
LONG lNumberOfCommands = 1;
LONG lNumberOfEvents = 2;
//
// initialize WIA driver capabilities ARRAY
// a member WIA_DEV_CAP_DRV m_Capabilities[3] variable
// This memory should live with the WIA minidriver.
// A pointer to this structure is given to the WIA service using
// ppCapabilities. Do not delete this memory until
// the WIA minidriver has been unloaded.
//
// This ARRAY should only be initialized once.
// The Descriptions and Names should be read from the proper
// string resource. These string values should be localized in
// multiple languages because an application will be use them to
// be displayed to the user.
//
// Command #1
m_Capabilities[0].wszDescription = L"Synchronize Command";
m_Capabilities[0].wszName = L"Synchronize";
m_Capabilities[0].guid = (GUID*)&WIA_CMD_SYNCHRONIZE;
m_Capabilities[0].lFlags = 0;
m_Capabilities[0].wszIcon = WIA_ICON_SYNCHRONIZE;
// Event #1
m_Capabilities[1].wszDescription = L"Scan Button";
m_Capabilities[1].wszName = L"Scan";
m_Capabilities[1].guid = (GUID*)&WIA_EVENT_SCAN_IMAGE;
m_Capabilities[1].lFlags = WIA_NOTIFICATION_EVENT | WIA_ACTION_EVENT;
m_Capabilities[1].wszIcon = WIA_ICON_SCAN_BUTTON_PRESS;
// Event #2
m_Capabilities[2].wszDescription = L"Copy Button";
m_Capabilities[2].wszName = L"Copy";
m_Capabilities[2].guid = (GUID*)&WIA_EVENT_SCAN_PRINT_IMAGE;
m_Capabilities[2].lFlags = WIA_NOTIFICATION_EVENT | WIA_ACTION_EVENT;
m_Capabilities[2].wszIcon = WIA_ICON_SCAN_BUTTON_PRESS;
//
// Return depends on flags. Flags specify whether we should return
// commands, events, or both.
//
//
switch (lFlags) {
case WIA_DEVICE_COMMANDS:
//
// report commands only
//
*pcelt = lNumberOfCommands;
*ppCapabilities = &m_Capabilities[0];
break;
case WIA_DEVICE_EVENTS:
//
// report events only
//
*pcelt = lNumberOfEvents;
*ppCapabilities = &m_Capabilities[1]; // start at the first event in the ARRAY
break;
case (WIA_DEVICE_COMMANDS | WIA_DEVICE_EVENTS):
//
// report both events and commands
//
*pcelt = (lNumberOfCommands + lNumberOfEvents);
*ppCapabilities = &m_Capabilities[0];
break;
default:
//
// invalid request
//
hr = E_INVALIDARG;
break;
}
return hr;
}
La méthode IStiUSD::SetNotificationHandle est appelée par le service WIA ou en interne par ce pilote pour démarrer ou arrêter les notifications d’événements. Le service WIA transmet un handle valide, créé à l’aide de CreateEvent (décrit dans la documentation Microsoft Windows SDK), indiquant que le pilote WIA doit signaler ce handle lorsqu’un événement se produit dans le matériel.
Null peut être passé à la méthode IStiUSD::SetNotificationHandle . NULL indique que le minidriver WIA doit arrêter toute l’activité de l’appareil et quitter toutes les opérations d’attente d’événement.
L’exemple suivant montre une implémentation de la méthode IStiUSD::SetNotificationHandle .
STDMETHODIMP CWIADevice::SetNotificationHandle(HANDLE hEvent)
{
HRESULT hr = S_OK;
if (hEvent && (hEvent != INVALID_HANDLE_VALUE)) {
//
// A valid handle indicates that we are asked to start our "wait"
// for device interrupt events
//
//
// reset last event GUID to GUID_NULL
//
m_guidLastEvent = GUID_NULL;
//
// clear EventOverlapped structure
//
memset(&m_EventOverlapped,0,sizeof(m_EventOverlapped));
//
// fill overlapped hEvent member with the event passed in by
// the WIA service. This handle will be automatically signaled
// when an event is triggered at the hardware level.
//
m_EventOverlapped.hEvent = hEvent;
//
// clear event data buffer. This is the buffer that will be used
// to determine what event was signaled from the device.
//
memset(m_EventData,0,sizeof(m_EventData));
//
// use the following call for interrupt events on your device
//
DWORD dwError = 0;
BOOL bResult = DeviceIoControl( m_hDeviceDataHandle,
IOCTL_WAIT_ON_DEVICE_EVENT,
NULL,
0,
&m_EventData,
sizeof(m_EventData),
&dwError,
&m_EventOverlapped );
if (bResult) {
hr = S_OK;
} else {
hr = HRESULT_FROM_WIN32(::GetLastError());
}
} else {
//
// stop any hardware waiting events here, the WIA service has
// notified us to stop all hardware event waiting
//
//
// Stop hardware interrupt events. This will stop all activity on
// the device. Since DeviceIOControl was used with OVERLAPPED i/o
// functionality the CancelIo() can be used to stop all kernel
// mode activity.
//
if(m_hDeviceDataHandle){
if(!CancelIo(m_hDeviceDataHandle)){
//
// canceling of the IO failed, call GetLastError() here to determine the cause.
//
LONG lError = ::GetLastError();
}
}
}
return hr;
}
Lorsque le minidriver WIA ou un appareil WIA a détecté et signalé un événement, le service WIA appelle la méthode IStiUSD::GetNotificationData . C’est dans cette méthode que le minidriver WIA doit signaler les détails de l’événement qui s’est produit.
Le service WIA appelle la méthode IStiUSD::GetNotificationData pour obtenir des informations sur un événement qui vient d’être signalé. La méthode IStiUSD::GetNotificationData peut être appelée à la suite de l’une des deux opérations d’événement.
IStiUSD::GetStatus a signalé qu’un événement était en attente en définissant l’indicateur STI_EVENTHANDLING_PENDING dans la structure STI_DEVICE_STATUS .
Le handle hEvent transmis par IStiUSD::SetNotificationHandle a été signalé par le matériel ou en appelant SetEvent (décrit dans la documentation Microsoft Windows SDK).
Le pilote WIA est chargé de remplir la structure STINOTIFY
L’exemple suivant montre une implémentation de la méthode IStiUSD::GetNotificationData .
STDMETHODIMP CWIADevice::GetNotificationData( LPSTINOTIFY pBuffer )
{
//
// If the caller did not pass in the correct parameters,
// then fail the call with E_INVALIDARG.
//
if(!pBuffer){
return E_INVALIDARG;
}
GUID guidEvent = GUID_NULL;
DWORD dwBytesRet = 0;
BOOL bResult = GetOverlappedResult(m_hDeviceDataHandle, &m_EventOverlapped, &dwBytesRet, FALSE );
if (bResult) {
//
// read the m_EventData buffer to determine the proper event.
// set guidEvent to the proper event GUID
// set guidEvent to GUID_NULL when an event has
// not happened that you are concerned with
//
if(m_EventData[0] == DEVICE_SCAN_BUTTON_PRESSED) {
guidEvent = WIA_EVENT_SCAN_IMAGE;
} else {
guidEvent = GUID_NULL;
}
}
//
// If the event was triggered, then fill in the STINOTIFY structure
// with the proper event information
//
if (guidEvent != GUID_NULL) {
memset(pBuffer,0,sizeof(STINOTIFY));
pBuffer->dwSize = sizeof(STINOTIFY);
pBuffer->guidNotificationCode = guidEvent;
} else {
return STIERR_NOEVENTS;
}
return S_OK;
}
Les événements d’interruption peuvent être arrêtés à tout moment en passant null comme handle d’événement. Le minidriver doit interpréter cela comme un signal pour arrêter les états d’attente sur l’appareil matériel.
La méthode IWiaMiniDrv::d rvNotifyPnpEvent peut recevoir des événements de gestion de l’alimentation qui affectent l’état d’attente de l’événement.
Le service WIA appelle la méthode IWiaMiniDrv::d rvNotifyPnpEvent et envoie un événement WIA_EVENT_POWER_SUSPEND lorsque le système est sur le point d’être mis en veille. Si cet appel se produit, l’appareil est peut-être déjà hors de son état d’attente. Les états de veille déclenchent automatiquement les pilotes en mode noyau pour quitter tout état d’attente pour permettre au système d’entrer dans cet état sous tension. Lorsque le système reprend son état de veille, le service WIA envoie l’événement WIA_EVENT_POWER_RESUME. À ce stade, le minidriver WIA doit rétablir l’état d’attente de l’événement d’interruption. Pour plus d’informations sur les états de veille, consultez System Power States et Device Power States.
Il est recommandé que le minidriver WIA cache le handle d’événement initialement passé à la méthode IStiUSD::SetNotificationHandle afin qu’il puisse être réutilisé lorsque le système se réveille d’une veille ou d’une mise en veille prolongée.
Le service WIA n’appelle pas la méthode IStiUSD::SetNotificationHandle après la reprise du système. Il est recommandé que le minidriver appelle sa méthode IStiUSD::SetNotificationHandle , en passant le handle d’événement mis en cache.
Le service WIA appelle la méthode IWiaMiniDrv::d rvNotifyPnpEvent lorsque des événements système se produisent. Le pilote WIA doit case activée le paramètre pEventGUID pour déterminer l’événement en cours de traitement.
Voici quelques événements courants qui doivent être traités :
WIA_EVENT_POWER_SUSPEND
Le système passe en mode interruption/veille.
WIA_EVENT_POWER_RESUME
Le système se réveille à partir du mode interruption/veille.
Le pilote WIA doit restaurer les états d’attente d’interruption de tout événement après un retour d’une interruption. Cela garantit que les événements fonctionnent toujours lorsque le système se réveille.
L’exemple suivant montre une implémentation de la méthode IWiaMiniDrv::d rvNotifyPnpEvent .
HRESULT _stdcall CWIADevice::drvNotifyPnpEvent(
const GUID *pEventGUID,
BSTR bstrDeviceID,
ULONG ulReserved)
{
//
// If the caller did not pass in the correct parameters,
// then fail the call with E_INVALIDARG.
//
if ((!pEventGUID)||(!bstrDeviceID)) {
return E_INVALIDARG;
}
HRESULT hr = S_OK;
if(*pEventGUID == WIA_EVENT_POWER_SUSPEND) {
//
// disable any driver activity to make sure we properly
// shut down (the driver is not being unloaded, just disabled)
//
} else if(*pEventGUID == WIA_EVENT_POWER_RESUME) {
//
// reestablish any event notifications to make sure we properly
// set up any event waiting status using the WIA service supplied
// event handle
//
if(m_EventOverlapped.hEvent) {
//
// call ourselves with the cached EVENT handle given to
// the WIA driver by the WIA service.
//
SetNotificationHandle(m_EventOverlapped.hEvent);
}
}
return hr;
}