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

时间:2021-03-20 22:35:53

After way too many experiments, I've come to the conclusion that Windows Installer is simply bad technology. But the customers want MSI files.

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

So, how can I create an MSI file that extracts an EXE file to a temporary directory and runs it with options same or similar as were passed to the EXE file?

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

Options to an MSI are explained in Msiexec (command-line options) (low level "run" of an MSI is msiexec option package.msi).

Msiexec(命令行选项)中解释了MSI的选项(MSI的低级“运行”是msiexec选项package.msi)。

EDIT: mjmarsh's WiX solution looks like it works. I just haven't had a chance to try it yet (crunch time). If it works, I'll be accepting it.

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

EDIT: it does not work. Missing piece: attended/unattended does not seem to be available.

编辑:它不起作用。遗失的部分:有人/无人看管似乎没有。

Anyway, the only to make this work at all would be for the custom action to kill its parent process!

无论如何,唯一能完成这项工作的是自定义动作来杀死它的父进程!

EDIT: So somebody posted as a further answer wrapping the whole thing as a post-install custom action. Theoretically possible but since a reboot may be required (thanks MS for .NET 4 requiring a reboot sometimes) we have to do further hackery. So from the matrix of advantages:

编辑:所以有人发布了一个进一步的答案包装整个事情作为安装后的自定义操作。理论上可行,但由于可能需要重新启动(感谢MS for .NET 4有时需要重新启动),我们不得不做进一步的hackery。所以从优势矩阵:

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.

No point.

12 个解决方案

#1


Well, there is the free way and the $$$ way. I cannot document everything here, but this should get you started.

好吧,有免费的方式和$$$方式。我不能在这里记录所有内容,但这应该让你开始。

On a side note, yes, Windows Installer is a maddening technology. There are many times where I think a task will be straightforward, but it actually becomes complicated. You definitely have to immerse yourself to understand it.

另外,Windows Installer是一项令人抓狂的技术。有很多次我认为任务很简单,但实际上它变得复杂了。你必须让自己沉浸在理解中。

In any case, here goes:

无论如何,这里是:

Free: WiX (here)

免费:WiX(这里)

This is a free tool to generate MSI files from a set of XML configuration files. I'll leave you to find tutorials online, but here is the crux:

这是一个从一组XML配置文件生成MSI文件的免费工具。我会让你在网上找到教程,但这里有关键:

You can compress your EXE into the installer by using the following tag in the WXS file:

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

<Binary Id="MYEXE" src="<path to my exe?"/>

Then you can create a custom action which launches your EXE file:

然后,您可以创建一个启动EXE文件的自定义操作:

<CustomAction Id="EXECA_CALLMYEXE" Return="check" Execute="deferred" BinaryKey="MYEXE"
      ExeCommand="my command line"/>

Then you insert your custom action into the InstallExecuteSequence in the appropriate spot (I almost always run mine somewhere between InstallInitialize and InstallFinalize)

然后将自定义操作插入适当位置的InstallExecuteSequence(我几乎总是在InstallInitialize和InstallFinalize之间的某处运行)

<InstallExecuteSequence>
   <Custom Action="EXECA_CALLMYEXE" After="InstallInitialize"><![CDATA[Not REMOVE]]></Custom>

$$$: Get InstallShield (HERE)

$$$:获取InstallShield(HERE)

First create a "Basic MSI" project and make sure you say you want no setup.exe generated. You set this in the Release settings.

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

Then you essentially do the same thing as with WiX, but you have a UI for it.

那你基本上和WiX做同样的事情,但你有一个用户界面。

  • You can specify your helper EXE file by using the Direct Editor and putting your EXE file in the 'Binary' table
  • 您可以使用直接编辑器指定助手EXE文件,并将EXE文件放在“二进制”表中

  • You can create a custom action to launch that EXE file from the "Custom Actions" Node in the tree on the left
  • 您可以创建自定义操作以从左侧树中的“自定义操作”节点启动该EXE文件

  • You can insert the custom action by selecting "Install Sequences" and putting it in the InstallExecuteSequence somewhere between InstallInitialize and InstallFinalize as I said before.
  • 您可以通过选择“安装序列”并将其放入InstallInitialize和InstallFinalize之间的InstallExecuteSequence来插入自定义操作,如前所述。

