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 では、イベントの後に登録が発生した場合でも、コールバックを少なくとも 1 回呼び出す必要があります。 たとえば、転送が発生した後にジョブ転送の通知を要求した場合、ジョブ転送コールバックを受け取ります。 また、ジョブが通知を受信し、その後ポインターが有効でなくなった場合、そのジョブにインターフェイス ポインターを後で設定すると、そのジョブは別の通知を受け取ります。
IBackgroundCopyCallback インターフェイスのすべてのメソッドを実装する必要があります。 たとえば、ジョブ変更コールバックに登録しない場合でも、 JobModification メソッドは S_OKを返す必要があります。
JobModification コールバックは優先度の低いスレッドを使用して起動されますが、JobTransferred コールバックと JobError コールバックは優先度の高いスレッドを使用して起動されます。 そのため、一部の JobModification コールバックが保留中の間、JobTransferred コールバックは、保留中の JobModification コールバックの後に起動されますが、最初にクライアントによって受信される可能性があります。
BITS では、ユーザーごとに最大 4 つの同時通知がサポートされます。 1 つ以上のアプリケーションでユーザーの 4 つの通知すべてが返されないようにブロックされている場合、同じユーザーとして実行されているアプリケーションは、1 つ以上のブロック通知が返されるまで通知を受信しません。 コールバックが他の通知をブロックする可能性を減らすには、実装を短くします。
管理者がジョブの所有権を取得した場合、通知コールバックは通知を要求したユーザーのコンテキストで行われます。
アプリケーションで シングルスレッド アパートメント モデルを使用している場合、コールバック メソッド内から 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 |