What is better to do from the very beginning, check whether the module is loaded into the memory of the process, or try to load it, catch the error via GetLastError , check its value, and if the library is already loaded, call GetModuleHandle , or do the opposite?

Those. something like this, but not only check for IntPtr.Zero but also check LastError for a match with the error code ( I don’t know the number of the error code, therefore there is no such verification )?

Although if the module was loaded, then LoadLibrary returns it to Handle and does not throw an error, which is strange.

 internal static class WinApi { internal static bool FreeLibrary(IntPtr moduleHandle) { return FreeLibraryEx(moduleHandle); } internal static TDelegateType GetProcDelegate<TDelegateType>(IntPtr moduleHandle, string procName) where TDelegateType : Delegate { return Marshal.GetDelegateForFunctionPointer<TDelegateType>(GetProcAddressEx(moduleHandle, procName)); } internal static SafeLibrary LoadLibrary(string modulePath) { IntPtr result = LoadLibraryEx(modulePath); if (result == IntPtr.Zero && (result = GetModuleHandleEx(Path.GetFileName(modulePath))) == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } return result; } #region Private native Methods [DllImport(Libraries.Kernel32, SetLastError = true, EntryPoint = "LoadLibrary", CallingConvention = CallingConvention.Winapi)] private static extern IntPtr LoadLibraryEx(string modulePath); [DllImport(Libraries.Kernel32, CallingConvention = CallingConvention.Winapi, EntryPoint = "FreeLibrary", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool FreeLibraryEx(IntPtr moduleHandle); [DllImport(Libraries.Kernel32, CallingConvention = CallingConvention.Winapi, EntryPoint = "GetProcAddress", CharSet = CharSet.Ansi, SetLastError = true)] private static extern IntPtr GetProcAddressEx(IntPtr moduleHandle, string procedureName); [DllImport(Libraries.Kernel32, CallingConvention = CallingConvention.Winapi, SetLastError = true, EntryPoint = "GetModuleHandle")] private static extern IntPtr GetModuleHandleEx(string moduleName); #endregion } 

    2 answers 2

    In the case of using the DllImport attribute and the extern modifier for the function being called from an external module, the need for the checks you specify is zero, but if you are going to call methods using delegates, then it is better to implement the SafeLibraryHandle class in your code in the same way as in the .NET platform itself Framework . As a result, you can check whether the module was loaded or not using the IsInvalid property. To make it clearer:

     using System; using System.Security; using Microsoft.Win32.SafeHandles; using System.Runtime.InteropServices; namespace SafeLibrary { [SecurityCritical] internal sealed class SafeLibraryHandle : SafeHandleZeroOrMinusOneIsInvalid { internal SafeLibraryHandle() : base(true) {} [SecurityCritical] override protected Boolean ReleaseHandle() { return NativeMethods.FreeLibrary(handle); } } internal static class NativeMethods { [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] internal static extern SafeLibraryHandle LoadLibrary(String lpLibFileName); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern Boolean FreeLibrary(IntPtr hLibModule); } internal sealed class Program { static void Main() { SafeLibraryHandle slh = NativeMethods.LoadLibrary("some.dll"); if (slh.IsInvalid) { Console.WriteLine("IsInvalid: {0} IsClosed: {1}", slh.IsInvalid, slh.IsClosed); // return; } slh.Dispose(); Console.WriteLine("IsInvalid: {0} IsClosed: {1}", slh.IsInvalid, slh.IsClosed); } } } 
    • How does the caste, or marshalling from IntPtr to SafeLibraryHandle ? - LLENN 5:56 pm
    • @LLENN, pick up ILDasm , open mscorlib.dll and go ahead to SafeHandleZeroOrMinusOneIsInvalid . Well, or you can just look at the source .NET to trace the entire chain. - greg zakharov

    Although if the module was loaded, then LoadLibrary returns it to Handle and does not throw an error, which is strange

    In fact, there is nothing strange about it. Loading DLL in Windows is designed so that two pieces of code in the same process can independently use the same library. When you call LoadLibrary and the library is already loaded, it does not just return the descriptor, but also increases the reference count for this library. A subsequent call to FreeLibrary will not immediately unload the library, but will decrease the reference count, and unload it only when the reference count reaches zero. About some "error code" in this case, there is no talk, it is absolutely normal situation.

    With the usual use of LoadLibrary / GetProcAddress functions, there is no particular need to think about whether the library is already loaded or not. If you need to check whether the library is loaded (for example, for debugging purposes), the GetModuleHandle function is suitable: it returns NULL for an unloaded module and GetLastError will be 0x0000007E (ERROR_MOD_NOT_FOUND).