Exemplo: classes comuns
Você pode usar os exemplos de código neste tópico como ponto de partida para muitos aplicativos BITS (Serviço de Transferência Inteligente em Segundo Plano) que executam a inicialização COM, precisam de tratamento de erros e recebem notificações de retorno de chamada.
O exemplo de código a seguir define uma classe de exceção para lidar com erros.
class MyException
{
public:
MyException(HRESULT hr, LPWSTR message):Error(hr), Message(message)
{
}
HRESULT Error;
std::wstring Message;
};
A classe MyException é uma classe de exceção genérica que aceita um código HRESULT e uma cadeia de caracteres de erro.
O exemplo de código a seguir define uma classe auxiliar de aquisição de recursos para a função CoInitializeEx.
class CCoInitializer
{
public:
CCoInitializer( DWORD dwCoInit )
{
HRESULT hr = CoInitializeEx( NULL, dwCoInit );
if (FAILED(hr))
{
throw MyException(hr,L"CoInitialize");
}
}
~CCoInitializer() throw()
{
CoUninitialize();
}
};
A classe CCoInitializer lida com alocação e desalocação de recursos para inicialização COM. Essa classe permite que o destruidor seja chamado quando a classe sair do escopo. Essa classe elimina a necessidade de o método CoUninitialize ser chamado após cada bloco de exceção.
O exemplo de código a seguir é a declaração da interface de retorno de chamada CNotifyInterface.
// Implementation of the Callback interface
//
class CNotifyInterface : public IBackgroundCopyCallback
{
LONG m_lRefCount;
public:
//Constructor
CNotifyInterface() {m_lRefCount = 1;};
//Destructor
~CNotifyInterface() {};
//IUnknown methods
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);
private:
CNotifyInterface(const CNotifyInterface&);
CNotifyInterface& operator=(const CNotifyInterface&);
};
A classe CNotifyInterface derivada da interfaceIBackgroundCopyCallback. A classe CNotifyInterface implementa a interface IUnknown. Para obter mais informações, consulte IUnknown.
O CNotifyInterface usa os seguintes métodos para receber a notificação de que um trabalho foi concluído, foi modificado ou está em um estado de erro: JobTransferred, JobModificatione JobError. Todos esses métodos levam uma objeto de trabalho IBackgroundCopyJob.
Este exemplo usa o CoTaskMemFree para liberar recursos de memória.
O exemplo de código a seguir é a implementação da interface de retorno de chamada IBackgroundCopyCallback.
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()
{
// not thread safe
ULONG ulCount = InterlockedDecrement(&m_lRefCount);
if(0 == ulCount)
{
delete this;
}
return ulCount;
}
HRESULT CNotifyInterface::JobTransferred(IBackgroundCopyJob* pJob)
{
HRESULT hr;
wprintf(L"Job transferred. Completing Job...\n");
hr = pJob->Complete();
if (FAILED(hr))
{
//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.
wprintf(L"Job Completion Failed with error %x\n", hr);
}
PostQuitMessage(0);
//If you do not return S_OK, BITS continues to call this callback.
return S_OK;
}
HRESULT CNotifyInterface::JobModification(IBackgroundCopyJob* pJob, DWORD dwReserved)
{
return S_OK;
}
HRESULT CNotifyInterface::JobError(IBackgroundCopyJob* pJob, IBackgroundCopyError* pError)
{
WCHAR* pszJobName = NULL;
WCHAR* pszErrorDescription = NULL;
//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.
wprintf(L"Job entered error state...\n");
HRESULT hr = pJob->GetDisplayName(&pszJobName);
if (FAILED(hr))
{
wprintf(L"Unable to get job name\n");
}
hr = pError->GetErrorDescription(GetUserDefaultUILanguage(), &pszErrorDescription);
if (FAILED(hr))
{
wprintf(L"Unable to get error description\n");
}
if (pszJobName && pszErrorDescription)
{
wprintf(L"Job %s ",pszJobName);
wprintf(L"encountered the following error:\n");
wprintf(L"%s\n",pszErrorDescription);
}
// Clean up
CoTaskMemFree(pszJobName);
CoTaskMemFree(pszErrorDescription);
PostQuitMessage(hr);
//If you do not return S_OK, BITS continues to call this callback.
return S_OK;
}
O arquivo de cabeçalho a seguir é usado para as classes de código comuns. Essas classes são usadas nos exemplos de código anteriores.
// commoncode.h
#pragma once
//
// Exception class used for error handling
//
class MyException
{
public:
MyException(HRESULT hr, LPWSTR message):Error(hr), Message(message)
{
}
HRESULT Error;
std::wstring Message;
};
// CoInitialize helper class
class CCoInitializer
{
public:
CCoInitializer( DWORD dwCoInit )
{
HRESULT hr = CoInitializeEx( NULL, dwCoInit );
if (FAILED(hr))
{
throw MyException(hr,L"CoInitialize");
}
}
~CCoInitializer() throw()
{
CoUninitialize();
}
};
//
// Implementation of the Callback interface
//
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();
//IBackgroundCopyCallback2 methods
HRESULT __stdcall JobTransferred(IBackgroundCopyJob* pJob);
HRESULT __stdcall JobError(IBackgroundCopyJob* pJob, IBackgroundCopyError* pError);
HRESULT __stdcall JobModification(IBackgroundCopyJob* pJob, DWORD dwReserved);
private:
CNotifyInterface(const CNotifyInterface&);
CNotifyInterface& operator=(const CNotifyInterface&);
};
O código de exemplo a seguir é a implementação das classes de código comuns.
//commoncode.cpp
#include <bits.h>
#include <bits4_0.h>
#include <stdio.h>
#include <tchar.h>
#include <lm.h>
#include <iostream>
#include <exception>
#include <string>
#include <atlbase.h>
#include <memory>
#include <new>
#include "CommonCode.h"
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()
{
// not thread safe
ULONG ulCount = InterlockedDecrement(&m_lRefCount);
if(0 == ulCount)
{
delete this;
}
return ulCount;
}
HRESULT CNotifyInterface::JobTransferred(IBackgroundCopyJob* pJob)
{
HRESULT hr;
wprintf(L"Job transferred. Completing Job...\n");
hr = pJob->Complete();
if (FAILED(hr))
{
//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.
wprintf(L"Job Completion Failed with error %x\n", hr);
}
PostQuitMessage(0);
//If you do not return S_OK, BITS continues to call this callback.
return S_OK;
}
HRESULT CNotifyInterface::JobModification(IBackgroundCopyJob* pJob, DWORD dwReserved)
{
return S_OK;
}
HRESULT CNotifyInterface::JobError(IBackgroundCopyJob* pJob, IBackgroundCopyError* pError)
{
WCHAR* pszJobName = NULL;
WCHAR* pszErrorDescription = NULL;
//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.
wprintf(L"Job entered error state...\n");
HRESULT hr = pJob->GetDisplayName(&pszJobName);
if (FAILED(hr))
{
wprintf(L"Unable to get job name\n");
}
hr = pError->GetErrorDescription(GetUserDefaultUILanguage(), &pszErrorDescription);
if (FAILED(hr))
{
wprintf(L"Unable to get error description\n");
}
if (pszJobName && pszErrorDescription)
{
wprintf(L"Job %s ",pszJobName);
wprintf(L"encountered the following error:\n");
wprintf(L"%s\n",pszErrorDescription);
}
CoTaskMemFree(pszJobName);
CoTaskMemFree(pszErrorDescription);
PostQuitMessage(hr);
//If you do not return S_OK, BITS continues to call this callback.
return S_OK;
}
Tópicos relacionados