File: System\Windows\Interop\ActiveXHost.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
//
// Description:
//      An ActiveXHost is a System.Windows.FrameworkElement which can
//      host a windowed ActiveX control.  This class provides a technology
//      bridge between ActiveX controls and Avalon by wrapping ActiveX controls
//      and exposing them as fully featured avalon elements. It implements both the
//      container interfaces (via aggregation) required to host the ActiveXControl
//      and also derives from HwndHost to support hosting an HWND in the avalon tree.
//
//      Currently the activex hosting support is limited to windowed controls.
//
//      Inheritors of this class simply need to concentrate on defining and implementing the
//      properties/methods/events of the specific ActiveX control they are wrapping, the
//      default properties etc and the code to implement the activation etc. are
//      encapsulated in the class below.
//
//      The classid of the ActiveX control is specified in the constructor.
//
 
using System.Collections;
using System.Collections.Specialized;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Controls;
using System.Windows.Input;
using MS.Internal;
using MS.Internal.Controls;
using MS.Win32;
 
// Since we disable PreSharp warnings in this file, PreSharp warning is unknown to C# compiler.
// We first need to disable warnings about unknown message numbers and unknown pragmas.
#pragma warning disable 1634, 1691
 
namespace System.Windows.Interop
{
    #region ActiveXHost
 
    /// <summary>
    ///     An ActiveXHost is a Systew.Windows.FrameworkElement which can
    ///     host an ActiveX control. Currently the support is limited to
    ///     windowed controls. This class provides a technology bridge
    ///     between unmanaged ActiveXControls and Avalon framework.
    ///
    ///     The only reason we expose this class public in ArrowHead without public OM
    ///     is for the WebBrowser control. The WebBrowser class derives from ActiveXHost, and
    ///     we are exposing the WebBrowser class in ArrowHead. This class does not have public
    ///     constructor and OM. It may be enabled in future releases.
    /// </summary>
    public class ActiveXHost : HwndHost
    {
        //------------------------------------------------------
        //
        //  Constructors and Finalizers
        //
        //------------------------------------------------------
 
        #region Constructors and Finalizers
 
        static ActiveXHost()
        {
            // We use this map to lookup which invalidator method to call
            // when the Avalon parent's properties change.
            invalidatorMap[UIElement.VisibilityProperty] = new PropertyInvalidator(OnVisibilityInvalidated);
            invalidatorMap[FrameworkElement.IsEnabledProperty] = new PropertyInvalidator(OnIsEnabledInvalidated);
 
            // register for access keys
            EventManager.RegisterClassHandler(typeof(ActiveXHost), AccessKeyManager.AccessKeyPressedEvent, new AccessKeyPressedEventHandler(OnAccessKeyPressed));
 
            Control.IsTabStopProperty.OverrideMetadata(typeof(ActiveXHost), new FrameworkPropertyMetadata(true));
 
            FocusableProperty.OverrideMetadata(typeof(ActiveXHost), new FrameworkPropertyMetadata(true));
 
            EventManager.RegisterClassHandler(typeof(ActiveXHost), Keyboard.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(OnGotFocus));
            EventManager.RegisterClassHandler(typeof(ActiveXHost), Keyboard.LostKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(OnLostFocus));
            KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(ActiveXHost), new FrameworkPropertyMetadata(KeyboardNavigationMode.Once));
        }
 
 
        /// constructor for ActiveXHost
        internal ActiveXHost(Guid clsid, bool fTrusted ) : base( fTrusted )
        {
            // Thread.ApartmentState is [Obsolete]
            #pragma warning disable 0618
            // What if the control is marked as free-threaded?
            if (Thread.CurrentThread.ApartmentState != ApartmentState.STA)
            {
                throw new ThreadStateException(SR.Format(SR.AxRequiresApartmentThread, clsid.ToString()));
            }
            #pragma warning restore 0618
 
            _clsid = clsid;
 
            // hookup so we are notified when loading is finished.
            Initialized += new EventHandler(OnInitialized);
        }
 
 
        #endregion Constructors and Finalizers
 
