//===     ,   
//===   
#if !defined(MY_ISAY_INTERFACE)
#define MY_ISAY_INTERFACE
#pragma once

//======  ,    COM API
#include <windows.h>
//======  ,    IUnknown
#include <initguid.h>

//  ISay     
// . ,   ,   IUnknown 
//     

interface ISay : public IUnknown
{
	//=== 2 ,  
	//===   
	virtual HRESULT __stdcall Say()=0;
	virtual HRESULT __stdcall SetWord (BSTR word)=0;
};

#endif



#if !defined(MY_COSAY_HEADER)
#define MY_COSAY_HEADER
#pragma once

class CoSay : public ISay
{
//====== ,   ISay, IUnknown
public:
	CoSay();
	virtual ~CoSay();
	
	// IUnknown
	HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
	ULONG __stdcall AddRef();
	ULONG __stdcall Release();
	
	// ISay
	HRESULT __stdcall Say();
	HRESULT __stdcall SetWord (BSTR word);

private:
	//======     
	ULONG m_ref;
	//====== ,   
	BSTR m_word;
};

#endif



#include "interfaces.h"
#include "MyCom.h"

//======    
#define MAX_LENGTH 128

CoSay::CoSay()
{
	//===     ,
	//---      
	m_ref = 0;
	//===      
	m_word = SysAllocString(L"Hi, there."
							"This is MyCom speaking");
}

CoSay::~CoSay()
{
	//===     
	if (m_word)
		SysFreeString(m_word);
}

//======   IUnknown
HRESULT __stdcall CoSay::QueryInterface(REFIID riid,
				void** ppv)
{
	//======     
	//======    
	*ppv = 0;
	if (riid==IID_IUnknown)
		*ppv = static_cast<IUnknown*>(this);
	else if (riid==IID_ISay)
		*ppv = static_cast<ISay*>(this);
	else
		return E_NOINTERFACE;
	
	//======    
	AddRef();
	return S_OK;
}

ULONG __stdcall CoSay::AddRef()
{
	return ++m_ref;
}

ULONG __stdcall CoSay::Release()
{
	if (--m_ref==0)
		delete this;
	return m_ref;
}

//======   ISay
HRESULT __stdcall CoSay::Say()
{
	//===   ( BSTR  char*), 
	//===    MessageBox
	char buff[MAX_LENGTH];
	WideCharToMultiByte(CP_ACP, 0, m_word, -1, buff,
							MAX_LENGTH, 0, 0);
	MessageBox (0, buff, "Interface ISay:", MB_OK);
	return S_OK;
}

HRESULT __stdcall CoSay::SetWord(BSTR word)
{
	//======   
	SysReAllocString(&m_word, word);
	return S_OK;
}



STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid,
								void** ppv)
{
	//===     ,
	if (rclsid != CLSID_CoSay)
		//       
		return CLASS_E_CLASSNOTAVAILABLE;

	//======   -
	CoSay *pSay = new CoSay;
	
	//===     
	HRESULT hr = pSay->QueryInterface (riid, ppv);
	
	if (FAILED(hr))
		delete pSay;
	return hr;
}



#include "interfaces.h"

void main()
{
	//======  COM Library
	CoInitialize(0);
 
	//======     
	ISay *pSay;

	//     COM DLL-,  
	//    , 
	//    CLSID_CoSay  IID_ISay

	HRESULT hr = CoGetClassObject (CLSID_CoSay,
		CLSCTX_INPROC_SERVER, 0, IID_ISay, (void**)&pSay);

	if (FAILED(hr))
	{
		MessageBox(0,"Could not get class object!",
					"CoGetClassObject",MB_OK);
		CoUninitialize();
		return;
	}

	//======     
	pSay->Say();
	BSTR word = SysAllocString(L"I hear you well");
	pSay->SetWord(word);
	SysFreeString(word);
	pSay->Say();

	//======  
	pSay->Release();

	//======    COM Library
	CoUninitialize();
}



//======    DLL
ULONG gLockCount;
//======    COM-
ULONG gObjCount;



STDAPI DllCanUnloadNow()
{
	//======   ,   
	//======   DLL-
	return !gLockCount && !gObjCount ? S_OK : S_FALSE;
}



//======   COM DLL-
class CoSayFactory : public IClassFactory
{
public:
	CoSayFactory();
	virtual ~CoSayFactory();

	// IUnknown
	HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
	ULONG __stdcall AddRef();
	ULONG __stdcall Release();

