//
// 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.
//
// 
using System;
using System.Collections;
using System.Runtime.InteropServices;

using System.IO;
using System.Reflection;
using System.Resources;
using System.Security;
using System.Security.Cryptography;
using System.Threading;
using System.Runtime.Remoting;
using System.Runtime.Serialization;
using System.Diagnostics;
using System.Drawing;

namespace InteropSample
{
	[ComVisible(false)]
	public delegate void ColorHandler(Color o);
	[ComVisible(false)]
	public delegate void DateHandler(DateTime dt);
	[ComVisible(false)]
	public delegate void NameHandler(string s);
	[ComVisible(false)]
	public delegate void DecimalHandler(decimal d);
	[ComVisible(false)]
	public delegate void VariantHandler(object o);
	[ComVisible(false)]
	public delegate void ArrayHandler(object [] o);
	[ComVisible(false)]
	public delegate void CounterHandler(int c);

	[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
	public interface _IComTypesEvents
	{
		[DispId(1)]
		void ColorChanged(Color o);
		[DispId(2)]
		void DateChanged(DateTime d);
		[DispId(3)]
		void NameChanged(string s);
		[DispId(4)]
		void DecimalChanged(decimal d);
		[DispId(5)]
		void VariantChanged(object o);
		[DispId(6)]
		void ArrayChanged(object [] o);
		[DispId(7)]
		void Counter(int c);
	}

	public interface IComTypes
	{
		Color ColorValue
		{
			get;
			set;
		}
		DateTime Date
		{
			get;
			set;
		}
		string Name
		{
			get;
			set;
		}
		decimal Decimal
		{
			get;
			set;
		}
		object Variant
		{
			get;
			set;
		}
		object [] Array
		{
			get;
			set;
		}
		IEnumerator Enumerator
		{
			get;
		}

		void ErrorTest(string error);
	}
	/// <summary>
	/// Podsumowanie dla CComTypes.
	/// </summary>
	[ClassInterface(ClassInterfaceType.None)]
	[ComSourceInterfaces("InteropSample._IComTypesEvents, dotNETCOMTypes")]
	public class CComTypes : IComTypes
	{
		public event ColorHandler ColorChanged;
		public event DateHandler DateChanged;
		public event NameHandler NameChanged;
		public event DecimalHandler DecimalChanged;
		public event VariantHandler VariantChanged;
		public event ArrayHandler ArrayChanged;
		public event CounterHandler Counter;
		Hashtable errorExceptions;
		void CounterEntry()
		{
			try
			{
				while(true)
				{
					Thread.Sleep(1000);
					if(Counter != null)
						Counter(counter++);
				}
			}
			finally
			{
				Debug.WriteLine("Wyjście z wątku licznika!");
			}
		}
		public CComTypes()
		{
			counter = 0;

			counterThread = new Thread(new ThreadStart(CounterEntry));
			counterThread.Start();

			errorExceptions = new Hashtable();
			errorExceptions.Add("COR_E_APPLICATION", new ApplicationException("To jest test"));
			errorExceptions.Add("COR_E_ARGUMENT", new ArgumentException("To jest test"));
			errorExceptions.Add("E_INVALIDARG", new ArgumentException("To jest test"));
			errorExceptions.Add("COR_E_ARGUMENTOUTOFRANGE", new ArgumentOutOfRangeException("To jest test"));
			errorExceptions.Add("COR_E_ARITHMETIC", new ArithmeticException("To jest test"));
			errorExceptions.Add("ERROR_ARITHMETIC_OVERFLOW", new ArithmeticException("To jest test"));
			errorExceptions.Add("COR_E_ARRAYTYPEMISMATCH", new ArrayTypeMismatchException("To jest test"));
			errorExceptions.Add("COR_E_BADIMAGEFORMAT", new BadImageFormatException("To jest test"));
			errorExceptions.Add("ERROR_BAD_FORMAT", new BadImageFormatException("To jest test"));
			errorExceptions.Add("COR_E_CONTEXTMARSHAL", new ContextMarshalException("To jest test"));
			errorExceptions.Add("NTE_FAIL", new CryptographicException("To jest test"));
			errorExceptions.Add("COR_E_DIRECTORYNOTFOUND", new DirectoryNotFoundException("To jest test"));
			errorExceptions.Add("ERROR_PATH_NOT_FOUND", new DirectoryNotFoundException("To jest test"));
			errorExceptions.Add("COR_E_DIVIDEBYZERO", new DivideByZeroException("To jest test"));
			errorExceptions.Add("COR_E_DUPLICATEWAITOBJECT", new DuplicateWaitObjectException("To jest test"));
			errorExceptions.Add("COR_E_ENDOFSTREAM", new EndOfStreamException("To jest test"));
			// errorExceptions.Add("COR_E_TYPELOAD", new EntryPointNotFoundException("To jest test"));
			errorExceptions.Add("COR_E_EXCEPTION", new Exception("To jest test"));
			errorExceptions.Add("COR_E_EXECUTIONENGINE", new ExecutionEngineException("To jest test"));
			errorExceptions.Add("COR_E_FIELDACCESS", new FieldAccessException("To jest test"));
			errorExceptions.Add("COR_E_FILENOTFOUND", new FileNotFoundException("To jest test"));
			errorExceptions.Add("ERROR_FILE_NOT_FOUND", new FileNotFoundException("To jest test"));
			errorExceptions.Add("COR_E_FORMAT", new FormatException("To jest test"));
			errorExceptions.Add("COR_E_INDEXOUTOFRANGE", new IndexOutOfRangeException("To jest test"));
			errorExceptions.Add("COR_E_INVALIDCAST", new InvalidCastException("To jest test"));
			errorExceptions.Add("E_NOINTERFACE", new InvalidCastException("To jest test"));
			errorExceptions.Add("COR_E_INVALIDCOMOBJECT", new InvalidComObjectException("To jest test"));
			errorExceptions.Add("COR_E_INVALIDFILTERCRITERIA", new InvalidFilterCriteriaException("To jest test"));
			errorExceptions.Add("COR_E_INVALIDOLEVARIANTTYPE", new InvalidOleVariantTypeException("To jest test"));
			errorExceptions.Add("COR_E_INVALIDOPERATION", new InvalidOperationException("To jest test"));
			errorExceptions.Add("COR_E_IO", new IOException("To jest test"));
			errorExceptions.Add("COR_E_MEMBERACCESS", new MemberAccessException("To jest test"));
			errorExceptions.Add("COR_E_METHODACCESS", new MethodAccessException("To jest test"));
			errorExceptions.Add("COR_E_MISSINGFIELD", new MissingFieldException("To jest test"));
			errorExceptions.Add("COR_E_MISSINGMANIFESTRESOURCE", new MissingManifestResourceException("To jest test"));
			errorExceptions.Add("COR_E_MISSINGMEMBER", new MissingMemberException("To jest test"));
			errorExceptions.Add("COR_E_MISSINGMETHOD", new MissingMethodException("To jest test"));
			errorExceptions.Add("COR_E_MULTICASTNOTSUPPORTED", new MulticastNotSupportedException("To jest test"));
			errorExceptions.Add("COR_E_NOTFINITENUMBER", new NotFiniteNumberException("To jest test"));
			errorExceptions.Add("E_NOTIMPL", new NotImplementedException("To jest test"));
			errorExceptions.Add("COR_E_NOTSUPPORTED", new NotSupportedException("To jest test"));
			errorExceptions.Add("COR_E_NULLREFERENCE", new NullReferenceException("To jest test"));
			errorExceptions.Add("E_POINTER", new NullReferenceException("To jest test"));
			errorExceptions.Add("COR_E_OUTOFMEMORY", new OutOfMemoryException("To jest test"));
			errorExceptions.Add("E_OUTOFMEMORY", new OutOfMemoryException("To jest test"));
			errorExceptions.Add("COR_E_OVERFLOW", new OverflowException("To jest test"));
			errorExceptions.Add("COR_E_PATHTOOLONG", new PathTooLongException("To jest test"));
			errorExceptions.Add("ERROR_FILENAME_EXCED_RANGE", new PathTooLongException("To jest test"));
			errorExceptions.Add("COR_E_RANK", new RankException("To jest test"));
			errorExceptions.Add("COR_E_REFLECTIONTYPELOAD", new COMException("This should be a ReflectionTypeLoadException"));
			errorExceptions.Add("COR_E_REMOTING", new RemotingException("To jest test"));
			errorExceptions.Add("COR_E_SAFEARRAYTYPEMISMATCH", new SafeArrayTypeMismatchException("To jest test"));
			errorExceptions.Add("COR_E_SECURITY", new SecurityException("To jest test"));
			errorExceptions.Add("COR_E_SERIALIZATION", new SerializationException("To jest test"));
			errorExceptions.Add("COR_E_STACKOVERFLOW", new StackOverflowException("To jest test"));
			errorExceptions.Add("ERROR_STACK_OVERFLOW", new StackOverflowException("To jest test"));
			errorExceptions.Add("COR_E_SYNCHRONIZATIONLOCK", new SynchronizationLockException("To jest test"));
			errorExceptions.Add("COR_E_SYSTEM", new SystemException("To jest test"));
			errorExceptions.Add("COR_E_TARGET", new TargetException("To jest test"));
			errorExceptions.Add("COR_E_TARGETINVOCATION", new COMException("This should be a TargetInvocationException"));
			errorExceptions.Add("COR_E_TARGETPARAMCOUNT", new TargetParameterCountException("To jest test"));
			errorExceptions.Add("COR_E_THREADABORTED", new COMException("This should be a ThreadAbortException"));
			errorExceptions.Add("COR_E_THREADINTERRUPTED", new ThreadInterruptedException("To jest test"));
			errorExceptions.Add("COR_E_THREADSTATE", new ThreadStateException("To jest test"));
			errorExceptions.Add("COR_E_THREADSTOP", new COMException("This should be a ThreadStopException"));
			errorExceptions.Add("COR_E_TYPELOAD", new TypeLoadException("To jest test"));
			errorExceptions.Add("COR_E_TYPEINITIALIZATION", new COMException("This should be a TypeInitializationException"));
			errorExceptions.Add("COR_E_VERIFICATION", new VerificationException("To jest test"));
			errorExceptions.Add("E_FAIL", new COMException("To jest test"));
		}
		public Color ColorValue
		{
			get
			{
				return colorValue;
			}
			set
			{
				colorValue = value;
				if(ColorChanged != null)
					ColorChanged(colorValue);
			}
		}
		public DateTime Date
		{
			get
			{
				return date;
			}
			set
			{
				date = value;
				if(DateChanged != null)
					DateChanged(date);
			}
		}
		public string Name
		{
			get
			{
				return name;
			}
			set
			{
				name = value;
				if(NameChanged != null)
					NameChanged(name);
			}
		}
		public decimal Decimal
		{
			get
			{
				return decimalValue;
			}
			set
			{
				decimalValue = value;
				if(DecimalChanged != null)
					DecimalChanged(decimalValue);
			}
		}
		public object Variant
		{
			get
			{
				return variantValue;
			}
			set
			{
				variantValue = value;
				if(VariantChanged != null)
					VariantChanged(variantValue);
			}
		}
		public object [] Array
		{
			get
			{
				return array;
			}
			set
			{
				array = value;
				if(ArrayChanged != null)
					ArrayChanged(array);
			}
		}
		public IEnumerator Enumerator
		{
			get
			{
				return array.GetEnumerator();
			}
		}
		public void ErrorTest(string error)
		{
			throw (Exception)errorExceptions[error];
		}
		Color colorValue;
		string name;
		decimal decimalValue;
		DateTime date;
		object variantValue;
		int counter;
		object [] array;
		Thread counterThread;
	}
}
