Есть ли способ выполнить только код из модуля из большого исполняемого файла, размещенного на общем диске? - PullRequest
0 голосов
/ 04 октября 2018

Я признаю, что нахожусь в области грязных хитростей в этом вопросе.

ПРОБЛЕМА: exe развернут в общей папке (с этого момента я называю ее ShaExe), без изменения правил развертывания каким-либо образом я хочу кэшироватьфайл локально (я называю это LocExe с этого момента) и при запуске ShaExe я, наконец, в конечном итоге запустить LocExe.LocExe должен обновляться (копироваться из ShaExe) каждый раз при изменении ShaExe (= обновляется).

Каким-то образом то, что я исследую, настраивает что-то вроде этого:

Предварительное условие: путь LocExe - это пользователь \AppData \ Local \ MyApp - зашифрованный путь, поэтому ShaExe знает, где находится LocExe.

  1. ShaExe запускается

  2. ShaExe сравнивает свой размер с размером LocExeесли он отличается, он копирует ShaExe в LocExe

  3. ShaExe выполняет LocExe с параметром командной строки -skiplauncher

  4. ShaExe завершается

при использовании -skiplauncher точки 2 3 4 из приведенного выше списка не выполняются (это позволяет избежать бесконечного цикла выполнения LocExe и завершения приложения)

Теперь этот подходработает, но узким местом является (1), потому что размер ShaExe составляет 110 МБ, поэтому запуск файла exe из общего пути занимает некоторое время (даже если я не использую флаг {$SetPEFlags IMAGE_FILE_NET_RUN_FROM_SWAP}).

Я пытался подготовить оченьмаленькая версия ShaExe (в основном построенный без юнитов, но только с логикой запуска в нем, заканчивающийся в 6 МБ exe).

С этим "легким, но бесполезным ShaExe" весь процесс быстрее.

Я бынапример, (2) (3) и (4) выполняются немедленно, возможно ли это в Windows или нет?

Я прекрасно знаю, что лучше всего будет либо вручную скопировать файл локально и запустить его, либосоздать простой запускаемый exe-файл, который выполняет работу по запуску LocExe и делать кеш-память, когда это необходимо, но у меня есть очень крупный клиент, который требует от меня сделать это без изменения процедуры развертывания.

Именно поэтому я и прошу экспертасовет здесь.

Это мой код (конечно, упрощенный, вместо Unit1 представьте 100 единиц):

//this is the dpr
program MYProgram;

uses
  Vcl.Forms,
  execache in 'execache.pas',
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  RunCachedExe;
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

//this is the execache unit
unit execache;

interface

uses
  Vcl.Forms,
  Windows,
  ShellAPi,
  sysutils,
  dialogs,
  system.IOUtils;

  procedure RunCachedExe;

implementation

procedure RunCachedExe;

function GetFileSize(const aFilename: String): Int64;
  var
    info: TWin32FileAttributeData;
  begin
    result := -1;
    if NOT GetFileAttributesEx(PWideChar(aFileName), GetFileExInfoStandard, @info) then
      EXIT;
    result := Int64(info.nFileSizeLow) or Int64(info.nFileSizeHigh shl 32);
  end;

var
  CurrentInstanceSize, CachedFileSize, i: integer;
  CachedFilePath, Outs: string;
  SkipLauncher: Boolean;
begin
  SkipLauncher := False;
  for i := 0 to paramcount -1 do
    begin
      if Paramstr(i) = '-SkipLauncher' then
        SkipLauncher := True;
    end;
  if not SkipLauncher then
  begin
    // in this code path is hardcoded, in real life I use a function that calls:
    // SHGetSpecialFolderPath with CSIDL_LOCAL_APPDATA
     CachedFilePath := 'C:\Users\myuser\AppData\Local\MyProject\bincache\MyProject.exe';
     CurrentInstanceSize := GetFileSize(Application.ExeName);
     // this will return -1 if file not found
     CachedFileSize := GetFileSize (CachedFilePath);
     if CachedFileSize <> CurrentInstanceSize then
     begin
       ForceDirectories('C:\Users\myuser\AppData\Local\MyProject\bincache\');
       CopyFile(PChar(Application.ExeName), PCHar(CachedFilePath), False);
     end;
     // launch local exe and close this one
     ShellExecute (0, 'open', PWideChar( CachedFilePath ), PWideChar('-SkipLauncher'), nil, SW_SHOWNORMAL);
     Application.Terminate;
  end;
end;

Этот код использует некоторые функции из других модулей, но я мог бы переместить все вмодуль execache, если это может помочь ускорить выполнение exe.

Каким-то образом я хотел бы запустить только часть инициализации, содержащую логику deздесь, а затем завершить работу приложения (когда ShaExe на месте, это в основном означает, что -skipLauncher не используется).

Итак, возможно ли запустить только логику инициализации большого exe-файла?

Надеюсь, я высказался, спасибо.

1 Ответ

0 голосов
/ 04 октября 2018

Независимо от того, какой у вас код, по сути вы спрашиваете, возможно ли частично загрузить исполняемый файл, чтобы он условно выполнял только часть кода, который он содержит.Или, возможно, потоковый исполняемый файл?Это невозможно, ОС должна будет извлекать всю среду выполнения из удаленного расположения вместе со всеми статическими зависимостями на локальный компьютер.Даже если исполняемый файл должен немедленно завершиться.

Вы можете получить желаемое поведение, если отделите условную часть от другого исполняемого файла: средства запуска.Без какой-либо зависимости от VCL вы можете иметь ее очень маленькойДаже тогда лучшая альтернатива - запускать исполняемый файл локально, чтобы он проверял, содержит ли удаленное местоположение обновленную версию, поскольку сетевой доступ более подвержен проблемам с производительностью и безопасностью.

...