	// IClassFactory
	HRESULT __stdcall CreateInstance(LPUNKNOWN pUnk,
										REFIID riid, void** ppv);
	HRESULT __stdcall LockServer(BOOL bLock);
private:
	ULONG m_ref;
};



//==========  
CoSayFactory::CoSayFactory() 
{
	m_ref = 0;
	gObjCount++;
}

CoSayFactory::~CoSayFactory() 
{
	gObjCount--;
}

//======  IUnknown
HRESULT __stdcall CoSayFactory::QueryInterface(REFIID riid,
												void** ppv)
{
	*ppv = 0;
	//===       static_cast<>
	if (riid == IID_IUnknown)
		*ppv = (IUnknown*)this;
	else if (riid == IID_IClassFactory)
		*ppv = (IClassFactory*)this;
	else
		return E_NOINTERFACE;
	
	AddRef();
	return S_OK;
}

ULONG __stdcall CoSayFactory::AddRef() 
{ 
	return ++m_ref; 
}

ULONG __stdcall CoSayFactory::Release()
{
	if (--m_ref==0)
		delete this;
	return m_ref;
}

//======   IClassFactory
HRESULT __stdcall CoSayFactory::CreateInstance
					(LPUNKNOWN pUnk, REFIID riid, void** ppv)
{
	//      COM,
	//    

	if (pUnk)
		return CLASS_E_NOAGGREGATION;
	
	//===       
	CoSay *pSay = new CoSay;
	
	HRESULT hr = pSay->QueryInterface (riid, ppv);
	if (FAILED(hr))
		delete pSay;
	return hr;
}

//=====      
HRESULT __stdcall CoSayFactory::LockServer(BOOL bLock)
{
	if (bLock)	//  TRUE,   
		++gLockCount;
	else			//  - 
		--gLockCount;
	return S_OK;
}


STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid,
								LPVOID* ppv)
{
	if (rclsid != CLSID_CoSay)
		return CLASS_E_CLASSNOTAVAILABLE;

	CoSayFactory *pCF = new CoSayFactory;
	
	HRESULT hr = pCF->QueryInterface(riid, ppv);
		
	if (FAILED(hr))
		delete pCF;
	
	return hr;
}



#include "interfaces.h"

void main()
{
	CoInitialize(0);

	IClassFactory *pCF;

	//      CoSay,
	//   DLL   ,   
	//    CoSay,   CoSayFactory
	// (.   DllGetClassObject).
	//      
	//  IClassFactory

	HRESULT hr = CoGetClassObject(CLSID_CoSay,
					CLSCTX_INPROC_SERVER,0,
					IID_IClassFactory,(void**)&pCF);

	if (FAILED(hr))
	{
		MessageBox(0,"Could not Get Class Factory !",
				"CoGetClassObject", MB_OK);
		CoUninitialize();
		return;
	}

	//      
	//   CoSay   
	//     ISay
	ISay *pSay;
	hr = pCF->CreateInstance(0,IID_ISay, (void**)&pSay);

	if (FAILED(hr))
	{
		MessageBox(0,"Could not create CoSay and get ISay !",
					"CreateInstance", MB_OK);
		CoUninitialize();
		return;
	}

	//      
	pCF->Release();

	//======  
	pSay->Say();
	BSTR word = SysAllocString(L"Yes, My Lord");
	pSay->SetWord(word);
	SysFreeString(word);
	pSay->Say();
	
	//======    
	pSay->Release();

	CoUninitialize();
}



//======   
import "oaidl.idl";
import "ocidl.idl";

//======    ISay
[
	object, uuid(170368D0-85BE-43af-AE71-053F506657A2),
	helpstring("My Test DLL COM-server ISay")
]
interface ISay : IUnknown
{
	HRESULT Say();
	HRESULT SetWord([in]BSTR word);
}

//======   
[
	uuid(0934DA90-608D-4107-9ECC-C7E828AD0928), 
	version(1.0),
	helpstring("My Test DLL COM-server Type Library")
]
library MyCom
{
	importlib("stdole32.tlb");
	[uuid(9B865820-2FFA-11d5-98B4-00E0293F01B2)]

	//======    
	coclass CoSay
	{
		[default] interface ISay;
	};
};



; MyComTLib.def : Declares the module parameters.

LIBRARY		"MYCOMTLIB.dll"

EXPORTS
	DllGetClassObject	PRIVATE
	DllCanUnloadNow		PRIVATE



#if !defined(MY_COSAY_HEADER)
#define MY_COSAY_HEADER
#pragma once

#include "MyComTLib_h.h"

