//	Copyright Pavel Zolnikov, 2002
//
//			BandObject - implements generic Band Object functionality.

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using SHDocVw;
using System.Reflection;
using System.Diagnostics;
using System.Drawing;
using System.ComponentModel;
using Microsoft.Win32;
using BandObjectLib;
using System.IO;

[assembly: AssemblyVersion("1.0.0.0")]


namespace BandObjectLib
{
	/// <summary>
	/// Implements generic Band Object functionality. 
	/// </summary>
	/// <example>
	/// [Guid("YOURGUID-GOES-HERE-YOUR-GUIDGOESHERE")]
   [Guid ("0CFB43EF-F61B-43b6-8142-0B505B524692")]
	/// [BandObject("Hello World Bar", BandObjectStyle.Horizontal | BandObjectStyle.ExplorerToolbar , HelpText = "Shows bar that says hello.")]
	/// public class HelloWorldBar : BandObject
	/// { /*...*/ }
	/// </example>
    [BandObject("UC Library Research Bar", BandObjectStyle.Horizontal | BandObjectStyle.ExplorerToolbar, HelpText = "University of Cincinnati Libraries Research Toolbar.")]
    public class BandObject : UserControl, IObjectWithSite, IDeskBand, IDockingWindow, IOleWindow, IInputObject 
	{
     
        /// <summary>
		/// Reference to the host explorer.
		/// </summary>
		protected WebBrowserClass	Explorer;
		protected IInputObjectSite 	BandObjectSite;
		/// <summary>
		/// This event is fired after reference to hosting explorer is retreived and stored in Explorer property.
		/// </summary>
		public event EventHandler ExplorerAttached;

		public BandObject()
		{
			InitializeComponent();
		}

		private void InitializeComponent()
		{
            this.SuspendLayout();
            // 
            // BandObject
            // 
            this.BackColor = System.Drawing.Color.Transparent;
            this.Name = "BandObject";
            this.Size = new System.Drawing.Size(800, 27);
            this.ResumeLayout(false);

         }

        #region Transparency

        [DllImport("uxtheme", ExactSpelling = true)]
        public extern static Int32 DrawThemeParentBackground(IntPtr hWnd, IntPtr hdc, ref Rectangle pRect);

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            if (this.BackColor == Color.Transparent)
            {
                IntPtr hdc = e.Graphics.GetHdc();
                Rectangle rec = new Rectangle(e.ClipRectangle.Left,
                    e.ClipRectangle.Top, e.ClipRectangle.Width, e.ClipRectangle.Height);
                DrawThemeParentBackground(this.Handle, hdc, ref rec);
                e.Graphics.ReleaseHdc(hdc);
            }
            else
            {
                base.OnPaintBackground(e);
            }
        }

        #endregion
      

		/// <summary>
		/// Title of band object. Displayed at the left or on top of the band object.
		/// </summary>
		[Browsable(true)]
		[DefaultValue("")]
		public String Title
		{
			get
			{
				return _title;
			}
			set
			{
				_title = value;
			}
		}String _title;


		/// <summary>
		/// Minimum size of the band object. Default value of -1 sets no minimum constraint.
		/// </summary>
		[Browsable(true)]
		[DefaultValue(typeof(Size),"-1,-1")]
		public Size MinSize
		{
			get
			{
				return _minSize;
			}
			set
			{
				_minSize = value;
			}
		}Size _minSize = new Size(-1,-1);

		/// <summary>
		/// Maximum size of the band object. Default value of -1 sets no maximum constraint.
		/// </summary>
		[Browsable(true)]
		[DefaultValue(typeof(Size),"-1,-1")]
		public Size MaxSize
		{
			get
			{
				return _maxSize;
			}
			set
			{
				_maxSize = value;
			}
		}Size _maxSize = new Size(-1,-1);

		/// <summary>
		/// Says that band object's size must be multiple of this size. Defauilt value of -1 does not set this constraint.
		/// </summary>
		[Browsable(true)]
		[DefaultValue(typeof(Size),"-1,-1")]
		public Size IntegralSize
		{
			get
			{
				return _integralSize;
			}
			set
			{
				_integralSize = value;
			}
		}Size _integralSize = new Size(-1,-1);


		public virtual void GetBandInfo(
			UInt32 dwBandID,
			UInt32 dwViewMode,
			ref DESKBANDINFO dbi)
		{
			dbi.wszTitle = this.Title;
		
			dbi.ptActual.X = this.Size.Width;
			dbi.ptActual.Y = this.Size.Height;

			dbi.ptMaxSize.X = this.MaxSize.Width;
			dbi.ptMaxSize.Y = this.MaxSize.Height;

			dbi.ptMinSize.X = this.MinSize.Width;
			dbi.ptMinSize.Y = this.MinSize.Height;

			dbi.ptIntegral.X = this.IntegralSize.Width;
			dbi.ptIntegral.Y = this.IntegralSize.Height;

            dbi.dwModeFlags = DBIMF.BREAK;
		}

