Интерфейс IBackgroundCopyCallback (bits.h)

Реализуйте интерфейс IBackgroundCopyCallback , чтобы получать уведомления о том, что задание завершено, изменено или находится в состоянии ошибки. Клиенты используют этот интерфейс вместо опроса состояния задания.

Наследование

Интерфейс IBackgroundCopyCallback наследуется от интерфейса IUnknown . IBackgroundCopyCallback также содержит следующие типы элементов:

Методы

Интерфейс IBackgroundCopyCallback содержит следующие методы.

 
IBackgroundCopyCallback::JobError

BITS вызывает реализацию метода JobError, когда состояние задания изменяется на BG_JOB_STATE_ERROR.
IBackgroundCopyCallback::JobModification

BITS вызывает реализацию метода JobModification при изменении задания.
IBackgroundCopyCallback::JobTransferred

BITS вызывает реализацию метода JobTransferred, если все файлы в задании успешно переданы.

Комментарии

Чтобы получать уведомления, вызовите метод IBackgroundCopyJob::SetNotifyInterface , чтобы указать указатель интерфейса на реализацию IBackgroundCopyCallback . Чтобы указать, какие уведомления вы хотите получать, вызовите метод IBackgroundCopyJob::SetNotifyFlags .

BITS будет вызывать обратные вызовы, если указатель интерфейса является допустимым. Интерфейс уведомлений больше недействителен при завершении работы приложения; BITS не сохраняет интерфейс уведомления. В результате процесс инициализации приложения должен вызвать метод SetNotifyInterface для существующих заданий, для которых требуется получать уведомления.

BITS гарантирует, что обратный вызов будет вызываться по крайней мере один раз, даже если регистрация происходит после события. Например, если вы запросите уведомление о переносе задания после переноса, вы получите обратный вызов, переданный заданием. Кроме того, если задание получило уведомление и указатель становится недействительным, это задание получит другое уведомление, если позже вы настроите указатель интерфейса для этого задания.

Необходимо реализовать все методы интерфейса IBackgroundCopyCallback . Например, если вы не регистрируетесь для обратного вызова изменения задания, метод JobModification по-прежнему должен возвращать S_OK.

Обратные вызовы JobModification запускаются с использованием низкоприоритетных потоков, тогда как обратные вызовы JobTransferred и JobError запускаются с использованием потоков с более высоким приоритетом. Поэтому вполне возможно, что в то время как некоторые обратные вызовы JobModification находятся в ожидании, обратный вызов JobTransferred сначала будет получен клиентом, хотя он запускается после ожидающих обратных вызовов JobModification.

BITS поддерживает до четырех одновременных уведомлений для каждого пользователя. Если одно или несколько приложений блокируют возврат всех четырех уведомлений для пользователя, приложение, работающее от имени одного и того же пользователя, не будет получать уведомления до тех пор, пока не вернется одно или несколько блокирующих уведомлений. Чтобы снизить вероятность того, что обратный вызов блокирует другие уведомления, не закрывайте реализацию.

Если администратор становится владельцем задания, обратные вызовы уведомлений выполняются в контексте пользователя, который запросил уведомление.

Если приложение использует модель однопотокового подразделения , методы обратного вызова могут стать повторными при вызове COM-объектов из метода обратного вызова. Например, если вы вызываете IBackgroundCopyJob::GetProgress из обратного вызова JobModification , BITS может отправить обратное уведомление об изменении задания, пока вы все еще обрабатываете текущее уведомление. Если для приложения не важно отвечать на каждый обратный вызов JobModification , можно игнорировать обратные вызовы повторного входа, как показано в следующем примере.

//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;

Примеры

В следующем примере показана реализация IBackgroundCopyCallback . Пример, вызывающий эту реализацию, см. в разделе Метод 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;
}

Требования

Требование Значение
Минимальная версия клиента Windows XP
Минимальная версия сервера Windows Server 2003
Целевая платформа Windows
Header bits.h

См. также раздел

IBackgroundCopyJob

IBackgroundCopyJob::SetNotifyFlags

IBackgroundCopyJob::SetNotifyInterface