[C#] 托管、非托管DLL、动态加载/卸载,各名词备忘

发布时间 2023-07-07 17:06:25作者: sssfffsssfff

托管DLL:由C#平台编译生成的库文件,使用方法(1.VS2015中添加引用 2.使用代码动态加载卸载)

非托管DLL:由其他平台(通常为C++)编译生成的库文件,使用方法(1.使用代码静态加载 2.使用代码动态加载。均不能直接添加引用)


 

以如下托管DLL代码为例:

托管DLL动态加载:

            private MethodInfo read_port = null;
            private MethodInfo write_port = null;
            private object instance = null;
            public void Load(string DllPath)
            {
                if (null == instance)
                {
                    Assembly assembly = System.Reflection.Assembly.LoadFile(DllPath);

                    // 获取类型, 传入函数所属namespace和class 
                    Type type = assembly.GetType("LaserHG.HelpHGApi");//与DLL工程保持一致

                    // 创建对象实例,传入函数所属namespace和class   
                    instance = assembly.CreateInstance("LaserHG.HelpHGApi");//与DLL工程保持一致

                    // 传参调用   
                    Type[] paramsTypes = new Type[1];
                    paramsTypes[0] = Type.GetType("System.Int32").MakeByRefType();//与DLL工程保持一致

                    //获取方法   
                    read_port = type.GetMethod("lmc1_ReadPort", paramsTypes);
                    write_port = type.GetMethod("Lmc1_WritePort", paramsTypes);

                    //执行方法
                    Object[] paramsValue = new Object[1] { DateTime.Now.Second };//与DLL工程保持一致
                    res = read_port.Invoke(instance, paramsValue);

                }
            }

托管DLL动态卸载:(需要使用程序集概念,即不能直接卸载DLL,需要卸载程序集)

    public class Test
    {
        private const string appDomainName = "TestSome";
        private AppDomain appDomain = null;
        private ApplicationProxy proxy = null;

        public Test()
        {
            appDomain = AppDomain.CreateDomain(appDomainName);
        }

        private class ApplicationProxy : MarshalByRefObject
        {
            private MethodInfo read_port = null;
            private MethodInfo write_port = null;
            private object instance = null;
            public void Load(string DllPath)
            {
                //load dll
            }
        }

        public void Load(string DllPath)
        {
            proxy = appDomain.CreateInstanceAndUnwrap(Assembly.GetAssembly(typeof(ApplicationProxy)).FullName,
               typeof(ApplicationProxy).ToString()) as ApplicationProxy;
            proxy.Load(DllPath);
        }
        public void Unloaded()
        {
            if (null != appDomain)
            {
                AppDomain.Unload(appDomain);
            }
        }
    }

 

非托管DLL静态加载:加载目标DLL中的GetPrivateProfileString方法

        [DllImport("kernel32.dll")]
        private static extern int GetPrivateProfileString(
            string section,
            string key,
            string defval,
            StringBuilder retval,
            int size,
            string filepath);

 

非托管DLL动态加载:加载目标DLL中的InitialMachine方法

    public class Test
    {
        [DllImport("kernel32.dll")]
        private extern static IntPtr LoadLibrary(String path);

        [DllImport("kernel32.dll")]
        private extern static IntPtr GetProcAddress(IntPtr lib, String funcName);

        [DllImport("kernel32.dll")]
        private extern static bool FreeLibrary(IntPtr lib);

        private readonly IntPtr hLib;

        public Test(string filepath)
        {
            if (hLib == null || hLib == (IntPtr)0)
            {
                hLib = LoadLibrary(filepath);
            }
            if (hLib != (IntPtr)0)
            {
                m_InitialMachine = Invoke<Type_InitialMachine>("InitialMachine");
            }
        }

        ~Test()
        {
            if (hLib != null) FreeLibrary(hLib);
        }

        //将要执行的函数转换为委托
        public T Invoke<T>(String APIName)
        {
            IntPtr api = GetProcAddress(hLib, APIName);
            var de = Marshal.GetDelegateForFunctionPointer(api, typeof(T));
            return (T)Convert.ChangeType(de, typeof(T));
        }

        /// <summary>
        /// 初始化控制系统
        /// </summary>
        public delegate int Type_InitialMachine(string HansProgramPath);
        public Type_InitialMachine m_InitialMachine;
    }

 

File.Exist("*.dll")结果为false问题:

            var ex1 = System.IO.File.Exists($@"{root}\self.dll");//返回false
            foreach(string file in System.IO.Directory.EnumerateFiles(root))
            {
                if (file.EndsWith("self.dll"))
                  ex1 = System.IO.File.Exists("file");//返回true
            }

            //DLL未卸载时,File操作会占用,抛出报错
            //DLL已卸载时,File操作正常结束,但实际可能操作失败,这里通过循环判定,确认是否操作成功
            for (int i = 0; i < 10; i++)
            {
                if (File.Exists(bak_dll)) File.Delete(bak_dll);
                File.Move(now_dll, bak_dll);
                if (!File.Exists(now_dll))
                    break;
                System.Threading.Thread.Sleep(500);
            }