Condividi tramite


Interfaccia IBackgroundCopyCallback (bits.h)

Implementare l'interfaccia IBackgroundCopyCallback per ricevere la notifica che un processo è stato completato, è stato modificato o è in errore. I client usano questa interfaccia anziché eseguire il polling per lo stato del processo.

Ereditarietà

L'interfaccia IBackgroundCopyCallback eredita dall'interfaccia IUnknown . IBackgroundCopyCallback include anche questi tipi di membri:

Metodi

L'interfaccia IBackgroundCopyCallback include questi metodi.

 
IBackgroundCopyCallback::JobError

BITS chiama l'implementazione del metodo JobError quando lo stato del processo viene modificato in BG_JOB_STATE_ERROR.
IBackgroundCopyCallback::JobModification

BITS chiama l'implementazione del metodo JobModification quando il processo è stato modificato.
IBackgroundCopyCallback::JobTransferred

BITS chiama l'implementazione del metodo JobTransferred quando tutti i file nel processo sono stati trasferiti correttamente.

Commenti

Per ricevere notifiche, chiamare il metodo IBackgroundCopyJob::SetNotifyInterface per specificare il puntatore dell'interfaccia all'implementazione di IBackgroundCopyCallback . Per specificare quali notifiche si desidera ricevere, chiamare il metodo IBackgroundCopyJob::SetNotifyFlags .

BITS chiamerà i callback finché il puntatore dell'interfaccia è valido. L'interfaccia di notifica non è più valida quando l'applicazione termina; BITS non mantiene l'interfaccia di notifica. Di conseguenza, il processo di inizializzazione dell'applicazione deve chiamare il metodo SetNotifyInterface su tali processi esistenti per cui si vuole ricevere una notifica.

BITS garantisce di chiamare il callback almeno una volta, anche se la registrazione si verifica dopo l'evento. Ad esempio, se si richiede la notifica di un trasferimento del processo dopo che si è verificato il trasferimento, si riceverà il callback trasferito del processo. Inoltre, se un processo ha ricevuto una notifica e il puntatore successivamente non è più valido, tale processo riceverà un'altra notifica se successivamente si imposta il puntatore dell'interfaccia su tale processo.

È necessario implementare tutti i metodi dell'interfaccia IBackgroundCopyCallback . Ad esempio, se non si esegue la registrazione per il callback della modifica del processo, il metodo JobModification deve comunque restituire S_OK.

I callback jobModification vengono avviati usando thread con priorità bassa, mentre i callback JobTransferred e jobError vengono avviati usando thread con priorità superiore. È quindi possibile che, mentre alcuni callback di JobModification sono in sospeso, il callback JobTransferred viene ricevuto prima dal client anche se viene avviato dopo i callback di JobModification in sospeso.

BITS supporta fino a quattro notifiche simultanee per utente. Se una o più applicazioni bloccano tutte e quattro le notifiche per un utente che restituisce, un'applicazione in esecuzione nello stesso utente non riceverà notifiche fino a quando non verrà restituita una o più notifiche di blocco. Per ridurre la possibilità che il callback blocchi altre notifiche, mantenere breve l'implementazione.

Se un amministratore assume la proprietà del processo, i callback di notifica vengono eseguiti nel contesto dell'utente che ha richiesto la notifica.

Se l'applicazione usa il modello di appartamento a thread singolo , i metodi di callback possono diventare reentrant se si chiamano oggetti COM dall'interno del metodo di callback. Ad esempio, se si chiama IBackgroundCopyJob::GetProgress dall'interno del callback jobModification , BITS può inviare un'altra notifica durante l'elaborazione della notifica corrente. Se non è importante per l'applicazione rispondere a ogni callback jobModification , è possibile ignorare i callback reentranti, come illustrato nell'esempio seguente.

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

Esempio

Nell'esempio seguente viene illustrata un'implementazione di IBackgroundCopyCallback . Per un esempio che chiama questa implementazione, vedere il metodo 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;
}

Requisiti

Requisito Valore
Client minimo supportato Windows XP
Server minimo supportato Windows Server 2003
Piattaforma di destinazione Windows
Intestazione bits.h

Vedi anche

IBackgroundCopyJob

IBackgroundCopyJob::SetNotifyFlags

IBackgroundCopyJob::SetNotifyInterface