使用非静态路径从DLL调用函数

时间:2009-04-10 19:06:13

标签: c# .net dll interop runtime

我有一个DLL,我需要从中访问方法。

在大多数情况下,我只是使用[DllImport]来访问非托管程序集中的方法,但在这种情况下的问题是它需要在实例化时获取DLL的路径,所以是一个常量字符串。

这个特殊的DLL是随我的应用程序安装的那个,我不能保证在安装程序之后它会在哪里(我宁愿不把它放在像%SystemRoot%这样的静态的地方)。

在C#中有一种方法可以在运行时使用变量路径声明并使用DLL中的方法吗?

非常感谢任何想法或建议!

3 个答案:

答案 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);