private static object[] CompileParameterArray(MethodInfo functionInfo, TSDictionary parameters) { Dictionary <string, object> parametersToCompile = new Dictionary <string, object>(); if (parameters != null) // copy dictionary (because content is "cleared" below, but could be necessary for a 2nd call) { Dictionary <string, object> pCopy = parameters.GetCopyOfContent(); foreach (string key in pCopy.Keys) { parametersToCompile.Add(key, pCopy[key]); } } ParameterInfo[] parameterInfo = functionInfo.GetParameters(); // obtain the info about the correct set of parameters for this function object[] paramArray = new object[parameterInfo.Count()]; string errorReport = string.Empty; for (int i = 0; i < parameterInfo.Count(); ++i) { if (parameterInfo[i].IsOut) { paramArray[i] = null; // setting out-parameters to anything else but null does not make sense, the input is anyway ignored parametersToCompile[parameterInfo[i].Name] = Type.Missing; // this is for error handling (to recognise an unknown parameter, see below) } else if (parametersToCompile.ContainsKey(parameterInfo[i].Name)) { paramArray[i] = parametersToCompile[parameterInfo[i].Name]; parametersToCompile[parameterInfo[i].Name] = Type.Missing; // this is for error handling (to recognise an unknown parameter, see below) } else if (parameterInfo[i].IsOptional) { paramArray[i] = Type.Missing; } else { errorReport += string.Format("{0}Missing parameter '{1}'.", Environment.NewLine, parameterInfo[i].Name); } } foreach (string parameterName in parametersToCompile.Keys) { if (parametersToCompile[parameterName] != Type.Missing) { errorReport += string.Format("{0}Unknown parameter '{1}'.", Environment.NewLine, parameterName); } } if (errorReport != string.Empty) { throw new ArgumentException("Parameter mismatch: " + errorReport); } return(paramArray); }
public static TSDictionary ComposeParameters(Dictionary <string, object> parameters) { TSDictionary parameterDic = new TSDictionary(); if (parameters != null) { foreach (string key in parameters.Keys) { parameterDic.SetItem(key, parameters[key]); } } return(parameterDic); }
// a more convenient way to pass parameters to CallStaticFunction public static TSDictionary ComposeParameters( string pName1, object pValue1, string pName2 = "", object pValue2 = null, string pName3 = "", object pValue3 = null, string pName4 = "", object pValue4 = null, string pName5 = "", object pValue5 = null, string pName6 = "", object pValue6 = null, string pName7 = "", object pValue7 = null, string pName8 = "", object pValue8 = null, string pName9 = "", object pValue9 = null, string pName10 = "", object pValue10 = null, string pName11 = "", object pValue11 = null, string pName12 = "", object pValue12 = null, string pName13 = "", object pValue13 = null, string pName14 = "", object pValue14 = null, string pName15 = "", object pValue15 = null) { TSDictionary parameterDic = new TSDictionary(); if (pName1 != string.Empty) { parameterDic.SetItem(pName1, pValue1); } if (pName2 != string.Empty) { parameterDic.SetItem(pName2, pValue2); } if (pName3 != string.Empty) { parameterDic.SetItem(pName3, pValue3); } if (pName4 != string.Empty) { parameterDic.SetItem(pName4, pValue4); } if (pName5 != string.Empty) { parameterDic.SetItem(pName5, pValue5); } if (pName6 != string.Empty) { parameterDic.SetItem(pName6, pValue6); } if (pName7 != string.Empty) { parameterDic.SetItem(pName7, pValue7); } if (pName8 != string.Empty) { parameterDic.SetItem(pName8, pValue8); } if (pName9 != string.Empty) { parameterDic.SetItem(pName9, pValue9); } if (pName10 != string.Empty) { parameterDic.SetItem(pName10, pValue10); } if (pName11 != string.Empty) { parameterDic.SetItem(pName11, pValue11); } if (pName12 != string.Empty) { parameterDic.SetItem(pName12, pValue12); } if (pName13 != string.Empty) { parameterDic.SetItem(pName13, pValue13); } if (pName14 != string.Empty) { parameterDic.SetItem(pName14, pValue14); } if (pName15 != string.Empty) { parameterDic.SetItem(pName15, pValue15); } return(parameterDic); }
// the function CallStaticFunction (and its overload) allows for calling any public static function of the running!!! UI // currently the only public functions of the UI are gathered in the class EM_UI.PlugInService.UISessionInfo // these functions (providing info about pathes, active countries, etc.) are replicated by EM_Common.dll for more convenient calling // for this purpose the class EM_Common.UISessionInfo uses the function CallStaticFunction below // in principle plug-ins can use CallStaticFunction themselves, provided we extend the UI by public static functions public static bool CallStaticFunction(string className, string functionName, out TSObject returnValue, out string errMsg, TSDictionary parameters = null) { returnValue = new TSObject(); errMsg = string.Empty; // initialise out-parameters try { Assembly assembly = GetUIAssembly(); // search for class (must be unique match) Type classType = null; foreach (Type t in assembly.GetExportedTypes()) { if (t.Name == className) { classType = t; } } if (classType == null) { throw new Exception($"class {className} not found"); } // searching for function is more complicated as there could be overloads List <MethodInfo> possibleMatches = new List <MethodInfo>(); foreach (MethodInfo possibleMatch in classType.GetMethods()) { if (possibleMatch.Name != functionName) { continue; } possibleMatches.Add(possibleMatch); } if (possibleMatches.Count == 0) { throw new Exception($"function {functionName} not found"); } // now try calling all overloads of the function to hopefully find a matching one foreach (MethodInfo possibleMatch in possibleMatches) { try { object[] outParameters = CompileParameterArray(possibleMatch, parameters); // put parameters from dictionary into array with correct order object[] inParameters = new object[outParameters.Count()]; outParameters.CopyTo(inParameters, 0); returnValue.SetValue(possibleMatch.Invoke(classType, outParameters)); // gather out- and ref-parameters for appropriate returning if (parameters != null) { parameters.Clear(); ParameterInfo[] parameterInfo = possibleMatch.GetParameters(); for (int i = 0; i < parameterInfo.Count(); ++i) { if (parameterInfo[i].ParameterType.IsByRef || parameterInfo[i].IsOut) { parameters.SetItem(parameterInfo[i].Name, outParameters[i]); } } } return(true); } catch (Exception exception) // remark: try/catch seems the most secure way to check parameter-matching { // "manual" check is quite problematic (consider: derived types, numeric parameters (is it int/long/double), etc.) if (exception is TargetParameterCountException || exception is ArgumentException) { if (possibleMatch != possibleMatches.Last()) { continue; // continue search as there may be an overload with matching parameters } } throw new Exception("no overload with matching parameters found"); } } return(true); } catch (Exception exception) { errMsg = $"Calling UI-function {className}.{functionName} from other assembly failed: {exception.Message}"; return(false); } }