如何在运行时指定[DllImport]路径?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (19)

实际上,我得到了一个C ++(工作)DLL,我想将它导入到我的C#项目中以调用它的函数。

当我指定DLL的完整路径时,它确实有效,如下所示:

string str = "C:\\Users\\userName\\AppData\\Local\\myLibFolder\\myDLL.dll";
[DllImport(str, CallingConvention = CallingConvention.Cdecl)]
public static extern int DLLFunction(int Number1, int Number2);

问题在于它将会是一个可安装的项目,所以用户的文件夹将不会相同(例如:皮尔,保罗,杰克,妈妈,爸爸......),这取决于计算机/会话在哪里运行。

所以我希望我的代码更通用一些,如下所示:

/* 
goes right to the temp folder of the user 
    "C:\\Users\\userName\\AppData\\Local\\temp"
then go to parent folder
    "C:\\Users\\userName\\AppData\\Local"
and finally go to the DLL's folder
    "C:\\Users\\userName\\AppData\\Local\\temp\\myLibFolder"
*/

string str = Path.GetTempPath() + "..\\myLibFolder\\myDLL.dll"; 
[DllImport(str, CallingConvention = CallingConvention.Cdecl)]
public static extern int DLLFunction(int Number1, int Number2);

重要的是,“DllImport”需要DLL目录的“const string”参数。

所以我的问题是::在这种情况下可以做些什么?

提问于
用户回答回答于

我真的不明白为什么你不能像世界上其他人那样做,并指定一个对于你的DLL的路径。是的,安装应用程序的路径在不同的人计算机上有所不同,但在部署时这基本上是一个通用规则。该DllImport机制的设计考虑到了这一点。

事实上,它甚至DllImport没有处理它。

在系统搜索DLL之前,它会检查以下内容:

  • 如果具有相同模块名称的DLL已经加载到内存中,系统将使用加载的DLL,而不管它在哪个目录中。系统不搜索该DLL。
  • 如果该DLL位于正在运行该应用程序的Windows版本的已知DLL的列表中,则系统使用其已知DLL的副本(以及已知DLL的依赖DLL,如果有的话)。系统不搜索该DLL。

如果SafeDllSearchMode启用(默认),搜索顺序如下:

  1. 加载应用程序的目录。
  2. 系统目录。使用该GetSystemDirectory函数获取此目录的路径。
  3. 16位系统目录。没有获得该目录路径的函数,但是它被搜索。
  4. Windows目录。使用该GetWindowsDirectory函数获取此目录的路径。
  5. 当前目录。
  6. PATH环境变量中列出的目录。请注意,这不包括App Paths注册表项指定的每个应用程序路径。计算DLL搜索路径时不使用App Paths键。

所以,除非你命名DLL的​​方式与系统DLL相同(在任何情况下你都应该这样做),默认的搜索顺序将开始在加载应用程序的目录中查找。如果您在安装过程中将DLL放在那里,它会被找到。如果只使用相对路径,所有复杂的问题都会消失。

写吧:

[DllImport("MyAppDll.dll")] // relative path; just give the DLL's name
static extern bool MyGreatFunction(int myFirstParam, int mySecondParam);

但是,如果出于任何原因无法正常工作,并且您需要强制应用程序查看DLL的其他目录,则可以使用该SetDllDirectory函数修改默认搜索路径。 请注意,根据文档:

调用后SetDllDirectory,标准的DLL搜索路径是:

  1. 加载应用程序的目录。
  2. lpPathName参数指定的目录。
  3. 系统目录。使用该GetSystemDirectory函数获取此目录的路径。
  4. 16位系统目录。没有获得该目录路径的函数,但是它被搜索。
  5. Windows目录。使用该GetWindowsDirectory函数获取此目录的路径。
  6. PATH环境变量中列出的目录。

因此,只要您在第一次调用从DLL导入的函数之前调用此函数,就可以修改用于定位DLL的默认搜索路径。当然,好处是您可以将动态值传递给在运行时计算的此函数。这对于DllImport属性来说是不可能的,所以你仍然会在那里使用相对路径(仅限于DLL的名称),并依靠新的搜索顺序为你找到它。

你必须P /调用这个函数。声明如下所示:

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);
用户回答回答于

只需在调用DllImport函数之前调用LoadLibrary(只有没有路径的文件名),然后他们会自动使用加载的模块。

我使用这种方法在运行时选择是否加载32位或64位本地DLL,而无需修改一堆P / Invoke-d函数。将加载代码粘贴到具有导入函数的类型的静态构造函数中,它将一切正常。

扫码关注云+社区