Sorry, I could not be more detailed, but this should be a good start.

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

#2


I think the easiest way to create a .MSI file is to use WiX.

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

Lesson 1 from the WiX tutorial is all you need to create a simple install.

WiX教程的第1课是创建简单安装所需的全部内容。

#3


Joshua, I understand your frustration very well. MSI is quirky to say the least - a completely new way to think of deployment. Still, applied correctly MSI offers the best possible deployment, especially for corporate customers.

约书亚,我很清楚你的挫折感。 MSI至少可以说是一种古怪 - 一种全新的部署思路。仍然,正确应用MSI提供了最佳的部署,特别是对于企业客户。

What operations does your installer EXE perform? Is it largely file copy, some COM registration and some registry writes, or does it run complex installation logic, setting up databases etc...? The reason I ask is because it probably would be very quick to create a well functioning WIX MSI for you so you can abandon the EXE approach.

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

It is indeed possible to run an EXE from inside an MSI, but it requires proper sequencing, and it is guaranteed to cause you more blues than a simple MSI. If the app is small, and not doing anything crazy during installation, I would be happy to provide you with a basic WIX conversion.

确实可以从MSI内部运行EXE,但它需要正确的排序,并且保证比单纯的MSI更加蓝调。如果应用程序很小,并且在安装过程中没有做任何疯狂的事情,我很乐意为您提供基本的WIX转换。

#4


No solution. We went NSIS as corporate MSI install is going to be broken anyway due to MSI nesting problem (just try installing EXE wrapping MSI from inside MSI someday).

没有解决方案。我们去了NSIS,因为MSI嵌套问题导致企业MSI安装无论如何都会被破坏(有一天我会尝试从MSI内部安装EXE包装MSI)。

#5


There is also a free version of the MSI Wrapper. It also supports uninstall and upgrades. Also, it only creates one entry in the Add or Remove programs.

还有免费版的MSI Wrapper。它还支持卸载和升级。此外,它只在“添加或删除”程序中创建一个条目。

#6


Adding to weir's answer, change the custom action attribute like below:

添加到weir的答案,更改自定义操作属性,如下所示:

<!--Run Action-->
    <CustomAction Id="RunWrappedExe"
                  Return="asyncNoWait"
                  FileKey="ApplicationFileId"
                  Execute="deferred"
                  ExeCommand=""
                  HideTarget="no"
                  Impersonate="yes"/>

Setting Return=asyncNoWai does not wait for the exe to return. The installer does it's job and closes normally. Meanwhile, the exe continous its execution.

设置Return = asyncNoWai不等待exe返回。安装程序完成它的工作并正常关闭。同时,exe继续执行。

-Madhuresh

#7


try this:

In MSI package, there is a behaviour call "Launch an application after installation", that means your exe file will be executed after the MSI installation(the MSI is closed).

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

Try to execute your exe there, so when your exe invoke other MSI packages, it won't conflict with the first one.

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

#8


Wix can do it. Here is my sample code for wix 3.5:

威克斯可以做到。这是我的wix 3.5的示例代码:

<?xml version='1.0'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
   <Product Id='*' UpgradeCode="11111111-2222-3333-4444-555555555555" 
        Name='My Setup' Language='1033' Version='1.0.0.0' 
        Manufacturer='Your company'>

    <Package Description='pak' InstallerVersion='200' Compressed='yes' />

    <Media Id='1' Cabinet='setup.cab' EmbedCab='yes' />

    <Directory Id='TARGETDIR' Name='SourceDir'>
        <Directory Id="TempFolder">
            <Directory Id="INSTALLLOCATION" Name="~_tmpdir">
                <Component Id='MyComponent' DiskId='1' Guid=''>
                    <File Id="File0" Name="setup.exe" Source="setup.exe" />
                    <File Id="File1" Name="file1.txt" Source="file1.txt" />
                </Component>
            </Directory>
        </Directory>
    </Directory>

    <Feature Id='InstallFeature' Title='Install Feature' Level='1'>
        <ComponentRef Id='MyComponent' />
    </Feature>

    <!-- Run Action -->
    <CustomAction Id="RunWrapExe" Return="ignore" Execute="deferred" 
                  FileKey="File0" ExeCommand="setup.exe param here"  
                  HideTarget="no" Impersonate="no" />

    <InstallExecuteSequence>
        <Custom Action="RunWrapExe" 
                After="InstallFiles">NOT REMOVE~="ALL"</Custom>
    </InstallExecuteSequence>

   </Product>
