C# 使用程式碼實現非託管dll、OCX動態註冊
阿新 • • 發佈:2018-12-10
一般我們註冊VB的ocx控制元件或者其他的dll需要手動在控制檯命令中用regsvr32來註冊,其實就是呼叫dll中的DllRegisterServer方法,用c#的DllImport也可以呼叫該方法,但是DllImport的路徑必須是靜態欄位,不能動態的,我們可以使用kernel32中的兩個函式來實現動態呼叫:LoadLibrary和GetProcAddress,呼叫完成之後再FreeLibrary就可以了,先上程式碼:
/// <summary>
/// 動態載入DLL
/// </summary>
public class DynamicLoadDll
{
/// <summary>
/// 根據非託管庫的控制代碼,函式名稱和指定委託型別,返回委託
/// </summary>
/// <param name="dllModule"></param>
/// <param name="functionName"></param>
/// <param name="t"></param>
/// <returns></returns>
private static Delegate GetFunctionAddress (int dllModule, string functionName, Type t)
{
int address = Kernel32Helper.GetProcAddress(dllModule, functionName); //得到地址
if (address == 0)
return null;
else
return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);//將非託管函式指標轉換為委託。
}
/// <summary>
/// 根據dll的路徑,dll中的方法名,動態呼叫非託管dll的方法
/// </summary>
/// <param name="dllPath">dll的路徑</param>
/// <param name="functionName">要呼叫的dll的方法名稱</param>
/// <param name="delegateType">要將對應非託管dll中的方法名對映為C#的簽名一致的委託型別</param>
/// <param name="msg">執行過程中的錯誤資訊</param>
/// <param name="par">執行方法的引數</param>
/// <returns></returns>
public static object DynamicInvoke(string dllPath, string functionName,Type delegateType,out string msg,params object[] par)
{
msg = "";
int address = 0;
try
{
address = Kernel32Helper.LoadLibrary(dllPath);
if (address == 0)
{
msg = "載入dll失敗,dll路徑:" + dllPath;
return null;
}
Delegate d1 = GetFunctionAddress(address, functionName, delegateType);
if (d1 == null)
{
msg = "獲取函式名稱失敗,函式名稱:" + functionName;
return null;
}
object result= d1.DynamicInvoke(par);
Kernel32Helper.FreeLibrary(address);
return result;
}
catch (Exception e)
{
msg = e.Message;
return null;
}
}
}
public class Kernel32Helper
{
/// <summary>
/// API LoadLibrary
/// </summary>
[DllImport("kernel32")]
public static extern int LoadLibrary(string funcName);
/// <summary>
/// API GetProcAddress
/// </summary>
[DllImport("kernel32")]
public static extern int GetProcAddress(int handle, string funcName);
/// <summary>
/// API FreeLibrary
/// </summary>
[DllImport("kernel32")]
public static extern int FreeLibrary(int handle);
}
使用:
class Program
{
public delegate int DllRegisterHandler();
public delegate int DllUnregisterHandler();
static void Main(string[] args)
{
string msg = "";
string dllFunction = "DllRegisterServer";
string[] dllPathList = System.IO.Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory,"*.ocx", System.IO.SearchOption.TopDirectoryOnly);
if (dllPathList != null && dllPathList.Length > 0)
{
foreach (var dllPath in dllPathList)
{
object o = DynamicLoadDll.DynamicInvoke(dllPath, dllFunction, typeof(DllRegisterHandler), out msg);
if (o != null && (int)o >= 0)
{
Console.WriteLine(dllPath + "註冊成功!");
}
else
{
Console.WriteLine(dllPath + "註冊失敗" + msg);
}
}
}
Console.Read();
}
static string[] GetFiles(string pattern)
{
string dir = AppDomain.CurrentDomain.BaseDirectory;
return System.IO.Directory.GetFiles(dir, pattern, System.IO.SearchOption.TopDirectoryOnly);
}
}
上面的程式碼就是獲取程式目錄下的ocx檔案,然後註冊這些獲取到的ocx檔案, 需要注意的是:編譯的時候不能選擇Any CPU,要選擇x86,不然LoadLibrary會不成功!!這是用經驗走過的坑