临时将目录添加到 Windows 7 的 DLL 搜索路径

发布于 2024-09-04 17:47:51 字数 1428 浏览 4 评论 0 原文

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

场景

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

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

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

根据 本文,将一个目录添加到 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,而不仅仅是文件) - 但它仍然声称找不到它。

I want to temporarily add a directory to the DLL search paths - is there a correct way to do this under Windows 7?

Scenario

I've got a C# application, let's call it WonderApp.

WonderApp needs to call a C++ DLL, located in C:\MyPath. So as part of WonderApp's Program.Main(), I added the following command:

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

According to this article, adding a directory to the PATH should also add it to the directories search for DLLs.

The solution works fine in Windows XP: if I add the directory to the PATH, the DLL loads and the program works just fine. If I don't add the directory, the DLL doesn't load, failing with a "not found" error.

However, this doesn't work for Windows 7.

So I figured, let's try using SetDllDirectory(). Like this:

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

And, later on:

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

The value of success is true, but the DLL still fails to load.

Finally, if I set the PATH to include C:\MyPath manually, before running the application - it all works! The DLL loads, and runs just fine.

So, to re-iterate:

Is there a correct way to temporarily add a directory to the DLL search paths under Windows 7?

UPDATE: Using Process Explorer, I checked the application's run-time Environment, and "C:\MyPath" was indeed in the PATH! Furthermore, I saw that Helper.dll was in the list of open handles (as a DLL, not just a file) - and it still claimed not to find it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

孤独患者 2024-09-11 17:47:51

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

此页面有一个很好的摘要,其中包含代码示例: http://support.microsoft.com/kb/837908

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

另请参阅如何在 .NET 运行时将文件夹添加到程序集搜索路径?

You can add custom DLL loading logic to a C# app using the 'AssemblyResolve' event.

This page has a good summary, with code samples: http://support.microsoft.com/kb/837908

Just as you did, I have found that changing the PATH environment variable of a running C# app does not affect the DLL search behaviour. Perhaps the AppDomain caches the PATH value at startup? You can use the AssemblyResolve event to work around this.

See also How to add folder to assembly search path at runtime in .NET?

夏至、离别 2024-09-11 17:47:51

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

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

如果确实如此,至少您知道从哪里开始......

I am thinking it has to do with permission problems.

Try turning off UAC and running your code again. Check to see if updating the path worked.

If it did, at least you know where to start...

哽咽笑 2024-09-11 17:47:51

我的解决方案很简单,但我觉得诉诸它很荒谬。

我编写了另一个程序集“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));
      }
   }
}

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

My solution is simple, but I feel ridiculous resorting to it.

I've written another assembly, "Shell", that modifies the Environment, runs WonderApp, and exits.

By modifying the PATH before running the main application (WonderApp), the main application's DLL search-path includes the directories added to the modified PATH.

It looks like this:

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

I wish I could find a better solution!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文