msi安装后运行exe?

Posted

技术标签:

【中文标题】msi安装后运行exe?【英文标题】:Run exe after msi installation? 【发布时间】:2010-12-12 16:50:05 【问题描述】:

使用 Visual Studio 2008 创建一个 msi 以使用安装项目部署我的程序。我需要知道如何让 msi 运行它刚刚安装的 exe。自定义动作?如果是这样,请解释在哪里/如何。谢谢。

【问题讨论】:

【参考方案1】:

这是一个常见的问题。我不使用只是自定义操作来做到这一点。我知道的唯一方法是在生成 .msi 后对其进行修改。我运行一个 javascript 脚本作为构建后事件来做到这一点。它在安装向导中插入一个新对话框,带有一个显示“Launch Application Foo?”的复选框。然后有一个自定义操作来运行应用程序,如果复选框被选中的话。

它显示为安装向导序列中的最后一个屏幕。看起来像这样:


这是我用来修改 MSI 的脚本:

// EnableLaunchApplication.js <msi-file>
// Performs a post-build fixup of an msi to launch a specific file when the install has completed

// Configurable values
var checkboxChecked = true;                     // Is the checkbox on the finished dialog checked by default?
var checkboxText = "Launch [ProductName]";      // Text for the checkbox on the finished dialog
var filename = "WindowsApplication1.exe";       // The name of the executable to launch - change this to match the file you want to launch at the end of your setup

// Constant values from Windows Installer
var msiOpenDatabaseModeTransact = 1;

var msiViewModifyInsert         = 1;
var msiViewModifyUpdate         = 2;
var msiViewModifyAssign         = 3;
var msiViewModifyReplace        = 4;
var msiViewModifyDelete         = 6;

if (WScript.Arguments.Length != 1)

        WScript.StdErr.WriteLine(WScript.ScriptName + " file");
        WScript.Quit(1);


var filespec = WScript.Arguments(0);
var installer = WScript.CreateObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);

var sql;
var view;
var record;

try

        var fileId = FindFileIdentifier(database, filename);
        if (!fileId)
                throw "Unable to find '" + filename + "' in File table";

        WScript.Echo("Updating the Control table...");
        // Modify the Control_Next of BannerBmp control to point to the new CheckBox
        sql = "SELECT `Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help` FROM `Control` WHERE `Dialog_`='FinishedForm' AND `Control`='BannerBmp'";
        view = database.OpenView(sql);
        view.Execute();
        record = view.Fetch();
        record.StringData(11) = "CheckboxLaunch";
        view.Modify(msiViewModifyReplace, record);
        view.Close();

        // Insert the new CheckBox control
        sql = "INSERT INTO `Control` (`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help`) VALUES ('FinishedForm', 'CheckboxLaunch', 'CheckBox', '9', '201', '343', '12', '3', 'LAUNCHAPP', '\\VSI_MS_Sans_Serif13.0_0_0" + checkboxText + "', 'CloseButton', '|')";
        view = database.OpenView(sql);
        view.Execute();
        view.Close();

        WScript.Echo("Updating the ControlEvent table...");
        // Modify the Order of the EndDialog event of the FinishedForm to 1
        sql = "SELECT `Dialog_`, `Control_`, `Event`, `Argument`, `Condition`, `Ordering` FROM `ControlEvent` WHERE `Dialog_`='FinishedForm' AND `Event`='EndDialog'";
        view = database.OpenView(sql);
        view.Execute();
        record = view.Fetch();
        record.IntegerData(6) = 1;
        view.Modify(msiViewModifyReplace, record);
        view.Close();

        // Insert the Event to launch the application
        sql = "INSERT INTO `ControlEvent` (`Dialog_`, `Control_`, `Event`, `Argument`, `Condition`, `Ordering`) VALUES ('FinishedForm', 'CloseButton', 'DoAction', 'VSDCA_Launch', 'LAUNCHAPP=1', '0')";
        view = database.OpenView(sql);
        view.Execute();
        view.Close();

        WScript.Echo("Updating the CustomAction table...");
        // Insert the custom action to launch the application when finished
        sql = "INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) VALUES ('VSDCA_Launch', '210', '" + fileId + "', '')";
        view = database.OpenView(sql);
        view.Execute();
        view.Close();

        if (checkboxChecked)
        
                WScript.Echo("Updating the Property table...");
                // Set the default value of the CheckBox
                sql = "INSERT INTO `Property` (`Property`, `Value`) VALUES ('LAUNCHAPP', '1')";
                view = database.OpenView(sql);
                view.Execute();
                view.Close();
        

        database.Commit();

