msi 설치 후 exe를 실행 하시겠습니까?
Visual Studio 2008을 사용하여 설치 프로젝트와 함께 내 프로그램을 배포하는 msi를 만듭니다. msi가 방금 설치 한 exe를 실행하도록하는 방법을 알고 싶습니다. 커스텀 액션? 그렇다면 장소 / 방법을 설명해주십시오. 감사.
이것은 일반적인 질문입니다. 나는 그것을하지 않는다 단지 사용자 지정 작업. 내가 아는 유일한 방법은 .msi가 생성 된 후 수정하는 것입니다. 자바 스크립트 스크립트를 빌드 후 이벤트로 실행하여 정확히 수행합니다. 설치 마법사에 "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의 블로그 에서 이것을 가져와 수정했습니다.
해당 Javascript 파일을 프로젝트 디렉토리 (.vdproj를 포함하는 것과 동일한 디렉토리)에 저장하고 이름을 ModifyMsiToEnableLaunchApplication.js
. 각각의 고유 한 설정 프로젝트에 대해 해당 스크립트를 수정하고 적절한 exe 이름을 입력해야합니다. 그런 다음 Setup 프로젝트에서 빌드 후 이벤트를 다음과 같이 설정해야합니다.
cscript.exe "$(ProjectDir)ModifyMsiToEnableLaunchApplication.js" "$(BuiltOuputPath)"
매크로 이름을 $(BuiltOuputPath)
올바르게 입력해야 합니다. 이 단어는 Ouput
Microsoft에서 철자가, 그리고 Built
철자가되지 않는다 Build
!
그렇게해야합니다.
참조 : UNINSTALL에 "run Foo.exe"확인란이 포함되지 않은 이 수정 .
이것은 훨씬 더 간단한 솔루션 인 것 같습니다. Visual Studio 설치 관리자> 설치 프로그램 종료시 앱을 시작하는 방법
확인!!! 다음은 체크 박스 컨트롤 가시성 조건을 추가하는 것과 함께 컨트롤의 Y 및 높이를 변경할 수있는 기능을 제공하는 코드 (두 가지 보조 기능 '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);
}
"숨겨진 확인란 버그"와 관련하여 위의 Cheeso와 Muleskinner의 답변에 설명되지 않은 다음을 알아 냈습니다.
The change of the script (provided by Muleskinner) places the Y position of the checkbox to 201 (I guess top Y pixel for the control). If you change Y to, say, 151 (in order to kind of align it in the center vertically), the bug "suddenly" appears. The reason for that is that there is another control in the Control table of the msi, namely the 'BodyText' ('Dialog' field = 'FinishedForm') which its Y is set to 63 and its height to 138. That is 138 + 63 = 201. Therefore, if you change the Y value for the checkbox, the 'BodyText' control overlaps the newly added control and that's why the user needs to put their mouse over in order to show the checkbox. If you have no 'BodyText' or its number of characters is small enough you could change (by using Orca msi editor as I do, or by altering the script above) the Ys and Heights of these 2 controls in order to be able and accomodate a different Y position for the newly added checkbox. The same applies for the control: 'BodyTextRemove' in which again we should alter its height value (which appears during uninstall)
Hope that this helps all the users that had the same question as I had about this "bug"
Nevertheless, the script does a really good job!
Another question was how to make invisible the Checkbox during unistallation procedure. Using the Orca msi editor I added the following 2 rows in the ControlCondition table of the msi:
Row 1 (When control should be shown):
(Dialog)FinishedForm (Control)CheckboxLaunch (Action)Show (Condition)REMOVE=""
Row 2 (When control should be invisible):
(Dialog)FinishedForm (Control)CheckboxLaunch (Action)Hide (Condition)REMOVE<>""
P.S. I am using VS 2010, on windows 7 (x64), but I believe these should work with previous versions too.
오류 코드 '1' 'Unspecified error' 오류로 인해 'PostBuildEvent'가 실패한 경우 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', '|')";
예 .. 사용자 지정 작업을 작성하여 InstallExecutionSequence 테이블 끝에 붙입니다.
참조 URL : https://stackoverflow.com/questions/1668274/run-exe-after-msi-installation
'Nice programing' 카테고리의 다른 글
dplyr mutate rowSums 계산 또는 사용자 지정 함수 (0) | 2021.01.10 |
---|---|
Docker 컨테이너에서 영구적으로 PATH 환경 변수 업데이트 (0) | 2021.01.10 |
"if"필터가있는 반복자에 대한 한 줄 for 루프? (0) | 2021.01.10 |
Excel의 하위 문자열 (0) | 2021.01.10 |
Ubuntu 10.4에서 RubyGems 1.3.6을 어떻게 구할 수 있습니까? (0) | 2021.01.10 |