Win32 Dynamic-Link Library 형식의 프로젝트를 만든다.
접기
#include <objbase.h>
//#include <iostream.h>
static HMODULE s_hModule = NULL ;
static long s_cServerLocks = 0;
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
// {
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
s_hModule = (HMODULE)hModule;
break;
}
// }
return TRUE;
}
void ClsidToChar(const CLSID& clsid, char* szCLSID, int length);
BOOL SetRegistryInform(const char* szKey, const char* szSubkey, const char* szValue);
DWORD DeleteRegistryKey(HKEY hStartKey , const char* pKeyName );
static const int CLSID_STRING_SIZE = 39;
// {504966F2-40AB-4bff-916A-15E3E91424B3}
static const CLSID CLSID_COMPONENT =
{ 0x504966f2, 0x40ab, 0x4bff,
{ 0x91, 0x6a, 0x15, 0xe3, 0xe9, 0x14, 0x24, 0xb3 } };
const char szFriendlyName[] = "CfwCom2 Example";
const char szVerIndProgID[] = "CfwCom2.Control";
const char szProgID[] = "CfwCom2.Control.1";
class CFactory : public IClassFactory
{
public:
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,
const IID& iid,
void** ppv);
virtual HRESULT __stdcall LockServer(BOOL bLock);
CFactory() : m_cRef(1){}
~CFactory()
{
// cout << "Class Factory is destoryed itself." << endl;
}
private:
long m_cRef;
};
static const IID IID_ISetValue = // {0CF9BAC4-79AB-444e-B5E6-B084ABE011D3}
{ 0xcf9bac4, 0x79ab, 0x444e, { 0xb5, 0xe6, 0xb0, 0x84, 0xab, 0xe0, 0x11, 0xd3 }};
static const IID IID_ISimpleCal = // {C8D5E047-DC09-4af0-965D-A4815ADA2A50}
{ 0xc8d5e047, 0xdc09, 0x4af0, { 0x96, 0x5d, 0xa4, 0x81, 0x5a, 0xda, 0x2a, 0x50 }};
interface ISetValue : IUnknown
{
virtual void __stdcall SetValue(int, int) = 0;
};
interface ISimpleCal : IUnknown
{
virtual int __stdcall Sum() = 0;
virtual int __stdcall Sub() = 0;
};
class CSimpleCalc : public ISetValue, ISimpleCal
{
int x,y;
public:
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
// ISetValue
virtual void __stdcall SetValue(int x1,int y1)
{
x = x1;
y = y1;
}
// ISimpleCal
virtual int __stdcall Sum()
{
return x + y;
}
virtual int __stdcall Sub()
{
return x - y;
}
public:
// Constructor
CSimpleCalc() : m_cRef(1)
{
}
// Destructor
~CSimpleCalc()
{
cout << "CSimpleCalc is Destoryed by itself." << endl;
}
private:
long m_cRef;
};
STDAPI DllRegisterServer()
{
// Get server location.
char szCLSID[CLSID_STRING_SIZE];
char szModule[512] ;
char szKey[64] ;
DWORD dwResult = ::GetModuleFileName(
s_hModule,
szModule,
sizeof(szModule)/sizeof(char)) ;
if(dwResult == 0)
return E_FAIL;
// CLSID\{504966F2-40AB-4bff-916A-15E3E91424B3}키를 조합하기 위한 루틴
ClsidToChar(CLSID_COMPONENT, szCLSID, sizeof(szCLSID));
strcpy(szKey, "CLSID\\") ;
strcat(szKey, szCLSID) ;
SetRegistryInform(szKey, NULL, szFriendlyName);
SetRegistryInform(szKey, "InprocServer32", szModule);
SetRegistryInform(szKey, "ProgID", szProgID);
SetRegistryInform(szKey, "VersionIndependentProgID",szVerIndProgID) ;
// HKEY_CLASSES_ROOT\LittleSum Example
SetRegistryInform(szVerIndProgID, NULL, szFriendlyName) ;
SetRegistryInform(szVerIndProgID, "CLSID", szCLSID) ;
SetRegistryInform(szVerIndProgID, "CurVer", szProgID) ;
// HKEY_CLASSES_ROOT\LittleSum.Control.1
SetRegistryInform(szProgID, NULL, szFriendlyName) ;
SetRegistryInform(szProgID, "CLSID", szCLSID) ;
return S_OK ;
}
STDAPI DllUnregisterServer()
{
// Build the key CLSID\\{...}
char szCLSID[CLSID_STRING_SIZE];
char szKey[64] ;
ClsidToChar(CLSID_COMPONENT, szCLSID, sizeof(szCLSID));
strcpy(szKey, "CLSID\\") ;
strcat(szKey, szCLSID) ;
// CLSID Key - CLSID\{...} 삭제.
LONG lResult = DeleteRegistryKey(HKEY_CLASSES_ROOT, szKey) ;
// version-independent ProgID Key 삭제.
lResult = DeleteRegistryKey(HKEY_CLASSES_ROOT, szVerIndProgID) ;
// ProgID key 삭제.
lResult = DeleteRegistryKey(HKEY_CLASSES_ROOT, szProgID) ;
return S_OK ;
}
STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv)
{
CFactory* pFactory = new CFactory;
if(pFactory == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pFactory->QueryInterface(iid,ppv);
pFactory->Release();
return hr;
}
void ClsidToChar(const CLSID& clsid, char* szCLSID, int length)
{
LPOLESTR wszCLSID = NULL ;
HRESULT hr = StringFromCLSID(clsid, &wszCLSID) ;
wcstombs(szCLSID, wszCLSID, length) ;
CoTaskMemFree(wszCLSID) ;
}
BOOL SetRegistryInform(const char* szKey, const char* szSubkey, const char* szValue)
{
HKEY hKey;
char szBuf[1024] ;
// 레지스터리의 키 와 서버 키의 값을 szBuf에 기록한다.
strcpy(szBuf, szKey) ;
if (szSubkey != NULL)
{
strcat(szBuf, "\\") ;
strcat(szBuf, szSubkey ) ;
}
// szBuf에 기록된 키 값의 정보를 가지고 키를 생성한다.
long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT,
szBuf,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL,
&hKey,
NULL) ;
if (lResult != ERROR_SUCCESS)
{
return FALSE ;
}
RegSetValueEx(hKey,
NULL,
0,
REG_SZ,
(BYTE *)szValue,
strlen(szValue)+1) ;
RegCloseKey(hKey) ;
return TRUE ;
}
DWORD DeleteRegistryKey(HKEY hStartKey , const char* pKeyName )
{
DWORD dwRtn, dwSubKeyLength;
LPTSTR pSubKey = NULL;
TCHAR szSubKey[256];
HKEY hKey;
// NULL 값 혹은 pKeyName에 정보가 없다면 리턴한다.
if ( pKeyName && lstrlen(pKeyName))
{
if( (dwRtn=RegOpenKeyEx(hStartKey,pKeyName,
0, KEY_ENUMERATE_SUB_KEYS | DELETE, &hKey )) == ERROR_SUCCESS)
{
while (dwRtn == ERROR_SUCCESS )
{
dwSubKeyLength = 256;
dwRtn=RegEnumKeyEx(
hKey,
0, // always index zero
szSubKey,
&dwSubKeyLength,
NULL,
NULL,
NULL,
NULL
);
if(dwRtn == ERROR_NO_MORE_ITEMS)
{
dwRtn = RegDeleteKey(hStartKey, pKeyName);
break;
}
else if(dwRtn == ERROR_SUCCESS)
dwRtn=DeleteRegistryKey(hKey, szSubKey);
}
RegCloseKey(hKey);
}
}
else
dwRtn = ERROR_BADKEY;
return dwRtn;
}
HRESULT __stdcall CFactory::QueryInterface(const IID& iid, void** ppv)
{
if((iid == IID_IUnknown) || (iid == IID_IClassFactory))
{
*ppv = static_cast<IClassFactory*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
ULONG __stdcall CFactory::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
ULONG __stdcall CFactory::Release()
{
if(InterlockedDecrement(&m_cRef) == 0)
{
delete this;
return 0;
}
return m_cRef;
}
HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,
const IID& iid,
void** ppv)
{
if(pUnknownOuter != NULL)
{
return CLASS_E_NOAGGREGATION;
}
CSimpleCalc* pSc = new CSimpleCalc;
if(pSc == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pSc->QueryInterface(iid,ppv);
pSc->Release();
return hr;
}
HRESULT __stdcall CFactory::LockServer(BOOL bLock)
{
if (bLock)
{
::InterlockedIncrement(&s_cServerLocks) ;
}
else
{
::InterlockedDecrement(&s_cServerLocks) ;
}
return S_OK;
}
다음은 인터페이스 구현 코드의 나머지이다.
HRESULT __stdcall CSimpleCalc::QueryInterface(const IID& iid, void** ppv)
{
if(iid == IID_IUnknown)
{
// cout << "QueryInterface: Return pointer to IUnknown." << endl;
*ppv = static_cast<ISetValue*>(this);
}
else if(iid == IID_ISetValue)
{
cout << "QueryInterface: Return pointer to ISetValue." << endl;
*ppv = static_cast<ISetValue*>(this);
}
else if(iid == IID_ISimpleCal)
{
// cout << "QueryInterface: Return pointer to ISimpleCal." << endl;
*ppv = static_cast<ISimpleCal*>(this);
}
else
{
// cout << "QueryInterface: Interface not supported." << endl;
*ppv = NULL;
return E_NOINTERFACE;
}
static_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
ULONG __stdcall CSimpleCalc::AddRef()
{
// cout << "CSimpleCalc: AddRef = " << m_cRef+1 << endl;
return InterlockedIncrement(&m_cRef) ;
}
ULONG __stdcall CSimpleCalc::Release()
{
// cout << "CSimpleCalc: Release = " << m_cRef-1 << endl << endl;
if (InterlockedDecrement(&m_cRef) == 0)
{
delete this ;
return 0 ;
}
return m_cRef ;
}
접기