Pregunta

Me gustaría proporcionar alguna forma de crear complementos cargables dinámicamente en mi software.La forma típica de hacer esto es usar el Cargar biblioteca Función WinAPI para cargar un dll y llamar Obtener dirección Proc para obtener un puntero a una función dentro de ese dll.

Mi pregunta es ¿cómo cargo dinámicamente un complemento en la aplicación C#/.Net?

¿Fue útil?

Solución

El siguiente fragmento de código (C#) construye una instancia de cualquier clase concreta derivada de Base se encuentra en las bibliotecas de clases (*.dll) en la ruta de la aplicación y las almacena en una lista.

using System.IO;
using System.Reflection;

List<Base> objects = new List<Base>();
DirectoryInfo dir = new DirectoryInfo(Application.StartupPath);

foreach (FileInfo file in dir.GetFiles("*.dll"))
{
    Assembly assembly = Assembly.LoadFrom(file.FullName);
    foreach (Type type in assembly.GetTypes())
    {
        if (type.IsSubclassOf(typeof(Base)) && type.IsAbstract == false)
        {
            Base b = type.InvokeMember(null,
                                       BindingFlags.CreateInstance,
                                       null, null, null) as Base;
            objects.Add(b);
        }
    }
}

Editar: Las clases a que se refiere Mate son probablemente una mejor opción en .NET 3.5.

Otros consejos

A partir de .NET 3.5, existe una forma formalizada e integrada de crear y cargar complementos desde una aplicación .NET.esta todo en el Sistema.AddIn espacio de nombres.Para obtener más información, puede consultar este artículo en MSDN: Complementos y extensibilidad

Carga dinámica de complementos

Para obtener información sobre cómo cargar dinámicamente ensamblados .NET, consulte esta pregunta (y mi respuesta).Aquí hay un código para cargar y crear un AppDomain y cargar un ensamblaje en él.

var domain = AppDomain.CreateDomain("NewDomainName");
var pathToDll = @"C:\myDll.dll"; 
var t = typeof(TypeIWantToLoad);
var runnable = domain.CreateInstanceFromAndUnwrap(pathToDll, t.FullName) 
    as IRunnable;
if (runnable == null) throw new Exception("broke");
runnable.Run();

Descarga de complementos

Un requisito típico de un marco de complementos es descargar los complementos.Para descargar ensamblajes cargados dinámicamente (p. ej.complementos y complementos) debe descargar el contenido AppDomain.Para más información, ver este artículo en MSDN sobre la descarga de AppDomains.

Usando WCF

Hay un pregunta y respuesta de desbordamiento de pila que describen cómo utilizar Windows Communication Framework (WCF) para crear un marco de complemento.

Marcos de complementos existentes

Conozco dos marcos de complementos:

Algunas personas hablan de la Marco de extensibilidad gestionada (MEF) como un complemento o marco de complemento, que no lo es.Para más información, ver esta pregunta de StackOverflow.com y esta pregunta de StackOverflow.com.

Un consejo es cargar todos los complementos y demás en un AppDomain propio, ya que el código que se ejecuta puede ser potencialmente malicioso.También se puede utilizar un AppDomain propio para "filtrar" ensamblados y tipos que no desea cargar.

AppDomain domain = AppDomain.CreateDomain("tempDomain");

Y para cargar un ensamblado en el dominio de la aplicación:

AssemblyName assemblyName = AssemblyName.GetAssemblyName(assemblyPath);
Assembly assembly = domain.Load(assemblyName);

Para descargar el dominio de la aplicación:

AppDomain.Unload(domain);

Sí, ++ a Matt y System.AddIn (hay disponible un artículo de dos partes de la revista MSDN sobre System.AddIn). aquí y aquí).Otra tecnología que quizás desee considerar para tener una idea de hacia dónde podría dirigirse .NET Framework en el futuro es la Marco de extensibilidad gestionada actualmente disponible en formato CTP en Codeplex.

Básicamente puedes hacerlo de dos maneras.

La primera es importar kernel32.dll y usar LoadLibrary y GetProcAddress como lo usaste antes:

[DllImport("kernel32.dll")]

internal static extern IntPtr LoadLibrary(String dllname);

[DllImport("kernel32.dll")]

internal static extern IntPtr GetProcAddress(IntPtr hModule, String procname);

El segundo es hacerlo en forma .NET:mediante el uso de la reflexión.Verifique el espacio de nombres System.Reflection y los siguientes métodos:

Primero carga el ensamblado por su ruta, luego obtiene el tipo (clase) por su nombre, luego obtiene el método de la clase por su nombre nuevamente y finalmente llama al método con los parámetros relevantes.

El artículo es un poco más antiguo, pero sigue siendo aplicable para crear una capa de extensibilidad dentro de su aplicación:

Permita que los usuarios agreguen funcionalidad a sus aplicaciones .NET con macros y complementos

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top