COM コールバックの登録

ジョブのステータスの変更をポーリングする代わりに、ジョブのステータスが変更されたときに通知を受け取るように登録できます。 通知を受信するには、IBackgroundCopyCallback2 インターフェイスを実装する必要があります。 インターフェイスには、登録に応じて BITS によって呼び出される次のメソッドが含まれています。

IBackgroundCopyCallback2 インターフェイスを実装する例については、IBackgroundCopyCallback インターフェイスのトピックのコード例を参照してください。

IBackgroundCopyCallback2 インターフェイスは、ファイルが転送されたときに通知を提供します。 通常、このメソッドを使用してファイルを検証し、ピアがファイルをダウンロードできるようにします。それ以外の場合、IBackgroundCopyJob::Complete メソッドを呼び出すまで、ファイルはピアで使用できません。 ファイルを検証するには、IBackgroundCopyFile3::SetValidationState メソッドを呼び出します。

COM コールバックを登録する方法には、コールバック オブジェクトの登録とコールバック クラス ID の登録の 2 つの方法があります。 コールバック オブジェクトの使用は、より簡単でオーバーヘッドが少なくなります。コールバック CLSID を使用する方が信頼性は高くなりますが、より複雑です。 どちらかを登録することも、両方を登録することも、どちらも登録することもできません。コールバック オブジェクトが存在し、まだ呼び出すことができる場合、BITS はコールバック オブジェクトを使用し、それが失敗した場合は、提供されたクラス ID に基づいて新しいオブジェクトのインスタンス化にフォールバックします。

コールバック オブジェクトの登録

BITS に実装を登録するには、IBackgroundCopyJob::SetNotifyInterface メソッドを呼び出します。 BITS 呼び出しのメソッドを指定するには、IBackgroundCopyJob::SetNotifyFlags メソッドを呼び出します。

アプリケーションが終了すると、通知インターフェイスが無効になります。BITS は通知インターフェイスを保持しません。 その結果、アプリケーションの初期化プロセスでは、通知を受信する既存のジョブを登録する必要があります。 アプリケーションが最後に実行されてから発生した状態と進行状況の情報を取得する必要がある場合は、アプリケーションの初期化中に状態と進行状況の情報をポーリングします。

終了する前に、アプリケーションでコールバック インターフェイス ポインター (SetNotifyInterface(NULL)) をクリアする必要があります。 コールバック ポインターをクリアする方が、BITS が無効であることを検出するよりも効率的です。

複数のアプリケーションが SetNotifyInterface メソッドを呼び出してジョブの通知インターフェイスを設定する場合、SetNotifyInterface メソッドを呼び出す最後のアプリケーションは通知を受信するアプリケーションであり、他のアプリケーションは通知を受信しないことに注意してください。

次の例は、通知に登録する方法を示しています。 この例では、IBackgroundCopyJob インターフェイス ポインターが有効であると想定しています。 次の例で使用する CNotifyInterface サンプル クラスの詳細については、IBackgroundCopyCallback インターフェイスを参照してください。

HRESULT hr;
IBackgroundCopyJob* pJob;
CNotifyInterface *pNotify = new CNotifyInterface();

if (pNotify)
{
    hr = pJob->SetNotifyInterface(pNotify);
    if (SUCCEEDED(hr))
    {
        hr = pJob->SetNotifyFlags(BG_NOTIFY_JOB_TRANSFERRED | 
                                  BG_NOTIFY_JOB_ERROR );
    }
    pNotify->Release();
    pNotify = NULL;

    if (FAILED(hr))
    {
        //Handle error - unable to register callbacks.
    }
}

コールバック CLSID の登録

BITS にコールバック CLSID を登録するには、BITS_JOB_PROPERTY_NOTIFICATION_CLSID PropertyId を使用して IBackgroundCopyJob5::SetProperty メソッドを呼び出します。 BITS 呼び出しのメソッドを指定するには、IBackgroundCopyJob::SetNotifyFlags メソッドを呼び出します。

CLSID を BITS ジョブに登録する前に、通知 CLSID がアウトプロセス COM サーバーに登録されていることを確認する必要があります。 COM サーバーの実装は、コールバック オブジェクトを定義して渡すよりもはるかに複雑ですが、いくつかの重要な利点があります。 COM サーバーを使用すると、BITS はシステムの再起動後も、大規模なジョブや存続期間の長いジョブに対して、BITS ジョブとアプリケーションのコードとの関連付けを維持できます。 COM サーバーを使用すると、BITS がバックグラウンドで転送を実行し続けている間、アプリケーションを完全にシャットダウンすることもできるため、システムのバッテリー、CPU、メモリの使用率が向上します。

受信登録した通知を提供するために、BITS はまず、アタッチされている既存のコールバック オブジェクトの対応するメソッドの呼び出しを試みます。 既存のオブジェクトがない場合、または既存のオブジェクトが切断された場合 (通常はアプリケーションが終了した結果)、BITS は通知 CLSID を使用して CoCreateInstance を呼び出して新しいコールバック オブジェクトをインスタンス化し、切断されるか、IBackgroundCopyJob::SetNotifyInterface への新しい呼び出しに置き換えられるまで、そのオブジェクトをそれ以降のコールバックに使用します。

コールバック オブジェクトとは異なり、BITS サービスまたはシステムがシャットダウンして再起動された場合、コールバック CLSID は対応する BITS ジョブとともに保持されます。 アプリケーションは、GUID_NULLの新しい通知 CLSID を渡すことによって、終了する前に (または他の時点で) 以前に設定した通知 CLSID をクリアできますが、アプリケーションが CLSID の CoCreateInstance 要求に応答して COM を開始するように登録されている場合は、通知 CLSID を登録したままにすることをお勧めします。 複数のアプリケーションが BITS_JOB_PROPERTY_NOTIFICATION_CLSID プロパティの呼び出しを設定する場合、設定する最後の CLSID は BITS がコールバック オブジェクトのインスタンス化に使用する CLSID であり、他の CLSID はインスタンス化されないことに注意してください。 同様に、あるアプリケーションが CLSID を登録し、別のアプリケーションがコールバック オブジェクトを登録する場合、コールバック オブジェクトの通常のルールが優先して適用され、コールバック オブジェクトがクリアされるか切断されない限り、CLSID は使用されません。

次の例は、CLSID 通知に登録する方法を示しています。 この例では、IBackgroundCopyJob5 インターフェイス ポインターが有効であり、アプリケーションが IBackgroundCopyJob5 クラスを実装するアウトプロセス COM サーバーとして既に登録されていることを前提としています。 次の例で使用する CNotifyInterface サンプル クラスの詳細については、IBackgroundCopyCallback インターフェイスを参照してください。

HRESULT hr; 
IBackgroundCopyJob5* job; 
BITS_JOB_PROPERTY_VALUE propertyValue; 
propertyValue.ClsID = __uuidof(CNotifyInterface); 

hr = job->SetProperty(BITS_JOB_PROPERTY_NOTIFICATION_CLSID, propertyValue); 
if (SUCCEEDED(hr)) 
{ 
    hr = job->SetNotifyFlags(BG_NOTIFY_JOB_TRANSFERRED |  
                             BG_NOTIFY_JOB_ERROR); 
} 

if (FAILED(hr)) 
{ 
    // Handle error - unable to register callbacks. 
}