using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

using System.Runtime;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

using System.Threading;
using System.Reflection;
using System.Net;


namespace DarkStrideToolbox
{
	public class DSNamedPipe
	{
		private const string m_sChannelName = "DSNamedPipe";

		public DSNamedPipe()
		{
		}


		public void SetPipe( string sPipeName,object oObjectToHost )
		{
			DSNamedPipeTransport oPipeTransport = new DSNamedPipeTransport( oObjectToHost );
			SetPipe( sPipeName,oPipeTransport );
		}
		public void SetPipe( string sPipeName,MarshalByRefObject oObjectToHost )
		{
			PipeChannel oPipeChannel = null;
			BinaryServerFormatterSinkProvider oServerProv = null;
			IDictionary oProperties = null;


			try
			{
				//Configure customErrors
				/*//RemotingConfiguration.Configure("DarkStrideToolbox.dll.config");
				//http://dotnetjunkies.com/WebLog/chris.taylor/comments/5566.aspx
				System.Reflection.Assembly remoting = System.Reflection.Assembly.GetAssembly( typeof(System.Runtime.Remoting.RemotingConfiguration) );
				Type remotingConfigHandler = remoting.GetType("System.Runtime.Remoting.RemotingConfigHandler");
				Type customErrorsModes = remoting.GetType("System.Runtime.Remoting.CustomErrorsModes");
				FieldInfo errorMode = remotingConfigHandler.GetField( "_errorMode",BindingFlags.Static | BindingFlags.NonPublic );
				FieldInfo mode = customErrorsModes.GetField( "Off" );
				errorMode.SetValue( null, mode.GetValue( null ) );*/



				////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				//Step 1: Create and register a TCP server channel that listens on a specific port
				////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				//We'll use the port the user specified in the GUI
				oProperties = new Hashtable();
				oProperties["pipe"] = sPipeName;
				//ToDo: specifiy a real SecurityDescriptor here
				oProperties["securityDescriptor"] = IntPtr.Zero;

				//We have to set the type filter to full filter level.  This is because in v1.0 sp3 and v1.1 versions 
				//of the .NET framework security was tightened.  Without full filtering the callbacks will be blocked
				//by security precautions.  http://blogs.msdn.com/manishg/archive/2004/10/27/248841.aspx seems to hint
				//that this can open you up to some security vulnerabilities.
				oServerProv = new BinaryServerFormatterSinkProvider();
				oServerProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
				oPipeChannel = new PipeChannel( oProperties, null, oServerProv );
				if( DSMisc.IsChannelRegistered( oPipeChannel.ChannelName ) == false )
				{
					ChannelServices.RegisterChannel( oPipeChannel );
				}

				////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				//Step 2: Register the service that publishes DbConnect for remote access in SingleCall mode
				////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				RemotingConfiguration.RegisterWellKnownServiceType( oObjectToHost.GetType(), sPipeName, WellKnownObjectMode.Singleton );

				////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				//Step 3: Setup our singleton registration object
				////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				//This passes in our object as "THE" singleton object.  By doing this we are able to access the ClientReg
				//object and see what other users are registered.
				RemotingServices.Marshal( oObjectToHost, sPipeName );
			}
			catch( System.Exception oErr )
			{
				throw new System.Exception( "Error Trying To Connect To named pipe (" + oErr.Message + ")" );
			}
		}


		public object GetPipe( string sPipeName,Type oTypeToGet )
		{
			object oRetVal = null;
			DSNamedPipeTransport oHostedObject = null;
			BinaryClientFormatterSinkProvider oClientProv = null;
			IDictionary oProperties = null;
			PipeChannel oPipeChannel = null;
			Type oTransportType = typeof( DSNamedPipeTransport );
			

			try
			{
				//Configure customErrors
				/*//RemotingConfiguration.Configure("DarkStrideToolbox.dll.config");
				//http://dotnetjunkies.com/WebLog/chris.taylor/comments/5566.aspx
				System.Reflection.Assembly remoting = System.Reflection.Assembly.GetAssembly( typeof(System.Runtime.Remoting.RemotingConfiguration) );
				Type remotingConfigHandler = remoting.GetType("System.Runtime.Remoting.RemotingConfigHandler");
				Type customErrorsModes = remoting.GetType("System.Runtime.Remoting.CustomErrorsModes");
				FieldInfo errorMode = remotingConfigHandler.GetField( "_errorMode",BindingFlags.Static | BindingFlags.NonPublic );
				FieldInfo mode = customErrorsModes.GetField( "Off" );
				errorMode.SetValue( null, mode.GetValue( null ) );*/


				////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				//Step 1: Create and register a TCP server channel that listens on a specific port
				////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				//We have to specify the binary serialization method.  This is because in v1.0 sp3 and v1.1 versions 
				//of the .NET framework security was tightened.  Without this we will get an error whenever the host
				//sents us an event.  The error occurs because the event is sending back a custom object, its
				//DSClientListUpdate object.  Delegates don't need this formater on the client unless the delegate 
				//includes a non-standard type.
				oClientProv = new BinaryClientFormatterSinkProvider();
				//In order for us to receive events a port has to be explicitly specified.  You should be able to specify
				//any port number but I can't seem to get that to work right.
				oProperties = new Hashtable();
				oProperties["pipe"] = sPipeName;
				oProperties["name"] = "DSNamed Pipe GetPipe Channel (" + DSMisc.GetGUID() + ")";
				//ToDo: specifiy a real SecurityDescriptor here
				oProperties["securityDescriptor"] = IntPtr.Zero;
				oPipeChannel = new PipeChannel( oProperties, null, null );
				if( DSMisc.IsChannelRegistered( oPipeChannel.ChannelName ) == false )
				{
					ChannelServices.RegisterChannel( oPipeChannel );
				}

				////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				//Step 3: Setup our singleton registration object
				////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				if( oTypeToGet.BaseType == typeof( MarshalByRefObject ) )
				{
					oRetVal = Activator.GetObject( oTypeToGet,"pipe://" + sPipeName + "/" + sPipeName );
				}
				else
				{
					oHostedObject = (DSNamedPipeTransport)Activator.GetObject( typeof( DSNamedPipeTransport ),"pipe://" + sPipeName + "/" + sPipeName );
					oRetVal = oHostedObject.ObjectBeingTransported;
				}
			}
			/*catch( System.NullReferenceException oEx )
			{
				oRetVal = null;
			}*/
			catch
			{
				oRetVal = null;
				//throw new System.Exception( "Error Trying To Connect To named pipe (" + oErr.Message + ")" );
			}
			finally
			{
				oHostedObject = null;

				if( oPipeChannel != null && DSMisc.IsChannelRegistered( oPipeChannel.ChannelName ) == true )
				{
					ChannelServices.UnregisterChannel( oPipeChannel );
				}
			}


			return( oRetVal );
		}
	}
}
