File: commonui\System\Drawing\Design\ToolboxItem.cs
Project: ndp\fx\src\System.Drawing.csproj (System.Drawing)
//------------------------------------------------------------------------------
// <copyright file="ToolboxItem.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
/*
 */
namespace System.Drawing.Design {
    using System.Configuration.Assemblies;
    using System.Runtime.InteropServices;
    using System.Runtime.Serialization;
    using System.ComponentModel;
    using System.Diagnostics;
    using System;
    using System.Reflection;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel.Design;
    using Microsoft.Win32;
    using System.Drawing;
    using System.IO;
    using System.Text;
    using System.Security;
    using System.Security.Permissions;
    using System.Diagnostics.CodeAnalysis;
    using System.Runtime.Versioning;
 
    using DpiHelper = System.Windows.Forms.DpiHelper;
 
    /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem"]/*' />
    /// <devdoc>
    ///    <para> Provides a base implementation of a toolbox item.</para>
    /// </devdoc>
    [Serializable]
    [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.InheritanceDemand, Name="FullTrust")]
    [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
    public class ToolboxItem : ISerializable {
    
        private static TraceSwitch ToolboxItemPersist = new TraceSwitch("ToolboxPersisting", "ToolboxItem: write data");
        
        private static object EventComponentsCreated = new object();
        private static object EventComponentsCreating = new object();
 
        private static bool isScalingInitialized = false;
        private const int ICON_DIMENSION = 16;
        private static int iconWidth = ICON_DIMENSION;
        private static int iconHeight = ICON_DIMENSION;
 
        private bool locked;
        private LockableDictionary properties;
        private ToolboxComponentsCreatedEventHandler  componentsCreatedEvent;
        private ToolboxComponentsCreatingEventHandler componentsCreatingEvent;
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.ToolboxItem"]/*' />
        /// <devdoc>
        ///    Initializes a new instance of the ToolboxItem class.
        /// </devdoc>
        public ToolboxItem() {
            if (!isScalingInitialized) {
                if (DpiHelper.IsScalingRequired) {
                    iconWidth = DpiHelper.LogicalToDeviceUnitsX(ICON_DIMENSION);
                    iconHeight = DpiHelper.LogicalToDeviceUnitsY(ICON_DIMENSION);
                }
                isScalingInitialized = true;
            }
        }
        
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.ToolboxItem1"]/*' />
        /// <devdoc>
        ///    Initializes a new instance of the ToolboxItem class using the specified type.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public ToolboxItem(Type toolType) : this() {
            Initialize(toolType);
        }
        
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.ToolboxItem2"]/*' />
        /// <devdoc>
        ///     Initializes a new instance of the <see cref='System.Drawing.Design.ToolboxItem'/>
        ///     class using the specified serialization information.
        /// </devdoc>
        private ToolboxItem(SerializationInfo info, StreamingContext context) : this() {
            Deserialize(info, context);
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.AssemblyName"]/*' />
        /// <devdoc>
        ///     The assembly name for this toolbox item. The assembly name describes the assembly
        ///     information needed to load the toolbox item's type.
        /// </devdoc>
        public AssemblyName AssemblyName {
            get {
                return (AssemblyName)Properties["AssemblyName"];
            }
            set {
                Properties["AssemblyName"] = value;
            }
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.AssemblyName"]/*' />
        /// <devdoc>
        ///     The assembly name for this toolbox item. The assembly name describes the assembly
        ///     information needed to load the toolbox item's type.
        /// </devdoc>
        public AssemblyName[] DependentAssemblies {
            get {
                AssemblyName[] names = (AssemblyName[]) Properties["DependentAssemblies"];
                if (names != null) {
                    return (AssemblyName[]) names.Clone();
                }
                return null;
            }
            set {
                Properties["DependentAssemblies"] = value.Clone();
            }
        }
 
        
        
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.Bitmap"]/*' />
        /// <devdoc>
        ///     Gets or sets the bitmap that will be used on the toolbox for this item. 
        ///     Use this property on the design surface as this bitmap is scaled according to the current the DPI setting.
        /// </devdoc>
        public Bitmap Bitmap {
            get {
                return (Bitmap)Properties["Bitmap"];
            }
            set {
                Properties["Bitmap"] = value;
            }
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.OriginalBitmap"]/*' />
        /// <devdoc>
        ///     Gets or sets the original bitmap that will be used on the toolbox for this item.
        ///     This bitmap should be 16x16 pixel and should be used in the Visual Studio toolbox, not on the design surface.
        /// </devdoc>
        public Bitmap OriginalBitmap {
            get {
                return (Bitmap)Properties["OriginalBitmap"];
            }
            set {
                Properties["OriginalBitmap"] = value;
            }
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.Company"]/*' />
        /// <devdoc>
        ///     Gets or sets the company name for this <see cref='System.Drawing.Design.ToolboxItem'/>.
        ///     This defaults to the companyname attribute retrieved from type.Assembly, if set.
        /// </devdoc>
        public string Company {
            get {
                return (string)Properties["Company"];
            }
            set {
                Properties["Company"] = value;
            }
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.ComponentType"]/*' />
        /// <devdoc>
        ///     The Component Type is ".Net Component" -- unless otherwise specified by a derived toolboxitem
        /// </devdoc>
        public virtual string ComponentType {
            get {
                return SR.GetString(SR.DotNET_ComponentType);
            }
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.Description"]/*' />
        /// <devdoc>
        ///     Description is a free-form, multiline capable text description that will be displayed in the tooltip
        /// for the toolboxItem.  It defaults to the path of the assembly that contains the item, but can be overridden.
        /// </devdoc>
        public string Description {
            get {
                return (string)Properties["Description"];
            }
            set {
                Properties["Description"] = value;
            }
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.DisplayName"]/*' />
        /// <devdoc>
        ///     Gets or sets the display name for this <see cref='System.Drawing.Design.ToolboxItem'/>.
        /// </devdoc>
        public string DisplayName {
            get {
                return (string)Properties["DisplayName"];
            }
            set {
                Properties["DisplayName"] = value;
            }
        }
        
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.Filter"]/*' />
        /// <devdoc>
        ///     Gets or sets the filter for this toolbox item.  The filter is a collection of
        ///     ToolboxItemFilterAttribute objects.
        /// </devdoc>
        public ICollection Filter {
            get {
                return (ICollection)Properties["Filter"];
            }
            set {
                Properties["Filter"] = value;
            }
        }
                
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.IsTransient"]/*' />
        /// <devdoc>
        ///     If true, it indicates that this toolbox item should not be stored in
        ///     any toolbox database when an application that is providing a toolbox
        ///     closes down.  This property defaults to false.
        /// </devdoc>
        public bool IsTransient {    
            [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")]
            get {
                return (bool)Properties["IsTransient"];
            }
            set {
                Properties["IsTransient"] = value;
            }
        }
        
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.Locked"]/*' />
        /// <devdoc>
        ///     Determines if this toolbox item is locked.  Once locked, a toolbox item will
        ///     not accept any changes to its properties.
        /// </devdoc>
        public virtual bool Locked {
            get {
                return locked;
            }
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.Properties"]/*' />
        /// <devdoc>
        ///     The properties dictionary is a set of name/value pairs.  The keys are property
        ///     names and the values are property values.  This dictionary becomes read-only
        ///     after the toolbox item has been locked.
        /// 
        ///     Values in the properties dictionary are validated through ValidateProperty
        ///     and default values are obtained from GetDefalutProperty.
        /// </devdoc>
        public IDictionary Properties {
            get {
                if (properties == null) {
                    properties = new LockableDictionary(this, 8 /* # of properties we have */);
                }
 
                return properties;
            }
        }
        
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.TypeName"]/*' />
        /// <devdoc>
        ///     Gets or sets the fully qualified name of the type this toolbox item will create.
        /// </devdoc>
        public string TypeName {
            get {
                return (string)Properties["TypeName"];
            }
            set {
                Properties["TypeName"] = value;
            }
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.DisplayName"]/*' />
        /// <devdoc>
        ///     Gets the version for this toolboxitem.  It defaults to AssemblyName.Version unless
        /// overridden in a derived toolboxitem.  This can be overridden to return an empty string
        /// to suppress its display in the toolbox tooltip.
        /// </devdoc>
        public virtual string Version {
            get {
                if (this.AssemblyName != null) {
                    return this.AssemblyName.Version.ToString();
                }
                return String.Empty;
            }
        }
 
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.ComponentsCreated"]/*' />
        /// <devdoc>
        ///    <para>Occurs when components are created.</para>
        /// </devdoc>
        public event ToolboxComponentsCreatedEventHandler ComponentsCreated {
            add {
                componentsCreatedEvent += value;
            }
            remove {
                componentsCreatedEvent -= value;
            }
        }
        
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.ComponentsCreating"]/*' />
        /// <devdoc>
        ///    <para>Occurs before components are created.</para>
        /// </devdoc>
        public event ToolboxComponentsCreatingEventHandler ComponentsCreating {
            add {
                componentsCreatingEvent += value;
            }
            remove {
                componentsCreatingEvent -= value;
            }
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.CheckUnlocked"]/*' />
        /// <devdoc>
        ///     This method checks that the toolbox item is currently unlocked (read-write) and
        ///     throws an appropriate exception if it isn't.
        /// </devdoc>
        protected void CheckUnlocked() {
            if (Locked) throw new InvalidOperationException(SR.GetString(SR.ToolboxItemLocked));
        }
        
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.CreateComponents"]/*' />
        /// <devdoc>
        ///     Creates objects from the type contained in this toolbox item.
        /// </devdoc>
        public IComponent[] CreateComponents() {
            return CreateComponents(null);
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.CreateComponents1"]/*' />
        /// <devdoc>
        ///     Creates objects from the type contained in this toolbox item.  If designerHost is non-null
        ///     this will also add them to the designer.
        /// </devdoc>
        public IComponent[] CreateComponents(IDesignerHost host) {
            OnComponentsCreating(new ToolboxComponentsCreatingEventArgs(host));
            IComponent[] comps = CreateComponentsCore(host, new Hashtable());
            if (comps != null && comps.Length > 0) {
                OnComponentsCreated(new ToolboxComponentsCreatedEventArgs(comps));
            }
            return comps;
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.CreateComponents2"]/*' />
        /// <devdoc>
        ///     Creates objects from the type contained in this toolbox item.  If designerHost is non-null
        ///     this will also add them to the designer.
        /// </devdoc>
        public IComponent[] CreateComponents(IDesignerHost host, IDictionary defaultValues) {
            OnComponentsCreating(new ToolboxComponentsCreatingEventArgs(host));
            IComponent[] comps = CreateComponentsCore(host, defaultValues);
            if (comps != null && comps.Length > 0) {
                OnComponentsCreated(new ToolboxComponentsCreatedEventArgs(comps));
            }
            return comps;
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.CreateComponentsCore"]/*' />
        /// <devdoc>
        ///     Creates objects from the type contained in this toolbox item.  If designerHost is non-null
        ///     this will also add them to the designer.
        /// </devdoc>
        protected virtual IComponent[] CreateComponentsCore(IDesignerHost host) {
            ArrayList comps = new ArrayList();
            
            Type createType = GetType(host, AssemblyName, TypeName, true);
            if (createType != null) {
                if (host != null) {
                    comps.Add(host.CreateComponent(createType));
                }
                else if (typeof(IComponent).IsAssignableFrom(createType)) {
                    comps.Add(TypeDescriptor.CreateInstance(null, createType, null, null));
                }
            }
            
            IComponent[] temp = new IComponent[comps.Count];
            comps.CopyTo(temp, 0);
            return temp;
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.CreateComponentsCore1"]/*' />
        /// <devdoc>
        ///     Creates objects from the type contained in this toolbox item.  If designerHost is non-null
        ///     this will also add them to the designer.
        /// </devdoc>
        protected virtual IComponent[] CreateComponentsCore(IDesignerHost host, IDictionary defaultValues) {
            IComponent[] components = CreateComponentsCore(host);
 
            if (host != null) {
                for (int i = 0; i < components.Length; i++) {
                    IComponentInitializer init = host.GetDesigner(components[i]) as IComponentInitializer;
                    if (init != null) {
                        bool removeComponent = true;
                        
                        try {
                            init.InitializeNewComponent(defaultValues);
                            removeComponent = false;
 
                        }
                        finally 
                        {
                            if (removeComponent) {
                                for (int index = 0; index < components.Length; index++) {
                                    host.DestroyComponent(components[index]);
                                }
                            }
                        }
 
                    }
                }
            }
 
            return components;
        }
 
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.Deserialize"]/*' />
        /// <devdoc>
        /// <para>Loads the state of this <see cref='System.Drawing.Design.ToolboxItem'/>
        /// from the stream.</para>
        /// </devdoc>
        protected virtual void Deserialize(SerializationInfo info, StreamingContext context) {
 
            // Do this in a couple of passes -- first pass, try to pull
            // out our dictionary of property names.  We need to do this
            // for backwards compatibilty because if we throw everything
            // into the property dictionary we'll duplicate stuff people
            // have serialized by hand.
 
            string[] propertyNames = null;
            foreach (SerializationEntry entry in info) {
                if (entry.Name.Equals("PropertyNames")) {
                    propertyNames = entry.Value as string[];
                    break;
                }
            }
 
            if (propertyNames == null) {
                // For backwards compat, here are the default property
                // names we use
                propertyNames = new string[] {
                    "AssemblyName",
                    "Bitmap",
                    "DisplayName",
                    "Filter",
                    "IsTransient",
                    "TypeName"
                };
            }
 
            foreach (SerializationEntry entry in info) {
 
                // Check to see if this name is in our
                // propertyNames array.
                foreach(string validName in propertyNames) {
                    if (validName.Equals(entry.Name)) {
                        Properties[entry.Name] = entry.Value;
                        break;
                    }
                }
            }
 
            // Always do "Locked" last (otherwise we can't do the others!)
            bool isLocked = info.GetBoolean("Locked");
            if (isLocked) {
                Lock();
            }
        }
 
        /// <devdoc>
        /// Check if two AssemblyName instances are equivalent
        /// </devdoc>
        private static bool AreAssemblyNamesEqual(AssemblyName name1, AssemblyName name2) {
            return name1 == name2 ||
                   (name1 != null && name2 != null && name1.FullName == name2.FullName);
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.Equals"]/*' />
        /// <internalonly/>
        public override bool Equals(object obj) {
            if (this == obj) {
                return true;
            }
 
            if (obj == null) {
                return false;
            }
 
            if (!(obj.GetType() == this.GetType())) {
                return false;
            }
 
            ToolboxItem otherItem = (ToolboxItem)obj;
 
            return TypeName == otherItem.TypeName &&
                   AreAssemblyNamesEqual(AssemblyName, otherItem.AssemblyName) &&
                   DisplayName == otherItem.DisplayName;
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.GetHashCode"]/*' />
        /// <internalonly/>
        public override int GetHashCode() {
 
            string typeName = TypeName;
            int hash = (typeName != null) ? typeName.GetHashCode() : 0;
            
            return unchecked(hash ^ DisplayName.GetHashCode());
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.FilterPropertyValue"]/*' />
        /// <devdoc>
        ///    Filters a property value before returning it.  This allows a property to always clone values,
        ///    or to provide a default value when none exists.
        /// </devdoc>
        protected virtual object FilterPropertyValue(string propertyName, object value) {
            switch (propertyName) {
                case "AssemblyName":
                    if (value != null) value = ((AssemblyName)value).Clone();
 
                    break;
 
                case "DisplayName":
                case "TypeName":
                    if (value == null) value = string.Empty;
 
                    break;
 
                case "Filter":
                    if (value == null) value = new ToolboxItemFilterAttribute[0];
 
                    break;
 
                case "IsTransient":
                    if (value == null) value = false;
 
                    break;
            }
            return value;
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.GetType1"]/*' />
        /// <devdoc>
        /// Allows access to the type associated with the toolbox item.
        /// The designer host is used to access an implementation of ITypeResolutionService.
        /// However, the loaded type is not added to the list of references in the designer host.
        /// </devdoc>
        public Type GetType(IDesignerHost host) {
            return GetType(host, AssemblyName, TypeName, false);
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.GetType"]/*' />
        /// <devdoc>
        ///     This utility function can be used to load a type given a name.  AssemblyName and
        ///     designer host can be null, but if they are present they will be used to help
        ///     locate the type.  If reference is true, the given assembly name will be added
        ///     to the designer host's set of references.
        /// </devdoc>        
        [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")]
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        protected virtual Type GetType(IDesignerHost host, AssemblyName assemblyName, string typeName, bool reference) {
            ITypeResolutionService ts = null;
            Type type = null;
            
            if (typeName == null) {
                throw new ArgumentNullException("typeName");
            }
            
            if (host != null) {
                ts = (ITypeResolutionService)host.GetService(typeof(ITypeResolutionService));
            }
            
            if (ts != null) {
                
                if (reference) {
                    if (assemblyName != null) {
                        ts.ReferenceAssembly(assemblyName);
                        type = ts.GetType(typeName);
                    }
                    else {
                        // Just try loading the type.  If we succeed, then use this as the
                        // reference.
                        type = ts.GetType(typeName);
                        if (type == null) {
                            type = Type.GetType(typeName);
                        }
                        if (type != null) {
                            ts.ReferenceAssembly(type.Assembly.GetName());
                        }
                    }
                }
                else {
                    if (assemblyName != null) {
                        Assembly a = ts.GetAssembly(assemblyName);
                        if (a != null) {
                            type = a.GetType(typeName);
                        }
                    }
                    
                    if (type == null) {
                        type = ts.GetType(typeName);
                    }
                }
            }
            else {
                if (!String.IsNullOrEmpty(typeName)) {
                    if (assemblyName != null) {
                        Assembly a = null;
                        try {
                            a = Assembly.Load(assemblyName);
                        }
                        catch (FileNotFoundException) {
                        }
                        catch (BadImageFormatException) {
                        }
                        catch (IOException) {
                        }
 
                        if (a == null && assemblyName.CodeBase != null && assemblyName.CodeBase.Length > 0)             {
                             try {
                                 a = Assembly.LoadFrom(assemblyName.CodeBase);
                             }
                             catch (FileNotFoundException) {
                             }
                             catch (BadImageFormatException) {
                             }
                             catch (IOException) {
                             }
                        }
 
                        if (a != null) {
                            type = a.GetType(typeName);
                        }
                    }
 
                    if (type == null) {
                        type = Type.GetType(typeName, false);
                    }
                }
            }
            
            return type;
        }
 
        /// <devdoc>
        /// Given an assemblyname and type, this method searches referenced assemblies from t.Assembly
        /// looking for a similar name.
        /// </devdoc>
        private AssemblyName GetNonRetargetedAssemblyName(Type type, AssemblyName policiedAssemblyName) {
            if (type == null || policiedAssemblyName == null)
                return null;
 
            //if looking for myself, just return it. (not a reference)
            if (type.Assembly.FullName == policiedAssemblyName.FullName) {
                return policiedAssemblyName;
            }
 
            //first search for an exact match -- we prefer this over a partial match.
            foreach (AssemblyName name in type.Assembly.GetReferencedAssemblies()) {
                if (name.FullName == policiedAssemblyName.FullName)
                    return name;
            }
 
            //next search for a partial match -- we just compare the Name portions (ignore version and publickey)
            foreach (AssemblyName name in type.Assembly.GetReferencedAssemblies()) {
                if (name.Name == policiedAssemblyName.Name)
                    return name;
            }
 
            //finally, the most expensive -- its possible that retargeting policy is on an assembly whose name changes
            // an example of this is the device System.Windows.Forms.Datagrid.dll
            // in this case, we need to try to load each device assemblyname through policy to see if it results
            // in assemblyname.
            foreach (AssemblyName name in type.Assembly.GetReferencedAssemblies()) {
                Assembly a = null;
                
                try {
                    a = Assembly.Load(name);
                    if (a != null && a.FullName == policiedAssemblyName.FullName)
                        return name;
                }
                catch {
                    //ignore all exceptions and just fall through if it fails (it shouldn't, but who knows).
                }
            }
 
            return null;
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.Initialize"]/*' />
        /// <devdoc>
        ///     Initializes a toolbox item with a given type.  A locked toolbox item cannot be initialized.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process | ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Process | ResourceScope.Machine)]
        public virtual void Initialize(Type type) {
            CheckUnlocked();
            
            if (type != null) {
                TypeName = type.FullName;
                AssemblyName assemblyName = type.Assembly.GetName(true);
                if (type.Assembly.GlobalAssemblyCache) {
                    assemblyName.CodeBase = null;
                }
 
                Dictionary<string, AssemblyName> parents = new Dictionary<string, AssemblyName>();
                Type parentType = type;
                while (parentType != null) {
                    AssemblyName policiedname = parentType.Assembly.GetName(true);
                    
                    AssemblyName aname = GetNonRetargetedAssemblyName(type, policiedname);
 
                    if (aname != null && !parents.ContainsKey(aname.FullName)) {
                        parents[aname.FullName] = aname;
                    }
                    parentType = parentType.BaseType;
                }
 
                AssemblyName[] parentAssemblies = new AssemblyName[parents.Count];
                int i = 0;
                foreach(AssemblyName an in parents.Values) {
                    parentAssemblies[i++] = an;
                }
 
                this.DependentAssemblies = parentAssemblies;
 
                AssemblyName = assemblyName; 
                DisplayName = type.Name;
 
                //if the Type is a reflectonly type, these values must be set through a config object or manually
                //after construction.
                if (!type.Assembly.ReflectionOnly) {
 
                    object[] companyattrs = type.Assembly.GetCustomAttributes(typeof(AssemblyCompanyAttribute), true);
                    if (companyattrs != null && companyattrs.Length > 0) {
                        AssemblyCompanyAttribute company = companyattrs[0] as AssemblyCompanyAttribute;
                        if (company != null && company.Company != null) {
                            Company = company.Company;
                        }
                    }
 
                    //set the description based off the description attribute of the given type.
                    DescriptionAttribute descattr = (DescriptionAttribute)TypeDescriptor.GetAttributes(type)[typeof(DescriptionAttribute)];
                    if (descattr != null) {
                        this.Description = descattr.Description;
                    }
 
                    ToolboxBitmapAttribute attr = (ToolboxBitmapAttribute)TypeDescriptor.GetAttributes(type)[typeof(ToolboxBitmapAttribute)];
                    if (attr != null) {
                        Bitmap itemBitmap = attr.GetImage(type, false) as Bitmap;
                        if (itemBitmap != null) {
                            // Original bitmap is used when adding the item to the Visual Studio toolbox 
                            // if running on a machine with HDPI scaling enabled.
                            OriginalBitmap = attr.GetOriginalBitmap();
                            if ((itemBitmap.Width != iconWidth || itemBitmap.Height != iconHeight)) {
                                itemBitmap = new Bitmap(itemBitmap, new Size(iconWidth, iconHeight));
                            }
                        }
                        Bitmap = itemBitmap;
                    }
 
                    bool filterContainsType = false;
                    ArrayList array = new ArrayList();
                    foreach (Attribute a in TypeDescriptor.GetAttributes(type)) {
                        ToolboxItemFilterAttribute ta = a as ToolboxItemFilterAttribute;
                        if (ta != null) {
                            if (ta.FilterString.Equals(TypeName)) {
                                filterContainsType = true;
                            }
                            array.Add(ta);
                        }
                    }
 
                    if (!filterContainsType) {
                        array.Add(new ToolboxItemFilterAttribute(TypeName));
                    }
 
                    Filter = (ToolboxItemFilterAttribute[])array.ToArray(typeof(ToolboxItemFilterAttribute));
                }
            }
        }
        
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.Lock"]/*' />
        /// <devdoc>
        ///     Locks this toolbox item.  Locking a toolbox item makes it read-only and 
        ///     prevents any changes to its properties.  
        /// </devdoc>
        public virtual void Lock() {
            locked = true;
        }
        
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.OnComponentsCreated"]/*' />
        /// <devdoc>
        ///    <para>Raises the OnComponentsCreated event. This
        ///       will be called when this <see cref='System.Drawing.Design.ToolboxItem'/> creates a component.</para>
        /// </devdoc>
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")] //full trust anyway
        protected virtual void OnComponentsCreated(ToolboxComponentsCreatedEventArgs args) {
            if (componentsCreatedEvent != null) {
                componentsCreatedEvent(this, args);
            }
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.OnComponentsCreating"]/*' />
        /// <devdoc>
        ///    <para>Raises the OnCreateComponentsInvoked event. This
        ///       will be called before this <see cref='System.Drawing.Design.ToolboxItem'/> creates a component.</para>
        /// </devdoc>
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")] //full trust anyway 
        protected virtual void OnComponentsCreating(ToolboxComponentsCreatingEventArgs args) {
            if (componentsCreatingEvent != null) {
                componentsCreatingEvent(this, args);
            }
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.Serialize"]/*' />
        /// <devdoc>
        /// <para>Saves the state of this <see cref='System.Drawing.Design.ToolboxItem'/> to
        ///    the specified serialization info.</para>
        /// </devdoc>        
        [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")]
        protected virtual void Serialize(SerializationInfo info, StreamingContext context) {
            
            if (ToolboxItemPersist.TraceVerbose) {
                Debug.WriteLine("Persisting: " + GetType().Name);
                Debug.WriteLine("\tDisplay Name: " + DisplayName);
            }
 
            info.AddValue("Locked", Locked);
            ArrayList propertyNames = new ArrayList(Properties.Count);
            foreach (DictionaryEntry de in Properties) {
                propertyNames.Add(de.Key);
                info.AddValue((string)de.Key, de.Value);
            }
            info.AddValue("PropertyNames", (string[])propertyNames.ToArray(typeof(string)));
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.ToString"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public override string ToString() {
            return this.DisplayName;            
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.ValidatePropertyType"]/*' />
        /// <devdoc>
        ///    Called as a helper to ValidatePropertyValue to validate that an object
        ///    is of a given type.
        /// </devdoc>
        protected void ValidatePropertyType(string propertyName, object value, Type expectedType, bool allowNull) {
            if (value == null) {
                if (!allowNull) {
                    throw new ArgumentNullException("value");
                }
            }
            else {
                if (!expectedType.IsInstanceOfType(value)) {
                    throw new ArgumentException(SR.GetString(SR.ToolboxItemInvalidPropertyType, propertyName, expectedType.FullName), "value");
                }
            }
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.ValidatePropertyValue"]/*' />
        /// <devdoc>
        ///    This is called whenever a value is set in the property dictionary.  It gives you a chance
        ///    to change the value of an object before comitting it, our reject it by throwing an 
        ///    exception.
        /// </devdoc>
        protected virtual object ValidatePropertyValue(string propertyName, object value) {
            switch (propertyName) {
                case "AssemblyName":
                    ValidatePropertyType(propertyName, value, typeof(AssemblyName), true);
                    break;
 
                case "Bitmap":
                    ValidatePropertyType(propertyName, value, typeof(Bitmap), true);
                    break;
 
                case "OriginalBitmap":
                    ValidatePropertyType(propertyName, value, typeof(Bitmap), true);
                    break;
 
                case "Company":
                case "Description":
                case "DisplayName":
                case "TypeName":
                    ValidatePropertyType(propertyName, value, typeof(string), true);
                    if (value == null) value = string.Empty;
 
                    break;
 
                case "Filter":
                    ValidatePropertyType(propertyName, value, typeof(ICollection), true);
 
                    int filterCount = 0;
                    ICollection col = (ICollection)value;
 
                    if (col != null) {
                        foreach (object f in col) {
                            if (f is ToolboxItemFilterAttribute) {
                                filterCount++;
                            }
                        }
                    }
 
                    ToolboxItemFilterAttribute[] filter = new ToolboxItemFilterAttribute[filterCount];
 
                    if (col != null) {
                        filterCount = 0;
                        foreach (object f in col) {
                            ToolboxItemFilterAttribute tfa = f as ToolboxItemFilterAttribute;
                            if (tfa != null) {
                                filter[filterCount++] = tfa;
                            }
                        }
                    }
 
                    value = filter;
                    break;
 
                case "IsTransient":
                    ValidatePropertyType(propertyName, value, typeof(bool), false);
                    break;
            }
            return value;
        }
 
        /// <include file='doc\ToolboxItem.uex' path='docs/doc[@for="ToolboxItem.ISerializable.GetObjectData"]/*' />
        /// <internalonly/> 
        // SECREVIEW NOTE: we do not put the linkdemand that should be here, because the one on the type is a superset of this one
        [SuppressMessage("Microsoft.Usage", "CA2240:ImplementISerializableCorrectly")]        
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
            IntSecurity.UnmanagedCode.Demand();
            Serialize(info, context);
        }
 
        /// <devdoc>
        ///     This is a simple IDictionary that supports locking so
        ///     changing values are not allowed after the toolbox
        ///     item has been locked.
        /// </devdoc>
        private class LockableDictionary : Hashtable
        {
            private ToolboxItem _item;
            internal LockableDictionary(ToolboxItem item, int capacity) : base(capacity)
            {
                _item = item;
            }
        
            public override bool IsFixedSize
            {
                get
                {
                    return _item.Locked;
                }
            }
        
            public override bool IsReadOnly
            {
                get
                {
                    return _item.Locked;
                }
            }
        
            public override object this[object key]
            {
                get
                {
                    string propertyName = GetPropertyName(key);
                    object value = base[propertyName];
        
                    return _item.FilterPropertyValue(propertyName, value);
                }
                set
                {
                    string propertyName = GetPropertyName(key);
                    value = _item.ValidatePropertyValue(propertyName, value);
                    CheckSerializable(value);
                    _item.CheckUnlocked();
                    base[propertyName] = value;
                }
            }
        
            public override void Add(object key, object value)
            {
                string propertyName = GetPropertyName(key);
                value = _item.ValidatePropertyValue(propertyName, value);
                CheckSerializable(value);
                _item.CheckUnlocked();
                base.Add(propertyName, value);
            }
        
            private void CheckSerializable(object value) {
                if (value != null && !value.GetType().IsSerializable) {
                    throw new ArgumentException(SR.GetString(SR.ToolboxItemValueNotSerializable, value.GetType().FullName));
                }
            }
        
            public override void Clear()
            {
                _item.CheckUnlocked();
                base.Clear();
            }
        
            private string GetPropertyName(object key) {
                if (key == null) {
                    throw new ArgumentNullException("key");
                }
        
                string propertyName = key as string;
        
                if (propertyName == null || propertyName.Length == 0) {
                    throw new ArgumentException(SR.GetString(SR.ToolboxItemInvalidKey), "key");
                }
        
                return propertyName;
            }
        
            public override void Remove(object key)
            {
                _item.CheckUnlocked();
                base.Remove(key);
            }
        }
    }
}