web-dev-qa-db-ja.com

msiインストール後にexeを実行しますか?

Visual Studio 2008を使用してmsiを作成し、セットアッププロジェクトでプログラムを展開します。 msiにインストールしたexeを実行させる方法を知る必要があります。カスタムアクションですか?その場合、どこで/どのように説明してください。ありがとう。

54
Shawn

これはよくある質問です。 justカスタムアクションでは実行しません。私が知っている唯一の方法は、生成された後に.msiを変更することです。まさにそれを行うために、ビルド後イベントとしてJavascriptスクリプトを実行します。インストーラウィザードに、「アプリケーションFooを起動しますか?」というチェックボックスが付いた新しいダイアログが挿入されます。そして、チェックボックスがチェックされている場合、アプリを実行するためのカスタムアクションがあります。

これは、インストールWizardシーケンスの最後の画面として表示されます。次のようになります。

alt text


これは、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のブログ から取得し、それを修正しました。

そのJavascriptファイルをプロジェクトディレクトリ(.vdprojを含むディレクトリと同じディレクトリ)に保存し、_ModifyMsiToEnableLaunchApplication.js_という名前を付けます。固有のセットアッププロジェクトごとに、そのスクリプトを変更し、適切なexe名をそれに入力する必要があります。次に、セットアッププロジェクトでビルド後のイベントを次のように設定する必要があります。

_cscript.exe "$(ProjectDir)ModifyMsiToEnableLaunchApplication.js" "$(BuiltOuputPath)"
_

マクロ$(BuiltOuputPath)の名前を正しく入力してください。 Word OuputのスペルはMicrosoftによって間違っており、BuiltのスペルはBuildではありません

それはそれをするべきです。

次も参照してくださいこの変更 UNINSTALLの「run Foo.exe」チェックボックスを含みません。

78
Cheeso

これは非常にシンプルなソリューションのようです: Visual Studio Installer>インストーラーの最後にアプリを起動する方法

19
dlchambers

OK!!!これは、チェックボックスコントロールの可視性条件を追加するとともに、コントロールのYと高さを変更する機能を提供するコード(最後に2つの補助関数「FindFileIdentifier」と「StringEndsWith」なし-代わりに元のものを使用)です。 (「NEW-START」から「NEW-END」までの間にマークされている2つのコメントを参照してください):


// 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);
}
11
akarkoulis

「隠れたチェックボックスのバグ」に関して、私は上記のCheesoとMuleskinnerの回答では説明されていない以下を見つけました。

スクリプトを変更すると(Muleskinnerが提供)、チェックボックスのY位置が201になります(コントロールのYピクセルの上部が推測されます)。 Yを、たとえば151に変更すると(垂直方向の中央に配置するため)、「突然」バグが表示されます。その理由は、msiのコントロールテーブルに別のコントロール、つまり 'BodyText'( 'Dialog'フィールド= 'FinishedForm')があり、Yが63に、高さが138に設定されているためです。つまり、138 + 63 =201。したがって、チェックボックスのY値を変更すると、「BodyText」コントロールが新しく追加されたコントロールと重なるため、ユーザーはチェックボックスを表示するためにマウスを置く必要があります。 「BodyText」がない場合、または文字数が十分に少ない場合は、これらの2つのコントロールのYsとHeightsを変更し、調整することができます(Orca msiエディターを使用するか、上記のスクリプトを変更します)。新しく追加されたチェックボックスの異なるY位置。同じことがコントロールにも当てはまります: 'BodyTextRemove'では、高さの値を再度変更する必要があります(アンインストール中に表示されます)

これが、この「バグ」について私と同じ質問を持っていたすべてのユーザーに役立つことを願っています

それにもかかわらず、スクリプトは本当に良い仕事をしています!

別の質問は、ユニスタレーション手順中にチェックボックスを非表示にする方法でした。 Orca msiエディターを使用して、msiのControlConditionテーブルに次の2行を追加しました。

行1(コントロールを表示する必要がある場合):

(ダイアログ)FinishedForm(コントロール)CheckboxLaunch(アクション)Show(条件)REMOVE = ""

行2(コントロールを非表示にする必要がある場合):

(ダイアログ)FinishedForm(コントロール)CheckboxLaunch(アクション)非表示(条件)REMOVE <> ""

追伸Windows 7(x64)でVS 2010を使用していますが、以前のバージョンでも動作するはずです。

8
akarkoulis

「PostBuildEvent」がエラーコード「1」「不明なエラー」で失敗しましたエラーについては、PostBuildEventを

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

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

隠されたチェックボックスのバグに関しては、スクリプトの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', '|')";
4
Muleskinner

はい。カスタムアクションを記述し、InstallExecutionSequenceテーブルの最後に貼り付けます

2
Nestor