Delen via


Ondersteuning voor interrupt-gebeurtenissen toevoegen

Ga als volgt te werk om uw WIA-stuurprogramma goed in te stellen om onderbrekingsgebeurtenissen te rapporteren:

  1. Stel Capabilities=0x31 in het INF-bestand van het apparaat in. (Zie INF-bestanden voor WIA-apparaten voor meer informatie.)

  2. Rapport STI_GENCAP_NOTIFICATIONS en STI_USD_GENCAP_NATIVE_PUSHSUPPORT in de methode IStiUSD::GetCapabilities.

  3. Alle ondersteunde gebeurtenissen rapporteren in de methode IWiaMiniDrv::drvGetCapabilities.

  4. Cache en gebruik de eventhandle die is doorgegeven in de methode IStiUSD::SetNotificationHandle. Dit is de gebeurtenishandle die het apparaat signaleert, of de WIA-minidriver direct gebruikmaakt van SetEvent (beschreven in de Microsoft Windows SDK-documentatie). Met deze methode start u de wachtstatus van het WIA-apparaat.

  5. Rapporteer de juiste reactie op gebeurtenisinformatie in de methode IStiUSD::GetNotificationData.

In de volgende twee voorbeelden ziet u hoe u uw apparaat configureert voor interrupts met implementaties van de methoden IWiaMiniDrv::drvGetCapabilities en IStiUSD::SetNotificationHandle.

Notitie Het is belangrijk om overlappende I/O-aanroepen te gebruiken met alle activiteiten met betrekking tot de kernelmodusstuurprogramma's. Hierdoor worden juiste time-outs en annuleringen van apparaataanvragen mogelijk gemaakt.

Uitleg van de IWiaMiniDrv::drvGetCapabilities-implementatie

De WIA-service roept de methode IWiaMiniDrv::d rvGetCapabilities aan om de door het WIA-apparaat ondersteunde gebeurtenissen en opdrachten te verkrijgen. Het WIA-stuurprogramma moet eerst de binnenkomende lFlags-parameter bekijken om te bepalen welke aanvraag het moet beantwoorden.

Het WIA-stuurprogramma moet geheugen toewijzen (om te worden gebruikt door het WIA-stuurprogramma en door het stuurprogramma vrijgemaakt) om een matrix van WIA_DEV_CAP_DRV structuren te bevatten. Geef in de aanroep van de IWiaMiniDrv::d rvGetCapabilities een aanwijzer door naar de geheugenlocatie die het adres van het toegewezen WIA-stuurprogramma bevat in de parameter ppCapabilities .

Notitie De WIA-service maakt dit geheugen niet vrij. Het is belangrijk dat het WIA-stuurprogramma het toegewezen geheugen beheert.

In het volgende voorbeeld ziet u een implementatie van de methode 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;
}

De methode IStiUSD::SetNotificationHandle wordt aangeroepen door de WIA-service of intern door dit stuurprogramma om gebeurtenismeldingen te starten of te stoppen. De WIA-service geeft een geldige ingang door die is gemaakt met CreateEvent (beschreven in de Microsoft Windows SDK-documentatie), waarmee wordt aangegeven dat het WIA-stuurprogramma deze ingang moet signaleren wanneer er een gebeurtenis optreedt in de hardware.

NULL kan worden doorgegeven aan de methode IStiUSD::SetNotificationHandle. NULL geeft aan dat de WIA minidriver bedoeld is om alle activiteit van het apparaat te stoppen en eventuele wachtbewerkingen voor gebeurtenissen af te sluiten.

In het volgende voorbeeld toont een implementatie van de methode 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;
}

Wanneer de WIA-minidriver of een WIA-apparaat een gebeurtenis heeft gedetecteerd en gesignaleerd, roept de WIA-service de methode IStiOPGEGEVEN::GetNotificationData aan. Het is in deze methode dat de WIA minidriver de details moet rapporteren van de gebeurtenis die heeft plaatsgevonden.

