在c#中动态加载和使用DLL

时间:2015-01-09 11:19:37

标签: c# .net dll

我想动态加载C#中的DLL,这样我就可以在执行时卸载它。我发现了一些文章,但没有人真正帮助我。我需要卸载DLL,因为它不提供释放/清理内存的任何功能。实际问题:它是一个硬件驱动程序(CAN-USB),如果硬件断开连接,我需要重启我的应用程序,这非常烦人。如果我可以将它加载到一个程序集(或类似的东西),我可以“卸载”分别“重新加载”它。我需要一个简短的,简约的,但相关的示例如何加载我的DLL以及如何导入和使用DLL函数。我附上了截图,我现在正在使用它们。

我需要总结的内容:

  1. 如何动态加载dll(附加类型)以及如何使用其功能的示例。

  2. 如何在硬件断开连接时取消/重新加载dll。

  3. 我很感激任何建议。

    dll functions

    编辑1: 我现在已经像this方法中描述的那样实现了它,但解决了我的问题。 CAN-USB硬件阻塞,直到我关闭我的应用程序并再次启动它。我做错了什么或有没有人有任何其他建议如何解决我的初始问题?

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    
    namespace InDiPro
    {
        public struct canData
        {
            public uint id;
            public uint length;
            public byte data0;
            public byte data1;
            public byte data2;
            public byte data3;
            public byte data4;
            public byte data5;
            public byte data6;
            public byte data7;
        }
    
        public class EsdCanDriver
        {
            private IntPtr pDll;
            private string dllPath;
    
            private IntPtr fptrCanOpen;
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
            private delegate int CanOpen(int net, int mode, int txqueueSize, int rxqueueSize, int txTimeout, int rxTimeout, ref int handle);
            private static CanOpen _canOpen;
            public int canOpen(int net, int mode, int txqueueSize, int rxqueueSize, int txTimeout, int rxTimeout, ref int handle)
            {
                return _canOpen(net, mode, txqueueSize, rxqueueSize, txTimeout, rxTimeout, ref handle);
            }
    
            private IntPtr fptrCanClose;
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
            private delegate int CanClose(int handle);
            private static CanClose _canClose;
            public int canClose(int handle)
            {
                return _canClose(handle);
            }
    
            private IntPtr fptrCanSetBaudrate;
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
            private delegate int CanSetBaudrate(int handle, int baudrate);
            private static CanSetBaudrate _canSetBaudrate;
            public int canSetBaudrate(int handle, int baudrate)
            {
                return _canSetBaudrate(handle, baudrate);
            }
    
            private IntPtr fptrCanGetBaudrate;
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
            private delegate int CanGetBaudrate(int handle, ref int baudrate);
            private static CanGetBaudrate _canGetBaudrate;
            public int canGetBaudrate(int handle, ref int baudrate)
            {
                return _canGetBaudrate(handle, ref baudrate);
            }
    
            private IntPtr fptrCanIdAdd;
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
            private delegate int CanIdAdd(int handle, int id);
            private static CanIdAdd _canIdAdd;
            public int canIdAdd(int handle, int id)
            {
                return _canIdAdd(handle, id);
            }
    
            private IntPtr fptrCanIdDelete;
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
            private delegate int CanIdDelete(int handle, int id);
            private static CanIdDelete _canIdDelete;
            public int canIdDelete(int handle, int id)
            {
                return _canIdDelete(handle, id);
            }
    
            private IntPtr fptrCanSend;
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
            private delegate int CanSend(int handle, ref canData msg, ref int length);
            private static CanSend _canSend;
            public int canSend(int handle, ref canData msg, ref int length)
            {
                return _canSend(handle, ref msg, ref length);
            }
    
            private IntPtr fptrCanTake;
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
            private delegate int CanTake(int handle, ref canData msg, ref int length);
            private static CanTake _canTake;
            public int canTake(int handle, ref canData msg, ref int length)
            {
                return _canTake(handle, ref msg, ref length);
            }
    
            private IntPtr fptrCanWrite;
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
            private delegate int CanWrite(int handle, ref canData msg, ref int length, ref int dummy);
            private static CanWrite _canWrite;
            public int canWrite(int handle, ref canData msg, ref int length, ref int dummy)
            {
                return _canWrite(handle, ref msg, ref length, ref dummy);
            }
    
            private IntPtr fptrCanRead;
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
            private delegate int CanRead(int handle, ref canData msg, ref int length, ref int dummy);
            private static CanRead _canRead;
            public int canRead(int handle, ref canData msg, ref int length, ref int dummy)
            {
                return _canRead(handle, ref msg, ref length, ref dummy);
            }
    
            public EsdCanDriver(string dllPath)
            {
                this.dllPath = dllPath;
            }
    
            public bool LoadDriver()
            {
                pDll = NativeMethods.LoadLibrary(this.dllPath);
                if(pDll == IntPtr.Zero)
                {
                    return false;
                }
                else
                {
                    fptrCanOpen = NativeMethods.GetProcAddress(pDll, "__canOpen@28");
                    if (fptrCanOpen == IntPtr.Zero) return false;
                    _canOpen = (CanOpen)Marshal.GetDelegateForFunctionPointer(fptrCanOpen, typeof(CanOpen));
    
                    fptrCanClose = NativeMethods.GetProcAddress(pDll, "__canClose@4");
                    if (fptrCanClose == IntPtr.Zero) return false;
                    _canClose = (CanClose)Marshal.GetDelegateForFunctionPointer(fptrCanClose, typeof(CanClose));
    
                    fptrCanSetBaudrate = NativeMethods.GetProcAddress(pDll, "__canSetBaudrate@8");
                    if (fptrCanSetBaudrate == IntPtr.Zero) return false;
                    _canSetBaudrate = (CanSetBaudrate)Marshal.GetDelegateForFunctionPointer(fptrCanSetBaudrate, typeof(CanSetBaudrate));
    
                    fptrCanGetBaudrate = NativeMethods.GetProcAddress(pDll, "__canGetBaudrate@8");
                    if (fptrCanGetBaudrate == IntPtr.Zero) return false;
                    _canGetBaudrate = (CanGetBaudrate)Marshal.GetDelegateForFunctionPointer(fptrCanGetBaudrate, typeof(CanGetBaudrate));
    
                    fptrCanIdAdd = NativeMethods.GetProcAddress(pDll, "__canIdAdd@8");
                    if (fptrCanIdAdd == IntPtr.Zero) return false;
                    _canIdAdd = (CanIdAdd)Marshal.GetDelegateForFunctionPointer(fptrCanIdAdd, typeof(CanIdAdd));
    
                    fptrCanIdDelete = NativeMethods.GetProcAddress(pDll, "__canIdDelete@8");
                    if (fptrCanIdDelete == IntPtr.Zero) return false;
                    _canIdDelete = (CanIdDelete)Marshal.GetDelegateForFunctionPointer(fptrCanIdDelete, typeof(CanIdDelete));
    
                    fptrCanSend = NativeMethods.GetProcAddress(pDll, "__canSend@12");
                    if (fptrCanSend == IntPtr.Zero) return false;
                    _canSend = (CanSend)Marshal.GetDelegateForFunctionPointer(fptrCanSend, typeof(CanSend));
    
                    fptrCanTake = NativeMethods.GetProcAddress(pDll, "__canTake@12");
                    if (fptrCanTake == IntPtr.Zero) return false;
                    _canTake = (CanTake)Marshal.GetDelegateForFunctionPointer(fptrCanTake, typeof(CanTake));
    
                    fptrCanWrite = NativeMethods.GetProcAddress(pDll, "__canWrite@16");
                    if (fptrCanWrite == IntPtr.Zero) return false;
                    _canWrite = (CanWrite)Marshal.GetDelegateForFunctionPointer(fptrCanWrite, typeof(CanWrite));
    
                    fptrCanRead = NativeMethods.GetProcAddress(pDll, "__canRead@16");
                    if (fptrCanRead == IntPtr.Zero) return false;
                    _canRead = (CanRead)Marshal.GetDelegateForFunctionPointer(fptrCanRead, typeof(CanRead));
    
                    return true;
                }         
            }
    
            public bool FreeDriver()
            {
                return NativeMethods.FreeLibrary(pDll);
            }
        }
    }
    

