gpt4 book ai didi

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

转载 作者:IT老高 更新时间:2023-10-28 11:34:16 29 4
gpt4 key购买 nike

事实上,我有一个 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);

问题在于它将是一个可安装的项目,因此用户的文件夹将不一样(例如:pierre、paul、jack、mum、dad...),具体取决于运行它的计算机/ session 开。

所以我希望我的代码更通用一点,像这样:

/* 
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”参数。

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

最佳答案

与其他一些答案的建议相反,使用 DllImport 属性仍然是正确的方法。

老实说,我不明白为什么你不能像世界上其他人一样为你的 DLL 指定一个相对路径。是的,您的应用程序在不同人的计算机上的安装路径不同,但这基本上是部署时的通用规则。 DllImport 机制就是考虑到这一点而设计的。

事实上,处理它的甚至不是 DllImport。无论您是否使用方便的托管包装器(P/Invoke marshaller 只需调用 LoadLibrary),它都是 native Win32 DLL 加载规则来管理事物。这些规则被详细列举了here ,但重要的摘录在这里:

Before the system searches for a DLL, it checks the following:

  • If a DLL with the same module name is already loaded in memory, the system uses the loaded DLL, no matter which directory it is in. The system does not search for the DLL.
  • If the DLL is on the list of known DLLs for the version of Windows on which the application is running, the system uses its copy of the known DLL (and the known DLL's dependent DLLs, if any). The system does not search for the DLL.

If SafeDllSearchMode is enabled (the default), the search order is as follows:

  1. The directory from which the application loaded.
  2. The system directory. Use the GetSystemDirectory function to get the path of this directory.
  3. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
  4. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  5. The current directory.
  6. The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.

因此,除非您将 DLL 命名为与系统 DLL 相同的名称(在任何情况下您显然都不应该这样做),否则默认搜索顺序将从您的应用程序所在的目录开始查找加载。如果您在安装过程中将 DLL 放在那里,它将被找到。如果只使用相对路径,所有复杂的问题都会迎刃而解。

只写:

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

但是,如果 由于某种原因不起作用,并且您需要强制应用程序在不同的目录中查找 DLL,您可以使用 SetDllDirectory function 修改默认搜索路径.
请注意,根据文档:

After calling SetDllDirectory, the standard DLL search path is:

  1. The directory from which the application loaded.
  2. The directory specified by the lpPathName parameter.
  3. The system directory. Use the GetSystemDirectory function to get the path of this directory.
  4. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable.

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

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

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

关于c# - 如何在运行时指定 [DllImport] 路径?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8836093/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com