De WIA-service roept de methode IStiOPGEGEVEN::GetNotificationData aan om informatie op te halen over een gebeurtenis die zojuist is gesignaleerd. De methode IStiUSD::GetNotificationData kan worden aangeroepen als resultaat van een van de twee gebeurtenisbewerkingen.

  1. IStiUSD::GetStatus heeft gemeld dat er een gebeurtenis in behandeling was door de STI_EVENTHANDLING_PENDING-vlag in te stellen in de STI_DEVICE_STATUS structuur.

  2. De hEvent-handle die is doorgegeven door IStiUSD::SetNotificationHandle is gesignaleerd door de hardware of door SetEvent aan te roepen (beschreven in de Microsoft Windows SDK-documentatie).

De WIA-chauffeur is verantwoordelijk voor het invullen van de STINOTIFY-structuur

In het volgende voorbeeld ziet u een implementatie van de IStiUSD::GetNotificationData methode.

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;
}

Interruptgebeurtenissen kunnen op elk gewenst moment worden gestopt door NULL door te geven als gebeurtenis-handle. De minidriver moet dit interpreteren als een signaal om eventuele wachtstatussen op het hardwareapparaat te stoppen.

De methode IWiaMiniDrv::d rvNotifyPnpEvent kan energiebeheergebeurtenissen ontvangen die van invloed zijn op de wachtstatus van gebeurtenissen.

De WIA-service roept de methode IWiaMiniDrv::d rvNotifyPnpEvent aan en verzendt een WIA_EVENT_POWER_SUSPEND gebeurtenis wanneer het systeem op het punt staat in een slaapstand te worden geplaatst. Als deze aanroep plaatsvindt, is het apparaat mogelijk al buiten de wachtstatus. Met slaapstanden worden stuurprogramma's in de kernelmodus automatisch geactiveerd om uit een wachtstatus te komen, om het systeem deze energiezuinige staat te laten invoeren. Wanneer het systeem wordt hervat vanuit de slaapstand, verzendt de WIA-service het WIA_EVENT_POWER_RESUME-evenement. Op dit moment moet de WIA-minidriver de wachtstatus van de interruptgebeurtenis herstellen. Zie Systeemstatussen en Apparaatstroomstatussen voor meer informatie over slaapstandstatussen.

Het wordt aanbevolen dat de WIA-minidriver de gebeurtenishandgreep cachet die in eerste instantie is doorgegeven aan de IStiUSD::SetNotificationHandle-methode, zodat deze opnieuw kan worden gebruikt wanneer het systeem ontwaakt uit slaap- of sluimerstand.

De WIA-service roept de methode IStiUSD::SetNotificationHandleniet aan nadat het systeem hervat is. Het wordt aanbevolen dat de minidriver zijn IStiUSD::SetNotificationHandle-methode aanroept, waarbij de gecacheerde gebeurtenishandle wordt doorgegeven.

De WIA-service roept de methode IWiaMiniDrv::d rvNotifyPnpEvent aan wanneer systeemgebeurtenissen optreden. Het WIA-stuurprogramma moet de parameter pEventGUID controleren om te bepalen welke gebeurtenis wordt verwerkt.

Enkele veelvoorkomende gebeurtenissen die moeten worden verwerkt, zijn:

WIA_EVENT_POWER_SUSPEND
Het systeem gaat in de slaapstand/onderbrekingsmodus.

WIA_EVENT_POWER_RESUME
Het systeem ontwaakt uit de standby-/slaapstand.

Het WIA-stuurprogramma moet de wachtstatussen van eventonderbrekingen herstellen nadat het is teruggekeerd van een onderbreking. Dit zorgt ervoor dat de gebeurtenissen nog steeds functioneren wanneer het systeem wakker wordt.

In het volgende voorbeeld ziet u een implementatie van de methode 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;
}