class CoSay : public ISay
{
//====== ,   ISay, IUnknown
public:
	CoSay();
	virtual ~CoSay();
	
	// IUnknown
	STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
	
	// ISay
	STDMETHODIMP Say();
	STDMETHODIMP SetWord (BSTR word);

private:
	//======     
	ULONG m_ref;
	//====== ,   
	BSTR m_word;
};

//======   COM DLL-
class CoSayFactory : public IClassFactory
{
public:
	CoSayFactory();
	virtual ~CoSayFactory();

	// IUnknown
	STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();

	// IClassFactory
	STDMETHODIMP CreateInstance(LPUNKNOWN pUnk,
										REFIID riid, void** ppv);
	STDMETHODIMP LockServer(BOOL bLock);
private:
	ULONG m_ref;
};

#endif



#include "MyComTLib_i.c"
#include "MyCom.h"

//======    
#define MAX_LENGTH 128
//======    DLL
ULONG gLockCount;
//======    COM-
ULONG gObjCount;

CoSay::CoSay()
{
//===     ,
	//===      
m_ref = 0;

	//===      
	m_word = SysAllocString(L"This is MyComTLib speaking");
	gObjCount++;
}

CoSay::~CoSay()
{
	//======     
	if (m_word)
		SysFreeString(m_word);
	gObjCount--;
}

//======   IUnknown
STDMETHODIMP CoSay::QueryInterface(REFIID riid,
												void** ppv)
{
	//     
	//    
	
	//======  IUnknown
	*ppv = 0;
	if (riid==IID_IUnknown)
		*ppv = static_cast<IUnknown*>(this);
	else if (riid==IID_ISay)
		*ppv = static_cast<ISay*>(this);
	else
		return E_NOINTERFACE;
	
	//======    
	//======   
	AddRef();
	return S_OK;
}

STDMETHODIMP_(ULONG) CoSay::AddRef()
{
 return ++m_ref; 
}

STDMETHODIMP_(ULONG) CoSay::Release()
{
	if (--m_ref==0)
		delete this;
	return m_ref;
}

//======  ISay
STDMETHODIMP CoSay::Say()
{
	//===   ( BSTR  char*),
	//===     MessageBox
	char buff[MAX_LENGTH];
	WideCharToMultiByte(CP_ACP, 0, m_word, -1, buff,
							MAX_LENGTH, 0, 0);
	MessageBox (0, buff, "Interface ISay:", MB_OK);
	return S_OK;
}

STDMETHODIMP CoSay::SetWord(BSTR word)
{
	//======   
	SysReAllocString(&m_word, word);
	return S_OK;
}

STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid,
									LPVOID* ppv)
{
	if (rclsid != CLSID_CoSay)
		return CLASS_E_CLASSNOTAVAILABLE;

	CoSayFactory *pCF = new CoSayFactory;
	
	HRESULT hr = pCF->QueryInterface(riid, ppv);
		
	if (FAILED(hr))
		delete pCF;
	
	return hr;
}

STDAPI DllCanUnloadNow()
{
	//======   ,   
	//======   DLL-
	return !gLockCount && !gObjCount ? S_OK : S_FALSE;
}

//======  
CoSayFactory::CoSayFactory() 
{
	m_ref = 0;
	gObjCount++;
}

CoSayFactory::~CoSayFactory() 
{
	gObjCount--;
}

//======  IUnknown
STDMETHODIMP CoSayFactory::QueryInterface(REFIID riid,
												void** ppv)
{
	*ppv = 0;
	//===       static_cast<>
	if (riid == IID_IUnknown)
		*ppv = (IUnknown*)this;
	else if (riid == IID_IClassFactory)
		*ppv = (IClassFactory*)this;
	else
		return E_NOINTERFACE;
	
	AddRef();
	return S_OK;
}

STDMETHODIMP_(ULONG) CoSayFactory::AddRef()
{
 return ++m_ref; 
}

STDMETHODIMP_(ULONG) CoSayFactory::Release()
{
	if (--m_ref==0)
		delete this;
	return m_ref;
}

//======  IClassFactory
STDMETHODIMP CoSayFactory::CreateInstance(LPUNKNOWN pUnk,
								REFIID riid, void** ppv)
{
	//      COM,
	//    
	if (pUnk)
		return CLASS_E_NOAGGREGATION;
	
	//===       
	CoSay *pSay = new CoSay;
	
	HRESULT hr = pSay->QueryInterface (riid, ppv);
	if (FAILED(hr))
		delete pSay;
	return hr;
}

