注册 COM 回调

可以在作业状态发生更改时注册以接收通知,而不是轮询作业状态的更改。 若要接收通知,必须实现 IBackgroundCopyCallback2 接口。 该接口包含以下 BITS 调用的方法,具体取决于注册:

有关实现 IBackgroundCopyCallback2 接口的示例,请参阅 IBackgroundCopyCallback 接口主题中的示例代码。

传输文件时,IBackgroundCopyCallback2 接口提供通知。 通常,使用此方法验证文件,以便可供对等方下载;否则,在调用 IBackgroundCopyJob::Complete 方法之前,该文件对等方不可用。 若要验证文件,请调用 IBackgroundCopyFile3::SetValidationState 方法。

有两种方法用于注册 COM 回调:注册回调对象或注册回调类 ID。 使用回调对象更简单,开销更低;使用回调 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 方法。

在向 BITS 作业注册 CLSID 之前,必须确保通知 CLSID 已注册到进程外 COM 服务器。 实现 COM 服务器比定义和传递回调对象要复杂得多,但提供了几个重要的优势。 COM 服务器允许 BITS 在系统重启以及大型或长期作业之间保持 BITS 作业与应用程序代码之间的关联。 COM 服务器还允许应用程序完全关闭,同时 BITS 继续在后台执行传输,从而提高系统的电池、CPU 和内存使用率。

若要提供已注册接收的通知,BITS 首先尝试调用你可能附加的任何现有回调对象的相应方法。 如果没有现有对象,或者如果现有对象已断开连接(通常是由于应用程序终止而导致),BITS 将使用通知 CLSID 调用 CoCreateInstance 来实例化新的回调对象,并将使用该对象进行进一步回调,直到它断开连接或被对 IBackgroundCopyJob::SetNotifyInterface 的新调用替换。

与回调对象不同,如果 BITS 服务或系统关闭并重启,回调 CLSID 将与其相应的 BITS 作业一起保留。 应用程序可以通过传递 GUID_NULL 的新通知 CLSID,在退出之前清除任何以前设置的通知 CLSID,但如果应用程序已注册到 COM 以响应 CLSID 的 CoCreateInstance 请求,应用程序可能更愿意保留注册的通知 CLSID。 请注意,如果多个应用程序设置调用 BITS_JOB_PROPERTY_NOTIFICATION_CLSID 属性,则要设置的最后一个 CLSID 是 BITS 将用于实例化回调对象的 CLSID - 不会实例化其他 CLSID。 同样,如果一个应用程序注册 CLSID,另一个应用程序注册回调对象,则优先应用的回调对象的常规规则适用,除非清除或断开连接回调对象,否则不会使用 CLSID。

以下示例演示如何注册 CLSID 通知。 该示例假定 IBackgroundCopyJob5 接口指针有效,并且应用程序已注册为实现 CNotifyInterface 类的进程外 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. 
}