代码之家  ›  专栏  ›  技术社区  ›  Mel Green

从具有非静态路径的dll调用函数

  •  1
  • Mel Green  · 技术社区  · 15 年前

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

    在大多数情况下,我只使用[dllimport]从非托管程序集访问方法,但在这种情况下,问题在于它需要在实例化时指向dll的路径,因此是一个常量字符串。

    这个特定的dll是随我的应用程序一起安装的,我不能保证在安装程序之后它会在哪里(我宁愿不把它放在像%systemroot%这样的静态位置)。

    那么,在C中有没有一种方法可以在运行时用变量路径声明和使用来自dll的方法?

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

    3 回复  |  直到 15 年前
        1
  •  2
  •   Erich Mirabal    15 年前

    这有点黑客行为,但是既然你说你可以在运行时找到dll的路径,为什么不在使用任何函数之前把它复制到你当前的工作目录中呢?这样,该dll将存在于您的exe旁边,并由LoadLibrary找到。您的dllimport中不需要任何其他路径。

    使用动态路径中的方法的唯一其他方法是:
    1)执行必要的P/Invoke签名 LoadLibrary 和; GetProcAddress
    2)从所需路径加载库(LoadLibrary)
    3)查找所需的函数(getprocaddress)
    4)将指针强制转换为委托 Marshal.GetDelegateForFunctionPointer
    5)调用它。

    当然,您需要为每个要“导入”的函数声明一个委托,因为您必须将指针强制转换为委托。

        2
  •  2
  •   Ken White    15 年前

    不要使用任何路径。当试图动态或静态加载函数时,Windows使用默认的方法来搜索DLL。

    精确的搜索逻辑在msdn文档中记录 LoadLibrary -基本上,如果应用程序刚刚使用了DLL,请在安装期间将其放在与应用程序相同的文件夹中,不要担心。如果它是一个常用的dll,把它放在loadLibrary()搜索的文件夹结构中,它就会被找到。

        3
  •  0
  •   Hersker    9 年前

    我也有类似的情况。我使用安装在计算机上的SDK中的DLL。我从该sdks注册表项获取DLL的目录位置。我在执行用户路径变量上设置了dll位置(仅临时修改)。基本上,它允许您为要调用的dll设置一个动态路径,因此它不必来自注册表。请注意,path var是Windows查找DLL的最后一个位置。但另一方面,它不会改变Windows查找DLL的其他位置。

    例子:

    我要调用的API,在dll上:

    [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的路径(concat()在linq中找到):

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