//===      
STDMETHODIMP CoSayFactory::LockServer(BOOL bLock)
{
	if (bLock)	//  TRUE,   
		++gLockCount;
	else			//  - 
		--gLockCount;
	return S_OK;
}



REGEDIT
HKEY_CLASSES_ROOT\MyComTLib.CoSay\CLSID =
		{9B865820-2FFA-11d5-98B4-00E0293F01B2}

HKEY_CLASSES_ROOT\CLSID\
		{9B865820-2FFA-11d5-98B4-00E0293F01B2} = 
		MyComTLib.CoSay

HKEY_CLASSES_ROOT\CLSID\
		{9B865820-2FFA-11d5-98B4-00E0293F01B2}\InprocServer32
		 = D:\My Projects\MyComTLib\Debug\MyComTLib.dll

HKEY_CLASSES_ROOT\CLSID\
		{9B865820-2FFA-11d5-98B4-00E0293F01B2}\TypeLib =
		 {0934DA90-608D-4107-9ECC-C7E828AD0928}

HKEY_CLASSES_ROOT\TypeLib\
		{0934DA90-608D-4107-9ECC-C7E828AD0928} = MyComTLib

HKEY_CLASSES_ROOT\TypeLib\
		{0934DA90-608D-4107-9ECC-C7E828AD0928}\1.0\0\Win32 =
		D:\My Projects\MyComTLib\Debug\MyComTLib.tlb



#import "C:\MyProjects\MyComTLib\Debug\ MyComTLib.tlb" \
				no_namespace named_guids

void main()
{
	CoInitialize(0);
	
	//======  "" 
	ISayPtr pSay(CLSID_CoSay);
	
	pSay->Say();
	pSay->SetWord(L"The client now uses smart pointers!");
	pSay->Say();

	pSay = 0;
	
	CoUninitialize();
}



OLE_COLOR m_clrFillColor;


COpenGL()
{
	m_clrFillColor = RGB(255,230,255);
}



HRESULT OnDraw(ATL_DRAWINFO& di)
{
	//=====  RECTL  RECT
	RECT& r = *(RECT*)di.prcBounds;
	//=====    
	HRGN hRgnOld = 0;

	//===  GetClipRgn  : 0, 1  -1
	if (GetClipRgn(di.hdcDraw, hRgnOld) != 1)
		hRgnOld = 0;

	//======   
	HRGN hRgnNew = CreateRectRgn(r.left,r.top,
								r.right,r.bottom);

	//===   (  )
	bool bSelectOldRgn = false;

	//===     r
	if (hRgnNew)
	{
		bSelectOldRgn = SelectClipRgn(di.hdcDraw,hRgnNew)
						 == ERROR;
	}

	//===      
	::SelectObject(di.hdcDraw,::CreateSolidBrush(
						m_clrFillColor));
	Rectangle(di.hdcDraw, r.left, r.top, r.right, r.bottom);

	//===      
	SetTextAlign(di.hdcDraw, TA_CENTER | TA_BASELINE);
	LPCTSTR pszText = _T("ATL 4.0 : OpenGL");
	//===     
	TextOut(di.hdcDraw,(r.left + r.right)/2,
				(r.top + r.bottom)/2,
				pszText,lstrlen(pszText));

	//===   ,    
	if (bSelectOldRgn)
		SelectClipRgn(di.hdcDraw, hRgnOld);

	return S_OK;
}



void OnFillColorChanged()
{
	//======    ,
	if (m_clrFillColor & 0x80000000)
		//======     
		m_clrFillColor = ::GetSysColor(m_clrFillColor & 0x1f);
	ATLTRACE(_T("OnFillColorChanged\n"));
}



HRESULT OnDraw(ATL_DRAWINFO& di)
{
	//======     RECT
	LPCRECTL p = di.prcBounds;
	//======   	
	::SetBkColor(di.hdcDraw,m_clrFillColor);

	//======   
	::SetTextColor(di.hdcDraw, ~m_clrFillColor & 0xffffff);
	//======  
	::SelectObject(di.hdcDraw,::CreateSolidBrush(
						m_clrFillColor));

	Rectangle(di.hdcDraw, p->left, p->top,
				 p->right, p->bottom);

	SetTextAlign(di.hdcDraw, TA_CENTER | TA_BASELINE);
	LPCTSTR pszText = _T("ATL 4.0 : OpenGL");
	TextOut(di.hdcDraw, (p->left + p->right)/2,
			(p->top + p->bottom)/2,
			pszText, lstrlen(pszText));
	return S_OK;
}




