Condividi tramite


Caricamento e scaricamento di un minidriver WIA

Dopo l'installazione del driver di dispositivo WIA, il servizio WIA tenta di caricarlo per la prima volta. Il metodo IStiUSD::Initialize di WIA minidriver viene chiamato e deve eseguire le attività seguenti:

  1. Controllare la modalità di trasferimento per determinare la finalità del chiamante per l'inizializzazione di questo driver di dispositivo. Questa operazione viene eseguita chiamando il metodo IStiDeviceControl::GetMyDeviceOpenMode .

  2. Ottenere il nome della porta del dispositivo installato, in modo che questo driver possa chiamare CreateFile (documentato nella Microsoft Windows SDK) sulla porta appropriata per accedere al dispositivo. A tale scopo, chiamare il metodo IStiDeviceControl::GetMyDevicePortName .

  3. Leggere le impostazioni del Registro di sistema specifiche del dispositivo scritte durante l'installazione del dispositivo. A tale scopo, usare il parametro hParametersKey passato a IStiUSD::Initialize.

Il servizio WIA chiama il metodo IStiUSD::Initialize al primo caricamento del driver. Il metodo IStiUSD::Initialize viene chiamato anche quando un client usa le DDI di STI legacy e chiama il metodo IStillImage::CreateDevice .

Il metodo IStiUSD::Initialize deve inizializzare il driver WIA e il dispositivo da usare. I driver WIA possono archiviare il puntatore all'interfaccia IStiDeviceControl , se necessario in un secondo momento. Il metodo IStiDeviceControl::AddRef deve essere chiamato prima di archiviare questa interfaccia. Se non è necessario archiviare l'interfaccia, ignorarla. Non rilasciare prima l'interfaccia IStiDeviceControl se non hai chiamato IStiDeviceControl::AddRef. Ciò potrebbe causare risultati imprevedibili. L'interfaccia COM IStiDeviceControl è necessaria per ottenere informazioni sulle porte del dispositivo. Il nome della porta usato in una chiamata alla funzione CreateFile può essere ottenuto chiamando il metodo IStiDeviceControl::GetMyDevicePortName . Per i dispositivi su porte condivise, ad esempio i dispositivi porta seriale, l'apertura della porta in IStiUSD::Initialize non è consigliata. La porta deve essere aperta solo nelle chiamate a IStiUSD::LockDevice. La chiusura delle porte deve essere controllata internamente per fornire un accesso rapido. L'apertura e la chiusura in IStiUSD::LockDevice e IStiUSD::UnLockDevice sono molto inefficienti. CreateFile può causare un ritardo che rende il dispositivo lento e non risponde all'utente.

Se un driver WIA non può supportare più chiamate CreateFile sulla stessa porta del dispositivo, è necessario chiamare il metodo IStiDeviceControl::GetMyDeviceOpenMode .

Il driver WIA deve controllare il valore della modalità restituita per il flag STI_DEVICE_CREATE_DATA e aprire di conseguenza la porta.

Se la porta del dispositivo deve essere aperta, deve essere usata una chiamata a CreateFile . Quando si apre una porta, è necessario usare il flag FILE_FLAG_OVERLAPPED. In questo modo è possibile usare la struttura OVERLAPPED (descritta nella documentazione di Windows SDK) durante l'accesso al dispositivo. L'uso di operazioni di I/O sovrapposte consente di controllare l'accesso reattivo all'hardware. Quando viene rilevato un problema, il driver WIA può chiamare CancelIo (descritto nella documentazione di Windows SDK) per arrestare l'accesso hardware corrente.

Nell'esempio seguente viene illustrata un'implementazione del metodo 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;
}

Il servizio WIA chiama IStiUSD::GetCapabilities dopo una chiamata riuscita al metodo IStiUSD::Initialize . IStiUSD::GetCapabilities fornisce quindi la struttura STI_USD_CAPS con informazioni sulla versione sti, flag di supporto WIA (flag di bit che indicano le funzionalità del driver) ed eventuali requisiti di evento.

L'esempio seguente mostra un'implementazione di 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;
}