0

I try to use LoadLibraryEx Function to load a xxx.dll. In ASP.NET CORE Web - MVC application. It can return a right value. But in a ASP.NET Web - Web API application. It return 0x00000000.But GetLastError() return 0. Here is my demo code

CODE IN ASP.NET Web - Web API application

        [DllImport("kernel32.dll")]
        static extern uint GetLastError();
        [DllImport("kernel32.dll", EntryPoint = "LoadLibraryEx", SetLastError = true)]
        private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);

        private static uint LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008;

        private static void LoadWin32Library(string libPath)
        {
            IntPtr moduleHandle = LoadLibraryEx(libPath, IntPtr.Zero, LOAD_WITH_ALTERED_SEARCH_PATH);
            uint code = GetLastError();
            Console.WriteLine(code);
            Console.WriteLine(moduleHandle);
            if (moduleHandle == IntPtr.Zero)
                throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        // GET api/values
        public IEnumerable<string> Get()
        {
            String lpFileName = "C:\\Program Files\\dotnet\\shared\\Microsoft.NETCore.App\\2.1.11\\System.dll";
            LoadWin32Library(lpFileName);
            return new string[] { "value1", "value2" };
        }

CODE IN ASP.NET CORE Web - MVC

        [DllImport("kernel32.dll")]
        static extern uint GetLastError();
        [DllImport("kernel32.dll", EntryPoint = "LoadLibraryEx", SetLastError = true)]
        private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);

        private static uint LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008;

        private static void LoadWin32Library(string libPath)
        {
            IntPtr moduleHandle = LoadLibraryEx(libPath, IntPtr.Zero, LOAD_WITH_ALTERED_SEARCH_PATH);
            uint code = GetLastError();
            Console.WriteLine(code);
            Console.WriteLine(moduleHandle);
            if (moduleHandle == IntPtr.Zero)
                throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        public string Index()
        {
            String lpFileName = "C:\\Program Files\\dotnet\\shared\\Microsoft.NETCore.App\\2.1.11\\System.dll";
            LoadWin32Library(lpFileName);
            return "This is my default action...";
        }

In fact. These two pieces of code are basically the same.But the results are completely different.So. If anybody can help me?

  • Why are you calling `LoadLibrary` on `System.dll`? And, do you realize you are trying to load the .NET Core version of `System.dll` into a .NET Framework app? – Flydog57 Jul 01 '20 at 14:14
  • It's just a test. It can be any other xxx.dll – Jermine Jul 01 '20 at 14:16
  • You generally don't use `LoadLibrary` to load managed DLLs, you call into them the normal way. You also generally don't use `LoadLibrary` to load non-managed DLLs either, you use P/Invoke to call into them (like you are doing to call `LoadLibrary`). Why do you think you want to call `LoadLibrary` – Flydog57 Jul 01 '20 at 14:19
  • I just want to loads the specified dynamic link library. and I only want to konw why the results are completely different.So could you explain that – Jermine Jul 01 '20 at 14:24

1 Answers1

0

This isn't really an "answer" but it's too involved to be a comment.

You should never need to call LoadLibrary from managed code

There are three ways DLLs can get loaded into managed code:

  1. Your program has a referenced to a managed assembly (in the References section under the project in Solution Explorer)
  2. You call Assembly.Load (or one of the variants) from your code, loading in a managed assembly
  3. You use P/Invoke to load an unmanaged DLL and execute a function within it (like how you are loading kernel32.dll and calling GetLastError or LoadLibraryEx in your code)

And, for completeness (and on the advice of @SeanSkelly), adding a fourth option that does involve LoadLibary(Ex), but with severe restrictions. This is definitely not a recommended option.

  1. Use LoadLibary(Ex), but with the caveat that you have to do much of the work of (and mimic the actions of) the P/Invoke marshaler. You also can't use this with a managed DLL because GetProcAddress will always fail on a managed assembly.

I have a guess as to why you are getting success in one case and a failure in the other. In one case, you are loading in the same System.dll that the framework has already loaded, so it just returns a handle to the loaded DLL. In the other, you are loading a different version of System.dll. The unmanaged loader doesn't understand versioning and strong names the way Assembly.Load does, so it says "hey, I already have a System.dll and it doesn't match up, so I'm failing your request". But, this is just a guess.

But, it doesn't really matter, you don't need to do this.

Flydog57
  • 6,851
  • 2
  • 17
  • 18
  • If your option 3. represents using `DllImport` to "statically" load an unmanaged assembly, then there is _technically_ an option 4. using LoadLibrary/LoadLibraryEx to "dynamically" load an _unmanaged_ assembly at runtime. You then need to dynamically create a delegate for a function pointer in that assembly. (See [here](https://stackoverflow.com/a/2818948/3791245) for an example.) That said, I agree with you overall - I would try to design things so you don't have to use an option like this. Also agree that OP should not use option 3. or 4. to load _managed_ assemblies, only unmanaged ones. – Sean Skelly Jul 01 '20 at 20:15
  • Mostly there's a symmetry in your answer: 1. Hard-coded reference to managed library, 2. Runtime loading of managed library, 3. Hard-coded reference to unmanaged library, and 4. Runtime loading of unmanaged library. Figured 4. was worth including. – Sean Skelly Jul 01 '20 at 20:20
  • @SeanSkelly: Right, but I didn't say you couldn't use LoadLibrary(Ex), I said "You should never need to call it". Obviously it's possible (that's how P/Invoke and I'm assuming Assembly.Load work under the covers). I've been working with this stuff since the Alpha versio in the fall of 2000 and I've never seen a need to use it. – Flydog57 Jul 01 '20 at 20:32
  • Agreed - I would avoid using LoadLibrary(Ex) too (as I said in the first comment). I'm just suggesting a way to improve the answer, by including the fourth option (using LoadLibrary) and explicitly saying what it should be used for, which is dynamically loading _unmanaged_ libraries, not managed ones. Using LoadLibrary(Ex) on a managed DLL is pointless, [as you can't use GetProcAddress to get a function pointer from a managed library](https://stackoverflow.com/a/11426390/3791245). – Sean Skelly Jul 01 '20 at 21:54
  • Yeah,you're both right. Maybe I shouldn't use system.dll as an example. In fact. It's another library in my program. But I have to use LoadLibraryEx. I also tested a lot of other libraries. The result is the same whether it is managed or unmanaged.You can test it out if you're interested – Jermine Jul 02 '20 at 00:50