我有一个用于编辑的窗口。编辑器应该加载一个dll(我完全控制它)以响应用户的选择,以了解如何直观地显示信息。 (它们是dll,因为用户不一定想要或不需要每一个显示模型,并且还允许添加新的模型而不会弄乱主项目)
它们都将简单地存储在一个子目录中(现在无论如何) 我很确定我可以枚举可用的dll,但我还需要做两件我不确定的事情
1)从dll获取元数据的一些方法,所以我可以构建可能的显示选择列表......
2)加载选定的dll,并根据需要卸载
任何建议都将不胜感激。
答案 0 :(得分:5)
如果您使用的是原始dll而不是.NET程序集,那么这里有一些方便的P / Invokes:
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern void SetDllDirectory(string lpPathName);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
privatestatic extern int GetModuleFileName(IntPtr module, [Out] StringBuilder fileName, int size);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static bool FreeLibrary(IntPtr module);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
请注意,SetDllDirectory可能需要一些保护,因为它在所有版本的Windows上都不可用(Windows 2000,特别是没有它)。
并在使用中:
SetDllDirectory(candidateFolder);
IntPtr dllHandle = LoadLibrary(dllName);
if (dllHandle != IntPtr.Zero)
{
_dllHandle = dllHandle;
_location = candidateFolder;
_fullPath = Path.Combine(candidateFolder, dllName);
IntPtr p = GetProcAddress(_dllHandle, procName);
if (p == IntPtr.Zero)
throw new ArgumentException("procName");
SomeDelegateType d = (SomeDelegateType)Marshal.GetDelegateForFunctionPointer(p, typeof(SomeDelegateType));
d(/* args */);
}
否则,您将使用Assembly方法。查看程序集级别属性或对象级别属性是获取额外信息的好方法,但如果您想要的是插件系统,则应使用插件系统,如{{ 3}}在CodePlex。另请参阅Managed Add-In Framework。
答案 1 :(得分:2)
看看Castle Windsor框架。它旨在处理您的所有要求,包括DLL卸载。它也是免费和开源的。
答案 2 :(得分:1)
我不知道是否可以更改程序的工作方式,但是,只要它们符合某个界面,就可以使用依赖注入。
用户选择,动态设置要加载的类,然后只获取该类的实例。
我不是在处理卸载,我只是在想你怎么可能上课,而且由于plinth已经提供了实际处理dll的函数的链接,我想我会在这里结束。
答案 3 :(得分:1)
对于本机模块,获取“元数据”的最简单方法是定义一些返回所需信息的C导出(非名称损坏)函数。最简单的是,它们会返回指向模块内静态数据的指针,例如:
extern "C" const char* GetModuleDescription();
...
const char* GetModuleDescription() { return "Dummy Module"; }
然后,您将使用LoadLibrary
在目录中加载每个“.dll”文件,使用GetProcAddress
加载并调用已知的导出文件。如果你无法加载文件或找到导出,那么它不是一个有效的插件模块,所以跳过它。
完成模块后,您可以致电FreeLibrary
。然后,Windows将从您的地址空间中卸载该模块。
答案 4 :(得分:1)
好的,我已经想通了我需要使用第二个AppDomain,将dll加载到那个,然后我可以根据需要卸载AppDomain。
string SignalSystemDLLPath = AppDomain.CurrentDomain.BaseDirectory + MyApp.Properties.Resources.SystemModuleFolder;
AppDomainSetup info = new AppDomainSetup();
info.ApplicationBase = DLLPath;
DLLDomain = AppDomain.CreateDomain("EditorDomain", null, info);
DLLPath设置为保存dll的子目录。
然后我在所有dll上预先获取AssemblyName,然后再获取 我用
DLLDomain.Load(SelectedAssemblyName)
加载DLL。我不断收到FileNotFound异常。 经过大量的谷歌搜索后,我已经决定它的工作量很大,我可以稍后重构它如果我真的需要这样做......
感谢您的回复!
答案 5 :(得分:0)
使用MEF了解如何轻松完成此操作,只需使用指向插件目录的DirectoryCatalog,只要您匹配[导出]和[导入],它就可以运行。