2 个答案:

答案 0 :(得分:2)

您正在使用DLLImport,因此您要从本机程序集导入函数,因此您需要使用将在本机语言中使用的相同函数:LoadLibrary,GetProcAddress,FreeLibrary。 这些函数执行以下任务:

  

LoadLibrary:将DLL加载到内存中并返回原始地址   DLL的句柄。如果找不到DLL,则返回IntPtr.Zero。

     

GetProcAddress:从DLL中按名称加载函数。返回原始   功能的地址。如果找不到该功能,则返回   IntPtr.Zero。

     

FreeLibrary:释放LoadLibrary加载的DLL   功能

使用LoadLibrary的一个例子可能是:

 IntPtr address = win32.GetProcAddress(m_dll, moduleName);
 System.Delegate fn_ptr = Marshal.GetDelegateForFunctionPointer(address, typeof(T));

虽然FreeLibrary的一个例子可能是:

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
static extern IntPtr GetModuleHandle(string moduleName); 
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
[return: MarshalAs(UnmanagedType.Bool)]  
static extern bool FreeLibrary(IntPtr hModule); 
// Unload the DLL by calling GetModuleHandle and FreeLibrary.  
FreeLibrary(GetModuleHandle(moduleName));

答案 1 :(得分:1)

你无法在.NET中真正卸载DLL。访问函数导入的样品瓶DllImport时,无法装入程序集和本机DLL。

但是,您可以删除应用程序域。因此,卸载DLL的常用方法是将其加载到单独的应用程序域中,然后在不再需要DLL时将其丢弃。

我实际上没有试过这个,但你可以尝试生成一个接口.NET DLL,它将DllImports作为一个类公开,然后将这个DLL加载到一个单独的应用领域。如果您释放域,理论上也应该卸载本机DLL。


当然,另一种方法可能是使用LoadLibraryFreeLibrary加载/卸载DLL,但我不知道如何访问DLL函数。