Uruchom exe po instalacji msi?

Użycie Visual Studio 2008 do stworzenia msi do wdrożenia mojego programu z projektem instalacyjnym. Muszę wiedzieć, jak sprawić, by msi uruchomił właśnie zainstalowany exe. Niestandardowa akcja? Jeśli tak, proszę wyjaśnić, gdzie/w jaki sposób. Dzięki.

Author: Shawn, 0000-00-00

6 answers

To częste pytanie. Nie robię tego z tylko niestandardową akcją. Jedynym sposobem, jaki znam, jest zmodyfikowanie .msi po jego wygenerowaniu. Uruchamiam skrypt Javascript jako zdarzenie post-build, aby to zrobić. Wstawia nowe okno dialogowe w kreatorze instalatora, z pole wyboru z napisem " Uruchom aplikację Foo?". Następnie istnieje niestandardowa akcja , aby uruchomić aplikację, jeśli pole wyboru jest zaznaczone.

Pojawia się jako ostatni ekran w sekwencji kreatora instalacji. Wygląda tak:

alt text


To jest skrypt, którego używam do modyfikacji 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);
}

Oryginalnie dostałem to z bloga Aarona Stebnera , a następnie go zmodyfikowałem.

Zapisz ten plik Javascript w katalogu projektu (tym samym katalogu, który zawiera.vdproj), nazwij to ModifyMsiToEnableLaunchApplication.js. Dla każdego unikalnego projektu instalacyjnego, musisz zmodyfikować ten skrypt i umieścić w nim właściwą nazwę exe. Następnie musisz ustawić Zdarzenie post-build w projekcie instalacyjnym na takie:

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

Pamiętaj, aby poprawnie wpisać nazwę makra $(BuiltOuputPath). Słowo Ouput jest błędnie napisane przez Microsoft, a Built nie jest napisane Build!

To powinno wystarczyć.

: ta modyfikacja , która nie zawiera " run Foo.exe " pole wyboru przy odinstalowywaniu.

 77
Author: Cheeso,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:12

To wydaje się być dużo prostsze rozwiązanie: Instalator Visual Studio > Jak uruchomić aplikację na końcu Instalatora

 19
Author: dlchambers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:17:29

OK!!! Oto kod (Bez 2 pomocniczych funkcji 'FindFileIdentifier' & 'StringEndsWith' na końcu - użyj oryginalnych), który daje nam możliwość zmiany Ys i wysokości kontrolek, wraz z dodaniem warunków widoczności kontrolek (zobacz 2 komentarze, które są oznaczone między 'NEW-START' do 'NEW-END'): {]}


// 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
Author: akarkoulis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-03 09:17:01

Odnośnie "ukrytego błędu checkboxa" doszedłem do tego co nie jest wyjaśnione przez Odpowiedzi Cheese ' a i Muleskinnera powyżej:

Zmiana skryptu (dostarczonego przez Muleskinnera) umieszcza pozycję y checkboxa na 201 (chyba górny piksel y dla kontrolki). Jeśli zmienisz Y na, powiedzmy, 151 (w celu wyrównania go w środku pionowo), pojawi się błąd "nagle". Powodem tego jest to, że w tabeli sterowania msi znajduje się inna kontrola, a mianowicie 'BodyText' ('Dialog' field = 'FinishedForm'), którego Y jest ustawione na 63, a jego wysokość na 138. To jest 138 + 63 = 201. W związku z tym, jeśli zmienisz wartość Y dla pola wyboru, kontrolka "BodyText" nakłada się na nowo dodaną kontrolkę i dlatego użytkownik musi przesunąć kursor myszy, aby wyświetlić pole wyboru. Jeśli nie masz 'BodyText' lub jego liczba znaków jest na tyle mała, możesz zmienić (używając edytora Orca msi tak jak ja, lub zmieniając skrypt powyżej) Ys i wysokości tych 2 kontrolki, aby móc I pomieścić inną pozycję Y dla nowo dodanego pola wyboru. To samo dotyczy kontrolki: 'BodyTextRemove', w której ponownie powinniśmy zmienić jej wartość wysokości (która pojawia się podczas deinstalacji)

Mam nadzieję, że pomoże to wszystkim użytkownikom, którzy mieli to samo pytanie co ja odnośnie tego "błędu"

Niemniej jednak skrypt robi naprawdę dobrą robotę!

Kolejnym pytaniem było jak zrobić niewidoczne pole wyboru podczas procedury unistalacji. Korzystanie z Edytor Orca MSI dodałem następujące 2 wiersze w tabeli ControlCondition msi:

Wiersz 1 (gdy kontrola powinna być pokazana):

(Dialog) FinishedForm (Control)CheckboxLaunch (Akcja)Pokaż (Warunek)REMOVE= ""

Wiersz 2 (gdy kontrola powinna być niewidoczna):

(Dialog) FinishedForm (Control)CheckboxLaunch (Akcja)Ukryj (Warunek)Usuń ""

P. S. używam VS 2010, na windows 7 (x64), ale uważam, że powinny one działać również z poprzednimi wersjami.

 8
Author: akarkoulis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-08 15:27:45

W przypadku braku kodu błędu " 1 ""Nieokreślony błąd" należy zmienić PostBuildEvent z

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

Do

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

Odnośnie błędu ukrytego pola wyboru możesz edytować linię 54 skryptu, aby stała się:

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
Author: Muleskinner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-09 10:23:12

Tak.. Chciałbym napisać niestandardową akcję i umieścić ją na końcu tabeli InstallExecutionSequence

 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-04 02:21:56