//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
//  
// TypeTest.h : Deklaracja CTypeTest

#pragma once
#include "resource.h"       // główne symbole
#include "CorError.h"
#include <map>
typedef std::pair <std::wstring, unsigned int> ComError;
typedef std::map <std::wstring, unsigned int> :: const_iterator ComErrorIterator;

// ITypeTest
[
	object,
	uuid("57101F2B-8A4F-44FB-AE5F-8011CD13D564"),
	dual,	helpstring("ITypeTest Interface"),
	pointer_default(unique)
]
__interface ITypeTest : IDispatch
{
	[propget, id(1), helpstring("właściwość Name")] HRESULT Name([out, retval] BSTR* pVal);
	[propput, id(1), helpstring("właściwość Name")] HRESULT Name([in] BSTR newVal);
	[propget, id(2), helpstring("właściwość Date")] HRESULT Date([out, retval] DATE* pVal);
	[propput, id(2), helpstring("właściwość Date")] HRESULT Date([in] DATE newVal);
	[propget, id(3), helpstring("właściwość Color")] HRESULT Color([out, retval] VARIANT* pVal);
	[propput, id(3), helpstring("właściwość Color")] HRESULT Color([in] VARIANT newVal);
	[propget, id(4), helpstring("właściwość Currency")] HRESULT Currency([out, retval] CY* pVal);
	[propput, id(4), helpstring("właściwość Currency")] HRESULT Currency([in] CY newVal);
	[propget, id(5), helpstring("właściwość Object")] HRESULT Object([out, retval] VARIANT* pVal);
	[propput, id(5), helpstring("właściwość Object")] HRESULT Object([in] VARIANT newVal);
	[propget, id(6), helpstring("właściwość Array")] HRESULT Array([out, retval] VARIANT* pVal);
	[propput, id(6), helpstring("właściwość Array")] HRESULT Array([in] VARIANT newVal);
	[id(7), helpstring("metoda ErrorTest")] HRESULT ErrorTest([in] BSTR error);
	[propget, id(8), helpstring("właściwość Enumerator")] HRESULT Enumerator([out, retval] IEnumVARIANT** pVal);
};


// _ITypeTestEvents
[
	dispinterface,
	uuid("9FA87D5F-F726-421F-869B-A84AF2A9B22A"),
	helpstring("Interfejs _ITypeTestEvents")
]
__interface _ITypeTestEvents
{
	[id(1), helpstring("metoda Callback")] HRESULT Callback([in] LONG count);
	[id(2), helpstring("metoda NameCallback")] HRESULT NameCallback(BSTR objectName);
	[id(3), helpstring("metoda DateCallback")] HRESULT DateCallback(DATE objectDate);
	[id(4), helpstring("metoda ColorCallback")] HRESULT ColorCallback(VARIANT objectColor);
	[id(5), helpstring("metoda CurrencyCallback")] HRESULT CurrencyCallback(CY objectCurrency);
	[id(6), helpstring("metoda ObjectCallback")] HRESULT ObjectCallback(VARIANT objectVariant);
	[id(7), helpstring("metoda ArrayCallback")] HRESULT ArrayCallback(VARIANT objectArray);
};


// CTypeTest

