인터럽트 이벤트 지원 추가
인터럽트 이벤트를 보고하도록 WIA 드라이버를 올바르게 설정하려면 다음을 수행합니다.
디바이스의 INF 파일에서 Capabilities=0x31 설정합니다. 자세한 내용은 WIA 디바이스용 INF 파일을 참조하세요 .
IStiUSD::GetCapabilities 메서드의 보고서 STI_GENCAP_NOTIFICATIONS 및 STI_USD_GENCAP_NATIVE_PUSHSUPPORT.
IWiaMiniDrv::d rvGetCapabilities 메서드에서 지원되는 모든 이벤트를 보고합니다.
IStiUSD::SetNotificationHandle 메서드에 전달된 이벤트 핸들을 캐시하고 사용합니다. 디바이스가 신호를 전송하는 이벤트 핸들이거나, SetEvent를 사용하여 WIA 미니드라이버가 직접 신호를 보냅니다(Microsoft Windows SDK 설명서에 설명됨). WIA 디바이스의 대기 상태를 시작하는 것은 이 메서드입니다.
IStiUSD::GetNotificationData 메서드에서 적절한 이벤트 정보 응답을 보고합니다.
다음 두 예제에서는 IWiaMiniDrv::d rvGetCapabilities 및 IStiUSD::SetNotificationHandle 메서드의 구현을 사용하여 인터럽트를 위해 디바이스를 구성하는 방법을 보여 줍니다.
참고 커널 모드 드라이버와 관련된 모든 활동에서 겹치는 I/O 호출을 사용하는 것이 중요합니다. 이렇게 하면 적절한 시간 제한 및 디바이스 요청 취소가 허용됩니다.
IWiaMiniDrv::d rvGetCapabilities 구현에 대한 설명
WIA 서비스는 IWiaMiniDrv::d rvGetCapabilities 메서드를 호출하여 WIA 디바이스 지원 이벤트 및 명령을 가져옵니다. WIA 드라이버는 먼저 들어오는 lFlags 매개 변수를 확인하여 응답해야 하는 요청을 결정해야 합니다.
WIA 드라이버는 WIA_DEV_CAP_DRV 구조의 배열을 포함하도록 메모리를 할당해야 합니다(WIA 드라이버에서 사용 및 해제). IWiaMiniDrv::d rvGetCapabilities 호출에서 ppCapabilities 매개 변수에 WIA 드라이버 할당 메모리의 주소를 포함하는 메모리 위치에 대한 포인터를 전달합니다.
참고 WIA 서비스는 이 메모리를 해제하지 않습니다. WIA 드라이버는 할당된 메모리를 관리하는 것이 중요합니다.
다음 예제에서는 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;
}
IStiUSD::SetNotificationHandle 메서드는 WIA 서비스 또는 내부적으로 이 드라이버에 의해 호출되어 이벤트 알림을 시작하거나 중지합니다. WIA 서비스는 CreateEvent(Microsoft Windows SDK 설명서에 설명됨)를 사용하여 만든 유효한 핸들을 전달하며, 이는 WIA 드라이버가 하드웨어에서 이벤트가 발생할 때 이 핸들에 신호를 보낼 것임을 나타냅니다.
NULL 은 IStiUSD::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 메서드를 호출할 수 있습니다.
IStiUSD::GetStatus 는 STI_DEVICE_STATUS 구조에서 STI_EVENTHANDLING_PENDING 플래그를 설정하여 보류 중인 이벤트가 있다고 보고했습니다.
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::d rvNotifyPnpEvent 메서드는 이벤트 대기 상태에 영향을 주는 전원 관리 이벤트를 수신할 수 있습니다.
WIA 서비스는 IWiaMiniDrv::d rvNotifyPnpEvent 메서드를 호출하고 시스템이 절전 모드 상태에 놓이려고 할 때 WIA_EVENT_POWER_SUSPEND 이벤트를 보냅니다. 이 호출이 발생하면 디바이스가 이미 대기 상태가 아닐 수 있습니다. 절전 모드 상태는 시스템이 이 전원이 켜진 상태로 전환될 수 있도록 커널 모드 드라이버를 자동으로 트리거하여 대기 상태를 종료합니다. 시스템이 절전 모드 상태에서 다시 시작되면 WIA 서비스는 WIA_EVENT_POWER_RESUME 이벤트를 보냅니다. 이때 WIA 미니드라이버가 인터럽트 이벤트 대기 상태를 다시 설정해야 합니다. 절전 모드 상태에 대한 자세한 내용은 시스템 전원 상태 및 디바이스 전원 상태를 참조하세요.
WIA 미니드라이버는 시스템이 절전 모드 또는 최대 절전 모드에서 해제될 때 다시 사용할 수 있도록 처음에 IStiUSD::SetNotificationHandle 메서드에 전달된 이벤트 핸들을 캐시하는 것이 좋습니다.
WIA 서비스는 시스템이 다시 시작된 후 IStiUSD::SetNotificationHandle 메서드를 호출하지 않습니다. 미니드라이버가 IStiUSD::SetNotificationHandle 메서드를 호출하여 캐시된 이벤트 핸들을 전달하는 것이 좋습니다.
WIA 서비스는 시스템 이벤트가 발생할 때 IWiaMiniDrv::d rvNotifyPnpEvent 메서드를 호출합니다. WIA 드라이버는 pEventGUID 매개 변수를 검사 처리 중인 이벤트를 결정해야 합니다.
처리해야 하는 몇 가지 일반적인 이벤트는 다음과 같습니다.
WIA_EVENT_POWER_SUSPEND
시스템이 일시 중단/절전 모드로 전환됩니다.
WIA_EVENT_POWER_RESUME
시스템이 일시 중단/절전 모드에서 해제됩니다.
WIA 드라이버는 일시 중단에서 반환된 후 이벤트 인터럽트 대기 상태를 복원해야 합니다. 이렇게 하면 시스템이 절전 모드에서 해제될 때 이벤트가 계속 작동합니다.
다음 예제에서는 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;
}