Win32 API 日本語リファレンス
ホームNetworking.BackgroundIntelligentTransferService › IBackgroundCopyCallback2

IBackgroundCopyCallback2

COM
IID659cdeac-489e-11d9-a9cd-000d56965251継承元IBackgroundCopyCallback自前メソッド開始 vtbl6

公式ドキュメント

ファイルのダウンロードが完了したことの通知を受け取るには、このインターフェイスを実装します。

解説(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。

vtbl 6 HRESULT FileTransferred(IBackgroundCopyJob* pJob, IBackgroundCopyFile* pFile)

BITS がファイルの転送を正常に完了すると、BITS は実装した FileTransferred メソッドを呼び出します。

pJobIBackgroundCopyJob*inジョブに関する情報を格納します。pJob は解放しないでください。このメソッドから復帰すると、BITS がインターフェイスを解放します。
pFileIBackgroundCopyFile*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 の Win32 API ドキュメント(MicrosoftDocs/sdk-api)を日本語に翻訳・改変したものです。© Microsoft Corporation. CC BY 4.0 で提供。
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 指定が可能。