非托管 DLL 的相对路径

Dee*_*mar 4 c# windows dll unmanaged

可能的重复:
在 .NET 中指定 DllImport 的搜索路径

我有一个非托管的 DLL。为了清除,它是我想在我的 c# 代码中使用的 C++ dll。问题是它是一个 Windows 应用程序,用户可以将它安装在他们选择的任何目录中。所以我不能用静态路径引用它,也找不到给出相对路径的方法。这是我试过的代码:

 [DllImport("mydll.dll", CharSet = CharSet.Auto, SetLastError = true)]
  static extern bool SetDllDirectory(string lpPathName);

  public void SetDllDirectory(string lpPathName)
        {
            try
            {
                bool r = SetDllDirectory(lpPathName);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void SetDirectoryPath()
        {
            try
            {
                DirectoryInfo directory = new DirectoryInfo(System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath));
                if (directory.Exists)
                    SetDllDirectory(directory.ToString() + "\\mydll.dll");

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
Run Code Online (Sandbox Code Playgroud)

下面是我收到的错误。

无法在 DLL“mydll.dll”中找到名为“SetDllDirectory”的入口点。

这个问题可能是复制品

C# 中的 C++ 非托管 DLL

平台调用语句中 DLL 的相对路径

抱歉,我在这些参考资料中没有找到任何解决方案。

Ian*_*ton 5

如果您尝试 pinvoke 到位于非标准位置的非托管库,则需要将此位置添加到 Windows 用于查找 dll 文件的 dll 搜索路径。

如果您的用户可以告诉程序 c/c++ 库文件在哪里,您可以在他们选择时手动加载它。

public class UnsafeNativeMethods {
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool SetDllDirectory(string lpPathName);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern int GetDllDirectory(int bufsize, StringBuilder buf);

    [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern IntPtr LoadLibrary(string librayName);

    [DllImport("mylibrary")]
    public static extern void InitMyLibrary();
}
Run Code Online (Sandbox Code Playgroud)

您可以以某种形式的预加载例程调用上述内容,如下所示:

public void LoadDllFile( string dllfolder, string libname ) {
    var currentpath = new StringBuilder(255);
    UnsafeNativeMethods.GetDllDirectory( currentpath.Length, currentpath );

    // use new path
    UnsafeNativeMethods.SetDllDirectory( dllfolder );

    UnsafeNativeMethods.LoadLibrary( libname );

    // restore old path
    UnsafeNativeMethods.SetDllDirectory( currentpath );
}
Run Code Online (Sandbox Code Playgroud)

然后你可以这样称呼它:

LoadDllFile( "c:\whatever", "mylibrary.dll" );
Run Code Online (Sandbox Code Playgroud)


Cod*_*ray 1

此错误消息:

无法在 DLL“mydll.dll”中找到名为“SetDllDirectory”的入口点。

没有提到找不到 DLL。它表示您的 P/Invoke 定义不正确。SetDllDirectory您的 DLL 中没有指定的函数( mydll.dll)。为什么会有?从 DLL 导出的唯一函数是您显式编码和导出的函数。由于您没有为 a 编写代码SetDllDirectory并指示应从 导出它mydll.dll,因此 DLL 中不存在它。

除此之外,除非您用真实的代码更新您的问题,否则这个问题是无法回答的。您至少需要发布您尝试从非托管 DLL 调用的函数的签名,以及您在 C#(托管)端尝试过的 P/Invoke 代码。

问题是它是一个 Windows 应用程序,用户可以将其安装在他们选择的任何目录中。所以我无法用静态路径引用它,也找不到给出相对路径的方法。

这不是一个真正的问题。相对路径工作得很好,并且它们的工作方式与您的问题表明您已经尝试过的方式完全相同。您只需在 P/Invoke 定义中包含 DLL 的名称即可。默认的 DLL 搜索顺序负责处理其他所有事情。如果托管 EXE 与您想要 P/Invoke 的非托管 DLL 位于同一目录中,则一切都将无缝运行。

用户选择将应用程序安装在哪里并不重要,只要 DLL 和 EXE 位于同一文件夹中即可。这就是安装人员的工作。

而且只要使用相对路径,就绝对不需要使用SetDllDirectoryWin32 API 中的函数(实际上是在 中定义的kernel32.dll)。