		/// <summary>
		/// Called by explorer when band object needs to be showed or hidden.
		/// </summary>
		/// <param name="fShow"></param>
		public virtual void ShowDW(bool fShow)
		{
			if( fShow )
				Show();
			else
				Hide();
		}

		/// <summary>
		/// Called by explorer when window is about to close.
		/// </summary>
		public virtual void CloseDW(UInt32  dwReserved)
		{
			Dispose( true );
		}

		/// <summary>
		/// Not used.
		/// </summary>
		public virtual void ResizeBorderDW(IntPtr prcBorder, Object punkToolbarSite, bool fReserved){}

		public virtual void GetWindow(out System.IntPtr phwnd)
		{		
			phwnd = Handle;
		}

		public virtual void ContextSensitiveHelp(bool fEnterMode){}

		public virtual void SetSite(Object pUnkSite)
		{
			if( BandObjectSite != null )
				Marshal.ReleaseComObject( BandObjectSite );

			if( Explorer != null )
			{
				Marshal.ReleaseComObject( Explorer );
				Explorer = null;
			}

			BandObjectSite = (IInputObjectSite)pUnkSite;
			if( BandObjectSite != null )
			{
				//pUnkSite is a pointer to object that implements IOleWindowSite or something  similar
				//we need to get access to the top level object - explorer itself
				//to allows this explorer objects also implement IServiceProvider interface
				//(don't mix it with System.IServiceProvider!)
				//we get this interface and ask it to find WebBrowserApp
				_IServiceProvider sp = BandObjectSite as _IServiceProvider;
				Guid guid = ExplorerGUIDs.IID_IWebBrowserApp;
				Guid riid = ExplorerGUIDs.IID_IUnknown;
				
				try
				{
					object w;
					sp.QueryService( 
						ref guid,
						ref riid,
						out w );
				
					//once we have interface to the COM object we can create RCW from it
					Explorer = (WebBrowserClass)Marshal.CreateWrapperOfType(
						w as IWebBrowser,
						typeof(WebBrowserClass)
						);

					OnExplorerAttached(EventArgs.Empty);
				}
				catch( COMException )
				{
					//we anticipate this exception in case our object instantiated 
					//as a Desk Band. There is no web browser service available.
				}
			}

		}

		public virtual void GetSite(ref Guid riid, out Object ppvSite)
		{
			ppvSite = BandObjectSite;			
		}

		/// <summary>
		/// Called explorer when focus has to be chenged.
		/// </summary>
		public virtual void UIActivateIO(Int32 fActivate, ref MSG Msg)
		{
			if( fActivate != 0 ) 
			{
				Control ctrl = GetNextControl(this,true);//first
				if( ModifierKeys == Keys.Shift )
					ctrl = GetNextControl(ctrl,false );//last

				if( ctrl != null ) ctrl.Select();
				this.Focus();
			}
		}



        /// The following is how others have Notifies Explorer that the band object has focus and should process keyboard events.
        ///
        /// 0 if has focus, 1 if not.
        /// BUT-- Visual Studio Rebuild will flat with an error that there is 'no suitable method found to override'.  If you leave out override, Studio
        /// complains that system.windows.forms.usercontrol does not contain a definition for HasFocusIO
        /// Is this why IE is also processing the input. -- Linda
        //public override Int32 HasFocusIO()
		//{
        //    if (base.HasFocusIO() == 0 || Focused || ContainsFocus)
        //        
        //        return 0; //S_OK
        //    else
        //        return 1; //S_FALSE
        //
		//}

       //from original sample project:
        public virtual Int32 HasFocusIO()
        {
            
            return this.ContainsFocus ? 0 : 1; //S_OK : S_FALSE;
        }


        //        *******************
        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, UInt32 Msg, UInt32 wParam, Int32 lParam);

        [DllImport("user32.dll")]
        public static extern int TranslateMessage(ref MSG lpMsg);

        [DllImport("user32", EntryPoint = "DispatchMessage")]
        static extern bool DispatchMessage(ref MSG msg);

        //        ******************



        
        public virtual Int32 TranslateAcceleratorIO(ref MSG msg)
        {
            if (msg.message == 0x100)//WM_KEYDOWN
            {
                switch (msg.wParam)
                {
                    case (uint)Keys.Tab:
                    case (uint)Keys.F6:
                        //check for keys used by explorer to navigate from control to control
                        if (SelectNextControl(
                        ActiveControl,
                        ModifierKeys == Keys.Shift ? false : true,
                        true,
                        true,
                        true)
                        )
                            return 0;//S_OK
                        break;

                    case (uint)Keys.Back:
                        const int WM_CHAR = 0x0102;
                        if (SendMessage(msg.hwnd, WM_CHAR, (uint)msg.wParam, msg.lParam) == 1)
                            //TranslateMessage(ref msg);
                            //DispatchMessage(ref msg);
                            return 0;//S_OK
                            break;
                    //case (int)Keys.Return: //ADDED BY ME TO HANDLE RETURN
                    //    ValidateButton_Click(txtValidate, EventArgs.Empty);
                    //    return 0;//S_OK BREAK
                    case (uint)Keys.Delete:
                    case (uint)Keys.Home:
                    case (uint)Keys.End:
                    case (uint)Keys.Up:
                    case (uint)Keys.Down:
                    case (uint)Keys.Left:
                    case (uint)Keys.Right:
                            if (SendMessage(msg.hwnd, (uint)msg.message, (uint)msg.wParam, msg.lParam) == 1)
                                //TranslateMessage(ref msg);
                                //DispatchMessage(ref msg);
                                return 0;//S_OK
                                break;
                    }
            }

            return 1;//S_FALSE
        }

        /// <summary>
        /// Called by explorer to process keyboard events. Undersatands Tab and F6.
        /// </summary>
        /// <param name="msg"></param>
        /// <returns>S_OK if message was processed, S_FALSE otherwise.</returns>
        ///
        //        public virtual Int32 TranslateAcceleratorIO(ref MSG msg)
