【问题标题】:LoadLibraryEx Function Probelem In C#C# 中的 LoadLibraryEx 函数问题
【发布时间】:2020-07-01 14:09:21
【问题描述】:

我尝试使用 LoadLibraryEx 函数加载xxx.dll。在 ASP.NET CORE Web - MVC 应用程序中。它可以返回正确的值。但在 ASP.NET Web - Web API 应用程序中。它返回0x00000000。但GetLastError() 返回0。这是我的演示代码

ASP.NET Web 中的代码 - Web API 应用程序

        [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" };
        }

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...";
        }

事实上。这两段代码基本一样。但是结果完全不同。所以。如果有人可以帮助我?

【问题讨论】:

  • 你为什么要在System.dll 上打电话给LoadLibrary?而且,您是否意识到您正在尝试将 .NET Core 版本的 System.dll 加载到 .NET Framework 应用程序中?
  • 这只是一个测试。它可以是任何其他 xxx.dll
  • 您通常不使用LoadLibrary 加载托管DLL,而是以正常方式调用它们。您通常也不使用 LoadLibrary 加载非托管 DLL,而是使用 P/Invoke 调用它们(就像您正在调用 LoadLibrary 一样)。为什么你认为你要打电话给LoadLibrary
  • 我只想加载指定的动态链接库。我只想知道为什么结果完全不同。所以你能解释一下吗

标签: c# asp.net


【解决方案1】:

这不是一个真正的“答案”,但它太复杂了,不能作为评论。

您永远不需要从托管代码调用LoadLibrary

DLL 可以通过三种方式加载到托管代码中:

  1. 您的程序有一个对托管程序集的引用(在 Solution Explorer 项目下的 References 部分中)
  2. 您从代码中调用 Assembly.Load(或其中一种变体),加载到托管程序集中
  3. 您使用 P/Invoke 加载非托管 DLL 并在其中执行一个函数(例如您如何在代码中加载 kernel32.dll 并调用 GetLastErrorLoadLibraryEx)李>

并且,为了完整起见(并根据@SeanSkelly 的建议),添加确实涉及LoadLibary(Ex) 的第四个选项,但有严格的限制。这绝对不是推荐的选项。

  1. 使用LoadLibary(Ex),但需要注意的是您必须完成P/Invoke 封送处理程序的大部分工作(并模仿其操作)。您也不能将其与托管 DLL because GetProcAddress will always fail on a managed assembly 一起使用。

我猜想为什么你在一种情况下取​​得了成功,而在另一种情况下却失败了。在一种情况下,您正在加载框架已经加载的同一个System.dll,因此它只返回一个已加载DLL 的句柄。另一方面,您正在加载不同版本的 System.dll。非托管加载程序不像Assembly.Load 那样理解版本控制和强名称,所以它说“嘿,我已经有一个System.dll 并且它不匹配,所以我没有满足您的要求”。但是,这只是猜测。

但是,没关系,你不需要这样做。

【讨论】:

  • 如果您的选项 3. 表示使用 DllImport“静态”加载非托管程序集,那么 技术上有一个选项 4. 使用 LoadLibrary/LoadLibraryEx “动态”在运行时加载 unmanaged 程序集。然后,您需要为该程序集中的函数指针动态创建委托。 (例如,参见here。)也就是说,我总体上同意你的观点——我会尝试设计一些东西,这样你就不必使用这样的选项。还同意 OP 不应使用选项 3. 或 4. 加载 托管 程序集,只能加载非托管程序集。
  • 您的答案大多是对称的:1. 对托管库的硬编码引用,2. 托管库的运行时加载,3. 对非托管库的硬编码引用,以及 4. 运行时加载非托管库。图 4. 值得包括在内。
  • @SeanSkelly:是的,但我没有说你不能使用 LoadLibrary(Ex),我说“你永远不需要调用它”。显然这是可能的(这就是 P/Invoke 和我假设 Assembly.Load 在幕后工作的方式)。自 2000 年秋季的 Alpha 版本以来,我一直在使用这些东西,但我从未见过需要使用它。
  • 同意 - 我也会避免使用 LoadLibrary(Ex) (正如我在第一条评论中所说)。我只是建议一种改进答案的方法,包括第四个选项(使用 LoadLibrary)并明确说明它应该用于什么,即动态加载 unmanaged 库,而不是托管库。在托管 DLL 上使用 LoadLibrary(Ex) 毫无意义,as you can't use GetProcAddress to get a function pointer from a managed library
  • 是的,你们都说得对。也许我不应该以 system.dll 为例。实际上。这是我程序中的另一个库。但我必须使用 LoadLibraryEx。我还测试了很多其他库。无论是托管还是非托管,结果都是一样的。有兴趣的可以测试一下
猜你喜欢
  • 1970-01-01
  • 2014-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-26
  • 1970-01-01
  • 2011-06-15
  • 1970-01-01
相关资源
最近更新 更多