/// <summary> /// Initialize the plugin dependencies and execute its entry point. /// </summary> /// <param name="remoteParameters">Parameters containing the plugin to load /// and the parameters to pass to it's entry point.</param> /// <returns>A status code representing the plugin initialization state.</returns> public static int Load(IntPtr remoteParameters) { try { if (remoteParameters == IntPtr.Zero) { throw new ArgumentOutOfRangeException(nameof(remoteParameters), "Remote arguments address was zero"); } // Extract the plugin initialization information // from the remote host loader arguments. IUserDataFormatter remoteInfoFormatter = CreateRemoteDataFormatter(); var pluginConfig = PluginConfiguration <RemoteEntryInfo, ManagedRemoteInfo> .LoadData( remoteParameters, remoteInfoFormatter ); // Start the IPC message notifier with a connection to the host application. var hostNotifier = new NotificationHelper(pluginConfig.RemoteInfo.ChannelName); hostNotifier.Log($"Initializing plugin: {pluginConfig.RemoteInfo.UserLibrary}."); IDependencyResolver resolver = CreateDependencyResolver( pluginConfig.RemoteInfo.UserLibrary); // Construct the parameter array passed to the plugin initialization function. var pluginParameters = new object[1 + pluginConfig.RemoteInfo.UserParams.Length]; hostNotifier.Log($"Initializing plugin with {pluginParameters.Length} parameter(s)."); pluginParameters[0] = pluginConfig.UnmanagedInfo; for (var i = 0; i < pluginConfig.RemoteInfo.UserParams.Length; ++i) { pluginParameters[i + 1] = pluginConfig.RemoteInfo.UserParams[i]; } hostNotifier.Log("Deserializing parameters."); DeserializeParameters(pluginParameters, remoteInfoFormatter); hostNotifier.Log("Successfully deserialized parameters."); // Execute the plugin library's entry point and pass in the user arguments. pluginConfig.State = LoadPlugin( resolver.Assembly, pluginParameters, hostNotifier); return((int)pluginConfig.State); } catch (ArgumentOutOfRangeException outOfRangeEx) { Log(outOfRangeEx.ToString()); throw; } catch (Exception e) { Log(e.ToString()); } return((int)PluginInitializationState.Failed); }
/// <summary> /// Send a exception message to the host and then throw the exception in the current application. /// </summary> /// <param name="notifier">Communication helper to send messages to the host application.</param> /// <param name="e">The exception that occurred.</param> private static void Log(NotificationHelper notifier, Exception e) { notifier.Log(e.Message, LogLevel.Error); throw e; }
/// <summary> /// Find the entry point of the plugin module, initialize it, and execute its Run method. /// </summary> /// <param name="assembly">The plugin assembly containing the entry point.</param> /// <param name="paramArray">The parameters passed to the plugin Run method.</param> /// <param name="hostNotifier">Used to notify the host about the state of the plugin initialization.</param> private static PluginInitializationState LoadPlugin(Assembly assembly, object[] paramArray, NotificationHelper hostNotifier) { Type entryPoint = FindEntryPoint(assembly); MethodInfo runMethod = FindMatchingMethod(entryPoint, EntryPointMethodName, paramArray); if (runMethod == null) { Log(hostNotifier, new MissingMethodException( $"Failed to find the 'Run' function with {paramArray.Length} parameter(s) in {assembly.FullName}.")); } hostNotifier.Log("Found entry point, initializing plugin class."); var instance = InitializeInstance(entryPoint, paramArray); if (instance == null) { Log(hostNotifier, new MissingMethodException( $"Failed to find the constructor {entryPoint.Name} in {assembly.FullName}")); } hostNotifier.Log("Plugin successfully initialized. Executing the plugin entry point."); if (hostNotifier.SendInjectionComplete(Process.GetCurrentProcess().Id)) { // Close the plugin loading message channel. hostNotifier.Dispose(); try { // Execute the plugin 'Run' entry point. runMethod?.Invoke(instance, BindingFlags.Public | BindingFlags.Instance | BindingFlags.ExactBinding | BindingFlags.InvokeMethod, null, paramArray, null); } catch { } return(PluginInitializationState.Initialized); } return(PluginInitializationState.Failed); }