1. 程式人生 > >C# 使用程式碼實現非託管dll、OCX動態註冊

C# 使用程式碼實現非託管dll、OCX動態註冊

一般我們註冊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會不成功!!這是用經驗走過的坑