Windows with C++ - COM Smart Pointers Revisited
마소가 사용하는 함수 결과 코드로 대개 마소의 함수들이 성공 여부를 반환하는 타입입니다.
Common NULL Facility Error Codes
Name | Description | Value |
---|---|---|
S_OK | Operation successful | 0x00000000 |
S_FALSE | Operation successful but returned no results | 0x00000001 |
E_ABORT | Operation aborted | 0x80004004 |
E_FAIL | Unspecified failure | 0x80004005 |
E_NOINTERFACE | No such interface supported | 0x80004002 |
E_NOTIMPL | Not implemented | 0x80004001 |
E_POINTER | Pointer that is not valid | 0x80004003 |
E_UNEXPECTED | Unexpected failure | 0x8000FFFF |
Common Win32 Facility Error Codes
Name | Description | Value |
---|---|---|
E_ACCESSDENIED | General access denied error | 0x80070005 |
E_HANDLE | Handle that is not valid | 0x80070006 |
E_INVALIDARG | One or more arguments are not valid | 0x80070057 |
E_OUTOFMEMORY | Failed to allocate necessary memory | 0x8007000E |
template <typename T>
ULONG GetRefCount(const ComPtr<T>& p)
{
T* temp = p.Get();
ULONG ret = 0;
if (temp != nullptr)
{
ret = temp->AddRef();
ret = temp->Release();
}
return ret;
}
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
ComPtr<IDXGIFactory6> factory6;
hr = factory->QueryInterface(IID_PPV_ARGS(&factory6)); // S_OK
refCount = GetRefCount(factory); // refCount = 2
assert(refCount == 2);
ComPtr<IUnknown> unknown;
hr = factory->QueryInterface(__uuidof(IDXGIFactory6), &unknown);
assert(hr == S_OK);
refCount = GetRefCount(factory); // refCount = 3
assert(refCount == 3);
#define WIN32_LEAN_AND_MEAN
#include <utility>
#include <cassert>
#include <windows.h>
#include <wrl.h>
#include <dxgi1_6.h>
#pragma comment(lib, "dxgi.lib")
using namespace Microsoft::WRL;
// Signature
template<typename U>
HRESULT As(
_Out_ ComPtr<U>* p
) const;
template<typename U>
HRESULT As(
_Out_ Details::ComPtrRef<ComPtr<U>> p
) const;
// 예제
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
ComPtr<IDXGIFactory6> factory6;
hr = factory.As(&factory6); // S_OK
refCount = GetRefCount(factory); // refCount = 2
assert(refCount == 2);
// Signature
WRL_NOTHROW HRESULT AsIID(
REFIID riid,
_Out_ ComPtr<IUnknown>* p
) const;
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
ComPtr<IUnknown> unknown;
hr = factory.AsIID(__uuidof(IDXGIFactory4), &unknown); // S_OK
refCount = GetRefCount(factory); // refCount = 2
assert(refCount == 2);
// Signature
HRESULT AsWeak(
_Out_ WeakRef* pWeakRef
);
// 예제
WeakRef wr;
strongComptrRef.AsWeak(&wr);
// Now suppose that the object strongComPtrRef points to no longer exists
// and the following code tries to get a strong ref from the weak ref:
ComPtr<ISomeInterface> strongRef;
HRESULT hr = wr.As(&strongRef);
// This check won't work with the Windows 10 SDK version of the library.
// Check the input pointer instead.
if(wr == nullptr)
{
wprintf(L"Couldn't get strong ref!");
}
약참조 할 수 있는 객체 반환.
약참조를 하려면 약참조하려는 클래스가 IInspectable을 상속해야 하는데 D3D 프로그래밍을 하는데 사용하는 클래스들은 IInspectable을 상속하지 않아서 쓸 수 없습니다.
어차피 다 마소가 만들어준 클래스를 사용하기 때문에 약참조를 사용할 일이 없다고 봅니다.
// Signature
void Attach(
_In_opt_ InterfaceType* other
);
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // 1
assert(refCount == 1);
ComPtr<IDXGIFactory4> factoryAttached;
factoryAttached.Attach(factory.Get());
refCount = GetRefCount(factory); // 1
assert(refCount == 1);
// Compile Error! Release() 두번
// Signature
// #1 기본 생성자
WRL_NOTHROW ComPtr();
// #2 nullptr을 넣는 생성자
WRL_NOTHROW ComPtr(
decltype(__nullptr)
);
// #3 Raw 포인터를 넣는 생성자
template<class U>
WRL_NOTHROW ComPtr(
_In_opt_ U *other
);
// #4 복사 생성자
WRL_NOTHROW ComPtr(
const ComPtr& other
);
// #5 복사 생성자
// U는 other의 타입, T는 현재 타입.
// 즉, U를 T로 변환할 수 있으면 사용할 수 있음.
template<class U>
WRL_NOTHROW ComPtr(
const ComPtr<U> &other,
typename ENABLE_IF<__is_convertible_to(U*, T*), void *>
);
// #6 이동 생성자
WRL_NOTHROW ComPtr(
_Inout_ ComPtr &&other
);
// #7 이동 생성자
// #5와 방식이 같음
template<class U>
WRL_NOTHROW ComPtr(
_Inout_ ComPtr<U>&& other, typename ENABLE_IF<__is_convertible_to(U*, T*), void *>
);
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // refCount = 1
ComPtr<IDXGIFactory4> factory1(); // #1
ComPtr<IDXGIFactory4> factory2(nullptr); // #2
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
ComPtr<IDXGIFactory4> factory3(factory.Get()); // #3
refCount = GetRefCount(factory); // refCount = 2
assert(refCount == 2);
ComPtr<IDXGIFactory4> factory4(factory); // #4
refCount = GetRefCount(factory); // refCount = 3
assert(refCount == 3);
// ComPtr<IDXGIAdapter> adapter(factory) Compile Error!
ComPtr<IDXGIFactory> factory5(factory); // #5
refCount = GetRefCount(factory); // refCount = 4
assert(refCount == 4);
ComPtr<IDXGIFactory4> factory6(std::move(factory)); // #6
assert(factory.Get() == nullptr);
refCount = GetRefCount(factory3); // refCount = 4
assert(refCount == 4);
ComPtr<IDXGIFactory3> factory7(std::move(factory3)); // #7
assert(factory3.Get() == nullptr);
refCount = GetRefCount(factory4); // refCount = 4
assert(refCount == 4);
// Signature
// #1
HRESULT CopyTo(
_Deref_out_ InterfaceType** ptr
);
// #2
// REFIID = const IID&
HRESULT CopyTo(
REFIID riid,
_Deref_out_ void** ptr
) const;
// #3
template<typename U>
HRESULT CopyTo(
_Deref_out_ U** ptr
) const;
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
ComPtr<IDXGIFactory4> factory1;
factory.CopyTo(&factory1); // #1
refCount = GetRefCount(factory); // refCount = 2
assert(refCount == 2);
// Signature
T* Detach();
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
ComPtr<IDXGIFactory4> factory1(factory.Detach()); // factory.Get() == nullptr이기 때문에
// factory의 refCount를 알 수 있는 방법이 없음.
refCount = GetRefCount(factory1); // refCount = 2
assert(refCount == 2);
// Signature
void Swap(
_Inout_ ComPtr&& r
);
void Swap(
_Inout_ ComPtr& r
);
#define WIN32_LEAN_AND_MEAN
#include <utility>
#include <cassert>
#include <windows.h>
#include <wrl.h>
#include <dxgi1_6.h>
#pragma comment(lib, "dxgi.lib")
using namespace Microsoft::WRL;
template <typename T>
ULONG GetRefCount(const ComPtr<T>& p)
{
T* temp = p.Get();
ULONG ret = 0;
if (temp != nullptr)
{
ret = temp->AddRef();
ret = temp->Release();
}
return ret;
}
int main()
{
// ************************** QueryInterface **************************
{
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
ComPtr<IDXGIFactory6> factory6;
hr = factory->QueryInterface(IID_PPV_ARGS(&factory6)); // S_OK
refCount = GetRefCount(factory); // refCount = 2
assert(refCount == 2);
ComPtr<IUnknown> unknown;
hr = factory->QueryInterface(__uuidof(IDXGIFactory6), &unknown);
assert(hr == S_OK);
refCount = GetRefCount(factory); // refCount = 3
assert(refCount == 3);
}
// ************************** As **************************
{
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
ComPtr<IDXGIFactory6> factory6;
hr = factory.As(&factory6); // S_OK
refCount = GetRefCount(factory); // refCount = 2
assert(refCount == 2);
}
// ************************** AsIID **************************
{
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
ComPtr<IUnknown> unknown;
hr = factory.AsIID(__uuidof(IDXGIFactory4), &unknown); // S_OK
refCount = GetRefCount(factory); // refCount = 2
assert(refCount == 2);
}
// ************************** Attach **************************
{
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // 1
assert(refCount == 1);
// ComPtr<IDXGIFactory4> factoryAttached;
// factoryAttached.Attach(factory.Get());
refCount = GetRefCount(factory); // 1
assert(refCount == 1);
// Compile Error! Release() 두번
}
// ************************** Constructor **************************
{
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // refCount = 1
ComPtr<IDXGIFactory4> factory1(); // #1
ComPtr<IDXGIFactory4> factory2(nullptr); // #2
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
ComPtr<IDXGIFactory4> factory3(factory.Get()); // #3
refCount = GetRefCount(factory); // refCount = 2
assert(refCount == 2);
ComPtr<IDXGIFactory4> factory4(factory); // #4
refCount = GetRefCount(factory); // refCount = 3
assert(refCount == 3);
// ComPtr<IDXGIAdapter> adapter(factory) Compile Error!
ComPtr<IDXGIFactory> factory5(factory); // #5
refCount = GetRefCount(factory); // refCount = 4
assert(refCount == 4);
ComPtr<IDXGIFactory4> factory6(std::move(factory)); // #6
assert(factory.Get() == nullptr);
refCount = GetRefCount(factory3); // refCount = 4
assert(refCount == 4);
ComPtr<IDXGIFactory3> factory7(std::move(factory3)); // #7
assert(factory3.Get() == nullptr);
refCount = GetRefCount(factory4); // refCount = 4
assert(refCount == 4);
}
// ************************** CopyTo **************************
{
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
ComPtr<IDXGIFactory4> factory1;
factory.CopyTo(&factory1);
refCount = GetRefCount(factory); // refCount = 2
assert(refCount == 2);
}
// ************************** Detach **************************
{
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
ComPtr<IDXGIFactory4> factory1(factory.Detach()); // factory.Get() == nullptr이기 때문에
// factory의 refCount를 알 수 있는 방법이 없음.
refCount = GetRefCount(factory1); // refCount = 2
assert(refCount == 2);
}
// ************************** operator& **************************
{
HRESULT hr;
ULONG refCount;
ComPtr<IDXGIFactory4> factory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); // S_OK
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
auto p = &factory;
refCount = GetRefCount(factory); // refCount = 1
assert(refCount == 1);
}
return 0;
}