在C#中动态加载C dll

时间:2019-01-05 08:17:23

标签: c# c windows

我有一个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 =新的Interop(“ KeyBoardHook.dll”);`

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

  

未找到dll:KeyBoardHook.dll

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

我使用相对目录和绝对目录进行尝试,并得到相同的错误结果。

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

2 个答案:

答案 0 :(得分:1)

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

  • 您确定要在与DLL相同的体系结构中编译项目吗?

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

  • 您是否在构造器public Interop(String DLLPath)开始时尝试过File.Exists?

也许您的应用程序目录不正确,如Stefan在评论中所述。

也尝试完整路径。


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

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

我不会使用这种方法。

恐怕我不确定如何在没有标题的情况下动态地进行操作。

答案 1 :(得分:0)

我相信您的声明是错误的,据我所知您应该:

[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),但是将{{1} }将解析为LoadLibraryA,它期望以null结尾的ansi字符串(LoadLibrary)。

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