【问题标题】:Adding a directory temporarily to Windows 7's DLL search paths将目录临时添加到 Windows 7 的 DLL 搜索路径
【发布时间】:2011-03-01 05:05:57
【问题描述】:

我想暂时在 DLL 搜索路径中添加一个目录 - 在 Windows 7 下是否有正确的方法来执行此操作?

场景

我有一个 C# 应用程序,我们称之为 WonderApp。

WonderApp 需要调用位于 C:\MyPath 的 C++ DLL。所以作为 WonderApp 的Program.Main() 的一部分,我添加了以下命令:

Environment.SetEnvironmentVariable("PATH",
   "C:\\MyPath;" + Environment.GetEnvironmentVariable("PATH"));

根据this article,将目录添加到PATH 也应该将其添加到搜索DLL 的目录中。

该解决方案在 Windows XP 中运行良好:如果我将目录添加到 PATH,DLL 加载并且程序运行正常。如果我不添加目录,则 DLL 不会加载,失败并出现“未找到”错误。

但是,这不适用于 Windows 7。

所以我想,让我们尝试使用SetDllDirectory()。像这样:

[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetDllDirectory(string lpPathName);

然后,以后:

 bool success = SetDllDirectory(Util.Paths.GetApplicationDataDir());

success 的值为true,但 DLL 仍然无法加载。

最后,如果我在运行应用程序之前手动将PATH 设置为包含C:\MyPath - 一切正常! DLL 加载并运行良好。

所以,重新迭代:

有没有正确的方法临时在Windows 7下的DLL搜索路径中添加目录?

更新:使用 Process Explorer,我检查了应用程序的运行时环境,“C:\MyPath”确实在 PATH!此外,我看到Helper.dll 在打开的句柄列表中(作为一个 DLL,而不仅仅是一个文件)——它仍然声称找不到它。

【问题讨论】:

  • 这是 64 位版本的 Windows 吗?真正的路径名是什么?
  • 这是 32 位 Windows 7 家庭版。 DLL 的完整路径是 C:\MyPath\Helper.dll
  • 可能缺少其他 dll 尝试在程序 "depends.exe" 中加载 helper.dll 并检查其他 dll 的依赖关系。
  • 这并不能解释为什么在运行应用程序之前将目录添加到 PATH 可以让 DLL 加载。
  • 嗯,...我使用的是 Win 7 x64,我也在做同样的事情(在特定目录中为 DllImport 设置 PATH)并且效果很好。

标签: c# windows-7 dllimport


【解决方案1】:

您可以使用“AssemblyResolve”事件将自定义 DLL 加载逻辑添加到 C# 应用程序。

这个页面有很好的总结,有代码示例:http://support.microsoft.com/kb/837908

正如您所做的那样,我发现更改正在运行的 C# 应用程序的 PATH 环境变量不会影响 DLL 搜索行为。也许 AppDomain 在启动时缓存 PATH 值?您可以使用 AssemblyResolve 事件来解决此问题。

另见How to add folder to assembly search path at runtime in .NET?

【讨论】:

  • 太棒了!!!非常感谢你让我知道!这听起来像是适用于任何 .NET 程序集,但我还需要针对非 .NET DLL 进行测试。
  • 好的,坏消息:它仅适用于 .NET 程序集。考虑到它的名字,这完全有道理。这是一个很棒的解决方案,但我不能使用它,因为我需要加载的 DLL 不是 .NET 程序集。 (更糟糕的是,这些 DLL 还需要加载与它们位于同一目录中的其他 DLL,因此我也需要找到一种方法让它们在那里搜索)。
【解决方案2】:

我的解决方案很简单,但我觉得很可笑。

我编写了另一个程序集“Shell”,它可以修改环境、运行 WonderApp 并退出。

通过在运行主应用程序(WonderApp)之前修改PATH,主应用程序的DLL搜索路径包括添加到修改后的PATH的目录。

看起来像这样:

namespace shell
{
   static class program
   {
      [dllimport("kernel32.dll", charset = charset.auto, setlasterror = true)]
      public static extern bool setenvironmentvariable(string lpname, string lpvalue);

      private static string joinargstosinglestring(string[] args)
      {
         string s = string.empty;
         for (int i = 0; i < args.length; ++i)
         {
            if (!string.isnullorempty(s))
            {
               s += " ";
            }
            s += "\"" + args[i] + "\"";
         }
         return s;
      }

      [stathread]
      static void main(string[] args)
      {    
         string pathbefore = environment.getenvironmentvariable("path");
         string wewant = util.paths.getapplicationdatadir() + ";" + pathbefore;
         setenvironmentvariable("path", wewant);

         Process process = Process.Start(".\\WonderApp.exe", joinArgsToSingleString(args));
      }
   }
}

希望我能找到更好的解决方案!

【讨论】:

    【解决方案3】:

    我认为这与权限问题有关。

    尝试关闭 UAC 并再次运行您的代码。检查更新路径是否有效。

    如果是这样,至少你知道从哪里开始......

    【讨论】:

    • 不 - 关闭 UAC 不起作用。不过,谢谢你的想法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    • 2010-11-17
    • 2013-03-15
    • 2019-11-22
    相关资源
    最近更新 更多