Dynamically loading and using DLLs in C #

I want to load a DLL in C # dynamically so that I can unload it at runtime. I found several articles but none helped me. I need to unload the DLL because it doesn't provide any functionality to release / clean up memory. Actual Problem: Its a hardware driver (CAN-USB) and I need to restart my application if the hardware goes down, which is very annoying. If I could load it into an assembly (or something like that), I could "unload" accordingly, "reload" it. I need a short and minimalistic but related example on how to load my dll and how to import and use the dll functions. I have attached a screenshot of how I am using them now.

What I need to summarize:

  • An example of how to dynamically load a dll (nested type) and how to use its functions.

  • How to disable / reload DLL in case of hardware failure.

Any suggestions would be appreciated.

dll functions

EDIT 1: I have now implemented it as described in this one , but it doesn't solve my problem. CAN-USB-Hardware blocks until I close the application and start it again. Did I do something wrong, or does anyone have any other suggestions on how to solve my original problem?

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);
        }
    }
}

      

+3


source to share


2 answers


You are using DLLImport, so you are importing a function from your own assembly, so you need to use the same function that you would use in native languages: LoadLibrary, GetProcAddress, FreeLibrary. These functions perform the following tasks:

LoadLibrary: Loads a DLL into memory and returns the unhandled address of the DLL being processed. Returns IntPtr.Zero if the DLL cannot be found.

GetProcAddress: Loads a function by name from a DLL. Returns the raw address of the function. If the function is not found, IntPtr.Zero is returned.

FreeLibrary: Frees the DLL loaded by the LoadLibrary function.

An example of using LoadLibrary would be:



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

      

Whereas a FreeLibrary example might be:

[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));

      

+2


source


You really can't unload DLLs in .NET. Neither an assembly nor a native DLL that is loaded when accessing the imported vial function DllImport

.

However, you can delete application domains. Thus, the usual way to unload a DLL is to load it into a separate application domain and then remove it if the DLL is no longer needed.

I haven't actually tried this, but you can try to create a .NET DLL interface that exposes DllImports

as a class and then loads that DLL into a separate application domain. If you free the domain for free, in theory, you also need to unload your own DLL.




Of course, another way could be to use LoadLibrary

it FreeLibrary

to load / unload the DLL as well, but I don't know how to access the DLL functions.

+1


source







All Articles