注册 COM 回调

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

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

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

注册 COM 回调有两种方法:注册回调对象或注册回调类 ID。 使用回调对象更简单且开销更低;使用回调 CLSID 更可靠,但更为复杂。 可以注册两者,或者两者都不能注册 – 如果存在回调对象,仍可调用回调对象,并且会回退到根据提供的类 ID 实例化新对象(如果失败)。

注册回调对象

若要向 BITS 注册实现,请调用 IBackgroundCopyJob::SetNotifyInterface 方法。 若要指定 BITS 调用的方法,请调用 IBackgroundCopyJob::SetNotifyFlagsmethod

应用程序终止时,通知接口变得无效;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

若要将回调 CLSID 注册到 BITS,请使用 BITS_JOB_PROPERTY_NOTIFICATION_CLSID PropertyId 调用 IBackgroundCopyJob5::SetProperty 方法。 若要指定 BITS 调用的方法,请调用 IBackgroundCopyJob::SetNotifyFlags 方法。

在向 BITS 作业注册 CLSID 之前,必须确保通知 CLSID 注册到进程外 COM 服务器。 实现 COM 服务器 比定义和传递回调对象要复杂得多,但具有几个重要的优势。 COM 服务器允许 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. 
}