Выполнение, а затем удаление DLL в C#
Я создаю самообновляющееся приложение, где у меня есть большая часть кода в отдельной DLL. Это командная строка и в конечном итоге будет запущена на Mono. Я просто пытаюсь заставить этот код работать в C# на окнах в командной строке.
Как я могу создать приложение AC#, которое я могу удалить поддерживающую DLL во время его работы?
AppDomain domain = AppDomain.CreateDomain("MyDomain");
ObjectHandle instance = domain.CreateInstance( "VersionUpdater.Core", "VersionUpdater.Core.VersionInfo");
object unwrap = instance.Unwrap();
Console.WriteLine(((ICommand)unwrap).Run());
AppDomain.Unload(domain);
Console.ReadLine();
на ReadLine VersionUpdater.Core.dll по-прежнему заблокирован от удаления
Интерфейс ICommand находится в VersionUpdater.Common.dll, на который ссылаются как приложение командной строки, так и VersionUpdater.Core.dll
4 ответа
Единственный способ, которым я когда-либо справлялся с чем-то подобным, - это иметь DLL в отдельном домене приложений для сборки, которая пытается удалить ее. Я выгружаю другой AppDomain, а затем удаляю DLL с диска.
Если вы ищете способ выполнить обновление, я бы предпочел заглушку exe, которая порождает настоящий AppDomain. Затем, когда этот stub exe обнаруживает, что должно быть применено обновление, он закрывает другой домен приложения и затем выполняет магию обновления.
РЕДАКТИРОВАТЬ: средство обновления не может делить библиотеки DLL с тем, что он обновляет, в противном случае он заблокирует эти библиотеки DLL и, следовательно, предотвратит их удаление. Я подозреваю, что именно поэтому вы все еще получаете исключение. Средство обновления должно быть автономным и не зависеть от всего, что использует другой домен приложений, и наоборот.
Вы всегда можете использовать MOVEFILE_DELAY_UNTIL_REBOOT
удалить при перезагрузке. Скорее всего, это наименее хаккейный способ делать подобные вещи, хаккей я обычно вижу такие вещи, как; загрузка новых DLL или внедрение в explorer.exe, даже исправление системной библиотеки DLL для загрузки в другой процесс и т. д.
MoveFileEx от MSDN;
lpNewFileName [in, необязательно] Новое имя файла или каталога на локальном компьютере.
При перемещении файла место назначения может находиться в другой файловой системе или томе. Если пункт назначения находится на другом диске, необходимо установить
MOVEFILE_COPY_ALLOWED
флаг в dwFlags.При перемещении каталога адресат должен находиться на том же диске.
Если dwFlags указывает
MOVEFILE_DELAY_UNTIL_REBOOT
и lpNewFileName имеет значение NULL, MoveFileEx регистрирует файл lpExistingFileName, который будет удален при перезапуске системы. Если lpExistingFileName ссылается на каталог, система удаляет каталог при перезапуске, только если каталог пуст.
Когда я создавал самообновляющееся приложение, я использовал идею заглушки, но заглушкой было само приложение.
Приложение запустится, поищите обновления. Если он обнаружит обновление, он загрузит копию нового приложения во временное хранилище, а затем запустит его (System.Diagnostics.Process.Start()), используя параметр командной строки, который говорит "вы обновляетесь". Тогда оригинальный exe выходит.
Порожденный exe запускается, видит, что это обновление, и копирует себя в исходный каталог приложения. Затем приложение запускается из этого нового местоположения. Тогда порожденный exe заканчивается.
Запускается только что запущенный exe из исходного места установки приложения - видит временный файл и удаляет его. Затем возобновляется нормальное исполнение.
Unwrap загрузит сборку типа объекта в домен приложения, который ее вызывает. Одним из способов решения этой проблемы является создание типа в вашей "базовой" сборке, который вызывает command.run, а затем загрузка его в новый домен приложения. Таким образом, вам никогда не придется вызывать развертку для объекта из типа в другой сборке, и вы можете удалить сборку на диске.