Partilhar via


Carregando e descarregando um minidriver WIA

Depois que o driver de dispositivo WIA é instalado, o serviço WIA tenta carregá-lo pela primeira vez. O método IStiUSD::Initialize do minidriver WIA é chamado e deve executar as seguintes tarefas:

  1. Verifique o modo de transferência para determinar a intenção do chamador de inicializar esse driver de dispositivo. Isso é feito chamando o método IStiDeviceControl::GetMyDeviceOpenMode .

  2. Obtenha o nome da porta do dispositivo instalado para que esse driver possa chamar CreateFile (documentado no SDK do Microsoft Windows) na porta adequada para acessar o dispositivo. Isso é feito chamando o método IStiDeviceControl::GetMyDevicePortName .

  3. Ler as configurações de registro específicas do dispositivo gravadas durante a instalação do dispositivo. Isso pode ser feito usando o parâmetro hParametersKey passado para IStiUSD::Initialize.

O serviço WIA chama o método IStiUSD::Initialize quando o driver é carregado pela primeira vez. O método IStiUSD::Initialize também é chamado quando um cliente usa os DDIs de STI herdados e chama o método IStillImage::CreateDevice .

O método IStiUSD::Initialize deve inicializar o driver WIA e o dispositivo para uso. Os drivers WIA podem armazenar o ponteiro da interface IStiDeviceControl se precisarem dele posteriormente. O método IStiDeviceControl::AddRef deve ser chamado antes de armazenar essa interface. Se você não precisar armazenar a interface, ignore-a. Nãolibere a interface IStiDeviceControl se você não tiver chamado IStiDeviceControl::AddRef primeiro. Isso pode causar resultados imprevisíveis. A interface COM IStiDeviceControl é necessária para obter informações sobre as portas do dispositivo. O nome da porta usado em uma chamada para a função CreateFile pode ser obtido chamando o método IStiDeviceControl::GetMyDevicePortName . Para dispositivos em portas compartilhadas, como dispositivos de porta serial, não é recomendável abrir a porta em IStiUSD::Initialize . A porta deve ser aberta somente em chamadas para IStiUSD::LockDevice. O fechamento das portas deve ser controlado internamente para fornecer acesso rápido. (Abrir e fechar em IStiUSD::LockDevice e IStiUSD::UnLockDevice é muito ineficiente. CreateFile pode causar um atraso ao fazer com que o dispositivo pareça lento e sem resposta para o usuário.)

Se um driver WIA não puder dar suporte a várias chamadas CreateFile na mesma porta do dispositivo, o método IStiDeviceControl::GetMyDeviceOpenMode deverá ser chamado.

O driver WIA deve marcar o valor de modo retornado para o sinalizador STI_DEVICE_CREATE_DATA e abrir a porta adequadamente.

Se a porta do dispositivo precisar ser aberta, uma chamada para CreateFile deverá ser usada. Ao abrir uma porta, o sinalizador FILE_FLAG_OVERLAPPED deve ser usado. Isso permite que a estrutura OVERLAPPED (descrita na documentação do SDK do Windows) seja usada ao acessar o dispositivo. O uso de E/S sobreposta ajudará a controlar o acesso responsivo ao hardware. Quando um problema é detectado, o driver WIA pode chamar CancelIo (descrito na documentação do SDK do Windows) para interromper todo o acesso de hardware atual.

O exemplo a seguir mostra uma implementação do método 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;
}

O serviço WIA chama IStiUSD::GetCapabilities após uma chamada bem-sucedida para o método IStiUSD::Initialize . IStiUSD::GetCapabilities fornece a estrutura STI_USD_CAPS com informações de versão de STI, sinalizadores de suporte wia (sinalizadores de bit indicando funcionalidades de driver) e quaisquer requisitos de evento.

O exemplo a seguir mostra uma implementação de 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;
}