Share via


IBackgroundCopyCallback-Schnittstelle (bits.h)

Implementieren Sie die IBackgroundCopyCallback-Schnittstelle , um eine Benachrichtigung zu erhalten , dass ein Auftrag abgeschlossen ist, geändert wurde oder ein Fehler vorliegt. Clients verwenden diese Schnittstelle, anstatt die status des Auftrags zu abfragen.

Vererbung

Die IBackgroundCopyCallback-Schnittstelle erbt von der IUnknown-Schnittstelle . IBackgroundCopyCallback verfügt auch über folgende Arten von Membern:

Methoden

Die IBackgroundCopyCallback-Schnittstelle verfügt über diese Methoden.

 
IBackgroundCopyCallback::JobError

BITS ruft Ihre Implementierung der JobError-Methode auf, wenn sich der Status des Auftrags in BG_JOB_STATE_ERROR ändert.
IBackgroundCopyCallback::JobModification

BITS ruft Ihre Implementierung der JobModification-Methode auf, wenn der Auftrag geändert wurde.
IBackgroundCopyCallback::JobTransferred

BITS ruft Ihre Implementierung der JobTransferred-Methode auf, wenn alle Dateien im Auftrag erfolgreich übertragen wurden.

Hinweise

Rufen Sie zum Empfangen von Benachrichtigungen die IBackgroundCopyJob::SetNotifyInterface-Methode auf, um den Schnittstellenzeiger auf Ihre IBackgroundCopyCallback-Implementierung anzugeben. Um anzugeben, welche Benachrichtigungen Sie empfangen möchten, rufen Sie die IBackgroundCopyJob::SetNotifyFlags-Methode auf.

BITS ruft Ihre Rückrufe auf, solange der Schnittstellenzeiger gültig ist. Die Benachrichtigungsschnittstelle ist nicht mehr gültig, wenn Ihre Anwendung beendet wird. BITS behält die Benachrichtigungsschnittstelle nicht bei. Daher sollte der Initialisierungsprozess Ihrer Anwendung die SetNotifyInterface-Methode für die vorhandenen Aufträge aufrufen, für die Sie Benachrichtigungen erhalten möchten.

BITS garantiert, dass Ihr Rückruf mindestens einmal aufgerufen wird, auch wenn die Registrierung nach dem Ereignis erfolgt. Wenn Sie beispielsweise eine Benachrichtigung über eine Auftragsübertragung anfordern, nachdem die Übertragung erfolgt ist, erhalten Sie den übertragenen Auftragsrückruf. Wenn ein Auftrag eine Benachrichtigung erhalten hat und der Zeiger anschließend nicht mehr gültig ist, erhält dieser Auftrag eine weitere Benachrichtigung, wenn Sie später den Schnittstellenzeiger auf diesen Auftrag festlegen.

Sie müssen alle Methoden der IBackgroundCopyCallback-Schnittstelle implementieren. Wenn Sie sich beispielsweise nicht für den Rückruf zur Auftragsänderung registrieren, muss die JobModification-Methode weiterhin S_OK zurückgeben.

Die JobModification-Rückrufe werden mithilfe von Threads mit niedriger Priorität gestartet, während die Rückrufe JobTransferred und JobError mithilfe von Threads mit höherer Priorität gestartet werden. Es ist also möglich, dass der JobTransferred-Rückruf zuerst vom Client empfangen wird, obwohl er nach den ausstehenden JobModification-Rückrufen gestartet wird.

BITS unterstützt bis zu vier gleichzeitige Benachrichtigungen pro Benutzer. Wenn eine oder mehrere Anwendungen verhindern, dass alle vier Benachrichtigungen für einen Benutzer zurückgegeben werden, erhält eine Anwendung, die als derselbe Benutzer ausgeführt wird, keine Benachrichtigungen, bis mindestens eine der blockierenden Benachrichtigungen zurückgegeben wird. Um das Risiko zu verringern, dass Ihr Rückruf andere Benachrichtigungen blockiert, halten Sie Ihre Implementierung kurz.

Wenn ein Administrator den Besitz des Auftrags übernimmt, werden die Benachrichtigungsrückrufe im Kontext des Benutzers durchgeführt, der eine Benachrichtigung angefordert hat.

Wenn Ihre Anwendung das Singlethread-Apartmentmodell verwendet, können Ihre Rückrufmethoden zu einem Erneutentrant werden, wenn Sie COM-Objekte innerhalb Ihrer Rückrufmethode aufrufen. Wenn Sie beispielsweise IBackgroundCopyJob::GetProgress in Ihrem JobModification-Rückruf aufrufen, kann BITS ihrem Auftragsänderungsrückruf eine weitere Benachrichtigung senden, während Sie die aktuelle Benachrichtigung noch verarbeiten. Wenn es für Ihre Anwendung nicht wichtig ist, auf jeden JobModification-Rückruf zu reagieren, können Sie reentrant-Rückrufe ignorieren, wie im folgenden Beispiel gezeigt.

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

Beispiele

Das folgende Beispiel zeigt eine IBackgroundCopyCallback-Implementierung . Ein Beispiel, das diese Implementierung aufruft, finden Sie in der IBackgroundCopyJob::SetNotifyInterface-Methode .

#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;
}

Anforderungen

Anforderung Wert
Unterstützte Mindestversion (Client) Windows XP
Unterstützte Mindestversion (Server) Windows Server 2003
Zielplattform Windows
Kopfzeile bits.h

Weitere Informationen

IBackgroundCopyJob

IBackgroundCopyJob::SetNotifyFlags

IBackgroundCopyJob::SetNotifyInterface