internal ExtenderItem(PropertyDescriptor prop, object extenderObject, ExtendedObjectWrapper owner, string propertyKey) : base(prop) {
     Debug.Assert(prop != null, "Null property passed to ExtenderItem");
     Debug.Assert(extenderObject != null, "Null extenderObject passed to ExtenderItem");
     this.property = prop;
     this.extender = extenderObject;
     this.owner = owner;
     this.propertyKey = propertyKey;
 }
        public object[] GetExtendedObjects(object[] selectedObjects) { // INTENTIONAL CHANGE from VSIP version of AutomationExtenderManager.cs: internal to public
            if (extensionMgr == null || selectedObjects == null || selectedObjects.Length == 0) {
                return selectedObjects;
            }

            Hashtable[] extenderList = null;
            ArrayList allExtenders = new ArrayList();
            bool fail = false;
            if (!GetAllExtenders(selectedObjects, allExtenders, ref extenderList, ref fail))
                return selectedObjects;

            // do the IFilterProperties stuff
            // here we walk through all the items and apply I filter properites...
            // 1: do the used items
            // 2: do the discarded items.
            // 
            // this makes me queasy just thinking about it.
            //
            IEnumerator extEnum = allExtenders.GetEnumerator();
            Hashtable modifiedObjects = new Hashtable();

            while (extEnum.MoveNext())
            {
                object extender = extEnum.Current;
                IFilterProperties dteFilter = extender as IFilterProperties;
                AutomationExtMgr_IFilterProperties privateFilter = extender as AutomationExtMgr_IFilterProperties;

                Debug.Assert(privateFilter == null || dteFilter != null, "How did we get a private filter but no public DTE filter?");

                if (dteFilter != null)
                {
                    vsFilterProperties filter;

                    // ugh, walk through all the properties of all the objects
                    // and see if this guy would like to filter them
                    // icky and n^2, but that's the spec...
                    //
                    for (int x = 0; x < selectedObjects.Length; x++)
                    {
                        PropertyDescriptorCollection props = TypeDescriptor.GetProperties(selectedObjects[x], new Attribute[0]); // INTENTIONAL CHANGE from VSIP version of AutomationExtenderManager.cs: passing in empty Attribute array instead of {BrowsableAttribute.Yes} - see comments at beginning
                        props.Sort();
                        for (int p = 0; p < props.Count; p++)
                        {
                            filter = vsFilterProperties.vsFilterPropertiesNone;
                            if (privateFilter != null)
                            {
                                if (VSConstants.S_OK != privateFilter.IsPropertyHidden(props[p].Name, out filter))
                                {
                                    filter = vsFilterProperties.vsFilterPropertiesNone;
                                }
                            }
                            else
                            {
                                filter = dteFilter.IsPropertyHidden(props[p].Name);
                            }

                            FilteredObjectWrapper filteredObject = (FilteredObjectWrapper)modifiedObjects[selectedObjects[x]];
                            if (filteredObject == null)
                            {
                                filteredObject = new FilteredObjectWrapper(selectedObjects[x]);
                                modifiedObjects[selectedObjects[x]] = filteredObject;
                            }

                            switch (filter)
                            {
                                case vsFilterProperties.vsFilterPropertiesAll:
                                    filteredObject.FilterProperty(props[p], BrowsableAttribute.No);
                                    break;
                                case vsFilterProperties.vsFilterPropertiesSet:
                                    filteredObject.FilterProperty(props[p], ReadOnlyAttribute.Yes);
                                    break;
                            }
                        }
                    }
                }
            }

            // finally, wrap any extended objects in extender proxies for browsing...
            //
            bool applyExtenders = extenderList[0].Count > 0 && !fail;
            if (modifiedObjects.Count > 0 || applyExtenders)
            {


                // create the return array
                selectedObjects = (object[])selectedObjects.Clone();
                Dictionary<object, ExtendedObjectWrapper> objectsWrapperCollection = new Dictionary<object, ExtendedObjectWrapper>();
                for (int i = 0; i < selectedObjects.Length; i++)
                {
                    object originalObj = selectedObjects[i];
                    object obj = modifiedObjects[originalObj];
                    if (obj == null)
                    {
                        if (applyExtenders)
                        {
                            obj = originalObj;
                        }
                        else
                        {
                            continue;
                        }
                    }
                    selectedObjects[i] = new ExtendedObjectWrapper(obj, extenderList[i], objectsWrapperCollection, originalObj);
                }
            }

            // phewwwy, done!
            return selectedObjects;
        }