//		{
//            if (msg.message == 0x100)//WM_KEYDOWN
//                   if( msg.wParam == (uint)Keys.Tab || msg.wParam == (uint)Keys.F6 )//keys used by explorer to navigate from control to control
//                		if( SelectNextControl( 
//                				ActiveControl,
//                				ModifierKeys == Keys.Shift  ? false : true,
//                				true,
//                				true,
//                				false ) 
//                			)
//                return 0;//S_OK
//			return 1;//S_FALSE

//              }


        //        public override Int TranslateAcceleratorIO(ref MSG msg)
//        {
//            //const int WM_CHAR = 0x0102;
//            TranslateMessage(ref msg);
//            DispatchMessage(ref msg);
//            return 0;
//        }

        


		/// <summary>
		/// Override this method to handle ExplorerAttached event.
		/// </summary>
		/// <param name="ea"></param>
		protected virtual void OnExplorerAttached(EventArgs ea)
		{
			if ( ExplorerAttached != null )
				ExplorerAttached(this, ea);
		}

		/// <summary>
		/// Notifies explorer of focus change.
		/// </summary>
		protected override void OnGotFocus(System.EventArgs e)
		{
			base.OnGotFocus(e);
			BandObjectSite.OnFocusChangeIS(this as IInputObject, 1);		
		}
		/// <summary>
		/// Notifies explorer of focus change.
		/// </summary>
		protected override void OnLostFocus(System.EventArgs e)
		{
			base.OnLostFocus(e);
			if( ActiveControl == null )
				BandObjectSite.OnFocusChangeIS(this as IInputObject, 0);		
		}


		/// <summary>
		/// Called when derived class is registered as a COM server.
		/// </summary>
		[ComRegisterFunctionAttribute]
		public static void Register(Type t)
		{
			string guid = t.GUID.ToString("B");
			
			RegistryKey rkClass = Registry.ClassesRoot.CreateSubKey(@"CLSID\"+guid );
			RegistryKey rkCat = rkClass.CreateSubKey("Implemented Categories");

			BandObjectAttribute[] boa = (BandObjectAttribute[])t.GetCustomAttributes(
				typeof(BandObjectAttribute),
				false );

			string name = t.Name;
			string help = t.Name;
			BandObjectStyle style = 0;
			if( boa.Length == 1 )
			{
				if( boa[0].Name != null )
					name = boa[0].Name;

				if( boa[0].HelpText != null )
					help = boa[0].HelpText;

				style = boa[0].Style;
			}

			rkClass.SetValue(null, name );
			rkClass.SetValue("MenuText", name );
			rkClass.SetValue("HelpText", help );

			if( 0 != (style & BandObjectStyle.Vertical) )
				rkCat.CreateSubKey("{00021493-0000-0000-C000-000000000046}");

			if( 0 != (style & BandObjectStyle.Horizontal) )
				rkCat.CreateSubKey("{00021494-0000-0000-C000-000000000046}");

			if( 0 != (style & BandObjectStyle.TaskbarToolBar) )
				rkCat.CreateSubKey("{00021492-0000-0000-C000-000000000046}");

			if( 0 != (style & BandObjectStyle.ExplorerToolbar) )
				Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Internet Explorer\Toolbar").SetValue(guid,name);

		}
   
		/// <summary>
		/// Called when derived class is unregistered as a COM server.
		/// </summary>
		[ComUnregisterFunctionAttribute]
		public static void Unregister(Type t)
		{
			string guid = t.GUID.ToString("B");
			BandObjectAttribute[] boa = (BandObjectAttribute[])t.GetCustomAttributes(
				typeof(BandObjectAttribute),
				false );

			BandObjectStyle style = 0;
			if( boa.Length == 1 ) style = boa[0].Style;

			if( 0 != (style & BandObjectStyle.ExplorerToolbar) )
				Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Internet Explorer\Toolbar").DeleteValue(guid,false);

			Registry.ClassesRoot.CreateSubKey(@"CLSID").DeleteSubKeyTree(guid);
		}

      }
}

 

