Installation 如何制作一个简单包装EXE文件的MSI

Installation 如何制作一个简单包装EXE文件的MSI,installation,windows-installer,Installation,Windows Installer,经过太多的实验,我得出结论,Windows Installer是一种糟糕的技术。但是客户需要MSI文件 那么,如何创建一个MSI文件,将EXE文件提取到一个临时目录中,并使用与传递给EXE文件相同或类似的选项运行它 MSI的选项在中进行了说明(MSI的低级“运行”是msiexec option package.MSI) 编辑:mjmarsh的WiX解决方案看起来很有效。我只是还没有机会尝试一下(关键时刻)。如果有效的话,我会接受的 编辑:它不工作。缺少的部分:似乎没有人值守/无人值守 无论如何,

经过太多的实验,我得出结论,Windows Installer是一种糟糕的技术。但是客户需要MSI文件

那么,如何创建一个MSI文件,将EXE文件提取到一个临时目录中,并使用与传递给EXE文件相同或类似的选项运行它

MSI的选项在中进行了说明(MSI的低级“运行”是msiexec option package.MSI)

编辑:mjmarsh的WiX解决方案看起来很有效。我只是还没有机会尝试一下(关键时刻)。如果有效的话,我会接受的

编辑:它不工作。缺少的部分:似乎没有人值守/无人值守

无论如何,唯一能让这一切工作的方法就是让自定义操作终止其父进程

编辑:所以有人发布了进一步的答案,将整个内容包装为安装后的自定义操作。理论上可能,但由于可能需要重新启动(感谢微软的.NET4有时需要重新启动),我们必须做进一步的黑客行为。因此,从优势矩阵来看:

Transparency: No. One big custom action.
Customizability: No.
Standardization: No. 
Management and reporting: No. Appears to work but will not.
Security: No benefit.
Validation: No. The hackery required to survive reboot makes this sure to not work.
Resiliency: Completely defeated.
Rollback: No. Rollback didn't work when we were using MSI anyway.
Patching & Updates: No. We have a local solution anyway.
Logging: No. Appears to work but will not.

没有意义。

我认为创建.MSI文件最简单的方法是使用


从WiX教程中,您只需创建一个简单的安装即可。

嗯,有免费方式和$$$方式。我无法在这里记录所有内容,但这应该让您开始

另一方面,是的,Windows Installer是一项令人疯狂的技术。很多时候,我认为一项任务会很简单,但实际上会变得复杂。你一定要全身心投入才能理解它

无论如何,这里有:

免费:WiX()

这是一个从一组XML配置文件生成MSI文件的免费工具。我将让您在线查找教程,但关键是:

您可以使用WXS文件中的以下标记将EXE压缩到安装程序中:

<Binary Id="MYEXE" src="<path to my exe?"/>
$$:获取InstallShield()

首先创建一个“基本MSI”项目,并确保您说不希望生成setup.exe。您可以在“发布设置”中进行设置

然后,您基本上可以做与WiX相同的事情,但是您有一个UI

  • 您可以通过使用直接编辑器并将EXE文件放入“二进制”表中来指定帮助程序EXE文件
  • 您可以创建自定义操作,从左侧树中的“自定义操作”节点启动该EXE文件
  • 您可以通过选择“安装序列”并将其放入
    InstallExecuteSequence
    之间的
    InstallInitialize
    InstallFinalize
    插入自定义操作

对不起,我不能说得更详细了,但这应该是一个好的开始。

约书亚,我非常理解你的沮丧。MSI至少可以说是古怪的——一种全新的部署方式。尽管如此,应用正确的MSI提供了最好的部署,特别是对于公司客户

安装程序EXE执行哪些操作?它主要是文件复制、一些COM注册和一些注册表写入,还是运行复杂的安装逻辑、设置数据库等。。。?我问这个问题的原因是,它可能会很快为您创建一个功能良好的WIX MSI,这样您就可以放弃EXE方法

从MSI内部运行EXE确实是可能的,但它需要正确的排序,而且它肯定会比简单的MSI更让人沮丧。如果应用程序很小,并且在安装过程中没有做任何疯狂的事情,我很乐意为您提供一个基本的WIX转换


    • 没有解决方案。我们使用了NSI,因为公司MSI安装将因MSI嵌套问题而中断(有一天尝试从MSI内部安装EXE包装MSI)。

      Wix可以做到这一点。以下是我的wix 3.5示例代码:

      
      不删除~=“全部”
      
      如果不想管理MSI,而只执行EXE,请尝试。您只需输入EXE的路径并获得一个MSI。

      还有一个。它还支持卸载和升级。此外,它仅在添加或删除程序中创建一个条目

      试试这个:

      在MSI包中,有一个行为调用“安装后启动应用程序”,这意味着您的exe文件将在MSI安装后执行(MSI关闭)


      尝试在那里执行您的exe,这样当您的exe调用其他MSI包时,它不会与第一个MSI包冲突。

      我也遇到了同样的问题(包装exe,从exe调用其他MSI,包括.net安装程序等), 以下是我的解决方案:

      我使用InstallAware构建setup exe。 它有自己的MSI包装,用MSI包装生成的EXE

      它工作正常,EXE可以毫无问题地调用其他MSI(包括.net安装程序、其他第三方安装程序),但这是因为启动MSI在启动setup EXE文件后结束(“返回”)权限,这样就避免了MSI递归调用的限制

      但是-某些使用MSI部署工具的客户(公司)仅在安装过程结束后才要求MSI(msiexec)返回(结束),这是上述解决方案的一个问题

      因此,要解决这个问题:

      还有另一个MSI包装器(exemsi.com),它生成仅在EXE安装结束后返回的MSI,但要使用它,您必须使用InstallAware的另一个唯一选项:

      InstallAware可以选择使用自己的本机引擎而不是基于Windows Installer引擎生成EXE设置,以避免MSI递归限制。 把这两者结合起来,你就有了完美的解决方案

      希望这将有助于一些人,虽然许多年过去了,因为这个问题是第一次张贴

      Nah-ma
      <CustomAction Id="EXECA_CALLMYEXE" Return="check" Execute="deferred" BinaryKey="MYEXE"
            ExeCommand="my command line"/>
      
      <InstallExecuteSequence>
         <Custom Action="EXECA_CALLMYEXE" After="InstallInitialize"><![CDATA[Not REMOVE]]></Custom>
      
      using System;
      using System.Diagnostics;
      using System.IO;
      using System.Reflection;
      using System.Runtime.InteropServices;
      
      namespace Setup
      {
          internal class Program
          {
              [DllImport("kernel32.dll")]
              private static extern IntPtr GetConsoleWindow();
      
              [DllImport("user32.dll")]
              private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
      
              private static void Main(string[] args)
              {
                  ShowWindow(GetConsoleWindow(), 0);
                  Stream st = Assembly.GetExecutingAssembly().GetManifestResourceStream("Setup.MSI.Temp.msi");
                  string path = Path.Combine(System.IO.Path.GetTempPath(), "Temp.msi");
                  using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write))
                  {
                      st.CopyTo(fileStream);
                  }
                  Process p = new Process();
                  p.StartInfo.FileName = path;
                  p.Start();
                  p.WaitForExit();
                  File.Delete(path);
              }
          }
      }
      
      <!--Run Action-->
          <CustomAction Id="RunWrappedExe"
                        Return="asyncNoWait"
                        FileKey="ApplicationFileId"
                        Execute="deferred"
                        ExeCommand=""
                        HideTarget="no"
                        Impersonate="yes"/>