</Wix>

#9


If you don't want to manage MSI, but only execute EXE, try Exe to MSI Converter Free. You just put in the path to the EXE and get an MSI.

如果您不想管理MSI,但只执行EXE,请尝试使用Exe to MSI Converter Free。你只需要输入EXE的路径并获得MSI。

#10


I was having the same problem (wrap EXE, call other MSI from the EXE including .net setup, etc.), and here is my solution:

我遇到了同样的问题(包装EXE,从EXE调用其他MSI,包括.net设置等),这是我的解决方案:

I build the setup exe using InstallAware. It has its own MSI Wrapper that wraps the generated EXE with MSI.

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

It works OK, the EXE can call other MSIs without any problem (including .net setup, other 3rd party setups), but that is because the launching MSI ends ("returns") rights after it launches the setup EXE file, and that way they avoid the MSI limitation of recursive MSI calls.

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

BUT - some customers (companies) that uses MSI deployment tools, requires the MSI (msiexec) to return (end) only after the setup process ends, and that is a problem with the above solution.

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

So - to solve this:

所以 - 解决这个问题:

There is another MSI Wrapper (exemsi.com) that generates MSI that returns only after the EXE setup ends, but for using that you must use another unique option of InstallAware:

还有另一个MSI Wrapper(exemsi.com)生成仅在EXE设置结束后才返回的MSI,但是为了使用它,您必须使用另一个独特的InstallAware选项:

InstallAware has the option to generate the EXE setup using their own native engine, and not based on Windows Installer engine, to avoid MSI recursive limitation. Combine those both, and you have the perfect solution.

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

Hope this will help someone, although many years passed since this question was first posted.

希望这会对某人有所帮助,尽管自这个问题首次发布以来已过去很多年。

#11


Simple trick:

Project image

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);
        }
    }
}

#12


Nah man, just use Inno Setup's wizard. It makes an setup EXE but not an MSI. It's like 5 mins and you'll have a windows installer.

不,只需使用Inno Setup的向导。它设置EXE而不是MSI。这就像5分钟,你将有一个Windows安装程序。

Simply download it, install it, point it to your EXE, and follow the on-screen prompts

只需下载,安装,指向EXE,然后按照屏幕上的提示操作即可

#1


Well, there is the free way and the $$$ way. I cannot document everything here, but this should get you started.

好吧,有免费的方式和$$$方式。我不能在这里记录所有内容,但这应该让你开始。

On a side note, yes, Windows Installer is a maddening technology. There are many times where I think a task will be straightforward, but it actually becomes complicated. You definitely have to immerse yourself to understand it.

另外,Windows Installer是一项令人抓狂的技术。有很多次我认为任务很简单,但实际上它变得复杂了。你必须让自己沉浸在理解中。

In any case, here goes:

无论如何,这里是:

Free: WiX (here)

免费:WiX(这里)

This is a free tool to generate MSI files from a set of XML configuration files. I'll leave you to find tutorials online, but here is the crux:

这是一个从一组XML配置文件生成MSI文件的免费工具。我会让你在网上找到教程,但这里有关键:

You can compress your EXE into the installer by using the following tag in the WXS file:

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

<Binary Id="MYEXE" src="<path to my exe?"/>

Then you can create a custom action which launches your EXE file:

然后,您可以创建一个启动EXE文件的自定义操作:

<CustomAction Id="EXECA_CALLMYEXE" Return="check" Execute="deferred" BinaryKey="MYEXE"
      ExeCommand="my command line"/>

