public void Uninitialise()
        {
            try
            {
                lock (m_objLock)
                {
                    if (!IsInitialised())
                    {
                        throw new InvalidOperationException("Cannot unitialise plugin assembly; it isn't initialised");
                    }

                    // If there are any plugin instances they need tearing down
                    if (m_dictInstances != null && m_dictInstances.Count > 0)
                    {
                        foreach (var instance in m_dictInstances.Values.SelectMany(l => l).Where(l => l.IsInitialised()))
                        {
                            instance.Unitialise();
                        }
                    }

                    m_asmManager = null;

                    try
                    {
                        AppDomain.Unload(m_adAssemblyAppDomain);
                    }
                    catch (Exception ex)
                    {
                        throw new ApplicationException("Failed to unload plugin assembly AppDomain", ex);
                    }

                    m_adAssemblyAppDomain = null;

                    m_bIsInitialised = false;
                }
            }
            catch (Exception ex)
            {
                throw new ApplicationException("Failed to unitialise plugin assembly", ex);
            }
        }
        /// <summary>
        /// Performs initialisation and loads the assembly
        /// </summary>
        public DistribPluginAssemblyInitialisationResult Initialise()
        {
            DistribPluginAssemblyInitialisationResult result = new DistribPluginAssemblyInitialisationResult();

            try
            {
                lock (m_objLock)
                {
                    if (IsInitialised())
                    {
                        throw new InvalidOperationException("Cannot initialise plugin assembly; it is already initialised");
                    }

                    // Set up the AppDomain
                    m_adAssemblyAppDomain = AppDomain.CreateDomain(Guid.NewGuid() + "_" + m_strAssemblyPath);

                    try
                    {
                        // Create the assembly manager for the plugin assembly isolated in the AppDomain
                        m_asmManager = (DistribPluginAssemblyManager)m_adAssemblyAppDomain
                                        .CreateInstanceAndUnwrap(
                                        typeof(DistribPluginAssemblyManager).Assembly.FullName,
                                        typeof(DistribPluginAssemblyManager).FullName,
                                        true,
                                        System.Reflection.BindingFlags.CreateInstance,
                                        null,
                                        new object[] { m_strAssemblyPath },
                                        null,
                                        null);

                    }
                    catch (Exception ex)
                    {
                        throw new ApplicationException("Failed to create manager in AppDomain", ex);
                    }

                    if (m_asmManager == null)
                    {
                        throw new ApplicationException("Manager in AppDomain was null after creation");
                    }

                    try
                    {
                        // Load the assembly into the domain
                        m_asmManager.LoadAssembly();
                    }
                    catch (Exception ex)
                    {
                        throw new ApplicationException("Manager failed to load assembly into AppDomain", ex);
                    }

                    // Retrieve the details for all plugins present in the assembly
                    // At this point these are the details that should be utilised by the developer and the system
                    // for *actual* work as they are serialised through the AppDomain and as a result
                    // any modifications here are not represented in the manager (usability etc)
                    // When pushing down to the manager to perform low-level work, the type-name is used as the key
                    // and the plugin details data will simply be used from the version given to the manager.
                    m_lstPluginDetails = m_asmManager.GetPluginDetails();

                    if (m_lstPluginDetails == null || m_lstPluginDetails.Count == 0)
                    {
                        throw new InvalidOperationException("The plugin assembly contains no Distrib Plugins");
                    }

                    // Go through all the plugins in the assembly
                    foreach (var pluginType in m_lstPluginDetails)
                    {
                        // Do any bootstrapping that's required to fill in defaults etc
                        // This has to be done before checking the usability as it could
                        // affect things.
                        var bootstrapResult = _PerformPluginBootstrapping(pluginType);

                        if (!bootstrapResult.Success)
                        {
                            pluginType.MarkAsUnusable(PluginExclusionReason.PluginBootstrapFailure,
                                bootstrapResult.Result);

                            result.AddPlugin(pluginType);

                            continue;
                        }

                        // Check over the usability of the plugin and mark it accordingly
                        var usabilityCheckResult = _CheckUsabilityOfPlugin(pluginType);

                        if (!usabilityCheckResult.Success)
                        {
                            pluginType.MarkAsUnusable(usabilityCheckResult.Result, usabilityCheckResult.ResultTwo);

                            result.AddPlugin(pluginType);

                            continue;
                        }

                        // Make sure that the additional metadata meets the existence / instancing requirements specified
                        var metadataConstraintsResult = _CheckAdditionalMetadataExistenceRequirements(pluginType);

                        if (!metadataConstraintsResult.Success)
                        {
                            pluginType.MarkAsUnusable(PluginExclusionReason.PluginAdditionalMetadataConstraintsNotMet,
                                metadataConstraintsResult.Result);

                            result.AddPlugin(pluginType);

                            continue;
                        }

                        pluginType.MarkAsUsable();
                        result.AddPlugin(pluginType);
                    }

                    m_bIsInitialised = true;
                }

                // Lock the result to ensure no modifications
                result.LockResult();
                return result;
            }
            catch (ReflectionTypeLoadException ex)
            {
                // Something has gone wrong when trying to load the types in the plugin
                // Mostly owing to missing references / plugins not adhering to interfaces

                var loaderExceptions = ex.LoaderExceptions;

                var sb = new StringBuilder();
                sb.AppendLine("Failed to initialise plugin assembly, type loading errors:");

                foreach (var te in loaderExceptions)
                {
                    sb.AppendLine(te.Message);
                }

                throw new ApplicationException(sb.ToString(), ex);
            }
            catch (Exception ex)
            {
                throw new ApplicationException("Failed to initialise plugin assembly", ex);
            }
        }