        //------------------------------------------------------
        //
        //  Protected Methods
        //
        //------------------------------------------------------
 
        #region Protected Methods
 
        #region Framework Related
 
        /// <internalonly>
        ///     Overriden to push the values of invalidated properties down to our
        ///     ActiveX control.
        /// </internalonly>
        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
 
            if (e.IsAValueChange || e.IsASubPropertyChange)
            {
                DependencyProperty dp = e.Property;
 
                // We lookup the property in our invalidatorMap
                // and call the appropriate method to push
                // down the changed value to the hosted ActiveX control.
                if (dp != null && invalidatorMap.ContainsKey(dp))
                {
                    PropertyInvalidator invalidator = (PropertyInvalidator)invalidatorMap[dp];
                    invalidator(this);
                }
            }
        }
 
        /// <internalonly>
        ///     Overriden to create our window and parent it.
        /// </internalonly>
        protected override HandleRef BuildWindowCore(HandleRef hwndParent)
        {
            this.ParentHandle = hwndParent;
 
            //BuildWindowCore should only be called if visible. Bug 1236445 tracks this.
            TransitionUpTo(ActiveXHelper.ActiveXState.InPlaceActive);
 
            //The above call should have set this interface
            Invariant.Assert(_axOleInPlaceActiveObject != null, "InPlace activation of ActiveX control failed");
 
            if (ControlHandle.Handle == IntPtr.Zero)
            {
                IntPtr inplaceWindow = IntPtr.Zero;
                _axOleInPlaceActiveObject.GetWindow(out inplaceWindow);
                AttachWindow(inplaceWindow);
            }
 
            return _axWindow;
        }
 
        /// <internalonly>
        ///     Overridden to plug the ActiveX control into Avalon's layout manager.
        /// </internalonly>
        /// <SecurityNote >
        ///     Critical - accesses ActiveXSite critical property
        ///     Not making TAS - you may be able to spoof content of web-pages if you could position any arbitrary
        ///                      control over a WebOC.
        protected override void OnWindowPositionChanged(Rect bounds)
        {
            //Its okay to process this if we the control is not yet created
 
            _boundRect = bounds;
 
            //These are already transformed to client co-ordinate/device units for high dpi also
            _bounds.left    = (int) bounds.X;
            _bounds.top     = (int) bounds.Y;
            _bounds.right   = (int) (bounds.Width + bounds.X);
            _bounds.bottom  = (int) (bounds.Height + bounds.Y);
 
            //SetExtent only sets height and width, can call it for perf if X, Y haven't changed
            //We need to call SetObjectRects instead, which updates X, Y, width and height
            //OnActiveXRectChange calls SetObjectRects
            this.ActiveXSite.OnActiveXRectChange(_bounds);
        }
 
        /// <summary>
        ///     Derived classes override this method to destroy the
        ///     window being hosted.
        /// </summary>
        protected override void DestroyWindowCore(HandleRef hwnd)
        {
        }
 
        /// <internalonly>
        ///     Overridden to plug the ActiveX control into Avalon's layout manager.
        /// </internalonly>
        protected override Size MeasureOverride(Size swConstraint)
        {
            base.MeasureOverride(swConstraint);
 
            double newWidth, newHeight;
 
            if (Double.IsPositiveInfinity(swConstraint.Width))
                newWidth = 150;
            else
                newWidth = swConstraint.Width;
 
            if (Double.IsPositiveInfinity(swConstraint.Height))
                newHeight = 150;
            else
                newHeight = swConstraint.Height;
 
            return new Size(newWidth, newHeight);
        }
 
 
        /// <internalOnly>
        ///     Forward the access key to our hosted ActiveX control
        ///</internalOnly>
        protected override void OnAccessKey(AccessKeyEventArgs args)
        {
            Debug.Assert(args.Key.Length > 0, "got an empty access key");
            //Consider adding: HostedControl.ProcessKey(args.Key[0]);  //used in winformshost
            // How do we pass this to the activex control - IOleControl.OnMnemonic?
        }
 
        #endregion Framework Related
 
        #region ActiveX Related
 
        protected override void Dispose(bool disposing)
        {
            try
            {
                if ((disposing) && (!_isDisposed))
                {
                    TransitionDownTo(ActiveXHelper.ActiveXState.Passive);
                    _isDisposed = true;
                }
            }
            finally
            {
                //This destroys the parent window, so call base after we have done our processing.
                base.Dispose(disposing);
            }
        }
 
        // The native ActiveX control QI's for interfaces on it's site to see if
        // it needs to change it's behaviour. Since the AxSite class is generic,
        // it only implements site interfaces that are generic to all sites. QI's
        // for any more specific interfaces will fail. This is a problem if anyone
        // wants to support any other interfaces on the site. In order to overcome
        // this, one needs to extend AxSite and implement any additional interfaces
        // needed.
        //
        // ActiveX wrapper controls that derive from this class should override the
        // below method and return their own AxSite derived object.
        //
        // This method is protected by an InheritanceDemand (from HwndSource) and
        // a LinkDemand because extending a site is strictly an advanced feature for
        // which one needs UnmanagedCode permissions.
        //
 
        /// Returns an object that will be set as the site for the native ActiveX control.
        /// Implementors of the site can derive from ActiveXSite class.
        internal virtual ActiveXSite CreateActiveXSite()
        {
            return new ActiveXSite(this);
        }
 
        internal virtual object CreateActiveXObject(Guid clsid)
        {
            return Activator.CreateInstance(Type.GetTypeFromCLSID(clsid));
        }
 
        /// This will be called when the native ActiveX control has just been created.
        /// Inheritors of this class can override this method to cast the nativeActiveXObject
        /// parameter to the appropriate interface. They can then cache this interface
        /// value in a member variable. However, they must release this value when
        /// DetachInterfaces is called (by setting the cached interface variable to null).
        internal virtual void AttachInterfaces(object nativeActiveXObject)
        {
        }
 
        /// See AttachInterfaces for a description of when to override DetachInterfaces.
        internal virtual void DetachInterfaces()
        {
        }
 
        /// This will be called when we are ready to start listening to events.
        /// Inheritors can override this method to hook their own connection points.
        internal virtual void CreateSink()
        {
        }
 
        /// <summary>
        /// This will be called when it is time to stop listening to events.
        /// This is where inheritors have to disconnect their connection points.
        /// </summary>
        internal virtual void DetachSink()
        {
        }
 
        /// <summary>
        /// Called whenever the ActiveX state changes. Subclasses can do additional hookup/cleanup depending
        /// on the state transitions
        /// </summary>
        /// <param name="oldState"></param>
        /// <param name="newState"></param>
        internal virtual void OnActiveXStateChange(int oldState, int newState)
        {
        }
 
        #endregion ActiveX Related
 
        #endregion Protected Methods
 
        //------------------------------------------------------
        //
        //  Protected Properties
        //
        //------------------------------------------------------
 
        #region Protected Properties
 
        protected bool IsDisposed
        {
            get { return _isDisposed; }
        }
 
        #endregion Protected Properties
 
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Methods
 
        #region ActiveX Related
 
        /// This method needs to be called by the user of ActiveXHost for each
        /// hosted ActiveX control that has a mnemonic bound to it
        internal void RegisterAccessKey(char key)
        {
            AccessKeyManager.Register(key.ToString(), this);
        }
 
        internal ActiveXSite ActiveXSite
        {
            get
            {
                if (_axSite == null)
                {
                    _axSite = CreateActiveXSite();
                }
                return _axSite;
            }
        }
 
        internal ActiveXContainer Container
        {
            get
            {
                if (_axContainer == null)
                {
                    _axContainer = new ActiveXContainer(this);
                }
                return _axContainer;
            }
        }
 
        internal ActiveXHelper.ActiveXState ActiveXState
        {
            get
            {
                return _axState;
            }
            set
            {
                _axState = value;
            }
        }
 
        internal bool GetAxHostState(int mask)
        {
            return _axHostState[mask];
        }
 
        internal void SetAxHostState(int mask, bool value)
        {
            _axHostState[mask] = value;
        }
 
        internal void TransitionUpTo(ActiveXHelper.ActiveXState state)
        {
            if (!this.GetAxHostState(ActiveXHelper.inTransition))
            {
                this.SetAxHostState(ActiveXHelper.inTransition, true);
 
                try
                {
                    ActiveXHelper.ActiveXState oldState;
 
                    while (state > this.ActiveXState)
                    {
                        oldState = this.ActiveXState;
 
                        switch (this.ActiveXState)
                        {
                            case ActiveXHelper.ActiveXState.Passive:
                                TransitionFromPassiveToLoaded();
                                Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.Loaded, "Failed transition");
                                this.ActiveXState = ActiveXHelper.ActiveXState.Loaded;
                                break;
                            case ActiveXHelper.ActiveXState.Loaded:
                                TransitionFromLoadedToRunning();
                                Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.Running, "Failed transition");
                                this.ActiveXState = ActiveXHelper.ActiveXState.Running;
                                break;
                            case ActiveXHelper.ActiveXState.Running:
                                TransitionFromRunningToInPlaceActive();
                                Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.InPlaceActive, "Failed transition");
                                this.ActiveXState = ActiveXHelper.ActiveXState.InPlaceActive;
                                break;
                            case ActiveXHelper.ActiveXState.InPlaceActive:
                                TransitionFromInPlaceActiveToUIActive();
                                Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.UIActive, "Failed transition");
                                this.ActiveXState = ActiveXHelper.ActiveXState.UIActive;
                                break;
                            default:
                                Debug.Fail("bad state");
                                this.ActiveXState = this.ActiveXState + 1;  // To exit the loop
                                break;
                        }
 
                        OnActiveXStateChange((int)oldState, (int)this.ActiveXState);
                    }
                }
                finally
                {
                    this.SetAxHostState(ActiveXHelper.inTransition, false);
                }
            }
        }
 
        internal void TransitionDownTo(ActiveXHelper.ActiveXState state)
        {
            if (!this.GetAxHostState(ActiveXHelper.inTransition))
            {
                this.SetAxHostState(ActiveXHelper.inTransition, true);
 
                try
                {
                    ActiveXHelper.ActiveXState oldState;
 
                    while (state < this.ActiveXState)
                    {
                        oldState = this.ActiveXState;
 
                        switch (this.ActiveXState)
                        {
                            case ActiveXHelper.ActiveXState.Open:
                                Debug.Fail("how did we ever get into the open state?");
                                this.ActiveXState = ActiveXHelper.ActiveXState.UIActive;
                                break;
                            case ActiveXHelper.ActiveXState.UIActive:
                                TransitionFromUIActiveToInPlaceActive();
                                Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.InPlaceActive, "Failed transition");
                                this.ActiveXState = ActiveXHelper.ActiveXState.InPlaceActive;
                                break;
                            case ActiveXHelper.ActiveXState.InPlaceActive:
                                TransitionFromInPlaceActiveToRunning();
                                Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.Running, "Failed transition");
                                this.ActiveXState = ActiveXHelper.ActiveXState.Running;
                                break;
                            case ActiveXHelper.ActiveXState.Running:
                                TransitionFromRunningToLoaded();
                                Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.Loaded, "Failed transition");
                                this.ActiveXState = ActiveXHelper.ActiveXState.Loaded;
                                break;
                            case ActiveXHelper.ActiveXState.Loaded:
                                TransitionFromLoadedToPassive();
                                Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.Passive, "Failed transition");
                                this.ActiveXState = ActiveXHelper.ActiveXState.Passive;
                                break;
                            default:
                                Debug.Fail("bad state");
                                this.ActiveXState = this.ActiveXState - 1;  // To exit the loop
                                break;
                        }
 
                        OnActiveXStateChange((int)oldState, (int)this.ActiveXState);
                    }
                }
                finally
                {
                    this.SetAxHostState(ActiveXHelper.inTransition, false);
                }
            }
        }
 
        internal bool DoVerb(int verb)
        {
            int hr = _axOleObject.DoVerb(verb,
                                         IntPtr.Zero,
                                         this.ActiveXSite,
                                         0,
                                         this.ParentHandle.Handle,
                                         _bounds);
 
            Debug.Assert(hr == NativeMethods.S_OK, $"DoVerb call failed for verb 0x{verb:X}");
            return hr == NativeMethods.S_OK;
        }
 
        internal void AttachWindow(IntPtr hwnd)
        {
            if (_axWindow.Handle == hwnd)
                return;
 
            //Ideally it shouldn't happen, but what if we already have a _axWindow?
            //should we call ReleaseHandle even though we don't own it?
            //should we also call UnsafeNativeMethods.SetParent(_axWindow, null); first?
 
            _axWindow = new HandleRef(this, hwnd);
 
            if (this.ParentHandle.Handle != IntPtr.Zero)
            {
                UnsafeNativeMethods.SetParent(_axWindow, this.ParentHandle);
            }
        }
 
        private void StartEvents()
        {
            if (!this.GetAxHostState(ActiveXHelper.sinkAttached))
            {
                this.SetAxHostState(ActiveXHelper.sinkAttached, true);
                CreateSink();
            }
            this.ActiveXSite.StartEvents();
        }
 
        private void StopEvents()
        {
            if (this.GetAxHostState(ActiveXHelper.sinkAttached))
            {
                this.SetAxHostState(ActiveXHelper.sinkAttached, false);
                DetachSink();
            }
            this.ActiveXSite.StopEvents();
        }
 
        private void TransitionFromPassiveToLoaded()
        {
            Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.Passive, "Wrong start state to transition from");
            if (this.ActiveXState == ActiveXHelper.ActiveXState.Passive)
            {
                //
                // First, create the ActiveX control
                Debug.Assert(_axInstance == null, "_axInstance must be null");
 
                _axInstance = CreateActiveXObject(_clsid);
                Debug.Assert(_axInstance != null, "w/o an exception being thrown we must have an object...");
 
                //
                // We are now Loaded!
                this.ActiveXState = ActiveXHelper.ActiveXState.Loaded;
 
                //
                // Lets give them a chance to cast the ActiveX object
                // to the appropriate interfaces.
                this.AttachInterfacesInternal();
            }
        }
 
        private void TransitionFromLoadedToPassive()
        {
            Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.Loaded, "Wrong start state to transition from");
            if (this.ActiveXState == ActiveXHelper.ActiveXState.Loaded)
            {
                //
                // Need to make sure that we don't handle any PropertyChanged
                // notifications at this point.
                //this.NoComponentChangeEvents++;
                try
                {
                    //
                    // Release the _axInstance
                    if (_axInstance != null)
                    {
                        //
                        // Lets first get the cached interface pointers of _axInstance released.
                        this.DetachInterfacesInternal();
 
                        Marshal.FinalReleaseComObject(_axInstance);
                        _axInstance = null;
                    }
                }
                finally
                {
                    //Consider: this.NoComponentChangeEvents--;
                }
 
                //
                // We are now Passive!
                this.ActiveXState = ActiveXHelper.ActiveXState.Passive;
            }
        }
 
        private void TransitionFromLoadedToRunning()
        {
            Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.Loaded, "Wrong start state to transition from");
            if (this.ActiveXState == ActiveXHelper.ActiveXState.Loaded)
            {
                //
                // See if the ActiveX control returns OLEMISC_SETCLIENTSITEFIRST
                int bits = 0;
                int hr = _axOleObject.GetMiscStatus(NativeMethods.DVASPECT_CONTENT, out bits);
                if (NativeMethods.Succeeded(hr) && ((bits & NativeMethods.OLEMISC_SETCLIENTSITEFIRST) != 0))
                {
                    //
                    // Simply setting the site to the ActiveX control should activate it.
                    // And this will take us to the Running state.
                    _axOleObject.SetClientSite(this.ActiveXSite);
                }
 
                StartEvents();
 
                //
                // We are now Running!
                this.ActiveXState = ActiveXHelper.ActiveXState.Running;
            }
        }
 
        private void TransitionFromRunningToLoaded()
        {
            Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.Running, "Wrong start state to transition from");
            if (this.ActiveXState == ActiveXHelper.ActiveXState.Running)
            {
                StopEvents();
 
                //
                // Inform the ActiveX control that it's been un-sited.
                _axOleObject.SetClientSite(null);
 
                //
                // We are now Loaded!
                this.ActiveXState = ActiveXHelper.ActiveXState.Loaded;
            }
        }
 
        private void TransitionFromRunningToInPlaceActive()
        {
            Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.Running, "Wrong start state to transition from");
            if (this.ActiveXState == ActiveXHelper.ActiveXState.Running)
            {
                try
                {
                    DoVerb(NativeMethods.OLEIVERB_INPLACEACTIVATE);
                }
                catch (Exception e)
                {
                    if(CriticalExceptions.IsCriticalException(e))
                    {
                        throw;
                    }
                    else
                    {
                        throw new TargetInvocationException(SR.Format(SR.AXNohWnd, GetType().Name), e);
                    }
                }
 
                //
                // We are now InPlaceActive!
                this.ActiveXState = ActiveXHelper.ActiveXState.InPlaceActive;
            }
        }
 
        private void TransitionFromInPlaceActiveToRunning()
        {
            Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.InPlaceActive, "Wrong start state to transition from");
            if (this.ActiveXState == ActiveXHelper.ActiveXState.InPlaceActive)
            {
                //
                // InPlaceDeactivate.
                _axOleInPlaceObject.InPlaceDeactivate();
 
                //
                // We are now Running!
                this.ActiveXState = ActiveXHelper.ActiveXState.Running;
            }
        }
 
        private void TransitionFromInPlaceActiveToUIActive()
        {
            Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.InPlaceActive, "Wrong start state to transition from");
            if (this.ActiveXState == ActiveXHelper.ActiveXState.InPlaceActive)
            {
                DoVerb(NativeMethods.OLEIVERB_UIACTIVATE);
 
                //
                // We are now UIActive!
                this.ActiveXState = ActiveXHelper.ActiveXState.UIActive;
            }
        }
 
        private void TransitionFromUIActiveToInPlaceActive()
        {
            Debug.Assert(this.ActiveXState == ActiveXHelper.ActiveXState.UIActive, "Wrong start state to transition from");
            if (this.ActiveXState == ActiveXHelper.ActiveXState.UIActive)
            {
                int hr = _axOleInPlaceObject.UIDeactivate();
                Debug.Assert(NativeMethods.Succeeded(hr), "Failed in IOleInPlaceObject.UiDeactivate");
 
                //
                // We are now InPlaceActive!
                this.ActiveXState = ActiveXHelper.ActiveXState.InPlaceActive;
            }
        }
 
        #endregion ActiveX Related
 
        #endregion Internal Methods
 
        //------------------------------------------------------
        //
        //  Internal Properties
        //
        //------------------------------------------------------
 
        #region Internal Properties
 
        #region Framework Related
 
        /// <summary>
        ///     The DependencyProperty for the TabIndex property.
        ///     Flags:              Can be used in style rules
        ///     Default Value:      1
        /// </summary>
        internal static readonly DependencyProperty TabIndexProperty
            = Control.TabIndexProperty.AddOwner(typeof(ActiveXHost));
 
        /// <summary>
        ///     TabIndex property change the order of Tab navigation between Controls.
        ///     Control with lower TabIndex will get focus before the Control with higher index
        /// </summary>
        internal int TabIndex
        {
            get { return (int) GetValue(TabIndexProperty); }
            set { SetValue(TabIndexProperty, value); }
        }
 
        internal HandleRef ParentHandle
        {
            get { return _hwndParent; }
 
            set { _hwndParent = value; }
        }
 
        // This returns a COMRECT.
        internal NativeMethods.COMRECT Bounds
        {
            get { return _bounds; }
            //How do we notify Avalon tree/layout that the control needs a new size?
            set { _bounds = value; }
        }
 
        // This returns a Rect.
        internal Rect BoundRect
        {
            get { return _boundRect; }
        }
 
        #endregion Framework Related
 
        #region ActiveX Related
 
        /// <summary>
        /// Returns the hosted ActiveX control's handle
        /// </summary>
        internal HandleRef ControlHandle
        {
            get { return _axWindow; }
        }
 
        ///<summary>
        ///Returns the native webbrowser object that this control wraps. Needs FullTrust to access.
        /// Internally we will access the private field directly for perf reasons, no security checks
        ///</summary>
        internal object ActiveXInstance
        {
            get
            {
                return _axInstance;
            }
        }
 
 
        internal UnsafeNativeMethods.IOleInPlaceObject ActiveXInPlaceObject
        {
            get
            {
                return _axOleInPlaceObject;
            }
        }
 
        internal UnsafeNativeMethods.IOleInPlaceActiveObject ActiveXInPlaceActiveObject
        {
            get
            {
                return _axOleInPlaceActiveObject;
            }
        }
 
        #endregion ActiveXRelated
 
        #endregion Internal Properties
 
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
 
        #region Framework Methods
 
        private void OnInitialized(object sender, EventArgs e)
        {
            // Do the needful for getting this info from the ActiveX control
            //ArrayList keys = new ArrayList();
            //GetMnemonicList(HostedControl, keys);
            //foreach(char k in keys)
            //{
            //    AccessKeyManager.Register(k.ToString(), this);
            //}
 
            this.Initialized -= new EventHandler(this.OnInitialized);
 
            //Cannot inplace activate yet, since BuildWindowCore is not called yet
            //and we need that for getting the parent handle to pass on to the control.
        }
 
        private static void OnIsEnabledInvalidated(ActiveXHost axHost)
        {
            //Consider: ActiveX equivalent?
            //if (axHost != null)
            //{
            //    axHost.HostedControl.Enabled = axHost.IsEnabled;
            //}
        }
 
        private static void OnVisibilityInvalidated(ActiveXHost axHost)
        {
            if (axHost != null)
            {
                switch (axHost.Visibility)
                {
                    case Visibility.Visible:
                        //Consider: axHost.HostedControl.Visible = true;
                        break;
                    case Visibility.Collapsed:
                        //Consider: axHost.HostedControl.Visible = false;
                        break;
                    case Visibility.Hidden:
                        //Consider:
                        //axHost._cachedSize = axHost.HostedControl.PreferredSize;
                        //axHost._hidden = true;
                        //axHost.HostedControl.Visible = false;
                        break;
                }
            }
        }
 
        ///     This event handler forwards focus events to the hosted ActiveX control
        private static void OnGotFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            ActiveXHost axhost = sender as ActiveXHost;
 
            if (axhost != null)
            {
                Invariant.Assert(axhost.ActiveXState >= ActiveXHelper.ActiveXState.InPlaceActive, "Should at least be InPlaceActive when getting focus");
 
                if (axhost.ActiveXState < ActiveXHelper.ActiveXState.UIActive)
                {
                    axhost.TransitionUpTo(ActiveXHelper.ActiveXState.UIActive);
                }
            }
        }
 
        ///     This event handler forwards focus events to the hosted WF controls
        private static void OnLostFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            ActiveXHost axhost = sender as ActiveXHost;
 
            if (axhost != null)
            {
                // If the focus goes from our control window to one of the child windows,
                // we should not deactivate.
                //
 
                Invariant.Assert(axhost.ActiveXState >= ActiveXHelper.ActiveXState.UIActive, "Should at least be UIActive when losing focus");
 
                bool uiDeactivate = !axhost.IsKeyboardFocusWithin;
 
                if (uiDeactivate)
                {
                    axhost.TransitionDownTo(ActiveXHelper.ActiveXState.InPlaceActive);
                }
            }
        }
 
        private static void OnAccessKeyPressed(object sender, AccessKeyPressedEventArgs args)
        {
            if (!args.Handled && args.Scope == null && args.Target == null)
            {
                args.Target = (UIElement)sender;
            }
        }
 
        /*
                private void GetMnemonicList(SWF.Control control, ArrayList mnemonicList) {
 
                    // Get the mnemonic for our control
                    //
                    char mnemonic = HostUtils.GetMnemonic(control.Text, true);
                    if (mnemonic != 0)
                    {
                        mnemonicList.Add(mnemonic);
                    }
 
                    // And recurse for our children, currently we only support one activex control
                    //
                    if (HostedControl != null) GetMnemonicList(HostedControl, mnemonicList);
                }
        */
 
        #endregion Framework Methods
 
        #region ActiveX Related
 
        private void AttachInterfacesInternal()
        {
            Debug.Assert(_axInstance != null, "The native control is null");
            _axOleObject = (UnsafeNativeMethods.IOleObject)_axInstance;
            _axOleInPlaceObject = (UnsafeNativeMethods.IOleInPlaceObject)_axInstance;
            _axOleInPlaceActiveObject = (UnsafeNativeMethods.IOleInPlaceActiveObject)_axInstance;
            //
            // Lets give the inheriting classes a chance to cast
            // the ActiveX object to the appropriate interfaces.
            AttachInterfaces(_axInstance);
        }
 
        private void DetachInterfacesInternal()
        {
            _axOleObject = null;
            _axOleInPlaceObject = null;
            _axOleInPlaceActiveObject = null;
            //
            // Lets give the inheriting classes a chance to release
            // their cached interfaces of the ActiveX object.
            DetachInterfaces();
        }
 
        private NativeMethods.SIZE SetExtent(int width, int height)
        {
            NativeMethods.SIZE sz = new NativeMethods.SIZE();
            sz.cx = width;
            sz.cy = height;
 
            bool resetExtents = false;
            try
            {
                _axOleObject.SetExtent(NativeMethods.DVASPECT_CONTENT, sz);
            }
            catch (COMException)
            {
                resetExtents = true;
            }
            if (resetExtents)
            {
                _axOleObject.GetExtent(NativeMethods.DVASPECT_CONTENT, sz);
                try
                {
                    _axOleObject.SetExtent(NativeMethods.DVASPECT_CONTENT, sz);
                }
                catch (COMException e)
                {
                    Debug.Fail(e.ToString());
                }
            }
            return GetExtent();
        }
 
        private NativeMethods.SIZE GetExtent()
        {
            NativeMethods.SIZE sz = new NativeMethods.SIZE();
            _axOleObject.GetExtent(NativeMethods.DVASPECT_CONTENT, sz);
            return sz;
        }
 
        #endregion ActiveX Related
 
        #endregion Private Methods
 
 
        //------------------------------------------------------
        //
        //  Private Properties
        //
        //------------------------------------------------------
 
        #region Private Properties
 
        #endregion Private Properties
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
 
        #region Private Fields
 
        #region Framework Related
 
        private static Hashtable invalidatorMap = new Hashtable();
 
        private delegate void PropertyInvalidator(ActiveXHost axhost);
 
        private NativeMethods.COMRECT _bounds    = new NativeMethods.COMRECT(0, 0, 0, 0);
        private Rect             _boundRect      = new Rect(0, 0, 0, 0);
 
        private Size             _cachedSize     = Size.Empty;
        private HandleRef        _hwndParent;
        private bool             _isDisposed;
 
        #endregion Framework Related
 
        #region ActiveX Related
 
        private Guid                        _clsid;
 
        private HandleRef                   _axWindow;
        private BitVector32                 _axHostState    = new BitVector32();
        private ActiveXHelper.ActiveXState  _axState        = ActiveXHelper.ActiveXState.Passive;
 
        private ActiveXSite                 _axSite;
 
        private ActiveXContainer            _axContainer;
 
        private object                      _axInstance;
 
        // Pointers to the ActiveX object: Interface pointers are cached for perf.
        private UnsafeNativeMethods.IOleObject              _axOleObject;
 
        private UnsafeNativeMethods.IOleInPlaceObject       _axOleInPlaceObject;
 
        private UnsafeNativeMethods.IOleInPlaceActiveObject _axOleInPlaceActiveObject;
 
        #endregion ActiveX Related
 
 
        #endregion Private Fields
    }
    #endregion ActiveXHost
}