이 소스로는 아직까지는 main 에서 LoadLibrary 를 사용하여 DLL의 이름을 로드해서 쓰는 DLL 의잔재가 남아있다.. 다음번에 해결 하도록 하고 일단 아래 소스로 개념을 이해하자.
( 레지스트리에 DLL의 CLSID를 등록한것을 이용해서 DLL의 경로명을 가져와 사용할 수 있도록 다음번엔)
Component DLL ------------------------ DLL 로 제작.
- Interface 선언 -> interface.h
- IID -> interface_i.h
- CoClass (실제 동작 클래스) -> Component.cpp
- CreateInstance() -> Component.cpp
component.def 파일도 만들어서 프로젝트에 같이 넣어준다.
Client -------------------------------- 사용하는 플그램
interface.h 와
interface_i.h 를 인쿨르드 하여 사용.
============= 실제 소스 ========= DLL ===================
CInside.cpp
#include <iostream.h>
#include <objbase.h>
#include "interface.h"
#include "interface_i.c"
extern const IID IID_ISetVal;
extern const IID IID_ICalcu;
class CInsideCom : public ISetVal, ICalcu
{
int x,y;
virtual HRESULT __stdcall QueryInterface(REFIID iid, void** ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
virtual void __stdcall SetValue(int x1, int y1)
{
x = x1;
y = y1;
}
virtual int __stdcall Sum() {
return x+y;
}
virtual int __stdcall Sub() {
return x-y;
}
public:
CInsideCom() : m_cRef(0) {}
~CInsideCom() {
cout << "CInsideCom is destroyed by itself." << endl;
}
private:
long m_cRef;
};
HRESULT __stdcall CInsideCom::QueryInterface(REFIID iid, void** ppv)
{
if(iid == IID_IUnknown) {
*ppv = static_cast<ISetVal*>(this);
}
else if(iid == IID_ISetVal) {
*ppv = static_cast<ISetVal*>(this);
}
else if(iid == IID_ICalcu) {
*ppv = static_cast<ICalcu*>(this);
}
else {
cout << "QueryInterface : interface not supported" << endl;
*ppv = NULL;
return E_NOINTERFACE;
}
static_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
ULONG __stdcall CInsideCom::AddRef()
{
cout << "m_cRef = " << m_cRef+1 << endl;
return InterlockedIncrement(&m_cRef);
}
ULONG __stdcall CInsideCom::Release()
{
cout << "m_cRef = " << m_cRef-1 << endl;
if(InterlockedDecrement(&m_cRef) == 0 ) {
delete this;
return 0;
}
return m_cRef;
}
// #define STDAPI_(type) EXTERN_C type STDAPICALLTYPE C함수로 동작. C++에서 이렇게 안하면 함수이름바뀜.
STDAPI_(IUnknown*) CreateInstance()
{
IUnknown *pI = static_cast<ISetVal*>(new CInsideCom);
pI->AddRef();
return pI;
}
interface_i.c
#pragma once
#include <objbase.h>
// {7D1DA4D3-2DD8-4317-937D-157BF19DE48C}
static const IID IID_ISetVal =
{ 0x7d1da4d3, 0x2dd8, 0x4317, { 0x93, 0x7d, 0x15, 0x7b, 0xf1, 0x9d, 0xe4, 0x8c } };
// {1BA9514E-9303-4c4d-948A-D1EAA0932A82}
static const IID IID_ICalcu =
{ 0x1ba9514e, 0x9303, 0x4c4d, { 0x94, 0x8a, 0xd1, 0xea, 0xa0, 0x93, 0x2a, 0x82 } };
interface.h
#pragma once
#include <objbase.h>
interface ISetVal : IUnknown
{
virtual void __stdcall SetValue(int , int) = 0;
};
interface ICalcu : IUnknown
{
virtual int __stdcall Sum() = 0;
virtual int __stdcall Sub() = 0;
};
Cinside.def
; module-definition file.... 이것이 주석의 개념이다.
LIBRARY CInsideComDll.dll
DESCRIPTION 'InsideCom‘
EXPORTS
CreateInstance @1 PRIVATE
============== 컴포넌트 사용 Console 프로젝트파일 ================
dll파일과 interface.h interface_i.c 파일 복사해옴.
//InsideComClient.cpp
#include <iostream.h>
#include <objbase.h>
#include "interface.h"
#include "interface_i.c"
HINSTANCE hc;
IUnknown* CreateInstance(char* name)
{
IUnknown* (*pFunc)();
hc = ::LoadLibrary(name);
if(hc == NULL) {
cout << "LoadLibrary() failed with error" << endl;
return NULL;
}
pFunc = (IUnknown * (*)()) ::GetProcAddress(hc,"CreateInstance");
if(pFunc == NULL) {
cout << "GetProcAddress() failed with Error" << endl;
return NULL;
}
return pFunc(); //객체 생성
}
void main(void)
{
HRESULT hr;
int x1, y1;
cout << "Please enter an integer x1 and y1" << endl;
cin >> x1 >> y1;
IUnknown* pIUnknown=NULL;
pIUnknown = CreateInstance("CInsideComDll.dll");
if(pIUnknown == NULL) {
cout << "CreateInstance() failed with error" << endl;
return;
}
ISetVal* pISetVal=NULL;
hr = pIUnknown->QueryInterface(IID_ISetVal,(void**)&pISetVal);
if(SUCCEEDED(hr)) {
pISetVal->SetValue(x1,y1);
pISetVal->Release();
}
ICalcu* pICalcu = NULL;
hr = pIUnknown->QueryInterface(IID_ICalcu,(void**)&pICalcu);
if(SUCCEEDED(hr)) {
cout << "x1 + y1 = " << pICalcu->Sum() << endl;
cout << "x1 - y1 = " << pICalcu->Sub() << endl;
pICalcu->Release();
}
pIUnknown->Release();
FreeLibrary(hc);
}