Временное добавление каталога в пути поиска DLL Windows 7

Я хочу временно добавить каталог в пути поиска DLL - есть ли правильный способ сделать это в Windows 7?

Сценарий

У меня есть приложение на C #, назовем его WonderApp.

WonderApp необходимо вызвать C ++ DLL, расположенную в C:\MyPath. Итак, как часть Program.Main() от WonderApp, я добавил следующую команду:

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 загружается и работает нормально.

Итак, чтобы повторить:

Есть ли правильный способ временно добавить каталог в пути поиска DLL в Windows 7?

ОБНОВЛЕНИЕ. Используя Process Explorer, я проверил среду выполнения приложения и обнаружил, что «C: \ MyPath» действительно находится в PATH! Более того, я увидел, что Helper.dll был в списке открытых дескрипторов (как DLL, а не просто файл) - и он по-прежнему утверждал, что не нашел его.


person Shalom Craimer    schedule 08.06.2010    source источник
comment
Это 64-битная версия Windows? Какое настоящее имя пути?   -  person Hans Passant    schedule 08.06.2010
comment
Это 32-битная Windows 7 Home. И полный путь к DLL - C: \ MyPath \ Helper.dll   -  person Shalom Craimer    schedule 09.06.2010
comment
возможно, отсутствуют другие библиотеки DLL, попробуйте загрузить helper.dll в программу sizes.exe и проверьте зависимости других библиотек.   -  person OlimilOops    schedule 09.06.2010
comment
Это не объясняет, почему добавление каталога в PATH перед запуском приложения позволяет загружать DLL.   -  person Shalom Craimer    schedule 10.06.2010
comment
Хммм ... Я использую Win 7 x64 и делаю то же самое (устанавливаю PATH для DllImport в определенном каталоге), и он работает хорошо.   -  person ulrichb    schedule 11.12.2010
comment
Возможно, поскольку я разрешаю C # обрабатывать dllimport, это происходит до того, как я смогу изменить PATH моей программы (что я делаю из той же программы). Вы меняете ПУТЬ перед запуском программы или когда программа уже запущена?   -  person Shalom Craimer    schedule 11.12.2010


Ответы (3)


Вы можете добавить пользовательскую логику загрузки DLL в приложение C # с помощью события AssemblyResolve.

На этой странице есть хорошее резюме с примерами кода: http://support.microsoft.com/kb/837908

Как и вы, я обнаружил, что изменение переменной среды PATH работающего приложения C # не влияет на поведение поиска DLL. Возможно, AppDomain кэширует значение PATH при запуске? Вы можете использовать событие AssemblyResolve, чтобы обойти это.

См. Также Как добавить папку в путь поиска сборки во время выполнения в .NET?

person Rich    schedule 22.08.2011
comment
Это круто !!! Большое спасибо за то, что дали мне знать! Похоже, это будет работать с любой сборкой .NET, но мне нужно протестировать это также для библиотек DLL, отличных от .NET. - person Shalom Craimer; 23.08.2011
comment
Хорошо, плохие новости: это работает только для сборок .NET. Что имеет смысл, учитывая его название. Это прекрасное решение, но я не могу его использовать, поскольку библиотеки DLL, которые мне нужно загрузить, не являются сборками .NET. (И что еще хуже, эти DLL также должны загружать другие библиотеки DLL, которые находятся в одном каталоге с ними, поэтому мне нужно было бы найти способ заставить их искать и там). - person Shalom Craimer; 23.08.2011

Я думаю, это связано с проблемами разрешения.

Попробуйте отключить UAC и снова запустить код. Проверьте, сработало ли обновление пути.

Если это так, по крайней мере, вы знаете, с чего начать ...

person MQS    schedule 08.06.2010
comment
Неа - выключить UAC не получилось. Но спасибо за идею. - person Shalom Craimer; 09.06.2010

Мое решение простое, но мне нелепо прибегать к нему.

Я написал другую сборку, «Shell», которая изменяет среду, запускает WonderApp и завершает работу.

Изменяя PATH перед запуском основного приложения (WonderApp), путь поиска 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));
      }
   }
}

Хотел бы я найти лучшее решение!

person Shalom Craimer    schedule 09.06.2010