Then you insert your custom action into the InstallExecuteSequence in the appropriate spot (I almost always run mine somewhere between InstallInitialize and InstallFinalize)

然后将自定义操作插入适当位置的InstallExecuteSequence(我几乎总是在InstallInitialize和InstallFinalize之间的某处运行)

<InstallExecuteSequence>
   <Custom Action="EXECA_CALLMYEXE" After="InstallInitialize"><![CDATA[Not REMOVE]]></Custom>

$$$: Get InstallShield (HERE)

$$$:获取InstallShield(HERE)

First create a "Basic MSI" project and make sure you say you want no setup.exe generated. You set this in the Release settings.

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

Then you essentially do the same thing as with WiX, but you have a UI for it.

那你基本上和WiX做同样的事情,但你有一个用户界面。

  • You can specify your helper EXE file by using the Direct Editor and putting your EXE file in the 'Binary' table
  • 您可以使用直接编辑器指定助手EXE文件,并将EXE文件放在“二进制”表中

  • You can create a custom action to launch that EXE file from the "Custom Actions" Node in the tree on the left
  • 您可以创建自定义操作以从左侧树中的“自定义操作”节点启动该EXE文件

  • You can insert the custom action by selecting "Install Sequences" and putting it in the InstallExecuteSequence somewhere between InstallInitialize and InstallFinalize as I said before.
  • 您可以通过选择“安装序列”并将其放入InstallInitialize和InstallFinalize之间的InstallExecuteSequence来插入自定义操作,如前所述。

Sorry, I could not be more detailed, but this should be a good start.

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

#2


I think the easiest way to create a .MSI file is to use WiX.

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

Lesson 1 from the WiX tutorial is all you need to create a simple install.

WiX教程的第1课是创建简单安装所需的全部内容。

#3


Joshua, I understand your frustration very well. MSI is quirky to say the least - a completely new way to think of deployment. Still, applied correctly MSI offers the best possible deployment, especially for corporate customers.

约书亚,我很清楚你的挫折感。 MSI至少可以说是一种古怪 - 一种全新的部署思路。仍然,正确应用MSI提供了最佳的部署,特别是对于企业客户。

What operations does your installer EXE perform? Is it largely file copy, some COM registration and some registry writes, or does it run complex installation logic, setting up databases etc...? The reason I ask is because it probably would be very quick to create a well functioning WIX MSI for you so you can abandon the EXE approach.

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

It is indeed possible to run an EXE from inside an MSI, but it requires proper sequencing, and it is guaranteed to cause you more blues than a simple MSI. If the app is small, and not doing anything crazy during installation, I would be happy to provide you with a basic WIX conversion.

确实可以从MSI内部运行EXE,但它需要正确的排序,并且保证比单纯的MSI更加蓝调。如果应用程序很小,并且在安装过程中没有做任何疯狂的事情,我很乐意为您提供基本的WIX转换。

#4


No solution. We went NSIS as corporate MSI install is going to be broken anyway due to MSI nesting problem (just try installing EXE wrapping MSI from inside MSI someday).

没有解决方案。我们去了NSIS,因为MSI嵌套问题导致企业MSI安装无论如何都会被破坏(有一天我会尝试从MSI内部安装EXE包装MSI)。

#5


There is also a free version of the MSI Wrapper. It also supports uninstall and upgrades. Also, it only creates one entry in the Add or Remove programs.

还有免费版的MSI Wrapper。它还支持卸载和升级。此外,它只在“添加或删除”程序中创建一个条目。

#6


Adding to weir's answer, change the custom action attribute like below:

添加到weir的答案,更改自定义操作属性,如下所示:

<!--Run Action-->
    <CustomAction Id="RunWrappedExe"
                  Return="asyncNoWait"
                  FileKey="ApplicationFileId"
                  Execute="deferred"
                  ExeCommand=""
                  HideTarget="no"
                  Impersonate="yes"/>

Setting Return=asyncNoWai does not wait for the exe to return. The installer does it's job and closes normally. Meanwhile, the exe continous its execution.

设置Return = asyncNoWai不等待exe返回。安装程序完成它的工作并正常关闭。同时,exe继续执行。

