Partager via


Interface IBackgroundCopyCallback (bits.h)

Implémentez l’interface IBackgroundCopyCallback pour recevoir une notification indiquant qu’un travail est terminé, qu’il a été modifié ou qu’il est en erreur. Les clients utilisent cette interface au lieu d’interroger la status du travail.

Héritage

L’interface IBackgroundCopyCallback hérite de l’interface IUnknown. IBackgroundCopyCallback a également les types de membres suivants :

Méthodes

L’interface IBackgroundCopyCallback possède ces méthodes.

 
IBackgroundCopyCallback ::JobError

BITS appelle votre implémentation de la méthode JobError lorsque l’état du travail devient BG_JOB_STATE_ERROR.
IBackgroundCopyCallback ::JobModification

BITS appelle votre implémentation de la méthode JobModification lorsque le travail a été modifié.
IBackgroundCopyCallback ::JobTransferred

BITS appelle votre implémentation de la méthode JobTransferred lorsque tous les fichiers du travail ont été transférés avec succès.

Remarques

Pour recevoir des notifications, appelez la méthode IBackgroundCopyJob ::SetNotifyInterface pour spécifier le pointeur d’interface vers votre implémentation IBackgroundCopyCallback . Pour spécifier les notifications que vous souhaitez recevoir, appelez la méthode IBackgroundCopyJob ::SetNotifyFlags .

BITS appelle vos rappels tant que le pointeur d’interface est valide. L’interface de notification n’est plus valide lorsque votre application se termine ; BITS ne conserve pas l’interface de notification. Par conséquent, le processus d’initialisation de votre application doit appeler la méthode SetNotifyInterface sur les travaux existants pour lesquels vous souhaitez recevoir une notification.

BITS garantit d’appeler votre rappel au moins une fois, même si l’inscription se produit après l’événement. Par exemple, si vous demandez la notification d’un transfert de travail après le transfert, vous recevez le rappel du travail transféré. En outre, si un travail a reçu une notification et que le pointeur n’est plus valide par la suite, ce travail reçoit une autre notification si vous définissez ultérieurement le pointeur d’interface sur ce travail.

Vous devez implémenter toutes les méthodes de l’interface IBackgroundCopyCallback . Par exemple, si vous ne vous inscrivez pas au rappel de modification de travail, la méthode JobModification doit toujours retourner S_OK.

Les rappels JobModification sont lancés à l’aide de threads de faible priorité, tandis que les rappels JobTransferred et JobError sont lancés à l’aide de threads de priorité supérieure. Il est donc possible que, pendant que certains rappels JobModification soient en attente, le rappel JobTransferred soit d’abord reçu par le client, bien qu’il soit lancé après les rappels JobModification en attente.

BITS prend en charge jusqu’à quatre notifications simultanées par utilisateur. Si une ou plusieurs applications bloquent le retour des quatre notifications d’un utilisateur, une application s’exécutant en tant qu’utilisateur ne recevra pas de notifications tant qu’une ou plusieurs notifications de blocage ne seront pas retournées. Pour réduire le risque que votre rappel bloque d’autres notifications, gardez votre implémentation courte.

Si un administrateur prend possession du travail, les rappels de notification sont effectués dans le contexte de l’utilisateur qui a demandé la notification.

Si votre application utilise le modèle d’appartement à thread unique , vos méthodes de rappel peuvent devenir réentrées si vous appelez des objets COM à partir de votre méthode de rappel. Par exemple, si vous appelez IBackgroundCopyJob ::GetProgress à partir de votre rappel JobModification , BITS peut envoyer une autre notification de modification de votre travail pendant que vous traitez toujours la notification actuelle. S’il n’est pas important pour votre application de répondre à chaque rappel JobModification , vous pouvez ignorer les rappels entrants, comme illustré dans l’exemple suivant.

//A member variable is used to determine if the callback
//is already processing another job modification callback.
LONG m_PendingJobModificationCount = 0;

//If you are already processing a callback, ignore this notification.
if (InterlockedCompareExchange(&m_PendingJobModificationCount, 1, 0) == 1)
{
  return S_OK;
}

...  //processing the current notification

m_PendingJobModificationCount = 0;
return hr;

Exemples

L’exemple suivant montre une implémentation IBackgroundCopyCallback . Pour obtenir un exemple qui appelle cette implémentation, consultez la méthode IBackgroundCopyJob ::SetNotifyInterface .

#define TWO_GB 2147483648    // 2GB


class CNotifyInterface : public IBackgroundCopyCallback
{
  LONG m_lRefCount;

public:
  //Constructor, Destructor
  CNotifyInterface() {m_lRefCount = 1;};
  ~CNotifyInterface() {};

  //IUnknown
  HRESULT __stdcall QueryInterface(REFIID riid, LPVOID *ppvObj);
  ULONG __stdcall AddRef();
  ULONG __stdcall Release();

  //IBackgroundCopyCallback methods
  HRESULT __stdcall JobTransferred(IBackgroundCopyJob* pJob);
  HRESULT __stdcall JobError(IBackgroundCopyJob* pJob, IBackgroundCopyError* pError);
  HRESULT __stdcall JobModification(IBackgroundCopyJob* pJob, DWORD dwReserved);
};

