Last Update: 2010/10/17 00:23
Intro
using System.Reflection;//Assembly, MethodInfo
using System.IO;//File
...
String dllPath = @"N:\Common.dll";
String typeName = "Common.Class1";
String methodName = "GetVersion";
Assembly assembly = Assembly.Load(
File.ReadAllBytes(dllPath));
//載入DLL, ReadAllBytes 是避免 Lock 實體檔案
Object obj = assembly.CreateInstance(typeName);
//創建物件實體
MethodInfo method = obj.GetType()
.GetMethod(methodName);
//取得Method資訊
Console.WriteLine(method.Invoke(obj, new Object[] { }));
這算是最簡單的方式唄
不過有個很嚴重的缺點
它無法卸載DLL(Assembly)(參閱 這裡)
你可以開啟工作管理員來檢視
每次執行都會增加一些記憶體
所以我就使用 AppDomain 來加載DLL
就能用 AppDomain.Unload 來卸載
Implementation
試作範例下載
現在有 3 個專案
◆ DynMountDll : 主執行
◆ DynMountDll.TestLib : 被掛載之DLL
◆ DynMountDllLib : interface或稱它為協定吧(WCF好像稱為Contract),被上述兩個專案所參照。
OK, 主要是這個函式
它就是負責掛載Assembly、調用Method、再卸載Assembly(AppDomain)
這幾行,應該滿好理解的
void MountDllInvokeMethod(String dllPath
, String typeName, String methodName)
{
AppDomain myAppDomain = null;
try
{
FileInfo fi = new FileInfo(dllPath);
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
setup.ApplicationName = "DynMountDll";
myAppDomain = AppDomain.CreateDomain(
"AppDomain01", null, setup);
DynMountDllLib.IBaseLoader obj =
(DynMountDllLib.IBaseLoader)
myAppDomain.CreateInstanceFromAndUnwrap(
fi.FullName, typeName);
MessageShow(obj.InvokeMethod(methodName, new Object[] { }));
}
finally
{
if (myAppDomain != null)
{ AppDomain.Unload(myAppDomain); }
}
}
我在試作過程遇到的其它問題大致如下
● AppDoman 間的傳遞物件 必須 Serializable 或是 繼承 MarshalByRefObject
● 主要的 AppDomain 並不認識 新的AppDomain 加載的 Assembly
因此,協定(interface)是必要的
AppDomain 和 Assembly 的關係可以參考下圖
順道一提
我這邊的協定只有一個函式 InvokeMethod
它是用來呼叫其它函式的
等於是提供一個進入點(Entry Point)
主要是因為 同組件、不同版本
可能會出現協定中不存在的函式
沒有留言:
張貼留言