catch(e)

        WScript.StdErr.WriteLine(e);
        WScript.Quit(1);


function FindFileIdentifier(database, fileName)

        // First, try to find the exact file name
        var sql = "SELECT `File` FROM `File` WHERE `FileName`='" + fileName + "'";
        var view = database.OpenView(sql);
        view.Execute();
        var record = view.Fetch();
        if (record)
        
                var value = record.StringData(1);
                view.Close();
                return value;
        
        view.Close();

        // The file may be in SFN|LFN format.  Look for a filename in this case next
        sql = "SELECT `File`, `FileName` FROM `File`";
        view = database.OpenView(sql);
        view.Execute();
        record = view.Fetch();
        while (record)
        
                if (StringEndsWith(record.StringData(2), "|" + fileName))
                
                        var value = record.StringData(1);
                        view.Close();
                        return value;
                

                record = view.Fetch();
        
        view.Close();


function StringEndsWith(str, value)

        if (str.length < value.length)
                return false;

        return (str.indexOf(value, str.length - value.length) != -1);

我最初是从Aaron Stebner's blog 获得的,然后对其进行了修改。

将该 Javascript 文件保存到项目目录(与包含 .vdproj 的目录相同),将其命名为 ModifyMsiToEnableLaunchApplication.js 。对于每个独特的安装项目,您需要修改该脚本并将正确的 exe 名称放入其中。然后,您需要将 Setup 项目中的构建后事件设置为:

cscript.exe "$(ProjectDir)ModifyMsiToEnableLaunchApplication.js" "$(BuiltOuputPath)"

请务必正确输入宏 $(BuiltOuputPath) 的名称。 Ouput这个词被微软拼错了,Built不是拼写Build

应该这样做。

另请参阅:this modification,其中不包括 UNINSTALL 上的“运行 Foo.exe”复选框。

【讨论】:

有点神奇。我不知道 MS 是否将该功能添加到 VS2010 的安装项目中。我认为在 WiX 中也可以这样做,但我从未使用过 Wix,所以这对我有用。 如果界面被隐藏(msi 被静默安装命令推送)这仍然有效吗? 这也增加了卸载过程的屏幕 - 在卸载过程结束时。 请务必正确输入宏 $(BuiltOuputPath) 的名称。我花了大约半个小时才意识到 Ouput 这个词被 Microsoft 拼错了,而 Built 不是拼写 Build! 这很好用,但过了一段时间我开始收到“安装程序在安装此软件包时遇到意外错误。这可能表明此软件包有问题。错误代码是 2810。” (即使安装完成)。登录后,我发现:“调试:错误 2810:在 FinishedForm 对话框中,下一个控件指针不形成循环。CheckboxLaunch 和 CancelButton 都有一个指向 CloseButton 的指针”对此有何帮助?【参考方案2】:

这似乎是一个更简单的解决方案: Visual Studio Installer > How To Launch App at End of Installer

【讨论】:

VS2005(也许是 VS2008)需要原始解决方案? 显然这个更简单的解决方案没有显示复选框选项。 在这个解决方案中的问题是设置将在接近完成之前卡住......几乎在 98% 点。当你退出应用程序时它就会结束。【参考方案3】:

好的!!!这是代码(最后没有 2 个辅助函数 'FindFileIdentifier' 和 'StringEndsWith' - 使用原始函数),它使我们能够更改控件的 Y 和高度,以及添加复选框控件可见性条件(请参阅标记在“新 - 开始”到“新 - 结束”之间的 2 个 cmets):


// EnableLaunchApplication.js 
// Performs a post-build fixup of an msi to launch a specific file when the install has completed


