/// <summary> /// /// </summary> private void UpdateDelgatesAndAtribs(MethodInfo method) { //Create the delgate, Taken from: http://stackoverflow.com/a/16364220 Delegate thisDelegate = method.CreateDelegate(Expression.GetDelegateType( (from parameter in method.GetParameters() select parameter.ParameterType) .Concat(new[] { method.ReturnType }) .ToArray())); delegates.Add(thisDelegate); //Create the function attribute QuantSAExcelFunctionAttribute quantsaAttribute = method.GetCustomAttribute <QuantSAExcelFunctionAttribute>(); functionAttributes.Add(quantsaAttribute.CreateExcelFunctionAttribute()); // Create the function argument attributes List <object> thisArgumentAttributes = new List <object>(); foreach (ParameterInfo param in method.GetParameters()) { var argAttrib = param.GetCustomAttribute <ExcelArgumentAttribute>(); if (argAttrib != null) { argAttrib.Name = param.Name; } thisArgumentAttributes.Add(argAttrib); } functionArgumentAttributes.Add(thisArgumentAttributes); }
/// <summary> /// Registers the single manual function. /// </summary> private void AddSingleManualFunction(MethodInfo method, bool?isHidden) { //Create the function attribute QuantSAExcelFunctionAttribute quantsaAttribute = method.GetCustomAttribute <QuantSAExcelFunctionAttribute>(); if (isHidden != null) { quantsaAttribute.IsHidden = isHidden.Value; } functionAttributes.Add(quantsaAttribute.CreateExcelFunctionAttribute()); // Create the function argument attributes List <object> thisArgumentAttributes = new List <object>(); foreach (ParameterInfo param in method.GetParameters()) { var argAttrib = param.GetCustomAttribute <ExcelArgumentAttribute>(); if (argAttrib != null) { argAttrib.Name = param.Name; } thisArgumentAttributes.Add(argAttrib); } functionArgumentAttributes.Add(thisArgumentAttributes); }
/// <summary> /// Expose a plugin from a dll filename, if the dll is a valid plugin. /// </summary> private void ExposePlugin(string filename) { Assembly DLL = Assembly.LoadFile(filename); string[] names = DLL.GetManifestResourceNames(); //ResourceSet set = new ResourceSet(names[0]); string shortName = null; foreach (Type type in DLL.GetExportedTypes()) { if (typeof(IQuantSAPlugin).IsAssignableFrom(type)) // This class is a QuantSA plugin { IQuantSAPlugin plugin = Activator.CreateInstance(type) as IQuantSAPlugin; shortName = plugin.GetShortName(); MyAddIn.plugins.Add(plugin); } } if (shortName == null) { throw new Exception(Path.GetFileName(filename) + " is in the Plugins directory but is not a valid plugin."); } foreach (Type type in DLL.GetExportedTypes()) { foreach (MemberInfo member in type.GetMembers()) { QuantSAExcelFunctionAttribute attribute = member.GetCustomAttribute <QuantSAExcelFunctionAttribute>(); if (attribute != null) // We have found an excel exposed function. { if (!attribute.Category.Equals(shortName)) { throw new Exception(attribute.Name + " in plugin " + shortName + " is not in the excel category " + shortName); } string[] parts = attribute.Name.Split('.'); if (!(parts.Length == 2 && parts[0].Equals(shortName))) { throw new Exception(attribute.Name + " in plugin " + shortName + "does not following the naming convention: " + shortName + ".FunctionName"); } // TODO: Check that the category and naming are all acceptable UpdateDelgatesAndAtribs((MethodInfo)member); } if (member.MemberType.Equals(MemberTypes.Method)) { if (((MethodInfo)member).ReturnType.Equals(typeof(System.Drawing.Bitmap))) { Bitmap image = ((MethodInfo)member).Invoke(null, null) as Bitmap; assemblyImageResources.Add(member.Name.Substring(4), image); } } } } }
/// <summary> /// Updates the functions from assembly. /// </summary> /// <param name="assembly">The assembly.</param> /// <param name="quantSAFunctions">The quant sa functions.</param> private static void UpdateFunctionsFromAssembly(Assembly assembly, Dictionary <string, MemberInfo> quantSAFunctions) { Type[] types = null; try { types = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { //TODO: This is for troubleshooting when the assembly does not load. Should be written to some more general log. StringBuilder sb = new StringBuilder(); foreach (Exception exSub in ex.LoaderExceptions) { sb.AppendLine(exSub.Message); FileNotFoundException exFileNotFound = exSub as FileNotFoundException; if (exFileNotFound != null) { if (!string.IsNullOrEmpty(exFileNotFound.FusionLog)) { sb.AppendLine("Fusion Log:"); sb.AppendLine(exFileNotFound.FusionLog); } } sb.AppendLine(); } string errorMessage = sb.ToString(); Console.WriteLine(errorMessage); } foreach (Type type in types) { if (!type.IsPublic) { continue; } MemberInfo[] members = type.GetMembers(); foreach (MemberInfo member in members) { QuantSAExcelFunctionAttribute attribute = member.GetCustomAttribute <QuantSAExcelFunctionAttribute>(); if (attribute != null) { if (attribute.HasGeneratedVersion) // if there is generated version then that will be used to constuct the delgate and this one will be used to get the help. { quantSAFunctions["_" + attribute.Name] = member; } else { quantSAFunctions[attribute.Name] = member; } } } } }
/// <summary> /// Use reflection on Excel.dll to find all the members that have /// the <see cref="QuantSAExcelFunctionAttribute"/> attribute. /// </summary> /// <remarks> /// This method is very simular to <see cref="GetFuncsWithGenVersion"/> in the AddIn</remarks> /// <returns></returns> public static Dictionary <string, MethodInfo> GetFuncsWithGenVersion(string filename) { Dictionary <string, MethodInfo> quantSAFunctions = new Dictionary <string, MethodInfo>(); Assembly excelAssemby = Assembly.LoadFile(filename); Type[] types = null; try { types = excelAssemby.GetTypes(); } catch (ReflectionTypeLoadException ex) { StringBuilder sb = new StringBuilder(); foreach (Exception exSub in ex.LoaderExceptions) { sb.AppendLine(exSub.Message); FileNotFoundException exFileNotFound = exSub as FileNotFoundException; if (exFileNotFound != null) { if (!string.IsNullOrEmpty(exFileNotFound.FusionLog)) { sb.AppendLine("Fusion Log:"); sb.AppendLine(exFileNotFound.FusionLog); } } sb.AppendLine(); } string errorMessage = sb.ToString(); Console.WriteLine(errorMessage); } foreach (Type type in types) { if (!type.IsPublic) { continue; } MemberInfo[] members = type.GetMembers(); foreach (MemberInfo member in members) { QuantSAExcelFunctionAttribute attribute = member.GetCustomAttribute <QuantSAExcelFunctionAttribute>(); if (attribute != null) { if (attribute.HasGeneratedVersion) // if there is generated version then that will be used to constuct the delgate and this one will be used to get the help. { quantSAFunctions[attribute.Name] = (MethodInfo)member; } } } } return(quantSAFunctions); }
/// <summary> /// Hides or shows Excel function based on the contents of functions_user.csv /// </summary> public void ExposeUserSelectedFunctions() { Dictionary <string, bool> funcsAndVisibility = GetFunctionVisibility(FunctionsFilenameUser); Dictionary <string, MemberInfo> functions = GetQuantSAFunctions(); delegates = new List <Delegate>(); functionAttributes = new List <object>(); functionArgumentAttributes = new List <List <object> >(); foreach (KeyValuePair <string, MemberInfo> entry in functions) { MethodInfo method = ((MethodInfo)entry.Value); QuantSAExcelFunctionAttribute quantsaAttribute = method.GetCustomAttribute <QuantSAExcelFunctionAttribute>(); // If the function appears in the user function list use the isHidden value from there. Otherwise use the default behaviour. bool?isHidden = null; if (funcsAndVisibility.ContainsKey(quantsaAttribute.Name)) { isHidden = !funcsAndVisibility[quantsaAttribute.Name]; } if (!quantsaAttribute.HasGeneratedVersion) // Make delegates for all but the methods that have generated versions of themselves { //Create the delgate, Taken from: http://stackoverflow.com/a/16364220 Delegate thisDelegate = method.CreateDelegate(Expression.GetDelegateType( (from parameter in method.GetParameters() select parameter.ParameterType) .Concat(new[] { method.ReturnType }) .ToArray())); delegates.Add(thisDelegate); if (quantsaAttribute.IsGeneratedVersion) { MethodInfo manualMethod = (MethodInfo)functions["_" + entry.Key]; AddSingleAutoFunction(method, manualMethod, isHidden); } else { AddSingleManualFunction(method, isHidden); } } } }
/// <summary> /// Generates the code for all the methods that have attribute value /// QuantSAExcelFunctionAttribute.HasGeneratedVersion=true /// </summary> /// <param name="functions">The selected functions.</param> private static void GenerateMethodCode(Dictionary <string, MethodInfo> functions) { foreach (KeyValuePair <string, MethodInfo> entry in functions) { QuantSAExcelFunctionAttribute quantsaAttribute = entry.Value.GetCustomAttribute <QuantSAExcelFunctionAttribute>(); string categoryName = entry.Value.DeclaringType.Name; string xlName = quantsaAttribute.Name; string fName = entry.Value.Name; String returnTypeName = entry.Value.ReturnType.Name; Type returnType = entry.Value.ReturnType; List <Type> argTypes = new List <Type>(); List <string> argNames = new List <string>(); List <string> defaultValues = new List <string>(); foreach (ParameterInfo paramInfo in entry.Value.GetParameters()) { argTypes.Add(paramInfo.ParameterType); argNames.Add(paramInfo.Name); QuantSAExcelArgumentAttribute argAttrib = paramInfo.GetCustomAttribute <QuantSAExcelArgumentAttribute>(); if (argAttrib == null) { defaultValues.Add(null); } else { defaultValues.Add(argAttrib.Default); } } var listOfNameSpaces = new List <string>(); string generatedMethod = GetGeneratedMethodCode(categoryName, xlName, fName, argNames, argTypes, defaultValues, returnType, listOfNameSpaces); if (!categoriesAndGeneratedMethods.ContainsKey(categoryName)) { categoriesAndGeneratedMethods[categoryName] = new List <string>(); categoriesAndUsings[categoryName] = new List <string>(); } categoriesAndGeneratedMethods[categoryName].Add(generatedMethod); categoriesAndUsings[categoryName].AddRange(listOfNameSpaces); } }
/// <summary> /// Registers a single function that is exposed by a manually and automatically written method. /// see http://www.quantsa.org/home_expose_to_excel.html /// </summary> /// <param name="method">The generated method.</param> /// <param name="manualMethod">The manual method.</param> /// <param name="isHidden">Is this function hidden.</param> private void AddSingleAutoFunction(MethodInfo method, MethodInfo manualMethod, bool?isHidden) { //Create the function attribute QuantSAExcelFunctionAttribute quantsaAttribute = manualMethod.GetCustomAttribute <QuantSAExcelFunctionAttribute>(); if (isHidden != null) { quantsaAttribute.IsHidden = isHidden.Value; } functionAttributes.Add(quantsaAttribute.CreateExcelFunctionAttribute()); // Create the function argument attributes List <object> thisArgumentAttributes = new List <object>(); if (manualMethod.GetParameters().Length < method.GetParameters().Length) { ExcelArgumentAttribute argAttrib = new ExcelArgumentAttribute(); argAttrib.Name = "objectName"; argAttrib.Description = "The name of the object to be created."; //Note that the above 2 strings are the same as those added in GenerateDocs, if they are changed here they should be changed there too. thisArgumentAttributes.Add(argAttrib); } foreach (ParameterInfo param in manualMethod.GetParameters()) { var argAttrib = param.GetCustomAttribute <ExcelArgumentAttribute>(); if (argAttrib != null) { argAttrib.Name = param.Name; } if (ExcelUtilities.InputTypeShouldHaveHelpLink(param.ParameterType)) { string typeName = param.ParameterType.IsArray ? param.ParameterType.GetElementType().Name : param.ParameterType.Name; argAttrib.Description += "(" + typeName + ")"; } thisArgumentAttributes.Add(argAttrib); } functionArgumentAttributes.Add(thisArgumentAttributes); }
/// <summary> /// Updates the content collection for a single dll. /// </summary> /// <param name="dllName">Name of the DLL.</param> private void UpdateContentCollection1dll(string dllName) { Assembly DLL = Assembly.LoadFile(dllName); foreach (Type type in DLL.GetExportedTypes()) { foreach (MemberInfo member in type.GetMembers()) { QuantSAExcelFunctionAttribute attribute = member.GetCustomAttribute <QuantSAExcelFunctionAttribute>(); if (attribute != null && attribute.IsGeneratedVersion) { MethodInfo method = (MethodInfo)member; string name = attribute.Name.Split('.')[1]; int argCount = method.GetParameters().Count(); generatedMethodArgCount[name] = argCount; } if (attribute != null && !attribute.IsGeneratedVersion) // We have found an excel exposed function and it is not the generated version. { FileContents contents = new FileContents(); // Check consistency of contents string[] categoryParts = attribute.Category.Split('.'); string[] nameParts = attribute.Name.Split('.'); if (attribute.Description.Length < 5) { errorInfo.Add(type.Name + "," + attribute.Name + ",,Does not have a description."); } if (!nameParts[0].Equals("QSA")) { errorInfo.Add(type.Name + "," + attribute.Name + ",,Name does not start with 'QSA'."); } if (!("XL" + categoryParts[1]).Equals(type.Name)) { errorInfo.Add(type.Name + "," + attribute.Name + ",,Category does not match file."); } if (attribute.HelpTopic == null) { errorInfo.Add(type.Name + "," + attribute.Name + ",,Does not have a help topic."); } else if (!attribute.HelpTopic.Equals(helpURL + nameParts[1] + ".html")) { errorInfo.Add(type.Name + "," + attribute.Name + ",,Help topic should be," + helpURL + nameParts[1] + ".html"); } if (attribute.ExampleSheet == null) { errorInfo.Add(type.Name + "," + attribute.Name + ",,Example sheet has not been set."); contents.exampleSheet = "Not available"; } else { contents.exampleSheet = attribute.ExampleSheet; } // Add details contents.name = attribute.Name.Split('.')[1]; contents.category = attribute.Category.Split('.')[1]; contents.Description = attribute.Description; MethodInfo method = (MethodInfo)member; foreach (ParameterInfo param in method.GetParameters()) { var argAttrib = param.GetCustomAttribute <ExcelArgumentAttribute>(); if (argAttrib != null) { contents.argNames.Add(param.Name); if (InputTypeShouldHaveHelpLink(param.ParameterType)) { string name = param.ParameterType.IsArray ? param.ParameterType.GetElementType().Name : param.ParameterType.Name; argAttrib.Description += "(" + name + ")"; } contents.argDescriptions.Add(argAttrib.Description); if (argAttrib.Description.Length < 5) { errorInfo.Add(type.Name + "," + attribute.Name + "," + param.Name + ",No argument description"); } } else { errorInfo.Add(type.Name + "," + attribute.Name + "," + param.Name + ",Argument does not have ExcelArgumentAttribute"); } } contentCollection.AddFile(contents); } } } }