Ejemplo: Clases comunes
Puede usar los ejemplos de código de este tema como punto de partida para muchas aplicaciones del Servicio de transferencia inteligente en segundo plano (BITS) que realizan la inicialización COM, necesitan control de errores y reciben notificaciones de devolución de llamada.
En el ejemplo de código siguiente se define una clase de excepción para controlar los errores.
class MyException
{
public:
MyException(HRESULT hr, LPWSTR message):Error(hr), Message(message)
{
}
HRESULT Error;
std::wstring Message;
};
La clase MyException es una clase de excepción genérica que acepta un código HRESULT y una cadena de error.
En el ejemplo de código siguiente se define una clase auxiliar de adquisición de recursos para la función CoInitializeEx .
class CCoInitializer
{
public:
CCoInitializer( DWORD dwCoInit )
{
HRESULT hr = CoInitializeEx( NULL, dwCoInit );
if (FAILED(hr))
{
throw MyException(hr,L"CoInitialize");
}
}
~CCoInitializer() throw()
{
CoUninitialize();
}
};
La clase CCoInitializer se ocupa de la asignación y desasignación de recursos para la inicialización COM. Esta clase permite llamar al destructor cuando la clase sale del ámbito. Esta clase elimina la necesidad de llamar al método CoUninitialize después de cada bloque de excepciones.
El siguiente ejemplo de código es la declaración de la interfaz de devolución de llamada 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&);
};
La clase CNotifyInterface derivada de la interfaz IBackgroundCopyCallback . La clase CNotifyInterface implementa la interfaz IUnknown. Para obtener más información, consulte IUnknown.
CNotifyInterface usa los métodos siguientes para recibir una notificación de que se ha completado un trabajo, se ha modificado o está en un estado de error: JobTransferred, JobModification y JobError. Todos estos métodos toman un objeto de trabajo IBackgroundCopyJob .
En este ejemplo se usa CoTaskMemFree para liberar recursos de memoria.
El ejemplo de código siguiente es la implementación de la interfaz de devolución de llamada 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;
}
El siguiente archivo de encabezado se usa para las clases de código comunes. Estas clases se usan en los ejemplos 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&);
};
El código de ejemplo siguiente es la implementación de las clases de código comunes.
//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;
}
Temas relacionados