// Configurable values
var checkboxChecked = true;                     // Is the checkbox on the finished dialog checked by default?
var checkboxText = "Launch [ProductName]?";     // Text for the checkbox on the finished dialog
var filename = "*.exe";                     // The name of the executable to launch - change * to match the file name you want to launch at the end of your setup


// Constant values from Windows Installer
var msiOpenDatabaseModeTransact = 1;

var msiViewModifyInsert         = 1
var msiViewModifyUpdate         = 2
var msiViewModifyAssign         = 3
var msiViewModifyReplace        = 4
var msiViewModifyDelete         = 6



if (WScript.Arguments.Length != 1)

        WScript.StdErr.WriteLine(WScript.ScriptName + " file");
        WScript.Quit(1);


var filespec = WScript.Arguments(0);
var installer = WScript.CreateObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);

var sql
var view
var record

try

        var fileId = FindFileIdentifier(database, filename);
        if (!fileId)
                throw "Unable to find '" + filename + "' in File table";


        WScript.Echo("Updating the Control table...");
        // Modify the Control_Next of BannerBmp control to point to the new CheckBox
        sql = "SELECT `Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help` FROM `Control` WHERE `Dialog_`='FinishedForm' AND `Control`='BannerBmp'";
        view = database.OpenView(sql);
        view.Execute();
        record = view.Fetch();
        record.StringData(11) = "CheckboxLaunch";
        view.Modify(msiViewModifyReplace, record);
        view.Close();

        // NEW - START
        // Insert the new CheckBox control
        // I changed the value for Y below from 201 to 191 in order to make the checkbox more obvious to the user's eye. In order to do so, and avoid the controls 'BodyText' & 'BodyTextRemove' in the same form to
        // overlap the checkbox, I added yet 2 more sql statements that change the values of the heights for the 'BodyText' & 'BodyTextRemove' from 138 to 128. This way I can play around with the values without using
        // the Orca msi editor.
        var CheckBoxY = 191; //This was initially set to 201
        var NewHeight = 128; //This was initially set to 138
        sql = "INSERT INTO `Control` (`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help`) VALUES ('FinishedForm', 'CheckboxLaunch', 'CheckBox', '9', '" + CheckBoxY + "', '343', '12', '3', 'LAUNCHAPP', '\\VSI_MS_Sans_Serif13.0_0_0" + checkboxText + "', 'CloseButton', '|')";
        view = database.OpenView(sql);
        view.Execute();
        view.Close();

        sql = "Select `Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help` FROM `Control` WHERE `Dialog_` = 'FinishedForm' AND `Control` = 'BodyText'";
        view = database.OpenView(sql);
        view.Execute();
        record = view.Fetch();
        record.IntegerData(7) = NewHeight;
        view.Modify(msiViewModifyReplace, record);
        view.Close();

        sql = "Select `Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help` FROM `Control` WHERE `Dialog_` = 'FinishedForm' AND `Control` = 'BodyTextRemove'";
        view = database.OpenView(sql);
        view.Execute();
        record = view.Fetch();
        record.IntegerData(7) = NewHeight;
        view.Modify(msiViewModifyReplace, record);
        view.Close();
        // NEW - END

        WScript.Echo("Updating the ControlEvent table...");
        // Modify the Order of the EndDialog event of the FinishedForm to 1
        sql = "SELECT `Dialog_`, `Control_`, `Event`, `Argument`, `Condition`, `Ordering` FROM `ControlEvent` WHERE `Dialog_`='FinishedForm' AND `Event`='EndDialog'";
        view = database.OpenView(sql);
        view.Execute();
        record = view.Fetch();
        record.IntegerData(6) = 1;
        view.Modify(msiViewModifyReplace, record);
        view.Close();

        // Insert the Event to launch the application
        sql = "INSERT INTO `ControlEvent` (`Dialog_`, `Control_`, `Event`, `Argument`, `Condition`, `Ordering`) VALUES ('FinishedForm', 'CloseButton', 'DoAction', 'VSDCA_Launch', 'LAUNCHAPP=1', '0')";
        view = database.OpenView(sql);
        view.Execute();
        view.Close();



        WScript.Echo("Updating the CustomAction table...");
        // Insert the custom action to launch the application when finished
        sql = "INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) VALUES ('VSDCA_Launch', '210', '" + fileId + "', '')";
        view = database.OpenView(sql);
        view.Execute();
        view.Close();

        if (checkboxChecked)
        
                WScript.Echo("Updating the Property table...");
                // Set the default value of the CheckBox
                sql = "INSERT INTO `Property` (`Property`, `Value`) VALUES ('LAUNCHAPP', '1')";
                view = database.OpenView(sql);
                view.Execute();
                view.Close();
        


        // NEW - START
        WScript.Echo("Updating the ControlCondition table...");
        // Insert the conditions where the Launch Application Checkbox appears
        sql = "INSERT INTO `ControlCondition` (`Dialog_`, `Control_`, `Action`, `Condition`) VALUES ('FinishedForm', 'CheckboxLaunch', 'Show', 'REMOVE=\"\"')";
        view = database.OpenView(sql);
        view.Execute();
        view.Close();

        sql = "INSERT INTO `ControlCondition` (`Dialog_`, `Control_`, `Action`, `Condition`) VALUES ('FinishedForm', 'CheckboxLaunch', 'Hide', 'REMOVE<>\"\"')";
        view = database.OpenView(sql);
        view.Execute();
        view.Close();
        //NEW - END


        database.Commit();

