COM2PropertyDescriptor.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / WinForms / Managed / System / WinForms / ComponentModel / COM2Interop / COM2PropertyDescriptor.cs / 1305376 / COM2PropertyDescriptor.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Windows.Forms.ComponentModel.Com2Interop { 
    using System.Runtime.Serialization.Formatters; 
    using System.Runtime.InteropServices;
    using System.ComponentModel; 
    using System.Diagnostics;
    using System;
    using System.Reflection;
    using System.ComponentModel.Design; 
    using Microsoft.Win32;
    using System.Collections; 
    using System.Text; 
    using System.Drawing.Design;
    using System.Globalization; 
    using System.Runtime.Versioning;

    /// 
    ///  
    /// This class wraps a com native property in a property descriptor.
    /// It maintains all information relative to the basic (e.g. ITypeInfo) 
    /// information about the member dispid function, and converts that info 
    /// to meaningful managed code information.
    /// 
    /// It also allows other objects to register listeners to add extended
    /// information at runtime such as attributes of TypeConverters.
    /// 
    internal class Com2PropertyDescriptor : PropertyDescriptor, ICloneable{ 
        private EventHandlerList events;
 
        ///  
        /// 
        /// Is this guy read only? 
        /// 
        private bool baseReadOnly;
        private bool readOnly;
 
        /// 
        ///  
        /// The resoved native type -> clr type 
        /// 
        private Type propertyType; 

        /// 
        /// 
        /// The dispid. This is also in a DispIDAttiribute, but we 
        /// need it a lot.
        ///  
        private int  dispid; 

        private TypeConverter   converter; 
        private object          editor;

        /// 
        ///  
        /// The current display name to show for this property
        ///  
        private string displayName; 

        ///  
        /// 
        /// This is any extra data needed.  For IDispatch types, it's the GUID of
        /// the interface, etc.
        ///  
        private object typeData;
 
 
        /// 
        ///  
        /// Keeps track of which data members need to be refreshed.
        /// 
        private int  refreshState;
 
        /// 
        ///  
        /// Should we bother asking if refresh is needed? 
        /// 
        private bool queryRefresh = false; 

        /// 
        /// 
        /// Our properties manager 
        /// 
        private Com2Properties com2props; 
 

        ///  
        /// 
        /// Our original baseline properties
        /// 
        private Attribute[] baseAttrs; 

        ///  
        ///  
        /// Our cached last value -- this is only
        /// for checking if we should ask for a display value 
        /// 
        private Object lastValue;

        ///  
        /// 
        /// For Object and dispatch types, we hide them by default. 
        ///  
        private bool   typeHide;
 
        /// 
        /// 
        /// Set if the metadata causes this property to always be hidden
        ///  
        private bool   canShow;
 
        ///  
        /// 
        /// This property is hidden because its get didn't return S_OK 
        /// 
        private bool   hrHidden;

        ///  
        /// 
        /// Set if we are in the process of asking handlers for attributes 
        ///  
        private bool   inAttrQuery;
 
        /// 
        /// 
        /// Our event signitures.
        ///  
        private static readonly Object EventGetBaseAttributes      = new Object();
        private static readonly Object EventGetDynamicAttributes   = new Object(); 
        private static readonly Object EventShouldRefresh          = new Object(); 
        private static readonly Object EventGetDisplayName         = new Object();
        private static readonly Object EventGetDisplayValue        = new Object(); 
        private static readonly Object EventGetIsReadOnly          = new Object();


        private static readonly Object EventGetTypeConverterAndTypeEditor   = new Object(); 

        private static readonly Object EventShouldSerializeValue = new Object(); 
        private static readonly Object EventCanResetValue      = new Object(); 
        private static readonly Object EventResetValue         = new Object();
 
        private static readonly Guid GUID_COLOR = new Guid("{66504301-BE0F-101A-8BBB-00AA00300CAB}");


        ///  
        /// 
        /// Our map of native types that we can map to managed types for editors 
        ///  
        private static IDictionary oleConverters;
 
        static Com2PropertyDescriptor() {
            oleConverters = new SortedList();
            oleConverters[GUID_COLOR] = typeof(Com2ColorConverter);
            oleConverters[typeof(SafeNativeMethods.IFontDisp).GUID] = typeof(Com2FontConverter); 
            oleConverters[typeof(UnsafeNativeMethods.IFont).GUID] = typeof(Com2FontConverter);
            oleConverters[typeof(UnsafeNativeMethods.IPictureDisp).GUID] = typeof(Com2PictureConverter); 
            oleConverters[typeof(UnsafeNativeMethods.IPicture).GUID] = typeof(Com2PictureConverter); 
        }
 
        /// 
        /// 
        /// Should we convert our type?
        ///  
        private Com2DataTypeToManagedDataTypeConverter valueConverter;
 
 
        /// 
        ///  
        /// Ctor.
        /// 
        public Com2PropertyDescriptor(int dispid, string name, Attribute[] attrs, bool readOnly, Type propType, Object typeData, bool hrHidden)
        : base(name, attrs) { 
            this.baseReadOnly = readOnly;
            this.readOnly = readOnly; 
 
            this.baseAttrs = attrs;
            SetNeedsRefresh(Com2PropertyDescriptorRefresh.BaseAttributes, true); 

            this.hrHidden = hrHidden;

            // readonly to begin with are always read only 
            SetNeedsRefresh(Com2PropertyDescriptorRefresh.ReadOnly, readOnly);
 
            this.propertyType = propType; 

            this.dispid = dispid; 

            if (typeData != null) {
                this.typeData = typeData;
                if (typeData is Com2Enum) { 
                     converter = new Com2EnumConverter((Com2Enum)typeData);
                } 
                else if (typeData is Guid) { 
                    valueConverter =  CreateOleTypeConverter((Type)oleConverters[(Guid)typeData]);
                } 
            }

            // check if this thing is hidden from metadata
            this.canShow = true; 

            if (attrs != null) { 
                for (int i = 0; i < attrs.Length; i++) { 
                    if (attrs[i].Equals(BrowsableAttribute.No) && !hrHidden) {
                        this.canShow = false; 
                        break;
                    }
                }
            } 

            if (this.canShow && (propType == typeof(Object) || (valueConverter == null && propType == typeof(UnsafeNativeMethods.IDispatch)))) { 
                this.typeHide = true; 
            }
        } 

        protected Attribute[] BaseAttributes {
            get {
 
                if (GetNeedsRefresh(Com2PropertyDescriptorRefresh.BaseAttributes)) {
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.BaseAttributes, false); 
 
                    int baseCount = baseAttrs == null ? 0 : baseAttrs.Length;
 
                    ArrayList attrList = new ArrayList();

                    if (baseCount != 0) {
                        attrList.AddRange(baseAttrs); 
                    }
 
                    OnGetBaseAttributes(new GetAttributesEvent(attrList)); 

                    if (attrList.Count != baseCount) { 
                        this.baseAttrs = new Attribute[attrList.Count];
                    }

                    if (baseAttrs != null) { 
                        attrList.CopyTo(this.baseAttrs, 0);
                    } 
                    else { 
                        baseAttrs = new Attribute[0];
                    } 
                }

                return baseAttrs;
            } 
            set {
                baseAttrs = value; 
            } 
        }
 
        /// 
        /// 
        ///     Attributes
        ///  
        public override AttributeCollection Attributes {
            get { 
                if (this.AttributesValid || this.InAttrQuery) { 
                    return base.Attributes;
                } 

                // restore our base attributes
                this.AttributeArray = this.BaseAttributes;
 
                ArrayList newAttributes = null;
 
                // if we are forcing a hide 
                if (typeHide && canShow) {
                    if (newAttributes == null) { 
                        newAttributes = new ArrayList(AttributeArray);
                    }
                    newAttributes.Add(new BrowsableAttribute(false));
                } 
                else if (hrHidden) {
                    // check to see if the get still fails 
                    Object target = this.TargetObject; 
                    if (target != null) {
                        int hr = new ComNativeDescriptor().GetPropertyValue(target, this.dispid, new object[1]); 

                        // if not, go ahead and make this a browsable item
                        if (NativeMethods.Succeeded(hr)) {
                            // make it browsable 
                            if (newAttributes == null) {
                                newAttributes = new ArrayList(AttributeArray); 
                            } 
                            newAttributes.Add(new BrowsableAttribute(true));
                            hrHidden = false; 
                        }
                    }
                }
 
                this.inAttrQuery = true;
                try { 
 
                    // demand get any extended attributes
                    ArrayList attrList = new ArrayList(); 

                    OnGetDynamicAttributes(new GetAttributesEvent(attrList));

                    Attribute ma; 

                    if (attrList.Count != 0 && newAttributes == null) { 
                        newAttributes = new ArrayList(AttributeArray); 
                    }
 
                    // push any new attributes into the base type
                    for (int i=0; i < attrList.Count; i++) {
                        ma = (Attribute)attrList[i];
                        newAttributes.Add(ma); 
                    }
                } 
                finally { 
                    this.inAttrQuery = false;
                } 

                // these are now valid.
                SetNeedsRefresh(Com2PropertyDescriptorRefresh.Attributes, false);
 
                // If we reconfigured attributes, then poke the new set back in.
                // 
                if (newAttributes != null) { 
                    Attribute[] temp = new Attribute[newAttributes.Count];
                    newAttributes.CopyTo(temp, 0); 
                    AttributeArray = temp;
                }

                return base.Attributes; 
            }
 
        } 

        ///  
        /// 
        ///     Checks if the attributes are valid.  Asks any clients if they
        ///     would like attributes requeried.
        ///  
        protected bool AttributesValid{
            get{ 
                bool currentRefresh = !GetNeedsRefresh(Com2PropertyDescriptorRefresh.Attributes); 
                if (queryRefresh) {
                    GetRefreshStateEvent rse = new GetRefreshStateEvent(Com2ShouldRefreshTypes.Attributes, !currentRefresh); 
                    OnShouldRefresh(rse);
                    currentRefresh = !rse.Value;
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.Attributes, rse.Value);
                } 
                return currentRefresh;
            } 
        } 

        ///  
        /// 
        ///     Checks if this item can be shown.
        /// 
        public bool CanShow{ 
            get{
                return this.canShow; 
            } 
        }
 

        /// 
        /// 
        ///     Retrieves the type of the component this PropertyDescriptor is bound to. 
        /// 
        public override Type ComponentType { 
            get { 
                return typeof(UnsafeNativeMethods.IDispatch);
            } 
        }

        /// 
        ///  
        ///      Retrieves the type converter for this property.
        ///  
        public override TypeConverter Converter { 
            get {
               if (TypeConverterValid) { 
                  return converter;
               }

               Object typeEd = null; 

               GetTypeConverterAndTypeEditor(ref converter, typeof(UITypeEditor), ref typeEd); 
 
               if (!TypeEditorValid) {
                  this.editor = typeEd; 
                  SetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeEditor, false);
               }
               SetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeConverter, false);
 
               return converter;
            } 
        } 

        ///  
        /// 
        ///     Retrieves whether this component is applying a type conversion...
        /// 
        public bool ConvertingNativeType { 
            get {
                return(valueConverter != null); 
            } 
        }
 
        /// 
        /// 
        ///      Retrieves the default value for this property.
        ///  
        protected virtual Object DefaultValue {
            get { 
                return null; 
            }
        } 

        /// 
        /// 
        ///     Retrieves the DISPID for this item 
        /// 
        public int DISPID{ 
            get{ 
                return this.dispid;
            } 
        }

        /// 
        ///  
        ///     Gets the friendly name that should be displayed to the user in a window like
        ///     the Property Browser. 
        ///  
        public override string DisplayName {
            get { 
                if (!this.DisplayNameValid) {
                    GetNameItemEvent gni = new GetNameItemEvent(base.DisplayName);
                    OnGetDisplayName(gni);
                    this.displayName = gni.NameString; 
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.DisplayName, false);
                } 
                return this.displayName; 
            }
        } 

        /// 
        /// 
        ///     Checks if the property display name is valid 
        ///     asks clients if they would like display name requeried.
        ///  
        protected bool DisplayNameValid{ 
            get{
                bool currentRefresh = !(displayName == null || GetNeedsRefresh(Com2PropertyDescriptorRefresh.DisplayName)); 
                if (queryRefresh) {
                    GetRefreshStateEvent rse = new GetRefreshStateEvent(Com2ShouldRefreshTypes.DisplayName, !currentRefresh);
                    OnShouldRefresh(rse);
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.DisplayName, rse.Value); 
                    currentRefresh = !rse.Value;
                } 
                return currentRefresh; 
            }
        } 

        protected EventHandlerList Events {
            get {
                if (events == null) { 
                    events = new EventHandlerList();
                } 
                return events; 
            }
        } 

        protected bool InAttrQuery{
            get{
                return this.inAttrQuery; 
            }
        } 
 
        /// 
        ///  
        ///     Indicates whether this property is read only.
        /// 
        public override bool IsReadOnly {
            get { 
                if (!this.ReadOnlyValid) {
                    this.readOnly |= (this.Attributes[typeof(ReadOnlyAttribute)].Equals(ReadOnlyAttribute.Yes)); 
                    GetBoolValueEvent gbv = new GetBoolValueEvent(this.readOnly); 
                    OnGetIsReadOnly(gbv);
                    this.readOnly = gbv.Value; 
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.ReadOnly, false);
                }
                return this.readOnly;
            } 
        }
 
        internal Com2Properties PropertyManager{ 
            set{
                this.com2props = value; 
            }
            get{
                return this.com2props;
            } 
        }
 
        ///  
        /// 
        ///     Retrieves the type of the property. 
        /// 
        public override Type PropertyType {
            get {
                // replace the type with the mapped converter type 
                if (valueConverter != null) {
                    return valueConverter.ManagedType; 
                } 
                else {
                    return propertyType; 
                }
            }
        }
 
        /// 
        ///  
        ///     Checks if the read only state is valid. 
        ///     Asks clients if they would like read-only requeried.
        ///  
        protected bool ReadOnlyValid{
            get{
                if (baseReadOnly) {
                    return true; 
                }
 
                bool currentRefresh = !GetNeedsRefresh(Com2PropertyDescriptorRefresh.ReadOnly); 

                if (queryRefresh) { 
                    GetRefreshStateEvent rse = new GetRefreshStateEvent(Com2ShouldRefreshTypes.ReadOnly, !currentRefresh);
                    OnShouldRefresh(rse);
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.ReadOnly, rse.Value);
                    currentRefresh = !rse.Value; 
                }
                return currentRefresh; 
            } 
        }
 
        /// 
        /// 
        ///     Gets the Object that this descriptor was created for.
        ///     May be null if the Object's ref has died. 
        /// 
        public virtual Object TargetObject{ 
            get{ 
                if (com2props != null) {
                    return com2props.TargetObject; 
                }
                return null;
            }
        } 

        protected bool TypeConverterValid { 
            get { 
                bool currentRefresh =!(converter == null || GetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeConverter));
                if (queryRefresh) { 
                    GetRefreshStateEvent rse = new GetRefreshStateEvent(Com2ShouldRefreshTypes.TypeConverter, !currentRefresh);
                    OnShouldRefresh(rse);
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeConverter, rse.Value);
                    currentRefresh = !rse.Value; 
                }
                return currentRefresh; 
            } 
        }
 
        protected bool TypeEditorValid {
            get {
                bool currentRefresh = !(editor == null || GetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeEditor));
 
                if (queryRefresh) {
                    GetRefreshStateEvent rse = new GetRefreshStateEvent(Com2ShouldRefreshTypes.TypeEditor, !currentRefresh); 
                    OnShouldRefresh(rse); 
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeEditor, rse.Value);
                    currentRefresh = !rse.Value; 
                }
                return currentRefresh;
            }
        } 

 
        public event GetBoolValueEventHandler QueryCanResetValue { 
            add {
                Events.AddHandler(EventCanResetValue, value); 
            }
            remove {
                Events.RemoveHandler(EventCanResetValue, value);
            } 
        }
 
        public event GetAttributesEventHandler QueryGetBaseAttributes { 
            add {
                Events.AddHandler(EventGetBaseAttributes, value); 
            }
            remove {
                Events.RemoveHandler(EventGetBaseAttributes, value);
            } 
        }
 
        public event GetAttributesEventHandler QueryGetDynamicAttributes { 
            add {
                Events.AddHandler(EventGetDynamicAttributes, value); 
            }
            remove {
                Events.RemoveHandler(EventGetDynamicAttributes, value);
            } 
        }
 
 
        public event GetNameItemEventHandler QueryGetDisplayName {
            add { 
                Events.AddHandler(EventGetDisplayName, value);
            }
            remove {
                Events.RemoveHandler(EventGetDisplayName, value); 
            }
        } 
 

        public event GetNameItemEventHandler QueryGetDisplayValue { 
            add {
                Events.AddHandler(EventGetDisplayValue, value);
            }
            remove { 
                Events.RemoveHandler(EventGetDisplayValue, value);
            } 
        } 

 
        public event GetBoolValueEventHandler QueryGetIsReadOnly {
            add {
                Events.AddHandler(EventGetIsReadOnly, value);
            } 
            remove {
                Events.RemoveHandler(EventGetIsReadOnly, value); 
            } 
        }
 

        public event GetTypeConverterAndTypeEditorEventHandler QueryGetTypeConverterAndTypeEditor {
            add {
                Events.AddHandler(EventGetTypeConverterAndTypeEditor, value); 
            }
            remove { 
                Events.RemoveHandler(EventGetTypeConverterAndTypeEditor, value); 
            }
        } 


        public event Com2EventHandler QueryResetValue {
            add { 
                Events.AddHandler(EventResetValue, value);
            } 
            remove { 
                Events.RemoveHandler(EventResetValue, value);
            } 
        }


        public event GetBoolValueEventHandler QueryShouldSerializeValue { 
            add {
                Events.AddHandler(EventShouldSerializeValue, value); 
            } 
            remove {
                Events.RemoveHandler(EventShouldSerializeValue, value); 
            }
        }

 

        ///  
        ///  
        ///     Indicates whether reset will change the value of the component.  If there
        ///     is a DefaultValueAttribute, then this will return true if getValue returns 
        ///     something different than the default value.  If there is a reset method and
        ///     a shouldPersist method, this will return what shouldPersist returns.
        ///     If there is just a reset method, this always returns true.  If none of these
        ///     cases apply, this returns false. 
        /// 
        public override bool CanResetValue(Object component) { 
 
            if (component is ICustomTypeDescriptor) {
                component = ((ICustomTypeDescriptor)component).GetPropertyOwner(this); 
            }

            if (component == this.TargetObject) {
                GetBoolValueEvent gbv = new GetBoolValueEvent(false); 
                OnCanResetValue(gbv);
                return gbv.Value; 
            } 
            return false;
        } 

        public object Clone() {
            return new Com2PropertyDescriptor(this.dispid, this.Name, (Attribute[])this.baseAttrs.Clone(), this.readOnly, this.propertyType, this.typeData, this.hrHidden);
        } 

        ///  
        ///  
        ///     Creates a converter Object, first by looking for a ctor with a Com2ProeprtyDescriptor
        ///     parameter, then using the default ctor if it is not found. 
        /// 
        private Com2DataTypeToManagedDataTypeConverter CreateOleTypeConverter(Type t) {

            if (t == null) { 
                return null;
            } 
 
            ConstructorInfo ctor = t.GetConstructor(new Type[]{typeof(Com2PropertyDescriptor)});
            Com2DataTypeToManagedDataTypeConverter converter; 
            if (ctor != null) {
                converter = (Com2DataTypeToManagedDataTypeConverter)ctor.Invoke(new Object[]{this});
            }
            else { 
                converter = (Com2DataTypeToManagedDataTypeConverter)Activator.CreateInstance(t);
            } 
            return converter; 
        }
 
        /// 
        /// 
        ///     Creates an instance of the member attribute collection. This can
        ///     be overriden by subclasses to return a subclass of AttributeCollection. 
        /// 
        protected override AttributeCollection CreateAttributeCollection() { 
            return new AttributeCollection(AttributeArray); 
        }
 
        private TypeConverter GetBaseTypeConverter() {

            if (PropertyType == null) {
                return new TypeConverter(); 
            }
 
            TypeConverter localConverter = null; 

            TypeConverterAttribute attr = (TypeConverterAttribute)Attributes[typeof(TypeConverterAttribute)]; 
            if (attr != null) {
               string converterTypeName = attr.ConverterTypeName;
               if (converterTypeName != null && converterTypeName.Length > 0) {
                   Type converterType = Type.GetType(converterTypeName); 
                   if (converterType != null && typeof(TypeConverter).IsAssignableFrom(converterType)) {
                       try { 
                          localConverter = (TypeConverter)Activator.CreateInstance(converterType); 
                          if (localConverter != null) {
                               refreshState |= Com2PropertyDescriptorRefresh.TypeConverterAttr; 
                          }
                       }
                       catch (Exception ex) {
                          Debug.Fail("Failed to create TypeConverter of type '" + attr.ConverterTypeName + "' from Attribute", ex.ToString()); 
                       }
                   } 
               } 
            }
 
            // if we didn't get one from the attribute, ask the type descriptor
            if (localConverter == null) {
               // we don't want to create the value editor for the IDispatch props because
                // that will create the reference editor.  We don't want that guy! 
                //
                if (!typeof(UnsafeNativeMethods.IDispatch).IsAssignableFrom(this.PropertyType)) { 
                     localConverter = base.Converter; 
                }
                else { 
                     localConverter = new Com2IDispatchConverter(this, false);
                }
            }
 
            if (localConverter == null) {
                localConverter = new TypeConverter(); 
            } 
            return localConverter;
        } 

        private Object GetBaseTypeEditor(Type editorBaseType) {

            if (PropertyType == null) { 
                return null;
            } 
 
            Object localEditor = null;
            EditorAttribute attr = (EditorAttribute)Attributes[typeof(EditorAttribute)]; 
            if (attr != null) {
               string editorTypeName = attr.EditorBaseTypeName;

               if (editorTypeName != null && editorTypeName.Length > 0) { 
                   Type attrEditorBaseType = Type.GetType(editorTypeName);
                   if (attrEditorBaseType != null && attrEditorBaseType == editorBaseType) { 
                        Type type = Type.GetType(attr.EditorTypeName); 
                        if (type != null) {
                            try { 
                               localEditor = Activator.CreateInstance(type);
                               if (localEditor != null) {
                                  refreshState |= Com2PropertyDescriptorRefresh.TypeEditorAttr;
                               } 
                            }
                            catch (Exception ex) { 
                               Debug.Fail("Failed to create edtior of type '" + attr.EditorTypeName + "' from Attribute", ex.ToString()); 
                            }
                        } 
                   }
               }
            }
            if (localEditor == null) { 
                 localEditor = base.GetEditor(editorBaseType);
            } 
            return localEditor; 
        }
 
        /// 
        /// 
        ///     Gets the value that should be displayed to the user, such as in
        ///     the Property Browser. 
        /// 
        public virtual string GetDisplayValue(string defaultValue) { 
 
            GetNameItemEvent nie = new GetNameItemEvent(defaultValue);
            OnGetDisplayValue(nie); 

            string str = (nie.Name == null ? null : nie.Name.ToString());
            return str;
        } 

        ///  
        ///  
        ///      Retrieves an editor of the requested type.
        ///  
        public override Object GetEditor(Type editorBaseType) {
               if (TypeEditorValid) {
                  return editor;
               } 

               if (PropertyType == null) { 
                   return null; 
               }
 
               if (editorBaseType == typeof(UITypeEditor)) {
                  TypeConverter c = null;
                  GetTypeConverterAndTypeEditor(ref c, editorBaseType, ref editor);
 
                  if (!TypeConverterValid) {
                     this.converter = c; 
                     SetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeConverter, false); 
                  }
                  SetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeEditor, false); 
               }
               else {
                  editor = base.GetEditor(editorBaseType);
               } 
               return editor;
 
        } 

        ///  
        /// 
        ///     Retrieves the current native value of the property on component,
        ///     invoking the getXXX method.  An exception in the getXXX
        ///     method will pass through. 
        /// 
        public Object GetNativeValue(Object component){ 
            if (component == null) 
                return null;
 
            if (component is ICustomTypeDescriptor) {
                component = ((ICustomTypeDescriptor)component).GetPropertyOwner(this);
            }
 
            if (component == null || !Marshal.IsComObject(component) || !(component is UnsafeNativeMethods.IDispatch))
                return null; 
 
            UnsafeNativeMethods.IDispatch pDisp = (UnsafeNativeMethods.IDispatch)component;
            Object[] pVarResult = new Object[1]; 
            NativeMethods.tagEXCEPINFO pExcepInfo = new NativeMethods.tagEXCEPINFO();
            Guid g = Guid.Empty;

            int hr = pDisp.Invoke(this.dispid, 
                                  ref g,
                                  SafeNativeMethods.GetThreadLCID(), 
                                  NativeMethods.DISPATCH_PROPERTYGET, 
                                  new NativeMethods.tagDISPPARAMS(),
                                  pVarResult, 
                                  pExcepInfo, null);

            switch (hr) {
            case NativeMethods.S_OK: 
            case NativeMethods.S_FALSE:
 
                if (pVarResult[0] == null || Convert.IsDBNull(pVarResult[0])) { 
                    lastValue = null;
                } 
                else {
                    lastValue = pVarResult[0];
                }
                return lastValue; 
            case NativeMethods.DISP_E_EXCEPTION:
                //PrintExceptionInfo(pExcepInfo); 
                return null; 
            default:
                throw new ExternalException(SR.GetString(SR.DispInvokeFailed, "GetValue" , hr), hr); 
            }
        }

        ///  
        /// 
        ///     Checks whether the particular item(s) need refreshing. 
        ///  
        private bool GetNeedsRefresh(int mask){
            return(refreshState & mask) != 0; 
        }


        ///  
        /// 
        ///     Retrieves the current value of the property on component, 
        ///     invoking the getXXX method.  An exception in the getXXX 
        ///     method will pass through.
        ///  
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public override Object GetValue(Object component) {
            lastValue = GetNativeValue(component); 
            // do we need to convert the type?
            if (this.ConvertingNativeType && lastValue != null) { 
                lastValue = valueConverter.ConvertNativeToManaged(lastValue, this); 
            }
            else if (lastValue != null && propertyType != null && propertyType.IsEnum && lastValue.GetType().IsPrimitive) { 
                // we've got to convert the value here -- we built the enum but the native object returns
                // us values as integers
                //
                try { 
                    lastValue = Enum.ToObject(propertyType, lastValue);
                } 
                catch { 
                }
            } 
            return lastValue;
        }

        ///  
        /// 
        ///     Retrieves the value editor for the property.  If a value editor is passed 
        ///     in as a TypeConverterAttribute, that value editor will be instantiated. 
        ///     If no such attribute was found, a system value editor will be looked for.
        ///     See TypeConverter for a description of how system value editors are found. 
        ///     If there is no system value editor, null is returned.  If the value editor found
        ///     takes an IEditorSite in its constructor, the parameter will be passed in.
        /// 
        public void GetTypeConverterAndTypeEditor(ref TypeConverter typeConverter, Type editorBaseType, ref Object typeEditor) { 

                // get the base editor and converter, attributes first 
                TypeConverter localConverter = typeConverter; 
                Object        localEditor    = typeEditor;
 
                if (localConverter == null) {
                     localConverter = GetBaseTypeConverter();
                }
 
                if (localEditor == null) {
                     localEditor = GetBaseTypeEditor(editorBaseType); 
                } 

                // if this is a object, get the value and attempt to create the correct value editor based on that value. 
                // we don't do this if the state came from an attribute
                //
                if (0 == (refreshState & Com2PropertyDescriptorRefresh.TypeConverterAttr) && this.PropertyType == typeof(Com2Variant)) {
                    Type editorType = PropertyType; 
                    Object value = GetValue(TargetObject);
                    if (value != null) { 
                        editorType = value.GetType(); 
                    }
                    ComNativeDescriptor.ResolveVariantTypeConverterAndTypeEditor(value, ref localConverter, editorBaseType, ref localEditor); 
                }

                // now see if someone else would like to serve up a value editor
                // 

                // unwrap the editor if it's one of ours. 
                if (localConverter is Com2PropDescMainConverter) { 
                    localConverter = ((Com2PropDescMainConverter)localConverter).InnerConverter;
                } 

                GetTypeConverterAndTypeEditorEvent e = new GetTypeConverterAndTypeEditorEvent(localConverter, localEditor);
                OnGetTypeConverterAndTypeEditor(e);
                localConverter = e.TypeConverter; 
                localEditor    = e.TypeEditor;
 
                // just in case one of the handlers removed our editor... 
                //
                if (localConverter == null) { 
                     localConverter = GetBaseTypeConverter();
                }

                if (localEditor == null) { 
                     localEditor = GetBaseTypeEditor(editorBaseType);
                } 
 
                // wrap the value editor in our main value editor, but only if it isn't "TypeConverter" or already a Com2PropDescMainTypeConverter
                // 
                Type localConverterType = localConverter.GetType();
                if (localConverterType != typeof(TypeConverter) && localConverterType != (typeof(Com2PropDescMainConverter))) {
                    localConverter = new Com2PropDescMainConverter(this, localConverter);
                } 

                // save the values back to the variables. 
                // 
                typeConverter = localConverter;
                typeEditor    = localEditor; 
        }

        /// 
        ///  
        ///     Is the given value equal to the last known value for this object?
        ///  
        public bool IsCurrentValue(object value) { 
            return (value == lastValue || (lastValue != null && lastValue.Equals(value)));
        } 

        /// 
        /// 
        ///     Raises the appropriate event 
        /// 
        protected void OnCanResetValue(GetBoolValueEvent gvbe) { 
            RaiseGetBoolValueEvent(EventCanResetValue, gvbe); 
        }
 
        protected void OnGetBaseAttributes(GetAttributesEvent e) {

            try {
                com2props.AlwaysValid = com2props.CheckValid(); 

                GetAttributesEventHandler handler = (GetAttributesEventHandler)Events[EventGetBaseAttributes]; 
                if (handler != null) handler(this, e); 
            }
            finally { 
                com2props.AlwaysValid = false;
            }
        }
 
        /// 
        ///  
        ///     Raises the appropriate event 
        /// 
        protected void OnGetDisplayName(GetNameItemEvent gnie) { 
            RaiseGetNameItemEvent(EventGetDisplayName, gnie);
        }

        ///  
        /// 
        ///     Raises the appropriate event 
        ///  
        protected void OnGetDisplayValue(GetNameItemEvent gnie) {
            RaiseGetNameItemEvent(EventGetDisplayValue, gnie); 
        }

        /// 
        ///  
        ///     Raises the appropriate event
        ///  
        protected void OnGetDynamicAttributes(GetAttributesEvent e) { 

            try { 
                com2props.AlwaysValid = com2props.CheckValid();
                GetAttributesEventHandler handler = (GetAttributesEventHandler)Events[EventGetDynamicAttributes];
                if (handler != null) handler(this, e);
            } 
            finally {
                com2props.AlwaysValid = false; 
            } 
        }
 


        /// 
        ///  
        ///     Raises the appropriate event
        ///  
        protected void OnGetIsReadOnly(GetBoolValueEvent gvbe) { 
            RaiseGetBoolValueEvent(EventGetIsReadOnly, gvbe);
        } 

        protected void OnGetTypeConverterAndTypeEditor(GetTypeConverterAndTypeEditorEvent e) {
            try {
                com2props.AlwaysValid = com2props.CheckValid(); 
                GetTypeConverterAndTypeEditorEventHandler handler = (GetTypeConverterAndTypeEditorEventHandler)Events[EventGetTypeConverterAndTypeEditor];
                if (handler != null) handler(this, e); 
            } 
            finally {
                com2props.AlwaysValid = false; 
            }
        }

        ///  
        /// 
        ///     Raises the appropriate event 
        ///  
        protected void OnResetValue(EventArgs e) {
            RaiseCom2Event(EventResetValue, e); 
        }

        /// 
        ///  
        ///     Raises the appropriate event
        ///  
        protected void OnShouldSerializeValue(GetBoolValueEvent gvbe) { 
            RaiseGetBoolValueEvent(EventShouldSerializeValue, gvbe);
        } 


        /// 
        ///  
        ///     Raises the appropriate event
        ///  
        protected void OnShouldRefresh(GetRefreshStateEvent gvbe) { 
            RaiseGetBoolValueEvent(EventShouldRefresh, gvbe);
        } 

        /// 
        /// 
        ///     Raises the appropriate event 
        /// 
        private void RaiseGetBoolValueEvent(Object key, GetBoolValueEvent e) { 
            try { 
                com2props.AlwaysValid = com2props.CheckValid();
                GetBoolValueEventHandler handler = (GetBoolValueEventHandler)Events[key]; 
                if (handler != null) handler(this, e);
            }
            finally {
                com2props.AlwaysValid = false; 
            }
        } 
 
        /// 
        ///  
        ///     Raises the appropriate event
        /// 
        private void RaiseCom2Event(Object key, EventArgs e) {
            try { 
                com2props.AlwaysValid = com2props.CheckValid();
                Com2EventHandler handler = (Com2EventHandler)Events[key]; 
                if (handler != null) handler(this, e); 
            }
            finally { 
                com2props.AlwaysValid = false;
            }
        }
 
        /// 
        ///  
        ///     Raises the appropriate event 
        /// 
        private void RaiseGetNameItemEvent(Object key, GetNameItemEvent e) { 
            try {
               com2props.AlwaysValid = com2props.CheckValid();
                GetNameItemEventHandler handler = (GetNameItemEventHandler)Events[key];
                if (handler != null) handler(this, e); 
            }
            finally { 
                com2props.AlwaysValid = false; 
            }
        } 

        /// 
        /// 
        ///     Will reset the default value for this property on the component.  If 
        ///     there was a default value passed in as a DefaultValueAttribute, that
        ///     value will be set as the value of the property on the component.  If 
        ///     there was no default value passed in, a ResetXXX method will be looked 
        ///     for.  If one is found, it will be invoked.  If one is not found, this
        ///     is a nop. 
        /// 
        public override void ResetValue(Object component) {
            if (component is ICustomTypeDescriptor) {
                component = ((ICustomTypeDescriptor)component).GetPropertyOwner(this); 
            }
 
            if (component == this.TargetObject) { 
                OnResetValue(EventArgs.Empty);
            } 
        }

        /// 
        ///  
        ///     Sets whether the particular item(s) need refreshing.
        ///  
        internal void SetNeedsRefresh(int mask, bool value){ 
            if (value) {
                refreshState |= mask; 
            }
            else {
                refreshState &= ~mask;
            } 
        }
 
        ///  
        /// 
        ///     This will set value to be the new value of this property on the 
        ///     component by invoking the setXXX method on the component.  If the
        ///     value specified is invalid, the component should throw an exception
        ///     which will be passed up.  The component designer should design the
        ///     property so that getXXX following a setXXX should return the value 
        ///     passed in if no exception was thrown in the setXXX call.
        ///  
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        public override void SetValue(Object component, Object value) { 

            if (this.readOnly) {
                throw new NotSupportedException(SR.GetString(SR.COM2ReadonlyProperty, this.Name ));
            } 

            if (component is ICustomTypeDescriptor) { 
                component = ((ICustomTypeDescriptor)component).GetPropertyOwner(this); 
            }
 
            if (component == null || !Marshal.IsComObject(component) || !(component is UnsafeNativeMethods.IDispatch)) {
                return;
            }
 
            // do we need to convert the type?
            if (valueConverter != null) { 
                bool cancel = false; 
                value = valueConverter.ConvertManagedToNative(value, this, ref cancel);
                if (cancel) { 
                    return;
                }
            }
 
            UnsafeNativeMethods.IDispatch pDisp = (UnsafeNativeMethods.IDispatch)component;
 
            NativeMethods.tagDISPPARAMS dp = new NativeMethods.tagDISPPARAMS(); 
            NativeMethods.tagEXCEPINFO excepInfo = new NativeMethods.tagEXCEPINFO();
            dp.cArgs = 1; 
            dp.cNamedArgs = 1;
            int[] namedArgs = new int[]{NativeMethods.DISPID_PROPERTYPUT};
            GCHandle gcHandle = GCHandle.Alloc(namedArgs, GCHandleType.Pinned);
 
            try {
                dp.rgdispidNamedArgs = Marshal.UnsafeAddrOfPinnedArrayElement(namedArgs, 0); 
                IntPtr mem = Marshal.AllocCoTaskMem( 16 /*Marshal.SizeOf(typeof(VARIANT)) */); 
                SafeNativeMethods.VariantInit(new HandleRef(null, mem));
                Marshal.GetNativeVariantForObject(value, mem); 
                dp.rgvarg = mem;
                try {

                    Guid g = Guid.Empty; 
                    int hr = pDisp.Invoke(this.dispid,
                                          ref g, 
                                          SafeNativeMethods.GetThreadLCID(), 
                                          NativeMethods.DISPATCH_PROPERTYPUT,
                                          dp, 
                                          null,
                                          excepInfo, new IntPtr[1]);

 
                    string errorInfo = null;
                    if (hr == NativeMethods.DISP_E_EXCEPTION && excepInfo.scode != 0) { 
                        hr = excepInfo.scode; 
                        errorInfo = excepInfo.bstrDescription;
                    } 

                    switch (hr) {
                    case NativeMethods.E_ABORT:
                    case NativeMethods.OLE_E_PROMPTSAVECANCELLED: 
                        // cancelled checkout, etc.
                        return; 
                    case NativeMethods.S_OK: 
                    case NativeMethods.S_FALSE:
                        OnValueChanged(component, EventArgs.Empty); 
                        lastValue = value;
                        return;
                    default:
 
                        //Debug.Fail(String.Format("IDispatch::Invoke(INVOKE_PROPPUT) returned hr=0x{0:X}", hr));
 
                        if (pDisp is UnsafeNativeMethods.ISupportErrorInfo) { 
                            g = typeof(UnsafeNativeMethods.IDispatch).GUID;
                            if (NativeMethods.Succeeded(((UnsafeNativeMethods.ISupportErrorInfo)pDisp).InterfaceSupportsErrorInfo(ref g))) { 
                                UnsafeNativeMethods.IErrorInfo pErrorInfo = null;
                                UnsafeNativeMethods.GetErrorInfo(0, ref pErrorInfo);
                                string info= null;
                                if (pErrorInfo != null) { 
                                    if (NativeMethods.Succeeded(pErrorInfo.GetDescription(ref info))) {
                                        errorInfo = info; 
                                    } 
                                }
 
                            }
                        }
                        else if (errorInfo == null) {
                            StringBuilder strMessage = new StringBuilder(256); 

                            int result = SafeNativeMethods.FormatMessage(NativeMethods.FORMAT_MESSAGE_FROM_SYSTEM | 
                                                                    NativeMethods.FORMAT_MESSAGE_IGNORE_INSERTS, 
                                                                    NativeMethods.NullHandleRef,
                                                                    hr, 
                                                                    CultureInfo.CurrentCulture.LCID,
                                                                    strMessage,
                                                                    255,
                                                                    NativeMethods.NullHandleRef); 

 
                            if (result == 0) { 
                                errorInfo = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.DispInvokeFailed, "SetValue", hr));
                            } 
                            else {
                                errorInfo = strMessage.ToString();
                                // strip of any trailing cr/lf
                                while (errorInfo.Length > 0 && 
                                        errorInfo[errorInfo.Length -1] == '\n' ||
                                        errorInfo[errorInfo.Length -1] == '\r') { 
                                    errorInfo = errorInfo.Substring(0, errorInfo.Length-1); 
                                }
                            } 
                        }
                        throw new ExternalException(errorInfo, hr);
                    }
                } 
                finally {
                    SafeNativeMethods.VariantClear(new HandleRef(null, mem)); 
                    Marshal.FreeCoTaskMem(mem); 
                }
            } 
            finally {
                gcHandle.Free();
            }
        } 

        ///  
        ///  
        ///     Indicates whether the value of this property needs to be persisted. In
        ///     other words, it indicates whether the state of the property is distinct 
        ///     from when the component is first instantiated. If there is a default
        ///     value specified in this PropertyDescriptor, it will be compared against the
        ///     property's current value to determine this.  If there is't, the
        ///     shouldPersistXXX method is looked for and invoked if found.  If both 
        ///     these routes fail, true will be returned.
        /// 
        ///     If this returns false, a tool should not persist this property's value. 
        /// 
        public override bool ShouldSerializeValue(Object component) { 
            GetBoolValueEvent gbv = new GetBoolValueEvent(false);
            OnShouldSerializeValue(gbv);
            return gbv.Value;
        } 
        /// 
        ///  
        /// we wrap all value editors in this one so we can intercept 
        /// the GetTextFromValue calls for objects that would like
        /// to modify the display name 
        /// 
        private class Com2PropDescMainConverter : Com2ExtendedTypeConverter {
            Com2PropertyDescriptor pd;
 
            private const int CheckSubprops = 0;
            private const int AllowSubprops = 1; 
            private const int SupressSubprops = 2; 

 
            private int subprops = CheckSubprops;

            public Com2PropDescMainConverter(Com2PropertyDescriptor pd, TypeConverter baseConverter) : base(baseConverter) {
                  this.pd = pd; 
            }
 
            public override Object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, Object value, Type destinationType) { 
                  Object baseConversion = base.ConvertTo(context, culture, value, destinationType);
                  if (destinationType == typeof(string)) { 
                      // if this is our current value, ask if it should be changed for display,
                      // otherwise we'll ask for our enum drop downs, which we don't wanna do!
                      //
                      if (pd.IsCurrentValue(value)) { 
                          // don't ever do this for enum types
                          if (!pd.PropertyType.IsEnum) { 
                              Com2EnumConverter baseConverter = (Com2EnumConverter)GetWrappedConverter(typeof(Com2EnumConverter)); 
                              if (baseConverter == null) {
                                return pd.GetDisplayValue((string)baseConversion); 
                              }
                              else {
                                  return baseConverter.ConvertTo(value, destinationType);
                              } 
                          }
                      } 
                  } 
                  return baseConversion;
            } 

            public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) {
                PropertyDescriptorCollection props = TypeDescriptor.GetProperties(value, attributes);
 
                if (props != null && props.Count > 0) {
                    // Return sorted read-only collection (can't sort original because its read-only) 
                    props = props.Sort(); 
                    PropertyDescriptor[] descs = new PropertyDescriptor[props.Count];
                    props.CopyTo(descs, 0); 
                    props = new PropertyDescriptorCollection(descs, true);
                }

                return props; 
            }
 
            public override bool GetPropertiesSupported(ITypeDescriptorContext context) { 
                  if (subprops == CheckSubprops) {
                     if (!base.GetPropertiesSupported(context)){ 
                        subprops = SupressSubprops;
                     }
                     else {
                        // special case the font converter here. 
                        //
                        if ((pd.valueConverter != null && pd.valueConverter.AllowExpand) || Com2IVsPerPropertyBrowsingHandler.AllowChildProperties(this.pd)) { 
                           subprops = AllowSubprops; 
                        }
                     } 
                  }
                  return (subprops == AllowSubprops);
            }
        } 
    }
 
    internal class GetAttributesEvent : EventArgs { 
        private ArrayList attrList;
 
        public GetAttributesEvent(ArrayList attrList) {
            this.attrList = attrList;

        } 

        public void Add(Attribute attribute) { 
            attrList.Add(attribute); 
        }
    } 

    internal delegate void Com2EventHandler(Com2PropertyDescriptor sender, EventArgs e);

    internal delegate void GetAttributesEventHandler(Com2PropertyDescriptor sender, GetAttributesEvent gaevent); 

    internal class GetNameItemEvent : EventArgs { 
        private Object nameItem; 

        public GetNameItemEvent(Object defName) { 
            this.nameItem = defName;

        }
 
        public Object Name{
            get{ 
                return nameItem; 
            }
            set{ 
                nameItem = value;
            }
        }
 
        public string NameString{
            get{ 
                if (nameItem != null) { 
                    return nameItem.ToString();
                } 
                return "";
            }
        }
    } 

 
    internal delegate void GetNameItemEventHandler(Com2PropertyDescriptor sender, GetNameItemEvent gnievent); 

 
    internal class GetBoolValueEvent : EventArgs {
        private bool value;

        public GetBoolValueEvent(bool defValue) { 
            this.value= defValue;
 
        } 

        public bool Value{ 
            get{
                return value;
            }
            set{ 
                this.value = value;
            } 
        } 
    }
 
    internal delegate void GetBoolValueEventHandler(Com2PropertyDescriptor sender, GetBoolValueEvent gbeevent);

    internal class GetRefreshStateEvent : GetBoolValueEvent {
 
        Com2ShouldRefreshTypes item;
 
        public GetRefreshStateEvent(Com2ShouldRefreshTypes item, bool defValue) : base(defValue) { 
            this.item = item;
        } 
    }

    internal delegate void GetTypeConverterAndTypeEditorEventHandler(Com2PropertyDescriptor sender, GetTypeConverterAndTypeEditorEvent e);
 
    internal class GetTypeConverterAndTypeEditorEvent : EventArgs {
        private TypeConverter typeConverter; 
        private Object        typeEditor; 

        public GetTypeConverterAndTypeEditorEvent(TypeConverter typeConverter, Object typeEditor) { 
            this.typeEditor = typeEditor;
            this.typeConverter = typeConverter;
        }
 
        public TypeConverter TypeConverter{
            get{ 
                return typeConverter; 
            }
            set{ 
                typeConverter = value;
            }
        }
 
        public Object TypeEditor{
            get{ 
                return typeEditor; 
            }
            set{ 
                typeEditor = value;
            }
        }
    } 

} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Windows.Forms.ComponentModel.Com2Interop { 
    using System.Runtime.Serialization.Formatters; 
    using System.Runtime.InteropServices;
    using System.ComponentModel; 
    using System.Diagnostics;
    using System;
    using System.Reflection;
    using System.ComponentModel.Design; 
    using Microsoft.Win32;
    using System.Collections; 
    using System.Text; 
    using System.Drawing.Design;
    using System.Globalization; 
    using System.Runtime.Versioning;

    /// 
    ///  
    /// This class wraps a com native property in a property descriptor.
    /// It maintains all information relative to the basic (e.g. ITypeInfo) 
    /// information about the member dispid function, and converts that info 
    /// to meaningful managed code information.
    /// 
    /// It also allows other objects to register listeners to add extended
    /// information at runtime such as attributes of TypeConverters.
    /// 
    internal class Com2PropertyDescriptor : PropertyDescriptor, ICloneable{ 
        private EventHandlerList events;
 
        ///  
        /// 
        /// Is this guy read only? 
        /// 
        private bool baseReadOnly;
        private bool readOnly;
 
        /// 
        ///  
        /// The resoved native type -> clr type 
        /// 
        private Type propertyType; 

        /// 
        /// 
        /// The dispid. This is also in a DispIDAttiribute, but we 
        /// need it a lot.
        ///  
        private int  dispid; 

        private TypeConverter   converter; 
        private object          editor;

        /// 
        ///  
        /// The current display name to show for this property
        ///  
        private string displayName; 

        ///  
        /// 
        /// This is any extra data needed.  For IDispatch types, it's the GUID of
        /// the interface, etc.
        ///  
        private object typeData;
 
 
        /// 
        ///  
        /// Keeps track of which data members need to be refreshed.
        /// 
        private int  refreshState;
 
        /// 
        ///  
        /// Should we bother asking if refresh is needed? 
        /// 
        private bool queryRefresh = false; 

        /// 
        /// 
        /// Our properties manager 
        /// 
        private Com2Properties com2props; 
 

        ///  
        /// 
        /// Our original baseline properties
        /// 
        private Attribute[] baseAttrs; 

        ///  
        ///  
        /// Our cached last value -- this is only
        /// for checking if we should ask for a display value 
        /// 
        private Object lastValue;

        ///  
        /// 
        /// For Object and dispatch types, we hide them by default. 
        ///  
        private bool   typeHide;
 
        /// 
        /// 
        /// Set if the metadata causes this property to always be hidden
        ///  
        private bool   canShow;
 
        ///  
        /// 
        /// This property is hidden because its get didn't return S_OK 
        /// 
        private bool   hrHidden;

        ///  
        /// 
        /// Set if we are in the process of asking handlers for attributes 
        ///  
        private bool   inAttrQuery;
 
        /// 
        /// 
        /// Our event signitures.
        ///  
        private static readonly Object EventGetBaseAttributes      = new Object();
        private static readonly Object EventGetDynamicAttributes   = new Object(); 
        private static readonly Object EventShouldRefresh          = new Object(); 
        private static readonly Object EventGetDisplayName         = new Object();
        private static readonly Object EventGetDisplayValue        = new Object(); 
        private static readonly Object EventGetIsReadOnly          = new Object();


        private static readonly Object EventGetTypeConverterAndTypeEditor   = new Object(); 

        private static readonly Object EventShouldSerializeValue = new Object(); 
        private static readonly Object EventCanResetValue      = new Object(); 
        private static readonly Object EventResetValue         = new Object();
 
        private static readonly Guid GUID_COLOR = new Guid("{66504301-BE0F-101A-8BBB-00AA00300CAB}");


        ///  
        /// 
        /// Our map of native types that we can map to managed types for editors 
        ///  
        private static IDictionary oleConverters;
 
        static Com2PropertyDescriptor() {
            oleConverters = new SortedList();
            oleConverters[GUID_COLOR] = typeof(Com2ColorConverter);
            oleConverters[typeof(SafeNativeMethods.IFontDisp).GUID] = typeof(Com2FontConverter); 
            oleConverters[typeof(UnsafeNativeMethods.IFont).GUID] = typeof(Com2FontConverter);
            oleConverters[typeof(UnsafeNativeMethods.IPictureDisp).GUID] = typeof(Com2PictureConverter); 
            oleConverters[typeof(UnsafeNativeMethods.IPicture).GUID] = typeof(Com2PictureConverter); 
        }
 
        /// 
        /// 
        /// Should we convert our type?
        ///  
        private Com2DataTypeToManagedDataTypeConverter valueConverter;
 
 
        /// 
        ///  
        /// Ctor.
        /// 
        public Com2PropertyDescriptor(int dispid, string name, Attribute[] attrs, bool readOnly, Type propType, Object typeData, bool hrHidden)
        : base(name, attrs) { 
            this.baseReadOnly = readOnly;
            this.readOnly = readOnly; 
 
            this.baseAttrs = attrs;
            SetNeedsRefresh(Com2PropertyDescriptorRefresh.BaseAttributes, true); 

            this.hrHidden = hrHidden;

            // readonly to begin with are always read only 
            SetNeedsRefresh(Com2PropertyDescriptorRefresh.ReadOnly, readOnly);
 
            this.propertyType = propType; 

            this.dispid = dispid; 

            if (typeData != null) {
                this.typeData = typeData;
                if (typeData is Com2Enum) { 
                     converter = new Com2EnumConverter((Com2Enum)typeData);
                } 
                else if (typeData is Guid) { 
                    valueConverter =  CreateOleTypeConverter((Type)oleConverters[(Guid)typeData]);
                } 
            }

            // check if this thing is hidden from metadata
            this.canShow = true; 

            if (attrs != null) { 
                for (int i = 0; i < attrs.Length; i++) { 
                    if (attrs[i].Equals(BrowsableAttribute.No) && !hrHidden) {
                        this.canShow = false; 
                        break;
                    }
                }
            } 

            if (this.canShow && (propType == typeof(Object) || (valueConverter == null && propType == typeof(UnsafeNativeMethods.IDispatch)))) { 
                this.typeHide = true; 
            }
        } 

        protected Attribute[] BaseAttributes {
            get {
 
                if (GetNeedsRefresh(Com2PropertyDescriptorRefresh.BaseAttributes)) {
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.BaseAttributes, false); 
 
                    int baseCount = baseAttrs == null ? 0 : baseAttrs.Length;
 
                    ArrayList attrList = new ArrayList();

                    if (baseCount != 0) {
                        attrList.AddRange(baseAttrs); 
                    }
 
                    OnGetBaseAttributes(new GetAttributesEvent(attrList)); 

                    if (attrList.Count != baseCount) { 
                        this.baseAttrs = new Attribute[attrList.Count];
                    }

                    if (baseAttrs != null) { 
                        attrList.CopyTo(this.baseAttrs, 0);
                    } 
                    else { 
                        baseAttrs = new Attribute[0];
                    } 
                }

                return baseAttrs;
            } 
            set {
                baseAttrs = value; 
            } 
        }
 
        /// 
        /// 
        ///     Attributes
        ///  
        public override AttributeCollection Attributes {
            get { 
                if (this.AttributesValid || this.InAttrQuery) { 
                    return base.Attributes;
                } 

                // restore our base attributes
                this.AttributeArray = this.BaseAttributes;
 
                ArrayList newAttributes = null;
 
                // if we are forcing a hide 
                if (typeHide && canShow) {
                    if (newAttributes == null) { 
                        newAttributes = new ArrayList(AttributeArray);
                    }
                    newAttributes.Add(new BrowsableAttribute(false));
                } 
                else if (hrHidden) {
                    // check to see if the get still fails 
                    Object target = this.TargetObject; 
                    if (target != null) {
                        int hr = new ComNativeDescriptor().GetPropertyValue(target, this.dispid, new object[1]); 

                        // if not, go ahead and make this a browsable item
                        if (NativeMethods.Succeeded(hr)) {
                            // make it browsable 
                            if (newAttributes == null) {
                                newAttributes = new ArrayList(AttributeArray); 
                            } 
                            newAttributes.Add(new BrowsableAttribute(true));
                            hrHidden = false; 
                        }
                    }
                }
 
                this.inAttrQuery = true;
                try { 
 
                    // demand get any extended attributes
                    ArrayList attrList = new ArrayList(); 

                    OnGetDynamicAttributes(new GetAttributesEvent(attrList));

                    Attribute ma; 

                    if (attrList.Count != 0 && newAttributes == null) { 
                        newAttributes = new ArrayList(AttributeArray); 
                    }
 
                    // push any new attributes into the base type
                    for (int i=0; i < attrList.Count; i++) {
                        ma = (Attribute)attrList[i];
                        newAttributes.Add(ma); 
                    }
                } 
                finally { 
                    this.inAttrQuery = false;
                } 

                // these are now valid.
                SetNeedsRefresh(Com2PropertyDescriptorRefresh.Attributes, false);
 
                // If we reconfigured attributes, then poke the new set back in.
                // 
                if (newAttributes != null) { 
                    Attribute[] temp = new Attribute[newAttributes.Count];
                    newAttributes.CopyTo(temp, 0); 
                    AttributeArray = temp;
                }

                return base.Attributes; 
            }
 
        } 

        ///  
        /// 
        ///     Checks if the attributes are valid.  Asks any clients if they
        ///     would like attributes requeried.
        ///  
        protected bool AttributesValid{
            get{ 
                bool currentRefresh = !GetNeedsRefresh(Com2PropertyDescriptorRefresh.Attributes); 
                if (queryRefresh) {
                    GetRefreshStateEvent rse = new GetRefreshStateEvent(Com2ShouldRefreshTypes.Attributes, !currentRefresh); 
                    OnShouldRefresh(rse);
                    currentRefresh = !rse.Value;
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.Attributes, rse.Value);
                } 
                return currentRefresh;
            } 
        } 

        ///  
        /// 
        ///     Checks if this item can be shown.
        /// 
        public bool CanShow{ 
            get{
                return this.canShow; 
            } 
        }
 

        /// 
        /// 
        ///     Retrieves the type of the component this PropertyDescriptor is bound to. 
        /// 
        public override Type ComponentType { 
            get { 
                return typeof(UnsafeNativeMethods.IDispatch);
            } 
        }

        /// 
        ///  
        ///      Retrieves the type converter for this property.
        ///  
        public override TypeConverter Converter { 
            get {
               if (TypeConverterValid) { 
                  return converter;
               }

               Object typeEd = null; 

               GetTypeConverterAndTypeEditor(ref converter, typeof(UITypeEditor), ref typeEd); 
 
               if (!TypeEditorValid) {
                  this.editor = typeEd; 
                  SetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeEditor, false);
               }
               SetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeConverter, false);
 
               return converter;
            } 
        } 

        ///  
        /// 
        ///     Retrieves whether this component is applying a type conversion...
        /// 
        public bool ConvertingNativeType { 
            get {
                return(valueConverter != null); 
            } 
        }
 
        /// 
        /// 
        ///      Retrieves the default value for this property.
        ///  
        protected virtual Object DefaultValue {
            get { 
                return null; 
            }
        } 

        /// 
        /// 
        ///     Retrieves the DISPID for this item 
        /// 
        public int DISPID{ 
            get{ 
                return this.dispid;
            } 
        }

        /// 
        ///  
        ///     Gets the friendly name that should be displayed to the user in a window like
        ///     the Property Browser. 
        ///  
        public override string DisplayName {
            get { 
                if (!this.DisplayNameValid) {
                    GetNameItemEvent gni = new GetNameItemEvent(base.DisplayName);
                    OnGetDisplayName(gni);
                    this.displayName = gni.NameString; 
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.DisplayName, false);
                } 
                return this.displayName; 
            }
        } 

        /// 
        /// 
        ///     Checks if the property display name is valid 
        ///     asks clients if they would like display name requeried.
        ///  
        protected bool DisplayNameValid{ 
            get{
                bool currentRefresh = !(displayName == null || GetNeedsRefresh(Com2PropertyDescriptorRefresh.DisplayName)); 
                if (queryRefresh) {
                    GetRefreshStateEvent rse = new GetRefreshStateEvent(Com2ShouldRefreshTypes.DisplayName, !currentRefresh);
                    OnShouldRefresh(rse);
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.DisplayName, rse.Value); 
                    currentRefresh = !rse.Value;
                } 
                return currentRefresh; 
            }
        } 

        protected EventHandlerList Events {
            get {
                if (events == null) { 
                    events = new EventHandlerList();
                } 
                return events; 
            }
        } 

        protected bool InAttrQuery{
            get{
                return this.inAttrQuery; 
            }
        } 
 
        /// 
        ///  
        ///     Indicates whether this property is read only.
        /// 
        public override bool IsReadOnly {
            get { 
                if (!this.ReadOnlyValid) {
                    this.readOnly |= (this.Attributes[typeof(ReadOnlyAttribute)].Equals(ReadOnlyAttribute.Yes)); 
                    GetBoolValueEvent gbv = new GetBoolValueEvent(this.readOnly); 
                    OnGetIsReadOnly(gbv);
                    this.readOnly = gbv.Value; 
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.ReadOnly, false);
                }
                return this.readOnly;
            } 
        }
 
        internal Com2Properties PropertyManager{ 
            set{
                this.com2props = value; 
            }
            get{
                return this.com2props;
            } 
        }
 
        ///  
        /// 
        ///     Retrieves the type of the property. 
        /// 
        public override Type PropertyType {
            get {
                // replace the type with the mapped converter type 
                if (valueConverter != null) {
                    return valueConverter.ManagedType; 
                } 
                else {
                    return propertyType; 
                }
            }
        }
 
        /// 
        ///  
        ///     Checks if the read only state is valid. 
        ///     Asks clients if they would like read-only requeried.
        ///  
        protected bool ReadOnlyValid{
            get{
                if (baseReadOnly) {
                    return true; 
                }
 
                bool currentRefresh = !GetNeedsRefresh(Com2PropertyDescriptorRefresh.ReadOnly); 

                if (queryRefresh) { 
                    GetRefreshStateEvent rse = new GetRefreshStateEvent(Com2ShouldRefreshTypes.ReadOnly, !currentRefresh);
                    OnShouldRefresh(rse);
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.ReadOnly, rse.Value);
                    currentRefresh = !rse.Value; 
                }
                return currentRefresh; 
            } 
        }
 
        /// 
        /// 
        ///     Gets the Object that this descriptor was created for.
        ///     May be null if the Object's ref has died. 
        /// 
        public virtual Object TargetObject{ 
            get{ 
                if (com2props != null) {
                    return com2props.TargetObject; 
                }
                return null;
            }
        } 

        protected bool TypeConverterValid { 
            get { 
                bool currentRefresh =!(converter == null || GetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeConverter));
                if (queryRefresh) { 
                    GetRefreshStateEvent rse = new GetRefreshStateEvent(Com2ShouldRefreshTypes.TypeConverter, !currentRefresh);
                    OnShouldRefresh(rse);
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeConverter, rse.Value);
                    currentRefresh = !rse.Value; 
                }
                return currentRefresh; 
            } 
        }
 
        protected bool TypeEditorValid {
            get {
                bool currentRefresh = !(editor == null || GetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeEditor));
 
                if (queryRefresh) {
                    GetRefreshStateEvent rse = new GetRefreshStateEvent(Com2ShouldRefreshTypes.TypeEditor, !currentRefresh); 
                    OnShouldRefresh(rse); 
                    SetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeEditor, rse.Value);
                    currentRefresh = !rse.Value; 
                }
                return currentRefresh;
            }
        } 

 
        public event GetBoolValueEventHandler QueryCanResetValue { 
            add {
                Events.AddHandler(EventCanResetValue, value); 
            }
            remove {
                Events.RemoveHandler(EventCanResetValue, value);
            } 
        }
 
        public event GetAttributesEventHandler QueryGetBaseAttributes { 
            add {
                Events.AddHandler(EventGetBaseAttributes, value); 
            }
            remove {
                Events.RemoveHandler(EventGetBaseAttributes, value);
            } 
        }
 
        public event GetAttributesEventHandler QueryGetDynamicAttributes { 
            add {
                Events.AddHandler(EventGetDynamicAttributes, value); 
            }
            remove {
                Events.RemoveHandler(EventGetDynamicAttributes, value);
            } 
        }
 
 
        public event GetNameItemEventHandler QueryGetDisplayName {
            add { 
                Events.AddHandler(EventGetDisplayName, value);
            }
            remove {
                Events.RemoveHandler(EventGetDisplayName, value); 
            }
        } 
 

        public event GetNameItemEventHandler QueryGetDisplayValue { 
            add {
                Events.AddHandler(EventGetDisplayValue, value);
            }
            remove { 
                Events.RemoveHandler(EventGetDisplayValue, value);
            } 
        } 

 
        public event GetBoolValueEventHandler QueryGetIsReadOnly {
            add {
                Events.AddHandler(EventGetIsReadOnly, value);
            } 
            remove {
                Events.RemoveHandler(EventGetIsReadOnly, value); 
            } 
        }
 

        public event GetTypeConverterAndTypeEditorEventHandler QueryGetTypeConverterAndTypeEditor {
            add {
                Events.AddHandler(EventGetTypeConverterAndTypeEditor, value); 
            }
            remove { 
                Events.RemoveHandler(EventGetTypeConverterAndTypeEditor, value); 
            }
        } 


        public event Com2EventHandler QueryResetValue {
            add { 
                Events.AddHandler(EventResetValue, value);
            } 
            remove { 
                Events.RemoveHandler(EventResetValue, value);
            } 
        }


        public event GetBoolValueEventHandler QueryShouldSerializeValue { 
            add {
                Events.AddHandler(EventShouldSerializeValue, value); 
            } 
            remove {
                Events.RemoveHandler(EventShouldSerializeValue, value); 
            }
        }

 

        ///  
        ///  
        ///     Indicates whether reset will change the value of the component.  If there
        ///     is a DefaultValueAttribute, then this will return true if getValue returns 
        ///     something different than the default value.  If there is a reset method and
        ///     a shouldPersist method, this will return what shouldPersist returns.
        ///     If there is just a reset method, this always returns true.  If none of these
        ///     cases apply, this returns false. 
        /// 
        public override bool CanResetValue(Object component) { 
 
            if (component is ICustomTypeDescriptor) {
                component = ((ICustomTypeDescriptor)component).GetPropertyOwner(this); 
            }

            if (component == this.TargetObject) {
                GetBoolValueEvent gbv = new GetBoolValueEvent(false); 
                OnCanResetValue(gbv);
                return gbv.Value; 
            } 
            return false;
        } 

        public object Clone() {
            return new Com2PropertyDescriptor(this.dispid, this.Name, (Attribute[])this.baseAttrs.Clone(), this.readOnly, this.propertyType, this.typeData, this.hrHidden);
        } 

        ///  
        ///  
        ///     Creates a converter Object, first by looking for a ctor with a Com2ProeprtyDescriptor
        ///     parameter, then using the default ctor if it is not found. 
        /// 
        private Com2DataTypeToManagedDataTypeConverter CreateOleTypeConverter(Type t) {

            if (t == null) { 
                return null;
            } 
 
            ConstructorInfo ctor = t.GetConstructor(new Type[]{typeof(Com2PropertyDescriptor)});
            Com2DataTypeToManagedDataTypeConverter converter; 
            if (ctor != null) {
                converter = (Com2DataTypeToManagedDataTypeConverter)ctor.Invoke(new Object[]{this});
            }
            else { 
                converter = (Com2DataTypeToManagedDataTypeConverter)Activator.CreateInstance(t);
            } 
            return converter; 
        }
 
        /// 
        /// 
        ///     Creates an instance of the member attribute collection. This can
        ///     be overriden by subclasses to return a subclass of AttributeCollection. 
        /// 
        protected override AttributeCollection CreateAttributeCollection() { 
            return new AttributeCollection(AttributeArray); 
        }
 
        private TypeConverter GetBaseTypeConverter() {

            if (PropertyType == null) {
                return new TypeConverter(); 
            }
 
            TypeConverter localConverter = null; 

            TypeConverterAttribute attr = (TypeConverterAttribute)Attributes[typeof(TypeConverterAttribute)]; 
            if (attr != null) {
               string converterTypeName = attr.ConverterTypeName;
               if (converterTypeName != null && converterTypeName.Length > 0) {
                   Type converterType = Type.GetType(converterTypeName); 
                   if (converterType != null && typeof(TypeConverter).IsAssignableFrom(converterType)) {
                       try { 
                          localConverter = (TypeConverter)Activator.CreateInstance(converterType); 
                          if (localConverter != null) {
                               refreshState |= Com2PropertyDescriptorRefresh.TypeConverterAttr; 
                          }
                       }
                       catch (Exception ex) {
                          Debug.Fail("Failed to create TypeConverter of type '" + attr.ConverterTypeName + "' from Attribute", ex.ToString()); 
                       }
                   } 
               } 
            }
 
            // if we didn't get one from the attribute, ask the type descriptor
            if (localConverter == null) {
               // we don't want to create the value editor for the IDispatch props because
                // that will create the reference editor.  We don't want that guy! 
                //
                if (!typeof(UnsafeNativeMethods.IDispatch).IsAssignableFrom(this.PropertyType)) { 
                     localConverter = base.Converter; 
                }
                else { 
                     localConverter = new Com2IDispatchConverter(this, false);
                }
            }
 
            if (localConverter == null) {
                localConverter = new TypeConverter(); 
            } 
            return localConverter;
        } 

        private Object GetBaseTypeEditor(Type editorBaseType) {

            if (PropertyType == null) { 
                return null;
            } 
 
            Object localEditor = null;
            EditorAttribute attr = (EditorAttribute)Attributes[typeof(EditorAttribute)]; 
            if (attr != null) {
               string editorTypeName = attr.EditorBaseTypeName;

               if (editorTypeName != null && editorTypeName.Length > 0) { 
                   Type attrEditorBaseType = Type.GetType(editorTypeName);
                   if (attrEditorBaseType != null && attrEditorBaseType == editorBaseType) { 
                        Type type = Type.GetType(attr.EditorTypeName); 
                        if (type != null) {
                            try { 
                               localEditor = Activator.CreateInstance(type);
                               if (localEditor != null) {
                                  refreshState |= Com2PropertyDescriptorRefresh.TypeEditorAttr;
                               } 
                            }
                            catch (Exception ex) { 
                               Debug.Fail("Failed to create edtior of type '" + attr.EditorTypeName + "' from Attribute", ex.ToString()); 
                            }
                        } 
                   }
               }
            }
            if (localEditor == null) { 
                 localEditor = base.GetEditor(editorBaseType);
            } 
            return localEditor; 
        }
 
        /// 
        /// 
        ///     Gets the value that should be displayed to the user, such as in
        ///     the Property Browser. 
        /// 
        public virtual string GetDisplayValue(string defaultValue) { 
 
            GetNameItemEvent nie = new GetNameItemEvent(defaultValue);
            OnGetDisplayValue(nie); 

            string str = (nie.Name == null ? null : nie.Name.ToString());
            return str;
        } 

        ///  
        ///  
        ///      Retrieves an editor of the requested type.
        ///  
        public override Object GetEditor(Type editorBaseType) {
               if (TypeEditorValid) {
                  return editor;
               } 

               if (PropertyType == null) { 
                   return null; 
               }
 
               if (editorBaseType == typeof(UITypeEditor)) {
                  TypeConverter c = null;
                  GetTypeConverterAndTypeEditor(ref c, editorBaseType, ref editor);
 
                  if (!TypeConverterValid) {
                     this.converter = c; 
                     SetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeConverter, false); 
                  }
                  SetNeedsRefresh(Com2PropertyDescriptorRefresh.TypeEditor, false); 
               }
               else {
                  editor = base.GetEditor(editorBaseType);
               } 
               return editor;
 
        } 

        ///  
        /// 
        ///     Retrieves the current native value of the property on component,
        ///     invoking the getXXX method.  An exception in the getXXX
        ///     method will pass through. 
        /// 
        public Object GetNativeValue(Object component){ 
            if (component == null) 
                return null;
 
            if (component is ICustomTypeDescriptor) {
                component = ((ICustomTypeDescriptor)component).GetPropertyOwner(this);
            }
 
            if (component == null || !Marshal.IsComObject(component) || !(component is UnsafeNativeMethods.IDispatch))
                return null; 
 
            UnsafeNativeMethods.IDispatch pDisp = (UnsafeNativeMethods.IDispatch)component;
            Object[] pVarResult = new Object[1]; 
            NativeMethods.tagEXCEPINFO pExcepInfo = new NativeMethods.tagEXCEPINFO();
            Guid g = Guid.Empty;

            int hr = pDisp.Invoke(this.dispid, 
                                  ref g,
                                  SafeNativeMethods.GetThreadLCID(), 
                                  NativeMethods.DISPATCH_PROPERTYGET, 
                                  new NativeMethods.tagDISPPARAMS(),
                                  pVarResult, 
                                  pExcepInfo, null);

            switch (hr) {
            case NativeMethods.S_OK: 
            case NativeMethods.S_FALSE:
 
                if (pVarResult[0] == null || Convert.IsDBNull(pVarResult[0])) { 
                    lastValue = null;
                } 
                else {
                    lastValue = pVarResult[0];
                }
                return lastValue; 
            case NativeMethods.DISP_E_EXCEPTION:
                //PrintExceptionInfo(pExcepInfo); 
                return null; 
            default:
                throw new ExternalException(SR.GetString(SR.DispInvokeFailed, "GetValue" , hr), hr); 
            }
        }

        ///  
        /// 
        ///     Checks whether the particular item(s) need refreshing. 
        ///  
        private bool GetNeedsRefresh(int mask){
            return(refreshState & mask) != 0; 
        }


        ///  
        /// 
        ///     Retrieves the current value of the property on component, 
        ///     invoking the getXXX method.  An exception in the getXXX 
        ///     method will pass through.
        ///  
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public override Object GetValue(Object component) {
            lastValue = GetNativeValue(component); 
            // do we need to convert the type?
            if (this.ConvertingNativeType && lastValue != null) { 
                lastValue = valueConverter.ConvertNativeToManaged(lastValue, this); 
            }
            else if (lastValue != null && propertyType != null && propertyType.IsEnum && lastValue.GetType().IsPrimitive) { 
                // we've got to convert the value here -- we built the enum but the native object returns
                // us values as integers
                //
                try { 
                    lastValue = Enum.ToObject(propertyType, lastValue);
                } 
                catch { 
                }
            } 
            return lastValue;
        }

        ///  
        /// 
        ///     Retrieves the value editor for the property.  If a value editor is passed 
        ///     in as a TypeConverterAttribute, that value editor will be instantiated. 
        ///     If no such attribute was found, a system value editor will be looked for.
        ///     See TypeConverter for a description of how system value editors are found. 
        ///     If there is no system value editor, null is returned.  If the value editor found
        ///     takes an IEditorSite in its constructor, the parameter will be passed in.
        /// 
        public void GetTypeConverterAndTypeEditor(ref TypeConverter typeConverter, Type editorBaseType, ref Object typeEditor) { 

                // get the base editor and converter, attributes first 
                TypeConverter localConverter = typeConverter; 
                Object        localEditor    = typeEditor;
 
                if (localConverter == null) {
                     localConverter = GetBaseTypeConverter();
                }
 
                if (localEditor == null) {
                     localEditor = GetBaseTypeEditor(editorBaseType); 
                } 

                // if this is a object, get the value and attempt to create the correct value editor based on that value. 
                // we don't do this if the state came from an attribute
                //
                if (0 == (refreshState & Com2PropertyDescriptorRefresh.TypeConverterAttr) && this.PropertyType == typeof(Com2Variant)) {
                    Type editorType = PropertyType; 
                    Object value = GetValue(TargetObject);
                    if (value != null) { 
                        editorType = value.GetType(); 
                    }
                    ComNativeDescriptor.ResolveVariantTypeConverterAndTypeEditor(value, ref localConverter, editorBaseType, ref localEditor); 
                }

                // now see if someone else would like to serve up a value editor
                // 

                // unwrap the editor if it's one of ours. 
                if (localConverter is Com2PropDescMainConverter) { 
                    localConverter = ((Com2PropDescMainConverter)localConverter).InnerConverter;
                } 

                GetTypeConverterAndTypeEditorEvent e = new GetTypeConverterAndTypeEditorEvent(localConverter, localEditor);
                OnGetTypeConverterAndTypeEditor(e);
                localConverter = e.TypeConverter; 
                localEditor    = e.TypeEditor;
 
                // just in case one of the handlers removed our editor... 
                //
                if (localConverter == null) { 
                     localConverter = GetBaseTypeConverter();
                }

                if (localEditor == null) { 
                     localEditor = GetBaseTypeEditor(editorBaseType);
                } 
 
                // wrap the value editor in our main value editor, but only if it isn't "TypeConverter" or already a Com2PropDescMainTypeConverter
                // 
                Type localConverterType = localConverter.GetType();
                if (localConverterType != typeof(TypeConverter) && localConverterType != (typeof(Com2PropDescMainConverter))) {
                    localConverter = new Com2PropDescMainConverter(this, localConverter);
                } 

                // save the values back to the variables. 
                // 
                typeConverter = localConverter;
                typeEditor    = localEditor; 
        }

        /// 
        ///  
        ///     Is the given value equal to the last known value for this object?
        ///  
        public bool IsCurrentValue(object value) { 
            return (value == lastValue || (lastValue != null && lastValue.Equals(value)));
        } 

        /// 
        /// 
        ///     Raises the appropriate event 
        /// 
        protected void OnCanResetValue(GetBoolValueEvent gvbe) { 
            RaiseGetBoolValueEvent(EventCanResetValue, gvbe); 
        }
 
        protected void OnGetBaseAttributes(GetAttributesEvent e) {

            try {
                com2props.AlwaysValid = com2props.CheckValid(); 

                GetAttributesEventHandler handler = (GetAttributesEventHandler)Events[EventGetBaseAttributes]; 
                if (handler != null) handler(this, e); 
            }
            finally { 
                com2props.AlwaysValid = false;
            }
        }
 
        /// 
        ///  
        ///     Raises the appropriate event 
        /// 
        protected void OnGetDisplayName(GetNameItemEvent gnie) { 
            RaiseGetNameItemEvent(EventGetDisplayName, gnie);
        }

        ///  
        /// 
        ///     Raises the appropriate event 
        ///  
        protected void OnGetDisplayValue(GetNameItemEvent gnie) {
            RaiseGetNameItemEvent(EventGetDisplayValue, gnie); 
        }

        /// 
        ///  
        ///     Raises the appropriate event
        ///  
        protected void OnGetDynamicAttributes(GetAttributesEvent e) { 

            try { 
                com2props.AlwaysValid = com2props.CheckValid();
                GetAttributesEventHandler handler = (GetAttributesEventHandler)Events[EventGetDynamicAttributes];
                if (handler != null) handler(this, e);
            } 
            finally {
                com2props.AlwaysValid = false; 
            } 
        }
 


        /// 
        ///  
        ///     Raises the appropriate event
        ///  
        protected void OnGetIsReadOnly(GetBoolValueEvent gvbe) { 
            RaiseGetBoolValueEvent(EventGetIsReadOnly, gvbe);
        } 

        protected void OnGetTypeConverterAndTypeEditor(GetTypeConverterAndTypeEditorEvent e) {
            try {
                com2props.AlwaysValid = com2props.CheckValid(); 
                GetTypeConverterAndTypeEditorEventHandler handler = (GetTypeConverterAndTypeEditorEventHandler)Events[EventGetTypeConverterAndTypeEditor];
                if (handler != null) handler(this, e); 
            } 
            finally {
                com2props.AlwaysValid = false; 
            }
        }

        ///  
        /// 
        ///     Raises the appropriate event 
        ///  
        protected void OnResetValue(EventArgs e) {
            RaiseCom2Event(EventResetValue, e); 
        }

        /// 
        ///  
        ///     Raises the appropriate event
        ///  
        protected void OnShouldSerializeValue(GetBoolValueEvent gvbe) { 
            RaiseGetBoolValueEvent(EventShouldSerializeValue, gvbe);
        } 


        /// 
        ///  
        ///     Raises the appropriate event
        ///  
        protected void OnShouldRefresh(GetRefreshStateEvent gvbe) { 
            RaiseGetBoolValueEvent(EventShouldRefresh, gvbe);
        } 

        /// 
        /// 
        ///     Raises the appropriate event 
        /// 
        private void RaiseGetBoolValueEvent(Object key, GetBoolValueEvent e) { 
            try { 
                com2props.AlwaysValid = com2props.CheckValid();
                GetBoolValueEventHandler handler = (GetBoolValueEventHandler)Events[key]; 
                if (handler != null) handler(this, e);
            }
            finally {
                com2props.AlwaysValid = false; 
            }
        } 
 
        /// 
        ///  
        ///     Raises the appropriate event
        /// 
        private void RaiseCom2Event(Object key, EventArgs e) {
            try { 
                com2props.AlwaysValid = com2props.CheckValid();
                Com2EventHandler handler = (Com2EventHandler)Events[key]; 
                if (handler != null) handler(this, e); 
            }
            finally { 
                com2props.AlwaysValid = false;
            }
        }
 
        /// 
        ///  
        ///     Raises the appropriate event 
        /// 
        private void RaiseGetNameItemEvent(Object key, GetNameItemEvent e) { 
            try {
               com2props.AlwaysValid = com2props.CheckValid();
                GetNameItemEventHandler handler = (GetNameItemEventHandler)Events[key];
                if (handler != null) handler(this, e); 
            }
            finally { 
                com2props.AlwaysValid = false; 
            }
        } 

        /// 
        /// 
        ///     Will reset the default value for this property on the component.  If 
        ///     there was a default value passed in as a DefaultValueAttribute, that
        ///     value will be set as the value of the property on the component.  If 
        ///     there was no default value passed in, a ResetXXX method will be looked 
        ///     for.  If one is found, it will be invoked.  If one is not found, this
        ///     is a nop. 
        /// 
        public override void ResetValue(Object component) {
            if (component is ICustomTypeDescriptor) {
                component = ((ICustomTypeDescriptor)component).GetPropertyOwner(this); 
            }
 
            if (component == this.TargetObject) { 
                OnResetValue(EventArgs.Empty);
            } 
        }

        /// 
        ///  
        ///     Sets whether the particular item(s) need refreshing.
        ///  
        internal void SetNeedsRefresh(int mask, bool value){ 
            if (value) {
                refreshState |= mask; 
            }
            else {
                refreshState &= ~mask;
            } 
        }
 
        ///  
        /// 
        ///     This will set value to be the new value of this property on the 
        ///     component by invoking the setXXX method on the component.  If the
        ///     value specified is invalid, the component should throw an exception
        ///     which will be passed up.  The component designer should design the
        ///     property so that getXXX following a setXXX should return the value 
        ///     passed in if no exception was thrown in the setXXX call.
        ///  
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        public override void SetValue(Object component, Object value) { 

            if (this.readOnly) {
                throw new NotSupportedException(SR.GetString(SR.COM2ReadonlyProperty, this.Name ));
            } 

            if (component is ICustomTypeDescriptor) { 
                component = ((ICustomTypeDescriptor)component).GetPropertyOwner(this); 
            }
 
            if (component == null || !Marshal.IsComObject(component) || !(component is UnsafeNativeMethods.IDispatch)) {
                return;
            }
 
            // do we need to convert the type?
            if (valueConverter != null) { 
                bool cancel = false; 
                value = valueConverter.ConvertManagedToNative(value, this, ref cancel);
                if (cancel) { 
                    return;
                }
            }
 
            UnsafeNativeMethods.IDispatch pDisp = (UnsafeNativeMethods.IDispatch)component;
 
            NativeMethods.tagDISPPARAMS dp = new NativeMethods.tagDISPPARAMS(); 
            NativeMethods.tagEXCEPINFO excepInfo = new NativeMethods.tagEXCEPINFO();
            dp.cArgs = 1; 
            dp.cNamedArgs = 1;
            int[] namedArgs = new int[]{NativeMethods.DISPID_PROPERTYPUT};
            GCHandle gcHandle = GCHandle.Alloc(namedArgs, GCHandleType.Pinned);
 
            try {
                dp.rgdispidNamedArgs = Marshal.UnsafeAddrOfPinnedArrayElement(namedArgs, 0); 
                IntPtr mem = Marshal.AllocCoTaskMem( 16 /*Marshal.SizeOf(typeof(VARIANT)) */); 
                SafeNativeMethods.VariantInit(new HandleRef(null, mem));
                Marshal.GetNativeVariantForObject(value, mem); 
                dp.rgvarg = mem;
                try {

                    Guid g = Guid.Empty; 
                    int hr = pDisp.Invoke(this.dispid,
                                          ref g, 
                                          SafeNativeMethods.GetThreadLCID(), 
                                          NativeMethods.DISPATCH_PROPERTYPUT,
                                          dp, 
                                          null,
                                          excepInfo, new IntPtr[1]);

 
                    string errorInfo = null;
                    if (hr == NativeMethods.DISP_E_EXCEPTION && excepInfo.scode != 0) { 
                        hr = excepInfo.scode; 
                        errorInfo = excepInfo.bstrDescription;
                    } 

                    switch (hr) {
                    case NativeMethods.E_ABORT:
                    case NativeMethods.OLE_E_PROMPTSAVECANCELLED: 
                        // cancelled checkout, etc.
                        return; 
                    case NativeMethods.S_OK: 
                    case NativeMethods.S_FALSE:
                        OnValueChanged(component, EventArgs.Empty); 
                        lastValue = value;
                        return;
                    default:
 
                        //Debug.Fail(String.Format("IDispatch::Invoke(INVOKE_PROPPUT) returned hr=0x{0:X}", hr));
 
                        if (pDisp is UnsafeNativeMethods.ISupportErrorInfo) { 
                            g = typeof(UnsafeNativeMethods.IDispatch).GUID;
                            if (NativeMethods.Succeeded(((UnsafeNativeMethods.ISupportErrorInfo)pDisp).InterfaceSupportsErrorInfo(ref g))) { 
                                UnsafeNativeMethods.IErrorInfo pErrorInfo = null;
                                UnsafeNativeMethods.GetErrorInfo(0, ref pErrorInfo);
                                string info= null;
                                if (pErrorInfo != null) { 
                                    if (NativeMethods.Succeeded(pErrorInfo.GetDescription(ref info))) {
                                        errorInfo = info; 
                                    } 
                                }
 
                            }
                        }
                        else if (errorInfo == null) {
                            StringBuilder strMessage = new StringBuilder(256); 

                            int result = SafeNativeMethods.FormatMessage(NativeMethods.FORMAT_MESSAGE_FROM_SYSTEM | 
                                                                    NativeMethods.FORMAT_MESSAGE_IGNORE_INSERTS, 
                                                                    NativeMethods.NullHandleRef,
                                                                    hr, 
                                                                    CultureInfo.CurrentCulture.LCID,
                                                                    strMessage,
                                                                    255,
                                                                    NativeMethods.NullHandleRef); 

 
                            if (result == 0) { 
                                errorInfo = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.DispInvokeFailed, "SetValue", hr));
                            } 
                            else {
                                errorInfo = strMessage.ToString();
                                // strip of any trailing cr/lf
                                while (errorInfo.Length > 0 && 
                                        errorInfo[errorInfo.Length -1] == '\n' ||
                                        errorInfo[errorInfo.Length -1] == '\r') { 
                                    errorInfo = errorInfo.Substring(0, errorInfo.Length-1); 
                                }
                            } 
                        }
                        throw new ExternalException(errorInfo, hr);
                    }
                } 
                finally {
                    SafeNativeMethods.VariantClear(new HandleRef(null, mem)); 
                    Marshal.FreeCoTaskMem(mem); 
                }
            } 
            finally {
                gcHandle.Free();
            }
        } 

        ///  
        ///  
        ///     Indicates whether the value of this property needs to be persisted. In
        ///     other words, it indicates whether the state of the property is distinct 
        ///     from when the component is first instantiated. If there is a default
        ///     value specified in this PropertyDescriptor, it will be compared against the
        ///     property's current value to determine this.  If there is't, the
        ///     shouldPersistXXX method is looked for and invoked if found.  If both 
        ///     these routes fail, true will be returned.
        /// 
        ///     If this returns false, a tool should not persist this property's value. 
        /// 
        public override bool ShouldSerializeValue(Object component) { 
            GetBoolValueEvent gbv = new GetBoolValueEvent(false);
            OnShouldSerializeValue(gbv);
            return gbv.Value;
        } 
        /// 
        ///  
        /// we wrap all value editors in this one so we can intercept 
        /// the GetTextFromValue calls for objects that would like
        /// to modify the display name 
        /// 
        private class Com2PropDescMainConverter : Com2ExtendedTypeConverter {
            Com2PropertyDescriptor pd;
 
            private const int CheckSubprops = 0;
            private const int AllowSubprops = 1; 
            private const int SupressSubprops = 2; 

 
            private int subprops = CheckSubprops;

            public Com2PropDescMainConverter(Com2PropertyDescriptor pd, TypeConverter baseConverter) : base(baseConverter) {
                  this.pd = pd; 
            }
 
            public override Object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, Object value, Type destinationType) { 
                  Object baseConversion = base.ConvertTo(context, culture, value, destinationType);
                  if (destinationType == typeof(string)) { 
                      // if this is our current value, ask if it should be changed for display,
                      // otherwise we'll ask for our enum drop downs, which we don't wanna do!
                      //
                      if (pd.IsCurrentValue(value)) { 
                          // don't ever do this for enum types
                          if (!pd.PropertyType.IsEnum) { 
                              Com2EnumConverter baseConverter = (Com2EnumConverter)GetWrappedConverter(typeof(Com2EnumConverter)); 
                              if (baseConverter == null) {
                                return pd.GetDisplayValue((string)baseConversion); 
                              }
                              else {
                                  return baseConverter.ConvertTo(value, destinationType);
                              } 
                          }
                      } 
                  } 
                  return baseConversion;
            } 

            public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) {
                PropertyDescriptorCollection props = TypeDescriptor.GetProperties(value, attributes);
 
                if (props != null && props.Count > 0) {
                    // Return sorted read-only collection (can't sort original because its read-only) 
                    props = props.Sort(); 
                    PropertyDescriptor[] descs = new PropertyDescriptor[props.Count];
                    props.CopyTo(descs, 0); 
                    props = new PropertyDescriptorCollection(descs, true);
                }

                return props; 
            }
 
            public override bool GetPropertiesSupported(ITypeDescriptorContext context) { 
                  if (subprops == CheckSubprops) {
                     if (!base.GetPropertiesSupported(context)){ 
                        subprops = SupressSubprops;
                     }
                     else {
                        // special case the font converter here. 
                        //
                        if ((pd.valueConverter != null && pd.valueConverter.AllowExpand) || Com2IVsPerPropertyBrowsingHandler.AllowChildProperties(this.pd)) { 
                           subprops = AllowSubprops; 
                        }
                     } 
                  }
                  return (subprops == AllowSubprops);
            }
        } 
    }
 
    internal class GetAttributesEvent : EventArgs { 
        private ArrayList attrList;
 
        public GetAttributesEvent(ArrayList attrList) {
            this.attrList = attrList;

        } 

        public void Add(Attribute attribute) { 
            attrList.Add(attribute); 
        }
    } 

    internal delegate void Com2EventHandler(Com2PropertyDescriptor sender, EventArgs e);

    internal delegate void GetAttributesEventHandler(Com2PropertyDescriptor sender, GetAttributesEvent gaevent); 

    internal class GetNameItemEvent : EventArgs { 
        private Object nameItem; 

        public GetNameItemEvent(Object defName) { 
            this.nameItem = defName;

        }
 
        public Object Name{
            get{ 
                return nameItem; 
            }
            set{ 
                nameItem = value;
            }
        }
 
        public string NameString{
            get{ 
                if (nameItem != null) { 
                    return nameItem.ToString();
                } 
                return "";
            }
        }
    } 

 
    internal delegate void GetNameItemEventHandler(Com2PropertyDescriptor sender, GetNameItemEvent gnievent); 

 
    internal class GetBoolValueEvent : EventArgs {
        private bool value;

        public GetBoolValueEvent(bool defValue) { 
            this.value= defValue;
 
        } 

        public bool Value{ 
            get{
                return value;
            }
            set{ 
                this.value = value;
            } 
        } 
    }
 
    internal delegate void GetBoolValueEventHandler(Com2PropertyDescriptor sender, GetBoolValueEvent gbeevent);

    internal class GetRefreshStateEvent : GetBoolValueEvent {
 
        Com2ShouldRefreshTypes item;
 
        public GetRefreshStateEvent(Com2ShouldRefreshTypes item, bool defValue) : base(defValue) { 
            this.item = item;
        } 
    }

    internal delegate void GetTypeConverterAndTypeEditorEventHandler(Com2PropertyDescriptor sender, GetTypeConverterAndTypeEditorEvent e);
 
    internal class GetTypeConverterAndTypeEditorEvent : EventArgs {
        private TypeConverter typeConverter; 
        private Object        typeEditor; 

        public GetTypeConverterAndTypeEditorEvent(TypeConverter typeConverter, Object typeEditor) { 
            this.typeEditor = typeEditor;
            this.typeConverter = typeConverter;
        }
 
        public TypeConverter TypeConverter{
            get{ 
                return typeConverter; 
            }
            set{ 
                typeConverter = value;
            }
        }
 
        public Object TypeEditor{
            get{ 
                return typeEditor; 
            }
            set{ 
                typeEditor = value;
            }
        }
    } 

} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK