다음을 통해 공유


WIA 미니드라이버 로드 및 언로드

WIA 디바이스 드라이버가 설치되면 WIA 서비스에서 처음으로 로드를 시도합니다. WIA 미니드라이버의 IStiUSD::Initialize 메서드가 호출되고 다음 작업을 수행해야 합니다.

  1. 전송 모드를 확인하여 이 디바이스 드라이버를 초기화하려는 호출자의 의도를 확인합니다. 이 작업은 IStiDeviceControl::GetMyDeviceOpenMode 메서드를 호출하여 수행됩니다.

  2. 설치된 디바이스의 포트 이름을 가져오면 이 드라이버가 적절한 포트에서 CreateFile(Microsoft Windows SDK 설명)을 호출하여 디바이스에 액세스할 수 있습니다. 이 작업은 IStiDeviceControl::GetMyDevicePortName 메서드를 호출하여 수행됩니다.

  3. 디바이스 설치 중에 작성된 디바이스별 레지스트리 설정을 읽습니다. 이 작업은 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::LockDeviceIStiUSD::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::GetCapabilitiesSTI_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;
}