实际上,我有一个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等),具体取决于运行该文件的计算机/会话。
所以我希望我的代码更加通用,例如:
/* 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属性仍然是正确的方法。
DllImport
老实说,我不明白为什么您不能像世界上其他所有人一样,并指定DLL 的 相对 路径。是的,在不同人的计算机上,应用程序的安装路径会有所不同,但这基本上是部署的通用规则。该DllImport机制的设计考虑到这一点。
实际上,它甚至DllImport无法解决问题。无论您是否使用方便的托管包装程序(P / Invoke marshaller只是调用LoadLibrary),它都是控制事情的本机Win32 DLL加载规则。这些规则在这里详细列出,但是重要的规则在这里摘录:
LoadLibrary
在系统搜索DLL之前,它会检查以下内容: 如果内存中已经加载了具有相同模块名称的DLL,则系统将使用已加载的DLL,无论它位于哪个目录中。系统都不会搜索该DLL。 * 如果该DLL在运行该应用程序的Windows版本的已知DLL列表中,则系统使用其已知DLL的副本(以及已知DLL的从属DLL,如果有的话)。系统不搜索DLL。 如果SafeDllSearchMode启用(默认),则搜索顺序如下: 从中加载应用程序的目录。 系统目录。使用该GetSystemDirectory函数获取此目录的路径。 16位系统目录。没有获取该目录路径的函数,但会对其进行搜索。 Windows目录。使用该GetWindowsDirectory函数获取此目录的路径。 当前目录。 6. PATH环境变量中列出的目录。请注意,这不包括“应用程序路径”注册表项指定的每个应用程序路径。计算DLL搜索路径时不使用“应用程序路径”键。
在系统搜索DLL之前,它会检查以下内容:
如果SafeDllSearchMode启用(默认),则搜索顺序如下:
SafeDllSearchMode
GetSystemDirectory
GetWindowsDirectory
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函数修改默认的搜索路径。 请注意,根据文档:
SetDllDirectory
调用后SetDllDirectory,标准DLL搜索路径为: 从中加载应用程序的目录。 lpPathName参数指定的目录。 系统目录。使用该GetSystemDirectory函数获取此目录的路径。 16位系统目录。没有获取该目录路径的函数,但会对其进行搜索。 Windows目录。使用该GetWindowsDirectory函数获取此目录的路径。 PATH环境变量中列出的目录。
调用后SetDllDirectory,标准DLL搜索路径为:
lpPathName
因此,只要您在第一次调用从DLL导入的函数之前调用此函数,就可以修改用于定位DLL的默认搜索路径。当然,这样做的好处是您可以将 动态 值传递给在运行时计算的该函数。使用DllImport属性是不可能的,因此您仍将在此处使用相对路径(仅DLL的名称),并依靠新的搜索顺序为您找到它。
您必须P /调用此功能。声明看起来像这样:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern bool SetDllDirectory(string lpPathName);