File: winforms\Managed\System\WinForms\ComponentModel\COM2Interop\COM2IManagedPerPropertyBrowsingHandler.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="COM2IManagedPerPropertyBrowsingHandler.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Windows.Forms.ComponentModel.Com2Interop {
    using System.Runtime.InteropServices;
    using System.ComponentModel;
    using System.Diagnostics;
    using System;
    using System.Reflection;
    using Microsoft.Win32;
    using System.Collections;
    using System.Globalization;
 
    [System.Security.SuppressUnmanagedCodeSecurityAttribute()]
    internal class Com2IManagedPerPropertyBrowsingHandler : Com2ExtendedBrowsingHandler {
 
        public override Type Interface {
            get {
                return typeof(NativeMethods.IManagedPerPropertyBrowsing);
            }
        }
 
        public override void SetupPropertyHandlers(Com2PropertyDescriptor[] propDesc) {
            if (propDesc == null) {
                return;
            }
            for (int i = 0; i < propDesc.Length; i++) {
                propDesc[i].QueryGetDynamicAttributes += new GetAttributesEventHandler(this.OnGetAttributes);
            }
        }
 
        /// <include file='doc\COM2IManagedPerPropertyBrowsingHandler.uex' path='docs/doc[@for="Com2IManagedPerPropertyBrowsingHandler.OnGetAttributes"]/*' />
        /// <devdoc>
        /// Here is where we handle IVsPerPropertyBrowsing.GetLocalizedPropertyInfo and IVsPerPropertyBrowsing.   HideProperty
        /// such as IPerPropertyBrowsing, IProvidePropertyBuilder, etc.
        /// </devdoc>
        private void OnGetAttributes(Com2PropertyDescriptor sender, GetAttributesEvent attrEvent) {
            Object target = sender.TargetObject;
 
            if (target is NativeMethods.IManagedPerPropertyBrowsing) {
                Attribute[] attrs = GetComponentAttributes((NativeMethods.IManagedPerPropertyBrowsing)target,sender.DISPID);
                if (attrs != null) {
                    for (int i = 0; i < attrs.Length; i++) {
                        attrEvent.Add(attrs[i]);
                    }
                }
            }
        }
 
        internal static Attribute[] GetComponentAttributes(NativeMethods.IManagedPerPropertyBrowsing target, int dispid) {
            int cItems = 0;
            IntPtr pbstrs = IntPtr.Zero;
            IntPtr pvars = IntPtr.Zero;
 
            int hr = target.GetPropertyAttributes(dispid, ref cItems, ref pbstrs, ref pvars);
 
            if (hr != NativeMethods.S_OK || cItems == 0) {
                return new Attribute[0];
            }
 
            ArrayList attrs = new ArrayList();
 
            string[] attrTypeNames = GetStringsFromPtr(pbstrs, cItems);
            Object[] varParams = GetVariantsFromPtr(pvars, cItems);
 
            Debug.Assert(attrTypeNames.Length == varParams.Length, "Mismatched parameter and attribute name length");
            if (attrTypeNames.Length != varParams.Length) {
                return new Attribute[0];
            }
 
            // get the types
            Type[] types = new Type[attrTypeNames.Length];
            for (int i = 0; i < attrTypeNames.Length; i++) {
                
                string attrName = attrTypeNames[i];
                
                // try the name first
                Type t = Type.GetType(attrName);
                Assembly a = null;
                
                if (t != null) {
                    a = t.Assembly;    
                }
 
                if (t == null) {
 
 
                    // check for an assembly name.
                    //
                    string assemblyName = "";
 
                    int comma = attrName.LastIndexOf(',');
 
                    if (comma != -1) {
                        assemblyName = attrName.Substring(comma);
                        attrName = attrName.Substring(0, comma);
                    }
 
                    string fieldName;
                    int lastDot = attrName.LastIndexOf('.');
                    if (lastDot != -1) {
                        fieldName = attrName.Substring(lastDot + 1);
                    }
                    else {
                        // somethings odd
                        Debug.Fail("No dot in class name?");
                        continue;
                    }
 
                    // try to get the field value
                    if (a == null) {
                        t = Type.GetType(attrName.Substring(0,lastDot) + assemblyName);
                    }
                    else {
                        t = a.GetType(attrName.Substring(0,lastDot) + assemblyName);
                    }
 
                    if (t == null){
                        Debug.Fail("Failed load attribute '" + attrName + assemblyName + "'.  It's Type could not be found.");
                        continue;
                    }
 
                    Debug.Assert(typeof(Attribute).IsAssignableFrom(t), "Attribute type " + t.FullName + " does not derive from Attribute");
                    if (!typeof(Attribute).IsAssignableFrom(t)) {
                        continue;
                    }
 
                    if (t != null) {
                        FieldInfo fi = t.GetField(fieldName);
 
                        // only if it's static
                        if (fi != null && fi.IsStatic) {
                            Object fieldValue = fi.GetValue(null);
                            if (fieldValue is Attribute) {
                                // add it to the list
                                attrs.Add(fieldValue);
                                continue;
                            }
                        }
                        else {
                            Debug.Fail("Couldn't load field '" + fieldName + "' from type '" + attrName.Substring(0,lastDot) + "'.  It does not exist or is not static");
                        }
                    }
                }
 
 
                Debug.Assert(typeof(Attribute).IsAssignableFrom(t), "Attribute type " + t.FullName + " does not derive from Attribute");
                if (!typeof(Attribute).IsAssignableFrom(t)) {
                    continue;
                }
 
                Attribute attr = null;
 
                // okay, if we got here, we need to build the attribute...
                // get the initalizer value if we've got a one item ctor
 
                if (!Convert.IsDBNull(varParams[i]) && varParams[i] != null) {
                    ConstructorInfo[] ctors = t.GetConstructors();
                    for (int c=0; c < ctors.Length; c++) {
                        ParameterInfo[] pis = ctors[c].GetParameters();
                        if (pis.Length == 1 && pis[0].ParameterType.IsAssignableFrom(varParams[i].GetType())) {
                            // found a one-parameter ctor, use it
                            // try to construct a default one
                            try {
                                attr = (Attribute)Activator.CreateInstance(t, new Object[]{varParams[i]});
                                attrs.Add(attr);
                            }
                            catch {
                                // bummer, nevermind
                                Debug.Fail("Attribute " + t.FullName + " did not have a initalizer specified and has no default constructor");
                                continue;
                            }
                        }
                    }
                }
                else {
                    // try to construct a default one
                    try {
                        attr = (Attribute)Activator.CreateInstance(t);
                        attrs.Add(attr);
                    }
                    catch {
                        // bummer, nevermind
                        Debug.Fail("Attribute " + t.FullName + " did not have a initalizer specified and has no default constructor");
                        continue;
                    }
                }
            }
 
            Attribute[] temp = new Attribute[attrs.Count];
            attrs.CopyTo(temp, 0);
            return temp;
        }
 
        private static string[] GetStringsFromPtr(IntPtr ptr, int cStrings) {
            if (ptr != IntPtr.Zero) {
                string[] strs = new string[cStrings];
                IntPtr bstr;
                for (int i = 0; i < cStrings; i++) {
                    try{
                        bstr = Marshal.ReadIntPtr(ptr, i*4);
                        if (bstr != IntPtr.Zero) {
                            strs[i] = Marshal.PtrToStringUni(bstr);
                            SafeNativeMethods.SysFreeString(new HandleRef(null, bstr));
                        }
                        else {
                            strs[i] = "";
                        }
                    }
                    catch (Exception ex) {
                        Debug.Fail("Failed to marshal component attribute BSTR " + i.ToString(CultureInfo.InvariantCulture), ex.ToString());
                    }
                }
                try{
                    Marshal.FreeCoTaskMem(ptr);
                }
                catch (Exception ex) {
                    Debug.Fail("Failed to free BSTR array memory", ex.ToString());
                }
                return strs;
            }
            else {
                return new string[0];
            }
        }
 
        private static Object[] GetVariantsFromPtr(IntPtr ptr, int cVariants) {
            if (ptr != IntPtr.Zero) {
                Object[] objects = new Object[cVariants];
                IntPtr curVariant;
                
                for (int i = 0; i < cVariants; i++) {
                    try{
                        curVariant = (IntPtr)((long)ptr + (i* 16 /*sizeof(VARIANT)*/));
                        if (curVariant != IntPtr.Zero) {
                            objects[i] = Marshal.GetObjectForNativeVariant(curVariant);
                            SafeNativeMethods.VariantClear(new HandleRef(null, curVariant));
                        }
                        else {
                            objects[i] = Convert.DBNull;
                        }
                    }
                    catch (Exception ex) {
                        Debug.Fail("Failed to marshal component attribute VARIANT " + i.ToString(CultureInfo.InvariantCulture), ex.ToString());
                    }
                }
                try{
                    Marshal.FreeCoTaskMem(ptr);
                }
                catch (Exception ex) {
                    Debug.Fail("Failed to free VARIANT array memory", ex.ToString());
                }
                return objects;
            }
            else {
                return new Object[cVariants];
            }
        }
    }
}