IBackgroundCopyCallback 接口 (bits.h)
实现 IBackgroundCopyCallback 接口以接收作业已完成、已修改或出错的 通知 。 客户端使用此接口,而不是 轮询作业的状态。
继承
IBackgroundCopyCallback 接口继承自 IUnknown 接口。 IBackgroundCopyCallback 还具有以下类型的成员:
方法
IBackgroundCopyCallback 接口具有这些方法。
IBackgroundCopyCallback::JobError 当作业的状态更改为BG_JOB_STATE_ERROR时,BITS 调用 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 回调挂起时,客户端可能会首先收到 JobTransferred 回调,尽管它在挂起的 JobModification 回调之后启动。
BITS 支持每个用户最多同时发出四个通知。 如果一个或多个应用程序阻止用户返回所有四个通知,则在一个或多个阻止通知返回之前,以同一用户身份运行的应用程序将不会收到通知。 若要降低回调阻止其他通知的可能性,请保持实现简短。
如果管理员拥有作业的所有权,则会在请求通知的用户的上下文中进行通知回调。
如果应用程序使用 单线程单元 模型,则从回调方法内部调用 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 |