[
	coclass,
	threading("apartment"),
	support_error_info("ITypeTest"),
	event_source("com"),
	vi_progid("COMTypes.TypeTest"),
	progid("COMTypes.TypeTest.1"),
	version(1.0),
	uuid("57DE8B2D-2A18-447B-917C-17AD18849A8C"),
	helpstring("Klasa TypeTest")
]
class ATL_NO_VTABLE CTypeTest : 
	public ITypeTest
{
public:
	CTypeTest()
	{
		count = 0;
		uiDatagramThreadID = 0;
		hDatagramThreadHandle = 0;
		hDatagramThreadTerminateEvent = 0;
		// errorMap.insert(ComError(L"MSEE_E_APPDOMAINUNLOADED",MSEE_E_APPDOMAINUNLOADED));
		// errorMap.insert(ComError(L"COR_E_CORE",COR_E_CORE));
		// errorMap.insert(ComError(L"COR_E_COMEMULATE_ERROR",COR_E_COMEMULATE_ERROR));
		// errorMap.insert(ComError(L"COR_E_WEAKREFERENCE",COR_E_WEAKREFERENCE));
		// errorMap.insert(ComError(L"COR_E_VTABLECALLSNOTSUPPORTED",COR_E_VTABLECALLSNOTSUPPORTED));
		errorMap.insert(ComError(L"COR_E_APPLICATION",COR_E_APPLICATION));
		errorMap.insert(ComError(L"COR_E_ARGUMENT",COR_E_ARGUMENT));
		errorMap.insert(ComError(L"E_INVALIDARG",E_INVALIDARG));
		errorMap.insert(ComError(L"COR_E_ARGUMENTOUTOFRANGE",COR_E_ARGUMENTOUTOFRANGE));
		errorMap.insert(ComError(L"COR_E_ARITHMETIC",COR_E_ARITHMETIC));
		errorMap.insert(ComError(L"ERROR_ARITHMETIC_OVERFLOW",ERROR_ARITHMETIC_OVERFLOW));
		errorMap.insert(ComError(L"COR_E_ARRAYTYPEMISMATCH",COR_E_ARRAYTYPEMISMATCH));
		errorMap.insert(ComError(L"COR_E_BADIMAGEFORMAT",COR_E_BADIMAGEFORMAT));
		errorMap.insert(ComError(L"ERROR_BAD_FORMAT",ERROR_BAD_FORMAT));
		errorMap.insert(ComError(L"COR_E_CONTEXTMARSHAL",COR_E_CONTEXTMARSHAL));
		errorMap.insert(ComError(L"NTE_FAIL",NTE_FAIL));
		errorMap.insert(ComError(L"COR_E_DIRECTORYNOTFOUND",COR_E_DIRECTORYNOTFOUND));
		errorMap.insert(ComError(L"ERROR_PATH_NOT_FOUND",ERROR_PATH_NOT_FOUND));
		errorMap.insert(ComError(L"COR_E_DIVIDEBYZERO",COR_E_DIVIDEBYZERO));
		errorMap.insert(ComError(L"COR_E_DUPLICATEWAITOBJECT",COR_E_DUPLICATEWAITOBJECT));
		errorMap.insert(ComError(L"COR_E_ENDOFSTREAM",COR_E_ENDOFSTREAM));
		errorMap.insert(ComError(L"COR_E_TYPELOAD",COR_E_TYPELOAD));
		errorMap.insert(ComError(L"COR_E_EXCEPTION",COR_E_EXCEPTION));
		errorMap.insert(ComError(L"COR_E_EXECUTIONENGINE",COR_E_EXECUTIONENGINE));
		errorMap.insert(ComError(L"COR_E_FIELDACCESS",COR_E_FIELDACCESS));
		errorMap.insert(ComError(L"COR_E_FILENOTFOUND",COR_E_FILENOTFOUND));
		errorMap.insert(ComError(L"ERROR_FILE_NOT_FOUND",ERROR_FILE_NOT_FOUND));
		errorMap.insert(ComError(L"COR_E_FORMAT",COR_E_FORMAT));
		errorMap.insert(ComError(L"COR_E_INDEXOUTOFRANGE",COR_E_INDEXOUTOFRANGE));
		errorMap.insert(ComError(L"COR_E_INVALIDCAST",COR_E_INVALIDCAST));
		errorMap.insert(ComError(L"E_NOINTERFACE",E_NOINTERFACE));
		errorMap.insert(ComError(L"COR_E_INVALIDCOMOBJECT",COR_E_INVALIDCOMOBJECT));
		errorMap.insert(ComError(L"COR_E_INVALIDFILTERCRITERIA",COR_E_INVALIDFILTERCRITERIA));
		errorMap.insert(ComError(L"COR_E_INVALIDOLEVARIANTTYPE",COR_E_INVALIDOLEVARIANTTYPE));
		errorMap.insert(ComError(L"COR_E_INVALIDOPERATION",COR_E_INVALIDOPERATION));
		errorMap.insert(ComError(L"COR_E_IO",COR_E_IO));
		errorMap.insert(ComError(L"COR_E_MEMBERACCESS",COR_E_MEMBERACCESS));
		errorMap.insert(ComError(L"COR_E_METHODACCESS",COR_E_METHODACCESS));
		errorMap.insert(ComError(L"COR_E_MISSINGFIELD",COR_E_MISSINGFIELD));
		errorMap.insert(ComError(L"COR_E_MISSINGMANIFESTRESOURCE",COR_E_MISSINGMANIFESTRESOURCE));
		errorMap.insert(ComError(L"COR_E_MISSINGMEMBER",COR_E_MISSINGMEMBER));
		errorMap.insert(ComError(L"COR_E_MISSINGMETHOD",COR_E_MISSINGMETHOD));
		errorMap.insert(ComError(L"COR_E_MULTICASTNOTSUPPORTED",COR_E_MULTICASTNOTSUPPORTED));
		errorMap.insert(ComError(L"COR_E_NOTFINITENUMBER",COR_E_NOTFINITENUMBER));
		errorMap.insert(ComError(L"E_NOTIMPL",E_NOTIMPL));
		errorMap.insert(ComError(L"COR_E_NOTSUPPORTED",COR_E_NOTSUPPORTED));
		errorMap.insert(ComError(L"COR_E_NULLREFERENCE",COR_E_NULLREFERENCE));
		errorMap.insert(ComError(L"E_POINTER",E_POINTER));
		errorMap.insert(ComError(L"COR_E_OUTOFMEMORY",COR_E_OUTOFMEMORY));
		errorMap.insert(ComError(L"E_OUTOFMEMORY",E_OUTOFMEMORY));
		errorMap.insert(ComError(L"COR_E_OVERFLOW",COR_E_OVERFLOW));
		errorMap.insert(ComError(L"COR_E_PATHTOOLONG",COR_E_PATHTOOLONG));
		errorMap.insert(ComError(L"ERROR_FILENAME_EXCED_RANGE",ERROR_FILENAME_EXCED_RANGE));
		errorMap.insert(ComError(L"COR_E_RANK",COR_E_RANK));
		errorMap.insert(ComError(L"COR_E_REFLECTIONTYPELOAD",COR_E_REFLECTIONTYPELOAD));
		errorMap.insert(ComError(L"COR_E_REMOTING",COR_E_REMOTING));
		errorMap.insert(ComError(L"COR_E_SAFEARRAYTYPEMISMATCH",COR_E_SAFEARRAYTYPEMISMATCH));
		errorMap.insert(ComError(L"COR_E_SECURITY",COR_E_SECURITY));
		errorMap.insert(ComError(L"COR_E_SERIALIZATION",COR_E_SERIALIZATION));
		errorMap.insert(ComError(L"COR_E_STACKOVERFLOW",COR_E_STACKOVERFLOW));
		errorMap.insert(ComError(L"ERROR_STACK_OVERFLOW",ERROR_STACK_OVERFLOW));
		errorMap.insert(ComError(L"COR_E_SYNCHRONIZATIONLOCK",COR_E_SYNCHRONIZATIONLOCK));
		errorMap.insert(ComError(L"COR_E_SYSTEM",COR_E_SYSTEM));
		errorMap.insert(ComError(L"COR_E_TARGET",COR_E_TARGET));
		errorMap.insert(ComError(L"COR_E_TARGETINVOCATION",COR_E_TARGETINVOCATION));
		errorMap.insert(ComError(L"COR_E_TARGETPARAMCOUNT",COR_E_TARGETPARAMCOUNT));
		errorMap.insert(ComError(L"COR_E_THREADABORTED",COR_E_THREADABORTED));
		errorMap.insert(ComError(L"COR_E_THREADINTERRUPTED",COR_E_THREADINTERRUPTED));
		errorMap.insert(ComError(L"COR_E_THREADSTATE",COR_E_THREADSTATE));
		errorMap.insert(ComError(L"COR_E_THREADSTOP",COR_E_THREADSTOP));
		errorMap.insert(ComError(L"COR_E_TYPELOAD",COR_E_TYPELOAD));
		errorMap.insert(ComError(L"COR_E_TYPEINITIALIZATION",COR_E_TYPEINITIALIZATION));
		errorMap.insert(ComError(L"COR_E_VERIFICATION",COR_E_VERIFICATION));
		errorMap.insert(ComError(L"E_FAIL",E_FAIL));
	}

	__event __interface _ITypeTestEvents;

	DECLARE_PROTECT_FINAL_CONSTRUCT()

	HRESULT FinalConstruct()
	{
		hDatagramThreadTerminateEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
		hDatagramThreadHandle = (HANDLE)_beginthreadex (NULL, 0, ProcessCallback, this, CREATE_SUSPENDED, &uiDatagramThreadID);
		SetThreadPriority(hDatagramThreadHandle, THREAD_PRIORITY_ABOVE_NORMAL);
		ResumeThread(hDatagramThreadHandle);
		return S_OK;
	}
	
	void FinalRelease() 
	{
		SetEvent(hDatagramThreadTerminateEvent);
		DWORD dwReturn = WaitForSingleObject(hDatagramThreadHandle, 2000);
		if(dwReturn == WAIT_OBJECT_0)
		{
			ATLTRACE("Przerwanie ProcessCallback zakończyło się powodzeniem.\n");
		}
		else if(dwReturn == WAIT_TIMEOUT)
		{
			ATLTRACE("Upłynął czas oczekiwania na powrót z ProcessCallback.\n");
		}
	}

public:

	STDMETHOD(get_Name)(BSTR* pVal);
	STDMETHOD(put_Name)(BSTR newVal);
	STDMETHOD(get_Date)(DATE* pVal);
	STDMETHOD(put_Date)(DATE newVal);
	STDMETHOD(get_Color)(VARIANT* pVal);
	STDMETHOD(put_Color)(VARIANT newVal);
	STDMETHOD(get_Currency)(CY* pVal);
	STDMETHOD(put_Currency)(CY newVal);
	STDMETHOD(get_Object)(VARIANT* pVal);
	STDMETHOD(put_Object)(VARIANT newVal);
	STDMETHOD(get_Array)(VARIANT* pVal);
	STDMETHOD(put_Array)(VARIANT newVal);
	STDMETHOD(ErrorTest)(BSTR error);
	STDMETHOD(get_Enumerator)(IEnumVARIANT** pVal);

private:
	static UINT __stdcall ProcessCallback (LPVOID lpParam);

	_bstr_t name;
	DATE date;
	_variant_t color;
	CY currency;
	_variant_t object;
	LONG count;
	CComSafeArray < VARIANT > array;
	std::map<std::wstring, unsigned int> errorMap;
	UINT uiDatagramThreadID;
	HANDLE hDatagramThreadHandle;
	HANDLE hDatagramThreadTerminateEvent;
};

