【问题标题】:Dynamic load c dll in C#在 C# 中动态加载 c dll
【发布时间】:2019-05-31 16:36:16
【问题描述】:

我有一个 c dll,想通过 C# 动态加载它。我是这样做的:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Dota2Plugins
{
    class Interop
    {
        #region Win API
        [DllImport("kernel32.dll")]
        private extern static IntPtr LoadLibrary(string lpLibFileName);

        [DllImport("kernel32.dll")]
        public extern static IntPtr GetProcAddress(IntPtr hLib, string lpProcName);

        [DllImport("kernel32.dll")]
        public extern static bool FreeLibrary(IntPtr hLib);
        #endregion

        private IntPtr hLib;

        public Interop(String DLLPath)
        {
            hLib = LoadLibrary(DLLPath);
            if (hLib == IntPtr.Zero)
            {
                throw new Exception("not found dll : " + DLLPath);
            }
        }

        ~Interop()
        {
            FreeLibrary(hLib);
        }

        public IntPtr GetIntPtr(string APIName)
        {
            IntPtr api = GetProcAddress(hLib, APIName);
            if (api == IntPtr.Zero)
            {
                throw new Exception("not found api : " + APIName);
            }

            return api;
        }

        public Delegate GetDelegate(string APIName, Type t)
        {
            IntPtr api = GetIntPtr(APIName);
            return Marshal.GetDelegateForFunctionPointer(api, t);
        }

    }
}

像这样加载 dll:

Interop interop = new Interop("KeyBoardHook.dll");`

但是当我运行我的应用程序时,它会抛出错误:

未找到 dll:KeyBoardHook.dll

我已将 dll 复制到应用程序目录。

我用相对论目录和绝对目录试了一下,得到了同样的错误结果。

如何在 C# 中动态加载 c DLL 并调用 DLL 导出 api ?

【问题讨论】:

  • application directory,这是exe所在的地方吗?
  • 欢迎来到本站。访问tour。您不想在 dll 中使用 DllImport 是否有特殊原因?
  • 是的,我确定 dll 文件目录是正确的。我已经解决了这个问题。谢谢!
  • 是的,我确定 dll 文件目录是正确的。我已经解决了这个问题。谢谢!

标签: c# c windows


【解决方案1】:

您提出了两个问题,第一,找不到 DLL,以及如何从 C 中进行动态加载。

  • 您是否确定要在与 DLL 相同的架构中编译项目?

这是尝试从 C# 32 位项目加载 X64 dll 时的常见问题。

  • 你有没有在构造函数public Interop(String DLLPath)开始时尝试过File.Exists?

也许您的应用程序目录不正确,正如 Stefan 在 cmets 中提到的那样。

也试试完整路径。


关于动态加载,这是另一个话题。必须在 DLL 中指定参数,理论上可以在运行时进行。

如果您有标头,您可以创建一个派生自 System.Dynamic.DynamicObject 的类并在运行时解析标头,覆盖 TryInvokeMember(一旦获得它,您就可以对其进行解析)。

虽然我不会使用这种方法。

恐怕如果没有标题,我不确定你如何动态地做到这一点。

【讨论】:

  • 我用的是C#64bit项目和X64 c dll,然后Load dll成功了,Thakns!
【解决方案2】:

我认为你的声明是错误的,据我所知你应该有:

[DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)]
private static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);

[DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FreeLibrary(IntPtr hModule);

我从http://pinvoke.net 拿走这些。

您面临的问题可能是由于默认情况下 C# 会将string 编组为BStr(长度前缀字符串)(documentation),但LoadLibrary 将解析为LoadLibraryA需要一个以 null 结尾的 ansi 字符串 (LPStr)。

您可能还对 Vanara.PInvoke.Kernel32(NuGetRepository)感兴趣,它连同它的配套库具有您可能需要的所有 Windows API 定义。

【讨论】:

  • 谢谢,这不是程序无法加载dll的原因。但它是找到dll函数入口的分辨率。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2011-09-06
  • 1970-01-01
  • 2010-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-03
  • 1970-01-01
相关资源
最近更新 更多