Partager via


Chargement et déchargement d’un minidriver WIA

Une fois le pilote de périphérique WIA installé, le service WIA tente de le charger pour la première fois. La méthode IStiUSD::Initialize du minidriver WIA est appelée et doit effectuer les tâches suivantes :

  1. Vérifiez le mode de transfert pour déterminer l’intention de l’appelant d’initialiser ce pilote de périphérique. Pour ce faire, appelez la méthode IStiDeviceControl::GetMyDeviceOpenMode .

  2. Obtenez le nom de port de l’appareil installé, afin que ce pilote puisse appeler CreateFile (documenté dans le Microsoft Windows SDK) sur le port approprié pour accéder à l’appareil. Pour ce faire, appelez la méthode IStiDeviceControl::GetMyDevicePortName .

  3. Lire les paramètres de Registre propres à l’appareil écrits lors de l’installation de l’appareil. Pour ce faire, utilisez le paramètre hParametersKey passé à IStiUSD::Initialize.

Le service WIA appelle la méthode IStiUSD::Initialize lors du premier chargement du pilote. La méthode IStiUSD::Initialize est également appelée lorsqu’un client utilise les DDIs STI hérités et appelle la méthode IStillImage::CreateDevice .

La méthode IStiUSD::Initialize doit initialiser le pilote WIA et le périphérique à utiliser. Les pilotes WIA peuvent stocker le pointeur d’interface IStiDeviceControl s’ils en ont besoin ultérieurement. La méthode IStiDeviceControl::AddRef doit être appelée avant de stocker cette interface. Si vous n’avez pas besoin de stocker l’interface, ignorez-la. Ne relâchez pas l’interface IStiDeviceControl si vous n’avez pas appelé IStiDeviceControl::AddRef en premier. Cela peut entraîner des résultats imprévisibles. L’interface COM IStiDeviceControl est nécessaire pour obtenir des informations sur les ports de l’appareil. Le nom de port utilisé dans un appel à la fonction CreateFile peut être obtenu en appelant la méthode IStiDeviceControl::GetMyDevicePortName . Pour les appareils sur des ports partagés, tels que les appareils de port série, l’ouverture du port dans IStiUSD::Initialize n’est pas recommandée. Le port doit être ouvert uniquement dans les appels à IStiUSD::LockDevice. La fermeture des ports doit être contrôlée en interne pour fournir un accès rapide. (L’ouverture et la fermeture dans IStiUSD::LockDevice et IStiUSD::UnLockDevice sont très inefficaces. CreateFile peut entraîner un retard qui fait apparaître l’appareil comme lent et ne répond pas à l’utilisateur.)

Si un pilote WIA ne peut pas prendre en charge plusieurs appels CreateFile sur le même port d’appareil, la méthode IStiDeviceControl::GetMyDeviceOpenMode doit être appelée.

Le pilote WIA doit case activée la valeur de mode retournée pour l’indicateur STI_DEVICE_CREATE_DATA et ouvrir le port en conséquence.

Si le port de l’appareil doit être ouvert, un appel à CreateFile doit être utilisé. Lors de l’ouverture d’un port, l’indicateur FILE_FLAG_OVERLAPPED doit être utilisé. Cela permet d’utiliser la structure CHEVAUCHEMENT (décrite dans la documentation du SDK Windows) lors de l’accès à l’appareil. L’utilisation d’E/S superposées permet de contrôler l’accès réactif au matériel. Lorsqu’un problème est détecté, le pilote WIA peut appeler CancelIo (décrit dans la documentation du SDK Windows) pour arrêter tout accès matériel actuel.

L’exemple suivant montre une implémentation de la méthode 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;
}

Le service WIA appelle IStiUSD::GetCapabilities après un appel réussi à la méthode IStiUSD::Initialize . IStiUSD::GetCapabilities fournit ensuite la structure de STI_USD_CAPS avec des informations de version STI, des indicateurs de prise en charge WIA (indicateurs de bits indiquant des fonctionnalités de pilote) et des exigences d’événement.

L’exemple suivant montre une implémentation 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;
}