You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Wix安装程序自定义动作执行Exe时触发FileNotFoundException问题求助

Wix安装程序自定义动作执行Exe时触发FileNotFoundException问题求助

看起来你遇到的这个问题确实挺典型的,结合你给出的错误日志、Wix配置和代码,我帮你梳理几个核心的问题点和解决思路:

1. 核心根源:自定义动作运行的是临时Exe,而非正式安装的Exe

你当前的Wix配置里,是把Middleware.exe作为Binary嵌入到MSI中,当自定义动作执行时,MSI会把这个Exe解压到系统临时目录(比如日志里的MSIB354.tmp这类临时文件),而非你最终安装的目标文件夹。

这里有两个致命问题:

  • 临时Exe的依赖DLL不会同步解压:手动运行时,Exe和依赖DLL在同一目录能正常加载;但MSI只会解压你指定的Exe,它的依赖DLL不在临时目录,运行时自然抛出FileNotFoundException。
  • 临时文件会被MSI自动清理:即使临时Exe侥幸运行,安装完成后MSI会清理临时目录,临时Exe被删除后,你的后台程序会直接崩溃。

而且你可疑的代码行Process.GetCurrentProcess().MainModule.FileName,在这个场景下拿到的是临时文件的路径,用这个路径注册开机启动项的话,下次开机根本找不到文件,完全没用。

2. 最有效的解决思路:运行安装到目标目录的正式Exe

你需要先把Middleware.exe和它的依赖DLL通过Wix的Component/File元素安装到目标目录,再通过自定义动作运行这个正式的Exe,具体步骤如下:

第一步:添加Component安装Exe到目标目录

在你的Wix Product或Fragment里添加安装组件(记得把所有依赖DLL也加进去):

<DirectoryRef Id="INSTALLFOLDER">
  <Component Id="MiddlewareComponent" Guid="*">
    <!-- 安装正式的Middleware.exe到目标目录 -->
    <File Id="MiddlewareExe" Source="$(var.MyApp.ProjectDir)..\..\bin.NET\Middleware.exe" KeyPath="yes" />
    <!-- 把所有依赖的DLL都添加为File元素,示例: -->
    <!-- <File Id="MiddlewareDependency1" Source="$(var.MyApp.ProjectDir)..\..\bin.NET\Dependency1.dll" /> -->
  </Component>
</DirectoryRef>

记得把这个Component包含到你的Feature中,确保安装时会被复制到目标目录。

第二步:修改自定义动作调用正式Exe

删掉原来的Binary配置,修改CustomAction为调用目标目录的Exe:

<!-- 直接调用安装后的正式Exe,不需要Binary元素 -->
<CustomAction Id='MiddlewareApp' Directory='INSTALLFOLDER' ExeCommand='[#MiddlewareExe]' Return='asyncNoWait' />
<Custom Action="MiddlewareApp" After="InstallFinalize">NOT Installed</Custom>

这里[#MiddlewareExe]是Wix的格式化引用,会自动替换成Middleware.exe安装后的完整路径。

3. 优化可疑代码:更可靠的路径获取方式

改成运行正式Exe后,Process.GetCurrentProcess().MainModule.FileName能拿到正确路径,但还有更稳妥的方式:直接把安装路径通过命令行参数传给Exe,彻底规避进程路径的不确定性。

修改CustomAction的命令行:

<CustomAction Id='MiddlewareApp' Directory='INSTALLFOLDER' ExeCommand='[#MiddlewareExe] "[#MiddlewareExe]"' Return='asyncNoWait' />

然后在Program.Main里接收参数:

static void Main(string[] args)
{
    // 优先用传入的正确路径, fallback 到当前进程路径
    string appPath = args.Length > 0 ? args[0] : Process.GetCurrentProcess().MainModule.FileName;
    // 后续代码使用这个appPath即可...
}

4. 额外的小建议

  • Return属性的合理性:你的Return='asyncNoWait'是合适的,因为你的Exe是长期运行的后台程序(代码里有Thread.Sleep(Timeout.Infinite)),MSI不需要等待它执行完成。
  • 日志修复:之前EventLog写不进去,大概率是临时Exe还没来得及写日志就崩溃了。改成正式Exe后,建议先注册EventLog源再写日志:
    if (!EventLog.SourceExists(appName))
    {
        EventLog.CreateEventSource(appName, "Application");
    }
    EventLog eventLog = new EventLog("Application");
    eventLog.Source = appName;
    eventLog.WriteEntry(appPath, EventLogEntryType.Information, 101, 1);
    
  • 控制台隐藏逻辑:!Environment.UserInteractive的判断在MSI环境下是有效的,这段代码可以保留。

先试试改成运行正式安装的Exe,这应该能直接解决FileNotFoundException和路径错误的核心问题。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 08:48:02