Запустите exe после установки msi?
использование Visual Studio 2008 для создания msi для развертывания моей программы с помощью проекта установки. Мне нужно знать, как заставить msi запустить exe, который он только что установил. Пользовательское действие? Если да, пожалуйста, объясните, где / как. Спасибо.
6 ответов:
это общий вопрос. Я не делаю этого с просто настраиваемое действие. Единственный способ, который я знаю, это изменить .компания MSI после того, как он был сформирован. Я запускаю скрипт Javascript как событие после сборки, чтобы сделать именно это. Он вставляет новый диалог в мастере установки, с флажком, который говорит "запустить приложение 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); }
Я изначально получил от Аарон Stebner блог, а затем изменить его.
Сохраните этот файл Javascript в каталог проекта (тот же каталог, что и contains .vdproj), назовите его
ModifyMsiToEnableLaunchApplication.js
. Для каждого уникального проекта установки необходимо изменить этот сценарий и ввести в него правильное имя exe. И тогда, вам нужно установите событие после сборки в проекте установки следующим образом:cscript.exe "$(ProjectDir)ModifyMsiToEnableLaunchApplication.js" "$(BuiltOuputPath)"
обязательно введите имя макроса
$(BuiltOuputPath)
правильно. СловоOuput
неправильно пишется Microsoft, иBuilt
попBuild
!это должно быть сделано.
см. также:эта модификация который не включает в себя "run Foo.exe " флажок при удалении.
Это, кажется, гораздо более простое решение: установщик Visual Studio > как запустить приложение в конце установщика
ОК!!! Вот код (без 2 вспомогательных функций 'FindFileIdentifier' & 'StringEndsWith' в конце-используйте вместо них исходные), который дает нам возможность изменять Ys и высоты элементов управления, а также добавлять условия видимости управления флажком (см. 2 комментария, которые отмечены между "NEW-START" и "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); }
относительно "скрытой ошибки флажка" я выяснил следующее, что не объясняется Ответы чизо и Muleskinner выше:
изменение скрипта (предоставленное Muleskinner) помещает положение y флажка в 201 (я думаю, верхний пиксель Y для элемента управления). Если вы измените Y, скажем, на 151 (чтобы выровнять его по центру вертикально), ошибка "внезапно" появится. Причина этого заключается в том, что в таблице управления msi есть еще один элемент управления, а именно "BodyText" ('Dialog'field = 'FinishedForm'), который его Y установлен в 63, а его высота-в 138. То есть 138 + 63 = 201. Поэтому, если вы измените значение Y для флажка, элемент управления "BodyText" перекрывает недавно добавленный элемент управления, и поэтому пользователю необходимо поместить курсор мыши, чтобы отобразить флажок. Если у вас нет "BodyText" или его количество символов достаточно мало, вы можете изменить (используя редактор Orca msi, как и я, или изменив сценарий выше) Ys и высоты из этих 2 элементов управления, чтобы иметь возможность и разместить другую позицию Y для вновь добавленного флажка. То же самое относится и к элементу управления: 'BodyTextRemove', в котором мы снова должны изменить его значение высоты (которое появляется во время удаления)
надеюсь, что это поможет всем пользователям, у которых был тот же вопрос, что и у меня об этой "ошибке"
тем не менее, скрипт делает действительно хорошую работу!
другой вопрос, как сделать невидимым флажок во время unistallation процедуры. С помощью редактора Orca msi я добавил следующие 2 строки в таблицу ControlCondition msi:
строка 1 (когда должен быть показан элемент управления):
(Диалог)FinishedForm (Контроль)CheckboxLaunch (Действие)Шоу (Условие)удалить=""
строка 2 (когда управление должно быть невидимым):
(Диалог)FinishedForm (Контроль)CheckboxLaunch (Действие)Скрыть (Условие)удалить""
P. S. Я, используя против 2010, на Windows 7 (х64), но я считаю, что они должны работать и с предыдущими версиями.
о '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', '|')";