Visual Studio Installer>如何在安装程序结束时启动应用程序

Tha*_*ORD 47 c# windows-installer setup-project visual-studio-2010

这可能是一个愚蠢的问题,我的谷歌搜索今天没有运作.

我有一个应用程序,我添加了一个Visual Studio安装程序>安装向导项目.我想知道如何添加一个按钮或复选框,成功安装后将启动该应用程序.这将位于MSI安装程序包的最后一页.我正在使用Visual Studio 2010 Ultimate.

我需要这样,以便当应用程序执行自动更新时,它会自动启动安装程序.我只需要安装程序在更新后重新启动应用程序.

这可能很简单,但对于我的生活,我无法弄明白.在此先感谢您的帮助.

sbe*_*rli 88

要在安装完成后运行任何应用程序,

  1. 右键单击您的安装项目,单击"自定义操作".
  2. 然后右键单击Commit,Add Custom Action,并选择要运行的文件.(请注意,它必须已经在您的应用程序文件夹中,因为您运行程序无论如何都不应该是您的问题.
  3. 只需选择项目的输出即可.
  4. 然后,单击此添加的.exe,并将InstallerClass更改为false.这很重要,因为它会寻找安装程序.
  5. 您甚至可以通过将参数添加到Arguments属性来将参数传递给.exe

  • 一个问题.安装应用程序启动我的应用程序但从未关闭,直到我退出我的应用 它停留在"98%",只有在我退出应用程序时才会完成.有没有办法优雅地关闭安装程序?我确保将InstallerClass设置为False.有什么我想念的吗? (40认同)
  • 我只是把 "安装程序" 中的参数,并在我的应用程序入口点,做的:如果(args.Length == 1个&& ARGS [0] == "安装程序"){的Process.Start(Application.ExecutablePath); 返回; 注意:不要使用Application.Restart(),因为它传递相同的arg ;-) (18认同)
  • 只是一个FYI,exe将最终作为高权限帐户运行,而不是"正常"帐户,可能或可能不是你的问题(这对我来说)http://stackoverflow.com/questions/3939731/如何对运行一个进程-AS-当前用户为特权从-的管理员处理 (13认同)
  • 是的,那将会发生......在我看来是可以接受的.您可以做的是从安装程序运行脚本,然后运行您的应用程序并退出.这样,您的应用程序就会运行,但脚本将退出,这也将使安装程序完成. (7认同)
  • 对不起,但这个答案是错的.对于初学者,提交自定义操作仅用于清除回滚数据.禁用回滚时,它们不会执行.然后讨论了安全模型问题. (3认同)

小智 7

在Visual Studio 2010中,这很容易......

步骤1:向安装后要运行的应用程序项目添加新的安装程序类,并根据需要调用它.

步骤2:将以下代码添加到刚刚添加的安装程序类中,使用您的名称重新命名MyApplication.exe.

Public Overrides Sub Commit(ByVal savedState As System.Collections.IDictionary)

    MyBase.Commit(savedState)
    System.Diagnostics.Process.Start(System.IO.Path.GetDirectoryName(Me.Context.Parameters("AssemblyPath")) + "\MyApplication.exe")

End Sub
Run Code Online (Sandbox Code Playgroud)

编译并去......

  • 使用此方法将启动具有管理员权限的新程序,这可能不利于安全。 (2认同)

小智 5

就我而言,我为此挣扎了一段时间,解决方案就在那里。使用自定义操作直接提供给应用程序主输出的解决方案对我不利,因为安装应用程序会一直保留到您离开主应用程序。因此,可以使用下一种方法解决该问题:

  1. 在你的项目中添加一个 Install 类;
  2. 在新类中,覆盖 Commit 方法,就像上面Jarrod 所说的那样。

    System.Diagnostics.Process.Start(System.IO.Path.GetDirectoryName(this.Context.Parameters["AssemblyPath"]) + @"\MyApplication.exe");

  3. 现在诀窍是:转到安装程序项目中的“自定义操作”窗格,并将项目的主要输出添加到“提交”和“安装”文件夹中。不要更改属性中的任何内容。它会像那样工作。默认情况下,它将获取您在上一点插入代码的安装程序类;
  4. 构建您的安装包并安装它。您应该注意到该应用程序将在最后启动;
  5. 只需关闭成功安装警告并执行它。

要了解有关此内容的更多信息以及我从何处获得它,请访问

PS.: 我是用 VS2017 和 Framework 2.0 做的。


Jay*_*Tee 5

来自https://blogs.msdn.microsoft.com/astebner/2006/08/12/mailbag-how-can-i-customize-an-msi-in-the-visual-studio-setupdeployment-project/的解决方案 添加了安装结束时的复选框,以选择是否要启动该应用程序。您可以修改默认情况下要检查的脚本...甚至隐藏它。

这里最大的好处是,该应用程序不会像Maurice Flanagan提到的那样以提升的权限运行。

您需要的脚本是:

// EnableLaaunchApplication.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();

    // 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 + "', '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)
{
    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);
}
Run Code Online (Sandbox Code Playgroud)

编辑文件以显示所需的名称和可执行文件的名称,将该文件放在.vdproj安装项目旁边,并在postbuild中添加以下行:

调用cscript.exe“ $(ProjectDir)EnableLaunchApplication.js”“ $(BuiltOuputPath)”

  • 这对我不起作用,我收到了 2810 错误。我能够发现这个SO答案/sf/answers/4162894571/,这导致我使用Orca并修改JS文件,在其中插入新的CheckboxLaunch控件以使其成为nextcontrol Line1而不是CloseButton。如果您遇到困难,请使用 Orca 进行调试,因为这样脚本就可以完美运行! (4认同)
  • 这确实是正确的答案,特别是考虑到我的应用程序使用 AD 登录信息,并且安装程序以系统用户身份运行。缺点是它不适用于安静或被动安装。现在把这个 js 拆开看看我是否能弄清楚。 (3认同)