예: 공용 클래스
이 항목의 코드 예제를 COM 초기화를 수행하고 오류 처리가 필요하며 콜백 알림을 수신하는 많은 BITS(Background Intelligent Transfer Service) 애플리케이션의 시작점으로 사용할 수 있습니다.
다음 코드 예제에서는 오류를 처리할 예외 클래스를 정의합니다.
class MyException
{
public:
MyException(HRESULT hr, LPWSTR message):Error(hr), Message(message)
{
}
HRESULT Error;
std::wstring Message;
};
MyException 클래스는 HRESULT 코드 및 오류 문자열을 허용하는 제네릭 예외 클래스입니다.
다음 코드 예제에서는 CoInitializeEx 함수에 대한 리소스 획득 도우미 클래스를 정의합니다.
class CCoInitializer
{
public:
CCoInitializer( DWORD dwCoInit )
{
HRESULT hr = CoInitializeEx( NULL, dwCoInit );
if (FAILED(hr))
{
throw MyException(hr,L"CoInitialize");
}
}
~CCoInitializer() throw()
{
CoUninitialize();
}
};
CCoInitializer 클래스는 COM 초기화를 위한 리소스 할당 및 할당 취소를 처리합니다. 이 클래스를 사용하면 클래스가 범위를 벗어날 때 소멸자를 호출할 수 있습니다. 이 클래스는 모든 예외 블록 후에 CoUninitialize 메서드를 호출할 필요가 없습니다.
다음 코드 예제는 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&);
};
IBackgroundCopyCallback 인터페이스에서 파생된 CNotifyInterface 클래스입니다. CNotifyInterface 클래스는 IUnknown 인터페이스를 구현합니다. 자세한 내용은 IUnknown 참조하세요.
CNotifyInterface는 작업이 완료되었거나 수정되었거나 오류 상태에 있다는 알림을 받기 위해 다음 메서드를 사용합니다. JobTransferred, JobModification및 JobError. 이러한 모든 메서드는 IBackgroundCopyJob 작업 개체를 사용합니다.
이 예제에서는 CoTaskMemFree 사용하여 메모리 리소스를 해제합니다.
다음 코드 예제는 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;
}
다음 헤더 파일은 공용 코드 클래스에 사용됩니다. 이러한 클래스는 이전 코드 예제에서 사용됩니다.
// 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&);
};
다음 예제 코드는 공용 코드 클래스의 구현입니다.
//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;
}
관련 항목