Published 2020. 10. 30. 00:06

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에서 제공하며, 스레드 세이프한 함수들이다.

 

Thread Safety (스레드 안전) Interlocked. 함수들.

개요 Interlocked 류 함수들은 멀티스레드 환경에서 long 타입, 포인터타입의 공유변수들의 단순한 처리(+1, -1,더하기, 대입, 비교대입) 에 있어서 함수 자체에서 스레드 안전을 보장한다. Interlocked

igotit.tistory.com

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
복사했습니다!