catch(e)

        WScript.StdErr.WriteLine(e);
        WScript.Quit(1);

【讨论】:

这修复了删除后出现的启动应用程序复选框! 它到底修复了什么?可能只是我起得太晚了,但我无法解析你在那里写的内容,@Fidelis。【参考方案4】:

关于“隐藏的复选框错误”,我发现了以下未解释的内容 上面 Cheeso 和 Muleskinner 的回答:

脚本的更改(由 Muleskinner 提供)将复选框的 Y 位置设置为 201(我猜是控件的顶部 Y 像素)。如果您将 Y 更改为 151(为了使其垂直居中对齐),则“突然”出现错误。原因是msi的Control表中还有另一个控件,即'BodyText'('Dialog'字段='FinishedForm'),其Y设置为63,高度设置为138。即138 + 63 = 201。因此,如果您更改复选框的 Y 值,“BodyText”控件会与新添加的控件重叠,这就是用户需要将鼠标悬停在上面才能显示复选框的原因。如果您没有“BodyText”或它的字符数足够小,您可以更改(通过像我一样使用 Orca msi 编辑器,或通过更改上面的脚本)这两个控件的 Ys 和 Heights 以便能够和适应新添加的复选框的不同 Y 位置。 这同样适用于控件:“BodyTextRemove”,我们应该在其中再次更改其高度值(在卸载期间出现)

希望这可以帮助所有与我对这个“错误”有相同问题的用户

不过,脚本确实做得很好!

另一个问题是如何在卸载过程中使复选框不可见。 使用 Orca msi 编辑器,我在 msi 的 ControlCondition 表中添加了以下 2 行:

第 1 行(应显示控件时):

(对话框)FinishedForm (控制)复选框启动 (动作)表演 (条件)REMOVE=""

第 2 行(当控件不可见时):

(对话框)FinishedForm (控制)复选框启动 (动作)隐藏 (条件)REMOVE""

附:我在 Windows 7 (x64) 上使用 VS 2010,但我相信这些也应该适用于以前的版本。

【讨论】:

【参考方案5】:

此 EnableLaunchApplication.js 脚本有一个小错误,即 Control_Next 选项卡顺序不正确。这将导致运行安装时出现错误代码 2810。

更改以下行以使用“Line1”控件而不是“CloseButton”,以便控件的选项卡顺序全部连接。

sql = "INSERT INTO `Control` (`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`,
   `Control_Next`, `Help`) VALUES ('FinishedForm', 'CheckboxLaunch',
   'CheckBox', '9', '201', '343', '12', '3', 'LAUNCHAPP',
   '\\VSI_MS_Sans_Serif13.0_0_0" + checkboxText + "', 'CloseButton',
   '|')";

【讨论】:

【参考方案6】:

