IBackgroundCopyCallback2
COM公式ドキュメント
ファイルのダウンロードが完了したことの通知を受け取るには、このインターフェイスを実装します。
解説(Remarks)
このインターフェイスの実装の詳細については、IBackgroundCopyCallback インターフェイスを参照してください。
例
次の例は、 IBackgroundCopyCallback2 の実装を示します。また、シングルスレッドアパートメントモデルにおける JobModification コールバックでの再入呼び出しの処理方法も示します。
#define TWO_GB 2147483648 // 2GB
class CNotifyInterface : public IBackgroundCopyCallback2
{
LONG m_lRefCount;
LONG m_PendingJobModificationCount;
public:
//Constructor, Destructor
CNotifyInterface() {m_lRefCount = 1; m_PendingJobModificationCount = 0;};
~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 __stdcall FileTransferred(IBackgroundCopyJob* pJob, IBackgroundCopyFile* pFile);
};
HRESULT CNotifyInterface::QueryInterface(REFIID riid, LPVOID* ppvObj)
{
if (riid == __uuidof(IUnknown) ||
riid == __uuidof(IBackgroundCopyCallback) ||
riid == __uuidof(IBackgroundCopyCallback2))
{
*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;
//コールバックスレッドをブロックしないロジックを追加します。この時点で
//大量の処理を行う必要がある場合は、別スレッドを作成してそこで処理することを
//検討してください。
hr = pJob->Complete();
if (FAILED(hr))
{
//エラーを処理します。BITS が一時ファイルの名前変更に失敗した可能性があります。
//詳細については、IBackgroundCopyJob::Complete メソッドの解説を参照してください。
}
//S_OK を返さない場合、BITS はこのコールバックを呼び出し続けます。
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;
//pJob と pError を使用して必要な情報を取得します。たとえば、ジョブが
//アップロード応答の場合は、IBackgroundCopyError::GetError メソッドを呼び出して
//ジョブが失敗したコンテキストを判断します。コンテキストが
//BG_JOB_CONTEXT_REMOTE_APPLICATION の場合、アップロードファイルを受信した
//サーバーアプリケーションが失敗しています。
hr = pError->GetError(&Context, &ErrorCode);
//プロキシまたはサーバーが Content-Range ヘッダーをサポートしていない場合や、
//ウイルス対策ソフトウェアが範囲要求を削除する場合、BITS は
//BG_E_INSUFFICIENT_RANGE_SUPPORT を返します。この実装では、コンテンツの
//ダウンロードが成功する可能性を高めるため、ジョブをフォアグラウンド優先度に
//切り替えます。
if (BG_E_INSUFFICIENT_RANGE_SUPPORT == ErrorCode)
{
hr = pError->GetFile(&pFile);
hr = pFile->GetProgress(&Progress);
if (BG_SIZE_UNKNOWN == Progress.BytesTotal)
{
//コンテンツが動的です。優先度は変更せず、エラーとして処理します。
}
else if (Progress.BytesTotal > TWO_GB)
{
//コンテンツが 2 GB 未満の場合、BITS は範囲要求を使用しません。
//ただし、コンテンツが 2 GB を超える場合、BITS は 2 GB 単位の範囲で
//ファイルをダウンロードするため、フォアグラウンド優先度に切り替えても
//効果はありません。
}
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)
{
//ジョブ名と説明を使用して何らかの処理を行います。
}
CoTaskMemFree(pszJobName);
CoTaskMemFree(pszErrorDescription);
}
//S_OK を返さない場合、BITS はこのコールバックを呼び出し続けます。
return S_OK;
}
HRESULT CNotifyInterface::JobModification(IBackgroundCopyJob* pJob, DWORD dwReserved)
{
HRESULT hr;
WCHAR* pszJobName = NULL;
BG_JOB_PROGRESS Progress;
BG_JOB_STATE State;
//既にコールバックを処理中の場合は、この通知を無視します。
if (InterlockedCompareExchange(&m_PendingJobModificationCount, 1, 0) == 1)
{
return S_OK;
}
hr = pJob->GetDisplayName(&pszJobName);
if (SUCCEEDED(hr))
{
hr = pJob->GetProgress(&Progress);
if (SUCCEEDED(hr))
{
hr = pJob->GetState(&State);
if (SUCCEEDED(hr))
{
//進行状況と状態の情報を使用して何らかの処理を行います。
//BITS は大量の変更通知コールバックを生成します。このコールバックの
//使用には注意してください。タイマーを作成して状態や進行状況の情報を
//ポーリングすることを検討してください。
}
}
CoTaskMemFree(pszJobName);
}
m_PendingJobModificationCount = 0;
return S_OK;
}
HRESULT CNotifyInterface::FileTransferred(IBackgroundCopyJob* pJob, IBackgroundCopyFile* pFile)
{
HRESULT hr = S_OK;
IBackgroundCopyFile3* pFile3 = NULL;
BOOL IsValid = FALSE;
hr = pFile->QueryInterface(__uuidof(IBackgroundCopyFile3), (void**)&pFile3);
if (SUCCEEDED(hr))
{
// ダウンロードしたコンテンツを検証し、IsValid を設定するコードを追加します。
hr = pFile3->SetValidationState(IsValid);
if (FAILED(hr))
{
// エラーを処理します
}
pFile3->Release();
}
return S_OK;
}
メソッド 1
vtbl = vtable インデックス(0始まり)。HSP等からCOMメソッドをインデックス指定で呼ぶ際に使用します。0〜2 は IUnknown。
BITS がファイルの転送を正常に完了すると、BITS は実装した FileTransferred メソッドを呼び出します。
| pJob | IBackgroundCopyJob* | in | ジョブに関する情報を格納します。pJob は解放しないでください。このメソッドから復帰すると、BITS がインターフェイスを解放します。 |
| pFile | IBackgroundCopyFile* | in | ファイルに関する情報を格納します。pFile は解放しないでください。このメソッドから復帰すると、BITS がインターフェイスを解放します。 |
戻り値
このメソッドは S_OK を返す必要があります。負の値を返した場合、BITS は S_OK が返されるまでこのメソッドを呼び出し続けます。パフォーマンス上の理由から、S_OK 以外の値を返す回数は数回程度に制限してください。エラーコードを返す代わりに、常に S_OK を返し、エラーを内部で処理することも検討してください。このメソッドが呼び出される間隔は不定です。
解説(Remarks)
通常、このコールバックはダウンロードされたファイルの内容を検証する場合を除いて使用しません。ピアに配信される可能性のあるコンテンツをダウンロードする場合、ファイルの検証は重要になります。
ダウンロードされたコンテンツを含む一時ファイルの名前を取得するには、IBackgroundCopyFile3::GetTemporaryName メソッドを呼び出します。コンテンツを検証した後、IBackgroundCopyFile3::SetValidationState メソッドを呼び出して、ファイルの内容が有効かどうかを BITS に通知します。検証状態を FALSE に設定し、そのコンテンツがオリジンサーバーからのものである場合、ジョブはエラー状態に移行します。
コンテンツがピアからのものである場合、BITS はオリジンサーバーからファイルをダウンロードします。オリジンサーバーからのファイル転送が完了すると、コールバックが再度呼び出されます。
BITS 3.0: オリジンサーバーからのファイル転送完了後にコールバックが再度呼び出されることはありません。
1 つのジョブにおいて、FileTransferred コールバックは直列化されます。現在のコールバックが正常に復帰するまで、BITS はそのジョブ内の次のファイルに対するコールバックをディスパッチしません。
FileTransferred コールバックは、JobTransferred および JobError コールバックよりも前にディスパッチされます。
FileTransferred コールバックは、ダウンロードジョブ、またはアップロード応答ジョブの応答部分を対象としています。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)
HSP用 COM定義
#usecom / #comfunc によるHSPのCOM呼び出し定義。数字は vtbl インデックス(0始まり)。クラスIDが無い場合 #usecom の末尾は "{}"、ある場合は "{CLSID}"。
#define global IID_IBackgroundCopyCallback2 "{659CDEAC-489E-11D9-A9CD-000D56965251}"
#usecom global IBackgroundCopyCallback2 IID_IBackgroundCopyCallback2 "{}"
#comfunc global IBackgroundCopyCallback2_FileTransferred 6 sptr,sptr
; ※数字は vtbl インデックス(0始まり)。0/1/2 は IUnknown(QueryInterface/AddRef/Release)。
; ※このインターフェースは直接 CoCreateInstance するクラスIDが無いため "{}"(他メソッド/アクティベーションで取得)。
; ※ハンドル/void*等の不透明ポインタは IronHSP では intptr 指定が可能。