Code:
/ 4.0 / 4.0 / untmp / 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.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- HttpListenerContext.cs
- GroupBoxAutomationPeer.cs
- BitArray.cs
- InteropEnvironment.cs
- ListBoxItemAutomationPeer.cs
- XmlDocumentFieldSchema.cs
- ColumnMapTranslator.cs
- Attachment.cs
- RenderOptions.cs
- AssertSection.cs
- ToolStripSplitButton.cs
- HwndHost.cs
- TextElementEditingBehaviorAttribute.cs
- IISMapPath.cs
- PlanCompilerUtil.cs
- CookieParameter.cs
- ComponentCommands.cs
- StylusPointCollection.cs
- Gdiplus.cs
- LinqExpressionNormalizer.cs
- Stack.cs
- SqlRecordBuffer.cs
- NameSpaceEvent.cs
- DomainUpDown.cs
- Asn1IntegerConverter.cs
- MessageBuffer.cs
- GroupBox.cs
- DataSourceCache.cs
- xdrvalidator.cs
- CroppedBitmap.cs
- ColorContextHelper.cs
- ItemCheckEvent.cs
- EntitySqlException.cs
- ColorBlend.cs
- ContextMenu.cs
- TcpHostedTransportConfiguration.cs
- DateBoldEvent.cs
- UserPreferenceChangingEventArgs.cs
- ApplicationContext.cs
- UnmanagedMarshal.cs
- TreeView.cs
- SecurityKeyUsage.cs
- DrawListViewItemEventArgs.cs
- SpecialTypeDataContract.cs
- SafeCryptHandles.cs
- HttpListener.cs
- CommandID.cs
- StorageInfo.cs
- XmlElement.cs
- CompilerGlobalScopeAttribute.cs
- Aggregates.cs
- MultitargetUtil.cs
- Attributes.cs
- EnumConverter.cs
- DataGridColumn.cs
- ReflectTypeDescriptionProvider.cs
- LineUtil.cs
- RequestCacheEntry.cs
- MessageProperties.cs
- TimeEnumHelper.cs
- HttpCookieCollection.cs
- ClientScriptItem.cs
- RuleSettingsCollection.cs
- Atom10FeedFormatter.cs
- InputManager.cs
- NGCSerializationManagerAsync.cs
- Opcode.cs
- ToolBar.cs
- CodeDesigner.cs
- WebUtil.cs
- BaseTemplateParser.cs
- TextLineResult.cs
- FixedDSBuilder.cs
- AutomationPeer.cs
- ProjectionCamera.cs
- ViewKeyConstraint.cs
- TimeSpanStorage.cs
- ToolStripProfessionalLowResolutionRenderer.cs
- FrameworkReadOnlyPropertyMetadata.cs
- ColumnHeader.cs
- RC2CryptoServiceProvider.cs
- TimeSpanMinutesOrInfiniteConverter.cs
- ConfigXmlCDataSection.cs
- TypeToStringValueConverter.cs
- OneToOneMappingSerializer.cs
- RemoteArgument.cs
- AnnotationResourceChangedEventArgs.cs
- QilFactory.cs
- NativeMethods.cs
- EntitySetDataBindingList.cs
- Identity.cs
- PerspectiveCamera.cs
- NonSerializedAttribute.cs
- DBConnectionString.cs
- _FixedSizeReader.cs
- InfoCardRSAOAEPKeyExchangeFormatter.cs
- Cursor.cs
- DataGridViewCellToolTipTextNeededEventArgs.cs
- TextBoxDesigner.cs
- FontDialog.cs