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 支援每個使用者最多四個同時通知。 如果一或多個應用程式封鎖用戶傳回所有四個通知,則執行為相同使用者的應用程式將不會收到通知,直到一或多個封鎖通知傳回為止。 若要減少回呼封鎖其他通知的機會,請縮短實作。
如果系統管理員取得作業的擁有權,則會在要求通知的用戶內容中進行通知回呼。
如果您的應用程式使用 單個線程 Apartment 模型,如果您從回呼方法內呼叫 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 |