关于 'PostBuildEvent' failed with error code '1' 'Unspecified error' 错误,将 PostBuildEvent 从

cscript.exe \"$(ProjectDir)ModifyMsiToEnableLaunchApplication.js\" \"$(BuiltOuputPath)\"

cscript.exe "$(ProjectDir)ModifyMsiToEnableLaunchApplication.js" "$(BuiltOuputPath)"

关于hidden checkbox bug,您可以将脚本的第54行编辑为:

sql = "INSERT INTO `Control` (`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help`) VALUES ('FinishedForm', 'CheckboxLaunch', 'CheckBox', '9', '201', '343', '12', '3', 'LAUNCHAPP', '\\VSI_MS_Sans_Serif13.0_0_0" + checkboxText + "', 'CloseButton', '|')";

【讨论】:

【参考方案7】:

是的.. 我会编写一个自定义操作,并将其粘贴在 InstallExecutionSequence 表的末尾

【讨论】:

我没有看到 InstallExecutionSequence 表?在自定义操作下,我看到了安装、提交、回滚和卸载。自定义操作会指向主程序的输出吗? InstallExecutionSequence 表在 MSI 内部,不通过 Visual Studio 公开。您将需要像 Orca 这样的 MSI 编辑器来编辑它。手动编辑 MSI 并非易事。 我同意 - 手动编辑 MSI 并不容易。使用 Orca 并非易事。您可以使用我在下面提供的脚本来自动执行任务。快速简单,经过测试和验证。 我知道问题是针对 VS2008 的,但对于 VS2010,创建自定义提交操作看起来相当容易。 msdn.microsoft.com/en-us/library/d9k65z2d.aspx【参考方案8】:

参考user3349200的建议,这里是一个完整的JS脚本,没有设置错误2810。

// post-build-script: CALL cscript.exe "$(ProjectDir)EnableLaunchApplication.js" "$(BuiltOuputPath)"
// EnableLaunchApplication.js <msi-file>
// Performs a post-build fixup of an msi to launch a specific file when the install has completed

// Configurable values
var checkboxChecked = true;         // Is the checkbox on the finished dialog checked by default?
var checkboxText = "Launch [ProductName]";  // Text for the checkbox on the finished dialog
var filename = "YourApp.exe";   // The name of the executable to launch - change this to match the file you want to launch at the end of your setup

// Constant values from Windows Installer
var msiOpenDatabaseModeTransact = 1;

var msiViewModifyInsert         = 1
var msiViewModifyUpdate         = 2
var msiViewModifyAssign         = 3
var msiViewModifyReplace        = 4
var msiViewModifyDelete         = 6

if (WScript.Arguments.Length != 1)

    WScript.StdErr.WriteLine(WScript.ScriptName + " file");
    WScript.Quit(1);


var filespec = WScript.Arguments(0);
var installer = WScript.CreateObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);

var sql
var view
var record