HRESULT CNotifyInterface::QueryInterface(REFIID riid, LPVOID* ppvObj) 
{
  if (riid == __uuidof(IUnknown) || riid == __uuidof(IBackgroundCopyCallback)) 
  {
    *ppvObj = this;
  }
  else
  {
    *ppvObj = NULL;
    return E_NOINTERFACE;
  }

  AddRef();
  return NOERROR;
}

ULONG CNotifyInterface::AddRef() 
{
  return InterlockedIncrement(&m_lRefCount);
}

ULONG CNotifyInterface::Release() 
{
  ULONG  ulCount = InterlockedDecrement(&m_lRefCount);

  if(0 == ulCount) 
  {
    delete this;
  }

  return ulCount;
}

HRESULT CNotifyInterface::JobTransferred(IBackgroundCopyJob* pJob)
{
  HRESULT hr;

  //Add logic that will not block the callback thread. If you need to perform
  //extensive logic at this time, consider creating a separate thread to perform
  //the work.

  hr = pJob->Complete();
  if (FAILED(hr))
  {
    //Handle error. BITS probably was unable to rename one or more of the 
    //temporary files. See the Remarks section of the IBackgroundCopyJob::Complete 
    //method for more details.
  }

  //If you do not return S_OK, BITS continues to call this callback.
  return S_OK;
}

HRESULT CNotifyInterface::JobError(IBackgroundCopyJob* pJob, IBackgroundCopyError* pError)
{
  HRESULT hr;
  BG_FILE_PROGRESS Progress;
  BG_ERROR_CONTEXT Context;
  HRESULT ErrorCode = S_OK;
  WCHAR* pszJobName = NULL;
  WCHAR* pszErrorDescription = NULL;
  BOOL IsError = TRUE;

  //Use pJob and pError to retrieve information of interest. For example,
  //if the job is an upload reply, call the IBackgroundCopyError::GetError method 
  //to determine the context in which the job failed. If the context is 
  //BG_JOB_CONTEXT_REMOTE_APPLICATION, the server application that received the 
  //upload file failed.

  hr = pError->GetError(&Context, &ErrorCode);

  //If the proxy or server does not support the Content-Range header or if
  //antivirus software removes the range requests, BITS returns BG_E_INSUFFICIENT_RANGE_SUPPORT.
  //This implementation tries to switch the job to foreground priority, so
  //the content has a better chance of being successfully downloaded.
  if (BG_E_INSUFFICIENT_RANGE_SUPPORT == ErrorCode)
  {
    hr = pError->GetFile(&pFile);
    hr = pFile->GetProgress(&Progress);
    if (BG_SIZE_UNKNOWN == Progress.BytesTotal)
    {
      //The content is dynamic, do not change priority. Handle as an error.
    }
    else if (Progress.BytesTotal > TWO_GB)
    {
      // BITS requires range requests support if the content is larger than 2 GB.
      // For these scenarios, BITS uses 2 GB ranges to download the file,
      // so switching to foreground priority will not help.

    }
    else
    {
      hr = pJob->SetPriority(BG_JOB_PRIORITY_FOREGROUND);
      hr = pJob->Resume();
      IsError = FALSE;
    }

    pFile->Release();
  }

  if (TRUE == IsError)
  {
    hr = pJob->GetDisplayName(&pszJobName);
    hr = pError->GetErrorDescription(LANGIDFROMLCID(GetThreadLocale()), &pszErrorDescription);

    if (pszJobName && pszErrorDescription)
    {
      //Do something with the job name and description. 
    }

    CoTaskMemFree(pszJobName);
    CoTaskMemFree(pszErrorDescription);
  }

  //If you do not return S_OK, BITS continues to call this callback.
  return S_OK;
}

HRESULT CNotifyInterface::JobModification(IBackgroundCopyJob* pJob, DWORD dwReserved)
{
  HRESULT hr;
  WCHAR* pszJobName = NULL;
  BG_JOB_PROGRESS Progress;
  BG_JOB_STATE State;

  hr = pJob->GetDisplayName(&pszJobName);
  if (SUCCEEDED(hr))
  {
    hr = pJob->GetProgress(&Progress);
    if (SUCCEEDED(hr))
    {
      hr = pJob->GetState(&State);
      if (SUCCEEDED(hr))
      {
        //Do something with the progress and state information.
        //BITS generates a high volume of modification
        //callbacks. Use this callback with discretion. Consider creating a timer and 
        //polling for state and progress information.
      }
    }
    CoTaskMemFree(pszJobName);
  }

  return S_OK;
}

Configuration requise

Condition requise Valeur
Client minimal pris en charge Windows XP
Serveur minimal pris en charge Windows Server 2003
Plateforme cible Windows
En-tête bits.h

Voir aussi

IBackgroundCopyJob

IBackgroundCopyJob ::SetNotifyFlags

IBackgroundCopyJob ::SetNotifyInterface