有没有办法从放在共享驱动器上的大 exe 中只执行一个单元的代码?

Is there a way to execute only code from a unit from a big exe placed on shared drive?

我承认我在这个问题上有点狡猾。

问题:exe 部署在共享文件夹上(我从现在开始称它为 ShaExe),在不更改部署规则的情况下,我想以某种方式在本地缓存文件(从现在开始我称它为 LocExe),在启动 ShaExe 时我终于结束了up 运行ning LocExe。每次修改 ShaExe(=更新)时,都必须更新(从 ShaExe 复制)LocExe。

不知何故,我正在研究的是设置这样的东西:

先决条件:LocExe 路径是 user\AppData\Local\MyApp 硬编码路径,因此 ShaExe 知道 LocExe 在哪里。

  1. ShaExe 已启动

  2. ShaExe 将其大小与 LocExe 的大小进行比较,如果不同则将 ShaExe 复制到 LocExe

  3. ShaExe用-skiplauncher命令行参数执行LocExe

  4. ShaExe 自行终止

当使用-skiplauncher时,上面列表中的点2 3 4不执行(这是为了避免执行LocExe并终止应用程序的死循环)

现在这种方法可行,但瓶颈是 (1) 因为 ShaExe 大小为 110MB,所以从共享路径启动 exe 需要时间(即使我不使用标志 {$SetPEFlags IMAGE_FILE_NET_RUN_FROM_SWAP})。

我试图准备一个非常小的 ShaExe 版本(基本上没有单元构建,但只有启动器逻辑,最终以 6MB 的 exe 结尾)。

有了这个 "light but useless ShaExe" 整个过程会更快。

我希望 (2) (3) 和 (4) 立即执行,Windows 是否可行?

我完全清楚最好的做法是在本地手动复制文件并 运行 它或者创建一个简单的启动器 exe 来完成 运行ning 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 的执行速度。

不知何故我只想 运行 一个初始化部分,包含这里描述的逻辑然后终止应用程序(当 ShaExe 到位时,这基本上意味着 -skipLauncher 不使用) .

那么,是否可以运行只做一个大exe文件的初始化逻辑?

希望表达出来,谢谢

不管您拥有什么代码,您实质上要问的是是否可以部分加载可执行文件,让它有条件地只执行它包含的部分代码。或者流式可执行文件?这些是不可能的,OS 将不得不从远程位置获取整个 运行 时间,连同任何静态依赖项一起到本地计算机。即使可执行文件要立即退出。

您可以通过将条件部分分离到不同的可执行文件来获得您想要的行为:启动器。没有任何 VCL 依赖,你可以让它非常小。即便如此,更好的选择是 运行 本地可执行文件,让它检查远程位置是否包含更新版本,因为网络访问更容易出现性能和安全问题。