簡體   English   中英

在C#中動態加載dll

[英]Dynamically loading a dll in C#

我有一個用於編輯的窗口。 編輯器應根據用戶的選擇加載一個dll(我具有完全控制權),以了解如何直觀地顯示信息。 (它們是dll的,因為用戶不一定需要或不需要每個單獨的顯示模型,並且還允許添加新的顯示模型而不會弄亂主項目)

它們都將簡單地存儲在子目錄中(無論如何現在還是這樣)。我很確定我可以枚舉可用的dll,但是我還需要執行2項我不確定的事情

1)通過某種方式從dll中獲取元數據,因此我可以構建可能的顯示選擇列表...

2)加載選定的dll,並根據需要將其卸載

任何建議將不勝感激。

如果您使用的是原始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方法。 查看程序集級屬性或對象級屬性是獲取更多信息的好方法,盡管如果您要使用的是插件系統,則應使用插件系統,例如CodePlex的Managed Add-In Framework 另請參閱此SO問答

看一下Castle Windsor框架。 它旨在滿足您的所有要求,包括DLL卸載。 它也是免費和開源的。

我不知道是否可以更改程序的工作方式,但是,只要它們遵循特定的接口,就可以使用依賴項注入。

用戶選擇后,可以動態設置要加載的類,然后僅獲取該類的實例。

我不是在處理卸載,我只是在考慮如何獲取類,並且由於底座已經提供了指向實際處理dll的函數的鏈接,因此我想就此結束。

對於本機模塊,獲取“元數據”的最簡單方法是定義一些C導出(非命名混用)函數,這些函數返回所需的信息。 最簡單的說,它們將返回指向模塊內靜態數據的指針,例如:

extern "C" const char* GetModuleDescription();
...
const char* GetModuleDescription() { return "Dummy Module"; }

然后,您將使用LoadLibrary加載目錄中的每個“ .dll”文件,並使用GetProcAddress加載並調用該文件中的已知導出。 如果您無法加載文件或找到導出文件,則它不是有效的插件模塊,因此請跳過它。

完成模塊后,可以調用FreeLibrary Windows然后將從您的地址空間中卸載該模塊。

好的,我已經確定我需要使用第二個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上進行foreach以獲得AssemblyName,然后再使用

DLLDomain.Load(SelectedAssemblyName)

加載DLL。 我一直收到FileNotFound異常。 經過大量的搜尋之后,我決定目前要進行很多工作,如果我真的需要的話,可以稍后再重構...

不過謝謝您的答復!

了解了如何使用MEF非常輕松地做到這一點,只需使用指向插件目錄的DirectoryCatalog,只要您具有匹配的[Export]和[Import],它就可以很好地工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM