Interface IBackgroundCopyCallback (bits.h)
Implemente a interface IBackgroundCopyCallback para receber a notificação de que um trabalho foi concluído, foi modificado ou está com erro. Os clientes usam essa interface em vez de sondar o status do trabalho.
Herança
A interface IBackgroundCopyCallback herda da interface IUnknown . IBackgroundCopyCallback também tem estes tipos de membros:
Métodos
A interface IBackgroundCopyCallback tem esses métodos.
IBackgroundCopyCallback::JobError O BITS chama a implementação do método JobError quando o estado do trabalho é alterado para BG_JOB_STATE_ERROR. |
IBackgroundCopyCallback::JobModification O BITS chama a implementação do método JobModification quando o trabalho é modificado. |
IBackgroundCopyCallback::JobTransferred O BITS chama a implementação do método JobTransferred quando todos os arquivos no trabalho foram transferidos com êxito. |
Comentários
Para receber notificações, chame o método IBackgroundCopyJob::SetNotifyInterface para especificar o ponteiro de interface para a implementação de IBackgroundCopyCallback . Para especificar quais notificações você deseja receber, chame o método IBackgroundCopyJob::SetNotifyFlags .
O BITS chamará seus retornos de chamada, desde que o ponteiro da interface seja válido. A interface de notificação não é mais válida quando seu aplicativo é encerrado; O BITS não persiste a interface de notificação. Como resultado, o processo de inicialização do aplicativo deve chamar o método SetNotifyInterface nesses trabalhos existentes para os quais você deseja receber notificação.
O BITS garante chamar o retorno de chamada pelo menos uma vez, mesmo que o registro ocorra após o evento. Por exemplo, se você solicitar a notificação de uma transferência de trabalho após a transferência, receberá o retorno de chamada transferido do trabalho. Além disso, se um trabalho receber uma notificação e o ponteiro não for mais válido posteriormente, esse trabalho receberá outra notificação se você definir posteriormente o ponteiro da interface nesse trabalho.
Você deve implementar todos os métodos da interface IBackgroundCopyCallback . Por exemplo, se você não se registrar para o retorno de chamada de modificação de trabalho, o método JobModification ainda deverá retornar S_OK.
Os retornos de chamada jobModification são iniciados usando threads de baixa prioridade, enquanto os retornos de chamada JobTransferred e JobError são iniciados usando threads de prioridade mais alta. Portanto, é possível que, embora alguns retornos de chamada JobModification estejam pendentes, o retorno de chamada JobTransferred seja recebido pelo cliente primeiro, embora seja iniciado após os retornos de chamada jobmodification pendentes.
O BITS dá suporte a até quatro notificações simultâneas por usuário. Se um ou mais aplicativos bloquearem o retorno de todas as quatro notificações para um usuário, um aplicativo em execução como o mesmo usuário não receberá notificações até que uma ou mais notificações de bloqueio retornem. Para reduzir a chance de que o retorno de chamada bloqueie outras notificações, mantenha sua implementação curta.
Se um administrador assumir a propriedade do trabalho, os retornos de chamada de notificação serão feitos no contexto do usuário que solicitou a notificação.
Se o aplicativo usar o modelo de apartment de thread único , seus métodos de retorno de chamada poderão se tornar reentrantes se você chamar objetos COM de dentro do método de retorno de chamada. Por exemplo, se você chamar IBackgroundCopyJob::GetProgress de dentro de seu retorno de chamada jobModification , o BITS poderá enviar outro retorno de chamada de modificação de trabalho enquanto você ainda estiver processando a notificação atual. Se não for importante que seu aplicativo responda a cada retorno de chamada jobModification , você poderá ignorar retornos de chamada reentrantes, conforme mostrado no exemplo a seguir.
//A member variable is used to determine if the callback
//is already processing another job modification callback.
LONG m_PendingJobModificationCount = 0;
//If you are already processing a callback, ignore this notification.
if (InterlockedCompareExchange(&m_PendingJobModificationCount, 1, 0) == 1)
{
return S_OK;
}
... //processing the current notification
m_PendingJobModificationCount = 0;
return hr;
Exemplos
O exemplo a seguir mostra uma implementação de IBackgroundCopyCallback . Para obter um exemplo que chama essa implementação, consulte o método IBackgroundCopyJob::SetNotifyInterface .
#define TWO_GB 2147483648 // 2GB
class CNotifyInterface : public IBackgroundCopyCallback
{
LONG m_lRefCount;
public:
//Constructor, Destructor
CNotifyInterface() {m_lRefCount = 1;};
~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 CNotifyInterface::QueryInterface(REFIID riid, LPVOID* ppvObj)
{
if (riid == __uuidof(IUnknown) || riid == __uuidof(IBackgroundCopyCallback))
{
*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;
//Add logic that will not block the callback thread. If you need to perform
//extensive logic at this time, consider creating a separate thread to perform
//the work.
hr = pJob->Complete();
if (FAILED(hr))
{
//Handle error. BITS probably was unable to rename one or more of the
//temporary files. See the Remarks section of the IBackgroundCopyJob::Complete
//method for more details.
}
//If you do not return S_OK, BITS continues to call this callback.
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;
//Use pJob and pError to retrieve information of interest. For example,
//if the job is an upload reply, call the IBackgroundCopyError::GetError method
//to determine the context in which the job failed. If the context is
//BG_JOB_CONTEXT_REMOTE_APPLICATION, the server application that received the
//upload file failed.
hr = pError->GetError(&Context, &ErrorCode);
//If the proxy or server does not support the Content-Range header or if
//antivirus software removes the range requests, BITS returns BG_E_INSUFFICIENT_RANGE_SUPPORT.
//This implementation tries to switch the job to foreground priority, so
//the content has a better chance of being successfully downloaded.
if (BG_E_INSUFFICIENT_RANGE_SUPPORT == ErrorCode)
{
hr = pError->GetFile(&pFile);
hr = pFile->GetProgress(&Progress);
if (BG_SIZE_UNKNOWN == Progress.BytesTotal)
{
//The content is dynamic, do not change priority. Handle as an error.
}
else if (Progress.BytesTotal > TWO_GB)
{
// BITS requires range requests support if the content is larger than 2 GB.
// For these scenarios, BITS uses 2 GB ranges to download the file,
// so switching to foreground priority will not help.
}
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)
{
//Do something with the job name and description.
}
CoTaskMemFree(pszJobName);
CoTaskMemFree(pszErrorDescription);
}
//If you do not return S_OK, BITS continues to call this callback.
return S_OK;
}
HRESULT CNotifyInterface::JobModification(IBackgroundCopyJob* pJob, DWORD dwReserved)
{
HRESULT hr;
WCHAR* pszJobName = NULL;
BG_JOB_PROGRESS Progress;
BG_JOB_STATE State;
hr = pJob->GetDisplayName(&pszJobName);
if (SUCCEEDED(hr))
{
hr = pJob->GetProgress(&Progress);
if (SUCCEEDED(hr))
{
hr = pJob->GetState(&State);
if (SUCCEEDED(hr))
{
//Do something with the progress and state information.
//BITS generates a high volume of modification
//callbacks. Use this callback with discretion. Consider creating a timer and
//polling for state and progress information.
}
}
CoTaskMemFree(pszJobName);
}
return S_OK;
}
Requisitos
Requisito | Valor |
---|---|
Cliente mínimo com suporte | Windows XP |
Servidor mínimo com suporte | Windows Server 2003 |
Plataforma de Destino | Windows |
Cabeçalho | bits.h |