try

    var fileId = FindFileIdentifier(database, filename);
    if (!fileId)
        throw "Unable to find '" + filename + "' in File table";


    WScript.Echo("Updating the Control table...");
    // Modify the Control_Next of BannerBmp control to point to the new CheckBox
    sql = "SELECT `Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help` FROM `Control` WHERE `Dialog_`='FinishedForm' AND `Control`='BannerBmp'";
    view = database.OpenView(sql);
    view.Execute();
    record = view.Fetch();
    record.StringData(11) = "CheckboxLaunch";
    view.Modify(msiViewModifyReplace, record);
    view.Close();

    // Resize the BodyText and BodyTextRemove controls to be reasonable
    sql = "SELECT `Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help` FROM `Control` WHERE `Dialog_`='FinishedForm' AND `Control`='BodyTextRemove'";
    view = database.OpenView(sql);
    view.Execute();
    record = view.Fetch();
    record.IntegerData(7) = 33;
    view.Modify(msiViewModifyReplace, record);
    view.Close();

    sql = "SELECT `Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help` FROM `Control` WHERE `Dialog_`='FinishedForm' AND `Control`='BodyText'";
    view = database.OpenView(sql);
    view.Execute();
    record = view.Fetch();
    record.IntegerData(7) = 33;
    view.Modify(msiViewModifyReplace, record);
    view.Close();

    // Insert the new CheckBox control
    sql = "INSERT INTO `Control` (`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help`) VALUES ('FinishedForm', 'CheckboxLaunch', 'CheckBox', '18', '117', '343', '12', '3', 'LAUNCHAPP', '\\VSI_MS_Sans_Serif13.0_0_0" + checkboxText + "', 'Line1', '|')";
    view = database.OpenView(sql);
    view.Execute();
    view.Close();

    WScript.Echo("Updating the ControlEvent table...");
    // Modify the Order of the EndDialog event of the FinishedForm to 1
    sql = "SELECT `Dialog_`, `Control_`, `Event`, `Argument`, `Condition`, `Ordering` FROM `ControlEvent` WHERE `Dialog_`='FinishedForm' AND `Event`='EndDialog'";
    view = database.OpenView(sql);
    view.Execute();
    record = view.Fetch();
    record.IntegerData(6) = 1;
    view.Modify(msiViewModifyReplace, record);
    view.Close();

    // Insert the Event to launch the application
    sql = "INSERT INTO `ControlEvent` (`Dialog_`, `Control_`, `Event`, `Argument`, `Condition`, `Ordering`) VALUES ('FinishedForm', 'CloseButton', 'DoAction', 'VSDCA_Launch', 'LAUNCHAPP=1', '0')";
    view = database.OpenView(sql);
    view.Execute();
    view.Close();

    WScript.Echo("Updating the CustomAction table...");
    // Insert the custom action to launch the application when finished
    sql = "INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) VALUES ('VSDCA_Launch', '210', '" + fileId + "', '')";
    view = database.OpenView(sql);
    view.Execute();
    view.Close();

    if (checkboxChecked)
    
        WScript.Echo("Updating the Property table...");
        // Set the default value of the CheckBox
        sql = "INSERT INTO `Property` (`Property`, `Value`) VALUES ('LAUNCHAPP', '1')";
        view = database.OpenView(sql);
        view.Execute();
        view.Close();
    

    database.Commit();

catch(e)

    WScript.StdErr.WriteLine(e);
    WScript.Quit(1);


function FindFileIdentifier(database, fileName)

    var sql
    var view
    var record

    // First, try to find the exact file name
    sql = "SELECT `File` FROM `File` WHERE `FileName`='" + fileName + "'";
    view = database.OpenView(sql);
    view.Execute();
    record = view.Fetch();
    if (record)
    
        var value = record.StringData(1);
        view.Close();
        return value;
    
    view.Close();

    // The file may be in SFN|LFN format.  Look for a filename in this case next
    sql = "SELECT `File`, `FileName` FROM `File`";
    view = database.OpenView(sql);
    view.Execute();
    record = view.Fetch();
    while (record)
    
        if (StringEndsWith(record.StringData(2), "|" + fileName))
        
            var value = record.StringData(1);
            view.Close();
            return value;
        

        record = view.Fetch();
    
    view.Close();


function StringEndsWith(str, value)

    if (str.length < value.length)
        return false;

    return (str.indexOf(value, str.length - value.length) != -1);

【讨论】:

我正在尝试使用这个脚本,但它似乎仍然存在运行复选框在卸载阶段仍然出现的问题。此外,我似乎遇到了一个问题,即安装程序完成后我的应用程序实际上并没有运行。 更正,我正在运行我的应用程序(我只是遇到了一个意外错误),但是在卸载阶段仍然会出现复选框。 对我来说它的工作,我可以看到复选框,但安装后应用程序不会自动启动

以上是关于msi安装后运行exe?的主要内容,如果未能解决你的问题,请参考以下文章

如何创建 MFC 应用程序来运行 setup.exe(msi 安装程序)?

WiX MSI 和 EXE 作为一个 EXE

在Visual Studio 2017中为WPF应用程序创建MSI安装程序后,EXE不执行任何操作

Wix - 如何从安装目录安装后运行exe文件?

.msi和.exe 文件的区别

在MSI安装期间重新启动Explorer.exe不起作用