次の方法で共有


割り込みイベントのサポートを追加

割り込みイベントを報告するように WIA ドライバーを適切に設定するには、次の操作を行います。

  1. デバイスの INF ファイルで Capabilities=0x31 を設定します。 ( 詳細については WIA デバイス 用の INF ファイル をご確認ください。)

  2. IStiUSD::GetCapabilities メソッドで STI_GENCAP_NOTIFICATIONS とSTI_USD_GENCAP_NATIVE_PUSHSUPPORT を報告します。

  3. IWiaMiniDrv::drvGetCapabilities メソッドでサポートされているすべてのイベントを報告します。

  4. IStiUSD::SetNotificationHandle メソッドで渡されたイベント ハンドルをキャッシュして使用します。 これは、デバイスが通知するイベント ハンドル、または SetEvent を使用して WIA ミニドライバーが直接通知するイベント ハンドルです (Microsoft Windows SDK ドキュメントで説明)。 このメソッドでは、WIA デバイスの待機状態を開始します。

  5. IStiUSD::GetNotificationData メソッドで 適切なイベント情報応答を報告します。

次の 2 つの例は、 IWiaMiniDrv::drvGetCapabilities メソッドと IStiUSD::SetNotificationHandle メソッドの実装を使用して、割り込み用にデバイスを構成する方法を示しています。

: カーネル モード ドライバーに関連するすべてのアクティビティで重複した I/O 呼び出しを使用することが重要です。 これにより、デバイス要求の適切なタイムアウトとキャンセルが可能になります。

IWiaMiniDrv::drvGetCapabilities 実装の説明

WIA サービスは、 IWiaMiniDrv::drvGetCapabilities メソッドを呼び出して、WIA デバイスでサポートされるイベントとコマンドを取得します。 WIA ドライバーは、最初に受信 lFlags パラメーターを調べて、応答する必要がある要求を決定する必要があります。

WIA ドライバーは、メモリを割り当てる必要があります (WIA ドライバーによって使用され、解放) WIA_DEV_CAP_DRV 構造体の配列を格納します。 IWiaMiniDrv::drvGetCapabilities の呼び出しで、 ppCapabilities パラメーターの WIA ドライバー割り当てメモリのアドレスを保持するメモリ位置へのポインターを渡します。

注: WIA サービスはこのメモリを解放しません。 WIA ドライバーが割り当てられたメモリを管理することが重要です。

次のコード例は IWiaMiniDrv::drvGetCapabilities メソッドの実装を示しています。

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

IStiUSD::SetNotificationHandle メソッドは、イベント通知を開始または停止するために、WIA サービスによって、またはこのドライバーによって内部的に呼び出されます。 WIA サービスは、 CreateEvent (Microsoft Windows SDK ドキュメントで説明) を使用して作成された有効なハンドルを渡します。これは、WIA ドライバーがハードウェアでイベントが発生したときにこのハンドルを通知することを示します。

NULLIStiUSD::SetNotificationHandle メソッドに渡すことができます。 NULL は、WIA ミニドライバーがすべてのデバイス アクティビティを停止し、イベント待機操作を終了することを示します。

次のコードは 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;
}

WIA ミニドライバーまたは WIA デバイスがイベントを検出して通知すると、WIA サービスは IStiUSD::GetNotificationData メソッドを呼び出します。 このメソッドでは、WIA ミニドライバーが発生したイベントの詳細を報告する必要があります。

WIA サービスは IStiUSD::GetNotificationData メソッドを呼び出して、通知されたイベントに関する情報を取得します。 IStiUSD::GetNotificationData メソッドは、2 つのイベント操作の結果として呼び出すことができます。

  1. IStiUSD::GetStatus は、 STI_DEVICE_STATUS 構造体に STI_EVENTHANDLING_PENDING フラグを設定して保留中のイベントがあることを報告しました。

  2. IStiUSD::SetNotificationHandle によって渡された hEvent ハンドルは、ハードウェアまたは SetEvent (Microsoft Windows SDK ドキュメントで説明) を呼び出すことによって通知されました。

WIA ドライバーは、 STINOTIFY 構造体の入力を担当します。

次のコードは 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;
}

割り込みイベントは、イベント ハンドルとして NULL を渡すことによって、いつでも停止できます。 ミニドライバーは、ハードウェア デバイス上の待機状態を停止する信号としてこれを解釈する必要があります。

IWiaMiniDrv::drvNotifyPnpEvent メソッドは、イベント待機状態に影響する電源管理イベントを受信できます。

WIA サービスは IWiaMiniDrv::drvNotifyPnpEvent メソッドを呼び出し、システムがスリープ状態になりようとしているときに WIA_EVENT_POWER_SUSPEND イベントを送信します。 この呼び出しが発生した場合、デバイスは既に待機状態から外れている可能性があります。 スリープ状態では、カーネル モード ドライバーが待機状態を終了して、システムがこの電源を切った状態に入れるように自動的にトリガーされます。 システムがスリープ状態から再開すると、WIA サービスは WIA_EVENT_POWER_RESUME イベントを送信します。 現時点では、WIA ミニドライバーは割り込みイベント待機状態を再確立する必要があります。 スリープ状態の詳細については、 「システムの電源状態」「デバイスの電源状態」 を参照してください。

WIA ミニドライバーは、システムがスリープ状態または休止状態から復帰したときに再利用できるように、最初に IStiUSD::SetNotificationHandle メソッドに渡されたイベント ハンドルをキャッシュすることをお勧めします。

WIA サービスは、システムの再開後に IStiUSD::SetNotificationHandle メソッドを呼び出し ません 。 ミニドライバーは、キャッシュされたイベント ハンドルを渡して、その IStiUSD::SetNotificationHandle メソッドを呼び出すことをお勧めします。

WIA サービスは、システム イベントが 発生したときに IWiaMiniDrv::drvNotifyPnpEvent メソッドを呼び出します。 WIA ドライバーは、処理されているイベントを決定する pEventGUID パラメーターをチェックする必要があります。

処理する必要がある一般的なイベントは次のとおりです。

WIA_EVENT_POWER_SUSPEND
システムは中断/スリープ モードになります。

WIA_EVENT_POWER_RESUME
システムが中断/スリープ モードから復帰しています。

WIA ドライバーは、中断から戻った後、イベント割り込み待機状態を復元する必要があります。 これにより、システムが起動したときにイベントが引き続き機能します。

次のコード例は IWiaMiniDrv::drvNotifyPnpEvent メソッドの実装を示しています。

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