我有一个DLL,我需要从中访问方法。
在大多数情况下,我只是使用[DllImport]来访问非托管程序集中的方法,但在这种情况下的问题是它需要在实例化时获取DLL的路径,所以是一个常量字符串。
这个特殊的DLL是随我的应用程序安装的那个,我不能保证在安装程序之后它会在哪里(我宁愿不把它放在像%SystemRoot%这样的静态的地方)。
在C#中有一种方法可以在运行时使用变量路径声明并使用DLL中的方法吗?
非常感谢任何想法或建议!
答案 0 :(得分:2)
根本不要使用路径。当尝试动态或静态地从中加载函数时,Windows使用搜索DLL的默认方法。
MSDN在LoadLibrary的文档中记录了确切的搜索逻辑 - 基本上,如果您的应用程序刚刚使用了DLL,请在安装过程中将其放在与应用程序相同的文件夹中,不要担心它。如果它是一个常用的DLL,将它放在LoadLibrary()搜索的文件夹结构中的某个地方,它就会被找到。
答案 1 :(得分:2)
这有点骇客,但是既然你说你可以在运行时找到dll的路径,为什么不在使用任何函数之前将它复制到当前的工作目录?这样,dll将存在于你的exe旁边,并将由LoadLibrary找到。您的DllImport中无需任何其他路径。
从动态路径使用方法的唯一方法是执行此操作:
1)为LoadLibrary&进行必要的P / Invoke签名。 GetProcAddress
2)从所需路径(LoadLibrary)加载库
3)找到所需的功能(GetProcAddress)
4)将指针投射到代表Marshal.GetDelegateForFunctionPointer
5)调用它。
当然,您需要以这种方式为每个要“导入”的函数声明一个委托,因为您必须将指针强制转换为委托。
答案 2 :(得分:0)
我有类似的情况。我使用安装在计算机上的SDK中的DLL。我从该SDKs注册表项获取DLL的目录位置。我在执行用户PATH变量上设置DLL位置(仅临时修改)。基本上它允许您为要调用的DLL设置动态路径,因此它不必来自注册表。请注意,PATH var是Windows查找DLL的最后一个位置。但另一方面,它并没有改变Windows寻找DLL的其他地方。
示例:
我想在DLL上调用API:
[DllImport("My.DLL")]
private static extern IntPtr ApiCall(int param);
获取注册表项(您需要使用Microsoft.Win32; ):
private static string GetRegistryKeyPath() {
string environmentPath = null;
using (var rk = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\SOMENNAME"))
{
if (rk != null)
{
environmentPath = rk.GetValue("Path(or whatever your key is)").ToString();
}
if (string.IsNullOrEmpty(environmentPath))
{
Log.Warn(
string.Format("Path not found in Windows registry, using key: {0}. Will default to {1}",
@"SOFTWARE\SOMETHING", @"C:\DefaultPath"));
environmentPath = @"C:\DefaultPath";
}
}
return environmentPath;
}
在PATH var上添加DLL的路径(在Linq中找到Concat()):
void UpdatePath(IEnumerable<string> paths){
var path = new[] { Environment.GetEnvironmentVariable("PATH") ?? "" };
path = path.Concat(paths);
string modified = string.Join(Path.PathSeparator.ToString(), path);
Environment.SetEnvironmentVariable("PATH", modified);
}
开始使用API调用:
var sdkPathToAdd = GetRegistryKeyPath();
IList<string> paths = new List<string>
{
Path.Combine(sdkPathToAdd),
Path.Combine("c:\anotherPath")
};
UpdatePath(paths);
//Start using
ApiCall(int numberOfEyes);