Выгрузите .NET DLL из неуправляемого процесса
Я расширяю свой Inno-Setup script с помощью кода, который лучше всего реализовать на С# в управляемой DLL. Я уже знаю, как экспортировать методы из управляемой библиотеки DLL в качестве функций для использования в неуправляемом процессе. Это можно сделать с помощью соткания IL, и есть инструменты для автоматизации этого:
Поэтому после экспорта я могу вызвать свои функции из Pascal script в установщике Inno-Setup. Но тогда есть одна проблема: DLL больше не может быть выгружена. Использование Inno-Setup UnloadDLL(...)
не имеет эффекта, и файл остается заблокированным до завершения установки. Из-за этого установка ждет 2 секунды, а затем не удалит мой DLL файл из временного каталога (или установочного каталога). Фактически, он действительно остается там, пока кто-то не очистит диск.
Я знаю, что управляемые сборки не могут быть выгружены из AppDomain больше, если весь AppDomain не закрыт (процесс завершается). Но что это означает для неуправляемого хост-процесса?
Есть ли лучший способ разрешить Inno-Setup выгружать или удалять мой DLL файл после загрузки и использования?
Ответы
Ответ 1
Как было предложено в других ответах, вы можете запустить отдельный процесс в конце установки, который позаботится об очистке после завершения процессов установки.
Простым решением является создание пакетного файла ad-hoc, который зацикливается до удаления DLL файла, а затем удаляет временную папку (теперь пустую) и сам.
procedure DeinitializeSetup();
var
FilePath: string;
BatchPath: string;
S: TArrayOfString;
ResultCode: Integer;
begin
FilePath := ExpandConstant('{tmp}\MyAssembly.dll');
if not FileExists(FilePath) then
begin
Log(Format('File %s does not exist', [FilePath]));
end
else
begin
BatchPath :=
ExpandConstant('{%TEMP}\') +
'delete_' + ExtractFileName(ExpandConstant('{tmp}')) + '.bat';
SetArrayLength(S, 7);
S[0] := ':loop';
S[1] := 'del "' + FilePath + '"';
S[2] := 'if not exist "' + FilePath + '" goto end';
S[3] := 'goto loop';
S[4] := ':end';
S[5] := 'rd "' + ExpandConstant('{tmp}') + '"';
S[6] := 'del "' + BatchPath + '"';
if not SaveStringsToFile(BatchPath, S, False) then
begin
Log(Format('Error creating batch file %s to delete %s', [BatchPath, FilePath]));
end
else
if not Exec(BatchPath, '', '', SW_HIDE, ewNoWait, ResultCode) then
begin
Log(Format('Error executing batch file %s to delete %s', [BatchPath, FilePath]));
end
else
begin
Log(Format('Executed batch file %s to delete %s', [BatchPath, FilePath]));
end;
end;
end;
Ответ 2
Вы можете добавить пакет script (в виде запуска cmd -c), который должен быть выполнен в конце настройки, ожидающей удаления файла и удаляющего его. (просто убедитесь, что параметр inno не дождался завершения процесса cmd)
Вы также можете сделать свою установленную программу обнаруженной и удалить ее при первом выполнении.
Ответ 3
Как предлагается в этом проекте Code Code: https://www.codeproject.com/kb/threads/howtodeletecurrentprocess.aspx
вызовите cmd с аргументами, как показано ниже.
Process.Start("cmd.exe", "/C ping 1.1.1.1 -n 1 -w 3000 > Nul & Del " + Application.ExecutablePath);
Но в основном, как предложил @Sean, убедитесь, что вы не дождались выхода cmd.exe в script.
Ответ 4
Если вы не ответите на свой вопрос, не можете ли вы просто пометить DLL, которая будет удалена при следующей перезагрузке компьютера?
Ответ 5
Простой способ сделать то, что вам нужно, - это приложение AppDomain. Вы можете выгрузить AppDomain, а не начальную. Итак, решение состоит в том, чтобы создать новый AppDomain, загрузить в него управляемую DLL и затем выгрузить AppDomain.
AppDomain ad = AppDomain.CreateDomain("Isolate DLL");
Assembly a = ad.Load(new AssemblyName("MyManagedDll"));
object d = a.CreateInstance("MyManagedDll.MyManagedClass");
Type t = d.GetType();
double result = (double)t.InvokeMember("Calculate", BindingFlags.InvokeMethod, null, d, new object[] { 1.0, 2.0 });
AppDomain.Unload(ad);
Вот как выглядит DLL-код...
namespace MyManagedDll
{
public class MyManagedClass
{
public double Calculate(double a, double b)
{
return a + b;
}
}
}