private unsafe static object[] GetVariantsFromPtr(Oleaut32.VARIANT *ptr, uint cVariants) { var objects = new object[cVariants]; for (int i = 0; i < cVariants; i++) { try { using Oleaut32.VARIANT variant = ptr[i]; objects[i] = variant.ToObject(); } catch (Exception ex) { Debug.Fail("Failed to marshal component attribute VARIANT " + i, ex.ToString()); } } try { Marshal.FreeCoTaskMem((IntPtr)ptr); } catch (Exception ex) { Debug.Fail("Failed to free VARIANT array memory", ex.ToString()); } return(objects); }
internal unsafe static Attribute[] GetComponentAttributes(VSSDK.IVSMDPerPropertyBrowsing target, Ole32.DispatchID dispid) { uint cItems = 0; IntPtr pbstrs = IntPtr.Zero; Oleaut32.VARIANT *pvars = null; HRESULT hr = target.GetPropertyAttributes(dispid, &cItems, &pbstrs, &pvars); if (hr != HRESULT.S_OK || cItems == 0 || pvars is null) { return(Array.Empty <Attribute>()); } 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(Array.Empty <Attribute>()); } // 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 is not null) { a = t.Assembly; } if (t is null) { // check for an assembly name. // string assemblyName = string.Empty; 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 is null) { t = Type.GetType(attrName.Substring(0, lastDot) + assemblyName); } else { t = a.GetType(attrName.Substring(0, lastDot) + assemblyName); } if (t is 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 is not null) { FieldInfo fi = t.GetField(fieldName); // only if it's static if (fi is not 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] is not 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 { // 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 { // nevermind Debug.Fail("Attribute " + t.FullName + " did not have a initalizer specified and has no default constructor"); continue; } } }