WIA 미니드라이버 로드 및 언로드
WIA 디바이스 드라이버가 설치되면 WIA 서비스에서 처음으로 로드를 시도합니다. WIA 미니드라이버의 IStiUSD::Initialize 메서드가 호출되고 다음 작업을 수행해야 합니다.
전송 모드를 확인하여 이 디바이스 드라이버를 초기화하려는 호출자의 의도를 확인합니다. 이 작업은 IStiDeviceControl::GetMyDeviceOpenMode 메서드를 호출하여 수행됩니다.
설치된 디바이스의 포트 이름을 가져오면 이 드라이버가 적절한 포트에서 CreateFile(Microsoft Windows SDK 설명)을 호출하여 디바이스에 액세스할 수 있습니다. 이 작업은 IStiDeviceControl::GetMyDevicePortName 메서드를 호출하여 수행됩니다.
디바이스 설치 중에 작성된 디바이스별 레지스트리 설정을 읽습니다. 이 작업은 IStiUSD::Initialize에 전달된 hParametersKey 매개 변수를 사용하여 수행할 수 있습니다.
WIA 서비스는 드라이버가 처음 로드될 때 IStiUSD::Initialize 메서드를 호출합니다. IStiUSD::Initialize 메서드는 클라이언트가 레거시 STI DDIs를 사용하고 IStillImage::CreateDevice 메서드를 호출할 때도 호출됩니다.
IStiUSD::Initialize 메서드는 WIA 드라이버와 사용할 디바이스를 초기화해야 합니다. WIA 드라이버는 나중에 필요한 경우 IStiDeviceControl 인터페이스 포인터를 저장할 수 있습니다. 이 인터페이스를 저장하기 전에 IStiDeviceControl::AddRef 메서드를 호출해야 합니다. 인터페이스를 저장할 필요가 없는 경우 무시합니다. IStiDeviceControl::AddRef를 먼저 호출하지 않은 경우 IStiDeviceControl 인터페이스를 해제하지 마세요. 이로 인해 예측할 수 없는 결과가 발생할 수 있습니다. 디바이스의 포트에 대한 정보를 얻으려면 IStiDeviceControl COM 인터페이스 가 필요합니다. CreateFile 함수 호출에 사용되는 포트 이름은 IStiDeviceControl::GetMyDevicePortName 메서드를 호출하여 가져올 수 있습니다. 직렬 포트 디바이스와 같은 공유 포트의 디바이스의 경우 IStiUSD::Initialize 에서 포트를 여는 것은 권장되지 않습니다. 포트는 IStiUSD::LockDevice 호출에서만 열어야 합니다. 빠른 액세스를 제공하려면 포트 닫기를 내부적으로 제어해야 합니다. ( IStiUSD::LockDevice 및 IStiUSD::UnLockDevice 에서 열기 및 닫는 것은 매우 비효율적입니다. CreateFile 을 사용하면 디바이스가 느리고 사용자에게 응답하지 않는 것처럼 보이도록 지연될 수 있습니다.)
WIA 드라이버가 동일한 디바이스 포트에서 여러 CreateFile 호출을 지원할 수 없는 경우 IStiDeviceControl::GetMyDeviceOpenMode 메서드를 호출해야 합니다.
WIA 드라이버는 STI_DEVICE_CREATE_DATA 플래그에 대해 반환된 모드 값을 검사 그에 따라 포트를 열어야 합니다.
디바이스 포트를 열어야 하는 경우 CreateFile 호출을 사용해야 합니다. 포트를 열 때 FILE_FLAG_OVERLAPPED 플래그를 사용해야 합니다. 이렇게 하면 디바이스에 액세스할 때 OVERLAPPED 구조(Windows SDK 설명서에 설명됨)를 사용할 수 있습니다. 겹치는 I/O를 사용하면 하드웨어에 대한 반응형 액세스를 제어하는 데 도움이 됩니다. 문제가 감지되면 WIA 드라이버는 CancelIo (Windows SDK 설명서에 설명됨)를 호출하여 모든 현재 하드웨어 액세스를 중지할 수 있습니다.
다음 예제에서는 IStiUSD::Initialize 메서드의 구현을 보여 줍니다.
STDMETHODIMP CWIADevice::Initialize(
PSTIDEVICECONTROL pIStiDeviceControl,
DWORD dwStiVersion,
HKEY hParametersKey)
{
if (!pIStiDeviceControl) {
return STIERR_INVALID_PARAM;
}
HRESULT hr = S_OK;
//
// Get the mode of the device to check why we were created. status, data, or both...
//
DWORD dwMode = 0;
hr = pIStiDeviceControl->GetMyDeviceOpenMode(&dwMode);
if(FAILED(hr)){
return hr;
}
if(dwMode & STI_DEVICE_CREATE_DATA)
{
//
// device is being opened for data
//
}
if(dwMode & STI_DEVICE_CREATE_STATUS)
{
//
// device is being opened for status
//
}
if(dwMode & STI_DEVICE_CREATE_BOTH)
{
//
// device is being opened for both data and status
//
}
//
// Get the name of the device port to be used in a call to CreateFile().
//
WCHAR szDevicePortNameW[MAX_PATH];
memset(szDevicePortNameW,0,sizeof(szDevicePortNameW));
hr = pIStiDeviceControl->GetMyDevicePortName(szDevicePortNameW,
sizeof(szDevicePortNameW)/sizeof(WCHAR));
if(FAILED(hr)) {
return hr;
}
//
// Open kernel-mode device driver. Use the FILE_FLAG_OVERLAPPED flag
// for proper cancellation
// of kernel-mode operations and asynchronous file IO.
// The CancelIo() call will function properly if this flag is used.
// It is recommended to use this flag.
//
m_hDeviceDataHandle = CreateFileW(szDevicePortNameW,
GENERIC_READ | GENERIC_WRITE, // Access mask
0, // Share mode
NULL, // SA
OPEN_EXISTING, // Create disposition
FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED,
NULL );
m_dwLastOperationError = ::GetLastError();
hr = (m_hDeviceDataHandle != INVALID_HANDLE_VALUE) ?
S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,m_dwLastOperationError);
if (FAILED(hr)) {
return hr;
}
//
// Open DeviceData section to read driver specific information
//
HKEY hKey = hParametersKey;
HKEY hOpenKey = NULL;
if (RegOpenKeyEx(hKey, // handle to open key
TEXT("DeviceData"), // address of name of subkey to open
0, // options (must be NULL)
KEY_QUERY_VALUE|KEY_READ, // just want to QUERY a value
&hOpenKey // address of handle to open key
) == ERROR_SUCCESS) {
//
// This is where you read registry entries for your device.
// The DeviceData section is the proper place to put this
// information. Information about your device should
// have been written using the WIA device's .INF installation
// file.
// You can access this information from this location in the
// Registry. The WIA service owns the hParameters HKEY.
// DO NOT CLOSE THIS KEY. Always close any HKEYS opened by
// this WIA driver after you are finished.
//
//
// close registry key when finished, reading DeviceData information.
//
RegCloseKey(hOpenKey);
} else {
return E_FAIL;
}
return hr;
}
WIA 서비스는 IStiUSD:: Initialize 메서드를 성공적으로 호출한 후 IStiUSD:: GetCapabilities를 호출합니다. 그런 다음 IStiUSD::GetCapabilities 는 STI_USD_CAPS 구조에 STI 버전 정보, WIA 지원 플래그(드라이버 기능을 나타내는 비트 플래그) 및 이벤트 요구 사항을 제공합니다.
다음 예제에서는 IStiUSD::GetCapabilities의 구현을 보여 줍니다.
/********************************************************************\
* CWIADevice::GetCapabilities
* Remarks:
* This WIA driver sets the following capability flags:
* 1. STI_GENCAP_WIA - This driver supports WIA
* 2. STI_USD_GENCAP_NATIVE_PUSHSUPPORT - This driver supports push
* buttons
* 3. STI_GENCAP_NOTIFICATIONS - This driver requires the use of
* interrupt events.
*
\********************************************************************/
STDMETHODIMP CWIADevice::GetCapabilities(PSTI_USD_CAPS pUsdCaps)
{
//
// If the caller did not pass in the correct parameters,
// then fail the call with E_INVALIDARG.
//
if (!pUsdCaps) {
return E_INVALIDARG;
}
memset(pUsdCaps, 0, sizeof(STI_USD_CAPS));
pUsdCaps->dwVersion = STI_VERSION; // STI version
pUsdCaps->dwGenericCaps = STI_GENCAP_WIA| // WIA support
STI_USD_GENCAP_NATIVE_PUSHSUPPORT| // button support
STI_GENCAP_NOTIFICATIONS; // interrupt event support
return S_OK;
}