GUID는 COM 인터페이스를 위한 식별자이다.
- 128bit
- Globally unique identifier
- UUID IID CLSID 도 결국엔 GUID 임
1 Library 헤더에 이식하기 위해서, PowerShell 에서 uuid를 생성한다음 클립보드에 복사한다.
uuidgen | clip
2. uuid로 인터페이스 구조체를 수정한다.
//Library.h
#pragma once
#include <Unknwn.h>
struct __declspec(uuid("26e278ff-5641-46da-94b3-1da3f19b315a"))
IHen : IUnknown
{
virtual void __stdcall Cluck() = 0;
virtual void __stdcall Roost() = 0;
};
struct __declspec(uuid("06845df9-7bb9-4d72-aaf7-0dc527078806"))
IHen2 : IHen
{
virtual void __stdcall Forage() = 0;
};
struct __declspec(uuid("eb0d7ddf-e1ad-41ef-8557-350dd8d71b2e"))
IOfflineChicken : IUnknown
{
virtual void __stdcall Load(const char* file) = 0;
virtual void __stdcall Save(const char* file) = 0;
};
HRESULT __stdcall CreateHen(IHen** result);
3. 구현한다.
//Library.cpp
#include "Library.h"
#include <Windows.h>
#include <crtdbg.h>
#define ASSERT _ASSERTE
#define TRACE OutputDebugStringA
struct Hen : IHen2, IOfflineChicken
{
long m_count;
Hen() : m_count(0)
{
TRACE("Constructor\n");
}
~Hen()
{
TRACE("Destructor\n");
}
// IUknown
ULONG __stdcall AddRef()
{
return _InterlockedIncrement(&m_count);
}
ULONG __stdcall Release()
{
const ULONG result = _InterlockedDecrement(&m_count);
if (result == 0)
{
delete this;
}
return result;
}
HRESULT __stdcall QueryInterface(const IID& id, void** result)
{
ASSERT(result);
if (id == __uuidof(IHen2) ||
id == __uuidof(IHen) ||
id == __uuidof(IUnknown))
{
*result = static_cast<IHen2*>(this);
}
else if (id == __uuidof(IOfflineChicken))
{
*result = static_cast<IOfflineChicken*>(this);
}
else
{
*result = 0;
return E_NOINTERFACE;
}
static_cast<IUnknown*>(*result)->AddRef();
return S_OK;
}
// IHen
void __stdcall Cluck()
{
TRACE("Cluck\n");
}
void __stdcall Roost()
{
TRACE("Roost\n");
}
// IHen2
void __stdcall Forage()
{
TRACE("Forage\n");
}
// IOfflineChicken
void __stdcall Load(const char* /*file*/) {}
void __stdcall Save(const char* /*file*/) {}
};
HRESULT __stdcall CreateHen(IHen** result)
{
ASSERT(result);
*result = new (std::nothrow) Hen;
if (0 == *result)
{
return E_OUTOFMEMORY;
}
(*result)->AddRef();
return S_OK;
}
4. 정상적으로 동작하는지 확인한다.
#include "Library.h"
int main()
{
IHen* hen;
if (CreateHen(&hen) != S_OK)
{
return 0;
}
hen->Cluck();
IHen2* hen2;
//if (S_OK == hen->QueryInterface(__uuidof(IHen2),
// reinterpret_cast<void**>(&hen2)))
if (S_OK == hen->QueryInterface(&hen2))
{
hen2->Forage();
hen2->Release();
}
IOfflineChicken* offline;
if (S_OK == hen->QueryInterface(&offline))
{
offline->Save("filename");
offline->Release();
}
hen->Release();
}
5. _InterLocked류의 함수들은 과거 API시절부터 있었던 친구들이다. SDK에서 제공하며, 스레드 세이프한 함수들이다.
6. C++ 코드를 바이너리 레벨로 옯겨서, 재사용, 통합하는 것이 COM 의 철학이다.
'삽질 > COM' 카테고리의 다른 글
Verify (0) | 2020.11.13 |
---|---|
COM study note 8 IUnknown C# 버전 (0) | 2020.10.30 |
COM study note 7 (0) | 2020.10.29 |
COM study note 6 인터페이스 상속 (0) | 2020.10.28 |
COM study note 5 레퍼런스 카운터 (0) | 2020.10.28 |