Share via


Interfaz IBackgroundCopyCallback (bits.h)

Implemente la interfaz IBackgroundCopyCallback para recibir una notificación de que se ha completado un trabajo, se ha modificado o está en error. Los clientes usan esta interfaz en lugar de sondear el estado del trabajo.

Herencia

La interfaz IBackgroundCopyCallback hereda de la interfaz IUnknown . IBackgroundCopyCallback también tiene estos tipos de miembros:

Métodos

La interfaz IBackgroundCopyCallback tiene estos métodos.

 
IBackgroundCopyCallback::JobError

BITS llama a la implementación del método JobError cuando el estado del trabajo cambia a BG_JOB_STATE_ERROR.
IBackgroundCopyCallback::JobModification

BITS llama a la implementación del método JobModification cuando se ha modificado el trabajo.
IBackgroundCopyCallback::JobTransferred

BITS llama a la implementación del método JobTransferred cuando todos los archivos del trabajo se han transferido correctamente.

Comentarios

Para recibir notificaciones, llame al método IBackgroundCopyJob::SetNotifyInterface para especificar el puntero de interfaz a la implementación de IBackgroundCopyCallback . Para especificar qué notificaciones desea recibir, llame al método IBackgroundCopyJob::SetNotifyFlags .

BITS llamará a las devoluciones de llamada siempre que el puntero de interfaz sea válido. La interfaz de notificación ya no es válida cuando la aplicación finaliza; BITS no conserva la interfaz de notificación. Como resultado, el proceso de inicialización de la aplicación debe llamar al método SetNotifyInterface en los trabajos existentes para los que desea recibir la notificación.

BITS garantiza llamar a la devolución de llamada al menos una vez, incluso si el registro se produce después del evento. Por ejemplo, si solicita una notificación de una transferencia de trabajo después de que se haya producido la transferencia, recibirá la devolución de llamada transferida del trabajo. Además, si un trabajo recibió una notificación y el puntero ya no es válido, ese trabajo recibirá otra notificación si posteriormente establece el puntero de interfaz en ese trabajo.

Debe implementar todos los métodos de la interfaz IBackgroundCopyCallback . Por ejemplo, si no se registra para la devolución de llamada de modificación del trabajo, el método JobModification todavía debe devolver S_OK.

Las devoluciones de llamada jobModification se inician mediante subprocesos de prioridad baja, mientras que JobTransferred y las devoluciones de llamada jobError se inician mediante subprocesos de prioridad más alta. Por lo tanto, es posible que, aunque algunas devoluciones de llamada jobModification estén pendientes, el cliente recibe primero la devolución de llamada JobTransferred, aunque se inicia después de las devoluciones de llamada pendientes de JobModification.

BITS admite hasta cuatro notificaciones simultáneas por usuario. Si una o varias aplicaciones bloquean la devolución de las cuatro notificaciones de un usuario, una aplicación que se ejecuta como el mismo usuario no recibirá notificaciones hasta que se devuelvan una o varias de las notificaciones de bloqueo. Para reducir la posibilidad de que la devolución de llamada bloquee otras notificaciones, mantenga la implementación corta.

Si un administrador toma posesión del trabajo, las devoluciones de llamada de notificación se realizan en el contexto del usuario que solicitó la notificación.

Si la aplicación usa el modelo de apartamento de un solo subproceso , los métodos de devolución de llamada se pueden volver a reentrante si llama a objetos COM desde dentro del método de devolución de llamada. Por ejemplo, si llama a IBackgroundCopyJob::GetProgress desde dentro de la devolución de llamada jobModification , BITS puede enviar la devolución de llamada de modificación del trabajo otra notificación mientras sigue procesando la notificación actual. Si no es importante que la aplicación responda a cada devolución de llamada jobModification , puede omitir las devoluciones de llamada reentrantes, como se muestra en el ejemplo siguiente.

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

Ejemplos

En el ejemplo siguiente se muestra una implementación de IBackgroundCopyCallback . Para obtener un ejemplo que llama a esta implementación, vea el método 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;
}

Requisitos

Requisito Value
Cliente mínimo compatible Windows XP
Servidor mínimo compatible Windows Server 2003
Plataforma de destino Windows
Encabezado bits.h

Consulte también

IBackgroundCopyJob

IBackgroundCopyJob::SetNotifyFlags

IBackgroundCopyJob::SetNotifyInterface