com기술내막-독서노트(5)

제 5 장
이 장은 DLL을 이용하여 COM 구성 요소(DLL은 구성 요소의 일종의 실현 형식일 뿐)를 실현하고 고객과 구성 요소의 완전한 분리를 초보적으로 실현할 것이다.그러나 이 장은 고객과 구성 요소가 철저하게 분리되지 않았기 때문에 6장과 7장에서는 더욱 유연한 방식을 소개할 것이다.
이 장은 구성 요소를 실행하는 DLL에서CreateInstance 함수를 출력하고 구성 요소를 만들 뿐입니다.
구성 요소의 모든 인터페이스 함수는 IUnknown 인터페이스를 통해 얻을 수 있기 때문에 제3장의CreateInstance 함수는 DLL에서 출력해야 합니다. 구성 요소의 실례를 만들어서 고객에게 IUnknown 인터페이스 바늘을 되돌려줍니다.
DLL을 사용하는 이유:
인터페이스 (예: IX) 는 실제적으로 함수를 가리키는 바늘 목록 (vtbl) 이며, 구성 요소는 vtbl에 메모리를 분배하고, 함수마다 주소를 사용해서 이 표를 초기화합니다.고객이 구성 요소의 인터페이스를 가져왔을 때, 그 인터페이스는 실제적으로 vtbl의 메모리를 가리킨다. DLL은 고객의 호출 프로세스와 같은 메모리 공간을 공유하기 때문에 정확한 vtbl이 분배한 메모리와 각 함수의 주소를 얻을 수 있다.
그중에 한 마디가 인상적이었다."두 프로세스의 바늘은 같은 주소 값을 포함할 수 있지만 실제로는 서로 다른 물리 메모리를 가리킨다."이것은 리눅스에서 포크를 사용하여 하위 프로세스를 만드는 코드를 떠올리게 한다.
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <cstdio>
using namespace std;


int main(void)
{
    int iTest;

    pid_t pid = fork();
    if(pid < 0)
    {
        perror("fork error");
        exit(1);
    }
    else if(pid == 0)
    {
        cout<<"main process iTest address: "<<std::hex<<&iTest<<endl;
        sleep(3);
        exit(0);
    }
    else
    {
         cout<<"fork process iTest address: "<<std::hex<<&iTest<<endl;
         sleep(3);
         exit(0);
    }
}

실행 결과
fork process iTest address: 0xbfb464cc main process iTest address: 0xbfb464cc
하위 프로세스에서 부모 프로세스의 데이터 세그먼트를 복사한 것을 볼 수 있지만, 사실 iTest는 서로 다른 물리 메모리 단원에 비추는 것이다
이 장의 프로그램 코드는 다음과 같습니다.
어셈블리 끝
cmpnt.cpp cmpnt.def
//
//cmpnt.cpp
//use: cl /LD cmpnt.cpp cmpnt.def guids.cpp uuid.lib
//
#include <objbase.h>
#include "iface.h"
#include <iostream>
#include <string>
using namespace std;

void trace(string msg)
{
	cout<<msg<<endl;
}

class CA:public IX
{
	virtual HRESULT __stdcall  QueryInterface(const IID &iid, void **ppv);
	virtual ULONG   __stdcall  AddRef();
	virtual ULONG   __stdcall  Release();

	virtual void __stdcall Fx() 
	{
		cout<<"CA:Fx"<<endl;
	}
	
public:		
	CA():m_cRef(0){;}
	~CA()
	{
		trace("Destroy self");
	}
private:
	long m_cRef;
};

HRESULT CA::QueryInterface(const IID &iid, void **ppv)
{
	if(iid == IID_IUnknown)
	{
		trace("return pointer to iunknown");
		*ppv = static_cast<IX*>(this);
	}	
	else if(iid == IID_IX)
	{
		trace("return pointer to ix");
		*ppv = static_cast<IX*>(this);
	}
	else
	{
		trace("interface not supported");
		*ppv = NULL;
		return E_NOINTERFACE;
	}
	reinterpret_cast<IUnknown*>(*ppv)->AddRef();
	return S_OK;
}

ULONG CA::AddRef()
{
	return InterlockedIncrement(&m_cRef);
}

ULONG CA::Release()
{
	if(InterlockedDecrement(&m_cRef) == 0)
	{
		delete this;
		return 0;
	}
	return m_cRef;
}

extern "C" IUnknown *CreateInstance()
{
	IUnknown *pIunknown = static_cast<IUnknown*>(new CA());
    pIunknown->AddRef();
	return pIunknown;
}

cmpnt.def
;
;compnt module-definition file
;
LIBRARY      cmpnt.dll
DESCRIPTION  'cmpnent.dll'
EXPORTS      CreateInstance @1 PRIVATE

클라이언트
create.h
//
//create.h

IUnknown *CallCreateInstance(char *name);

create.cpp
//
//create.cpp
//
#include <iostream>
#include <unknwn.h>
using namespace std;


typedef IUnknown* (*CreateFuncPtr)();
IUnknown *CallCreateInstance(char *name)
{
	HINSTANCE hInstance = ::LoadLibrary(name);
	if(hInstance == NULL)
	{
		cout<<"callcreateinstance error:can not load compnent"<<endl;
		return NULL;
	}
	CreateFuncPtr CreateInstance = (CreateFuncPtr)::GetProcAddress(hInstance , "CreateInstance");
	if(CreateInstance == NULL)
	{
		cout<<"callcreateinstance error:can not find createinstance func"<<endl;
		return NULL;
	}
	return CreateInstance();
}

client.cpp
//client.cpp
//use: cl client.cpp create.cpp guids.cpp uuid.lib
//
#include <objbase.h>
#include "iface.h"
#include "create.h"
#include <iostream>
#include <string>
using namespace std;

void trace(string msg)
{
	cout<<"client: "<<msg<<endl;
}

int main(void)
{
	HRESULT hr;
	IUnknown *pIunknown = CallCreateInstance("cmpnt.dll");
	if(pIunknown == NULL)
	{
		trace("callcreateinstance failed");
		return 1;
	}
	trace("get interface ix");

	IX *pIx = NULL;
	hr = pIunknown->QueryInterface(IID_IX, (void**)&pIx);
	if(SUCCEEDED(hr))
	{
		trace("succeeded getting ix");
		pIx->Fx();
		pIx->Release();
	}
	else
	{
		trace("could not get ix");
	}
	trace("release iunknown interface");
	pIunknown->Release();
	return 0;
}

클라이언트 및 어셈블리 측 공용 파일
iface.h
#include "objbase.h"

interface IX:IUnknown
{
	virtual void __stdcall Fx() = 0;
};

interface IY:IUnknown
{
	virtual void __stdcall Fy() = 0;
};

interface IZ:IUnknown
{
	virtual void __stdcall Fz() = 0;
};

extern const IID IID_IX

guids.cpp
#include <objbase.h>

// IIDs
// {32bb8320-b41b-11cf-a6bb-0080c7b2d682}
extern const IID IID_IX = {0x32bb8320, 0xb41b, 0x11cf,
	{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;

// {32bb8321-b41b-11cf-a6bb-0080c7b2d682}
extern const IID IID_IY = {0x32bb8321, 0xb41b, 0x11cf,
	{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;

// {32bb8322-b41b-11cf-a6bb-0080c7b2d682}
extern const IID IID_IZ = {0x32bb8322, 0xb41b, 0x11cf,
	{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;

각각 구성 요소와 클라이언트를 컴파일하여 실행합니다
실행 결과

좋은 웹페이지 즐겨찾기