다음을 통해 공유


IBackgroundCopyCallback 인터페이스(bits.h)

IBackgroundCopyCallback 인터페이스를 구현하여 작업이 완료되었거나 수정되었거나 오류가 발생했음을 알 수 있습니다. 클라이언트는 작업의 상태 폴링하는 대신 이 인터페이스를 사용합니다.

상속

IBackgroundCopyCallback 인터페이스는 IUnknown 인터페이스에서 상속됩니다. IBackgroundCopyCallback 에는 다음과 같은 유형의 멤버도 있습니다.

메서드

IBackgroundCopyCallback 인터페이스에는 이러한 메서드가 있습니다.

 
IBackgroundCopyCallback::JobError

BITS는 작업 상태가 BG_JOB_STATE_ERROR 변경되면 JobError 메서드의 구현을 호출합니다.
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 콜백이 보류 중인 동안 보류 중인 JobModification 콜백 이후에 시작되지만 먼저 클라이언트에서 JobTransferred 콜백을 수신할 수 있습니다.

BITS는 사용자당 최대 4개의 동시 알림을 지원합니다. 하나 이상의 애플리케이션이 사용자가 반환하지 못하도록 4개의 알림을 모두 차단하는 경우 하나 이상의 차단 알림이 반환될 때까지 동일한 사용자로 실행되는 애플리케이션은 알림을 받지 않습니다. 콜백이 다른 알림을 차단할 가능성을 줄이려면 구현을 짧게 유지합니다.

관리자가 작업의 소유권을 가져오는 경우 알림 콜백은 알림을 요청한 사용자의 컨텍스트에서 수행됩니다.

애플리케이션에서 단일 스레드 아파트 모델을 사용하는 경우 콜백 메서드 내에서 COM 개체를 호출하면 콜백 메서드가 다시 활성화될 수 있습니다. 예를 들어 JobModification 콜백 내에서 IBackgroundCopyJob::GetProgress를 호출하는 경우 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
헤더 bits.h

추가 정보

IBackgroundCopyJob

IBackgroundCopyJob::SetNotifyFlags

IBackgroundCopyJob::SetNotifyInterface