-Madhuresh

#7


try this:

In MSI package, there is a behaviour call "Launch an application after installation", that means your exe file will be executed after the MSI installation(the MSI is closed).

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

Try to execute your exe there, so when your exe invoke other MSI packages, it won't conflict with the first one.

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

#8


Wix can do it. Here is my sample code for wix 3.5:

威克斯可以做到。这是我的wix 3.5的示例代码:

<?xml version='1.0'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
   <Product Id='*' UpgradeCode="11111111-2222-3333-4444-555555555555" 
        Name='My Setup' Language='1033' Version='1.0.0.0' 
        Manufacturer='Your company'>

    <Package Description='pak' InstallerVersion='200' Compressed='yes' />

    <Media Id='1' Cabinet='setup.cab' EmbedCab='yes' />

    <Directory Id='TARGETDIR' Name='SourceDir'>
        <Directory Id="TempFolder">
            <Directory Id="INSTALLLOCATION" Name="~_tmpdir">
                <Component Id='MyComponent' DiskId='1' Guid=''>
                    <File Id="File0" Name="setup.exe" Source="setup.exe" />
                    <File Id="File1" Name="file1.txt" Source="file1.txt" />
                </Component>
            </Directory>
        </Directory>
    </Directory>

    <Feature Id='InstallFeature' Title='Install Feature' Level='1'>
        <ComponentRef Id='MyComponent' />
    </Feature>

    <!-- Run Action -->
    <CustomAction Id="RunWrapExe" Return="ignore" Execute="deferred" 
                  FileKey="File0" ExeCommand="setup.exe param here"  
                  HideTarget="no" Impersonate="no" />

    <InstallExecuteSequence>
        <Custom Action="RunWrapExe" 
                After="InstallFiles">NOT REMOVE~="ALL"</Custom>
    </InstallExecuteSequence>

   </Product>
</Wix>

#9


If you don't want to manage MSI, but only execute EXE, try Exe to MSI Converter Free. You just put in the path to the EXE and get an MSI.

如果您不想管理MSI,但只执行EXE,请尝试使用Exe to MSI Converter Free。你只需要输入EXE的路径并获得MSI。

#10


I was having the same problem (wrap EXE, call other MSI from the EXE including .net setup, etc.), and here is my solution:

我遇到了同样的问题(包装EXE,从EXE调用其他MSI,包括.net设置等),这是我的解决方案:

I build the setup exe using InstallAware. It has its own MSI Wrapper that wraps the generated EXE with MSI.

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

It works OK, the EXE can call other MSIs without any problem (including .net setup, other 3rd party setups), but that is because the launching MSI ends ("returns") rights after it launches the setup EXE file, and that way they avoid the MSI limitation of recursive MSI calls.

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

BUT - some customers (companies) that uses MSI deployment tools, requires the MSI (msiexec) to return (end) only after the setup process ends, and that is a problem with the above solution.

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

So - to solve this:

所以 - 解决这个问题:

There is another MSI Wrapper (exemsi.com) that generates MSI that returns only after the EXE setup ends, but for using that you must use another unique option of InstallAware:

还有另一个MSI Wrapper(exemsi.com)生成仅在EXE设置结束后才返回的MSI,但是为了使用它,您必须使用另一个独特的InstallAware选项:

InstallAware has the option to generate the EXE setup using their own native engine, and not based on Windows Installer engine, to avoid MSI recursive limitation. Combine those both, and you have the perfect solution.

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

Hope this will help someone, although many years passed since this question was first posted.

希望这会对某人有所帮助,尽管自这个问题首次发布以来已过去很多年。

#11


Simple trick:

Project image

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);
        }
    }
}

#12


Nah man, just use Inno Setup's wizard. It makes an setup EXE but not an MSI. It's like 5 mins and you'll have a windows installer.

不,只需使用Inno Setup的向导。它设置EXE而不是MSI。这就像5分钟,你将有一个Windows安装程序。

Simply download it, install it, point it to your EXE, and follow the on-screen prompts

只需下载,安装,指向EXE,然后按照屏幕上的提示操作即可