在C#中动态加载插件的类,支持COM对象和Net的插件

时间:2022-08-30 17:15:36
使用了应用程序域来加载 COM,本想都采用应用程序域的,但没找到传对象到新域里的方法(如传 DataTable、TcpClient 等主域中的对象),所以 Net 的插件采用了读入内存的方法载入,这样就可以给 Net 的插件传主域中的对象了。
using System;
using System.Reflection;
using System.IO;
namespace Loader
{
class LoaderDomain
{
AppDomain appDomain;
public RemoteLoader remoteLoader;
public LoaderDomain(string path)
{
AppDomainSetup tmpSetup = new AppDomainSetup();
tmpSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
tmpSetup.ShadowCopyDirectories = path;
appDomain = AppDomain.CreateDomain("newDomain",
new System.Security.Policy.Evidence(AppDomain.CurrentDomain.Evidence), tmpSetup);
RemoteLoader tmpRemoteLoader = new RemoteLoader();
remoteLoader = (RemoteLoader)
appDomain.CreateInstanceAndUnwrap(tmpRemoteLoader.GetType().Assembly.FullName,
tmpRemoteLoader.GetType().FullName);
tmpRemoteLoader = null;
}
public void Unload()
{
AppDomain.Unload(appDomain);
appDomain = null;
}
}
public class RemoteLoader : MarshalByRefObject
{
Object tmpClass = null;
Type tmpType = null;
public void LoadAssembly(string path, string typeName)
{
/*tmpClass = Assembly.LoadFile(path).CreateInstance(typeName);
tmpType = tmpClass.GetType();*/
tmpClass = Assembly.Load(File.ReadAllBytes(path)).CreateInstance(typeName);
tmpType = tmpClass.GetType();
}
public void LoadCOM(string progID)
{
tmpType = Type.GetTypeFromProgID(progID);
tmpClass = Activator.CreateInstance(tmpType);
}
public object InvokeMember(string name, BindingFlags invokeAttr, object[] args)
{
if (tmpClass != null && tmpType != null)
{
return tmpType.InvokeMember(name,
invokeAttr | BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance,
null, tmpClass, args);
}
else
{
return null;
}
}
public bool IsMember(string name, MemberTypes type)
{
if (tmpClass != null && tmpType != null)
{
try
{
if (tmpType.GetMember(name, type,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase).Length >= 1)
{
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}
else
{
return false;
}
}
}
}

调用 COM 插件的方法。
//调用COM插件
LoaderDomain tmpLoaderDomain = new LoaderDomain(AppDomain.CurrentDomain.BaseDirectory);
try
{
tmpLoaderDomain.remoteLoader.LoadCOM("类名");
}
catch (Exception err)
{//创建COM插件。
    MessageBox.Show(err.Message);
}
finally
{
try { tmpLoaderDomain.Unload(); }
catch { }
}
tmpLoaderDomain = null;

调用 Net 插件的方法。
//调用.Net插件
string tmpClassPath = "插件路径";
if (File.Exists(tmpClassPath))
{
RemoteLoader tmpRemoteLoader = new RemoteLoader();
try
{
tmpRemoteLoader.LoadAssembly(tmpClassPath, "类名");
}
catch (Exception err)
{//创建.Net插件失败
        MessageBox.Show(err.Message);
}
tmpRemoteLoader = null;
}

统一的访问属性、方法。
tmpRemoteLoader.InvokeMember("属性名", BindingFlags.SetProperty, new Object[] { "参数1", "参数2" });
bool tmpReturn = (bool) tmpRemoteLoader.InvokeMember("方法名", BindingFlags.InvokeMethod, null);