Подтвердить что ты не робот

Выгрузите .NET DLL из неуправляемого процесса

Я расширяю свой Inno-Setup script с помощью кода, который лучше всего реализовать на С# в управляемой DLL. Я уже знаю, как экспортировать методы из управляемой библиотеки DLL в качестве функций для использования в неуправляемом процессе. Это можно сделать с помощью соткания IL, и есть инструменты для автоматизации этого:

Поэтому после экспорта я могу вызвать свои функции из Pascal script в установщике Inno-Setup. Но тогда есть одна проблема: DLL больше не может быть выгружена. Использование Inno-Setup UnloadDLL(...) не имеет эффекта, и файл остается заблокированным до завершения установки. Из-за этого установка ждет 2 секунды, а затем не удалит мой DLL файл из временного каталога (или установочного каталога). Фактически, он действительно остается там, пока кто-то не очистит диск.

Я знаю, что управляемые сборки не могут быть выгружены из AppDomain больше, если весь AppDomain не закрыт (процесс завершается). Но что это означает для неуправляемого хост-процесса?

Есть ли лучший способ разрешить Inno-Setup выгружать или удалять мой DLL файл после загрузки и использования?

4b9b3361

Ответ 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;
      }
   }
}