可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a Visual Studio setup project.
Upon installation, it creates an uninstall batch file in the application folder. IF the user wants to uninstall the product, he can go to "Add/Remove Programs", or he can just double-click the uninstall.cmd. The contents are:
%windir%\system32\msiexec /x {CC3EB7BF-DD82-48B9-8EC5-1B0B62B6D285}
The GUID there is the ProductCode from the Setup Project in Visual Studio.
But, in order for upgrades to work properly, I have to increment the Version number, every time I produce a new MSI. And, if I increment the Version number, then I also have to generate a new Guid for the ProductCode. Which means the static uninstall.cmd file needs to change.
How can I dynamically generate a batch file that contains the ProductCode for the, at build time?
回答1:
I found this solution here
"Using Visual Studio 2005/2008, you don’t need to write any code to add a uninstall option for a Setup project (Yes I know some people can write code to do it)
1) In the Setup Project –> File System windows –> Right Click “File System on Target machine” –> add a Special Folder, select System Folder;
2) Into this system folder Add a file. Browse for msiexec.exe from local System32 folder and add it. Override default properties of this file as follows:
Condition:=Not Installed (make sure you put ‘Not Installed’ exactly like that, same case and everything),
Permanent:=True,
System:=True,
Transitive:=True,
Vital:=False.
3) Create a new shortcut under the ‘Users Program Menu’, Set Target to the System Folder which you created in the step 1. and point it’s at the msiexec.exe. Rename the shortcut to ‘Uninstall Your Application’. Set the Arguments property to /x{space}[ProductCode].
4) Build the project, ignore warning about the fact that msiexec should be excluded, DONT exclude it or the setup project wont build.
The ‘Not Installed’ condition and Permananet:=True ensure that the msiexec.exe is only placed into the system folder as part of the install IF it doesn’t aready exist, and it is not removed on an uninstall - therefore it;s pretty safe to ignore that warning and just go for it.
(Based on the description from SlapHead)"
回答2:
I just made this work:
Add an uninstall.bat file to your project. The file contents is:
msiexec.exe /x %1
Make a shortcut to that batch file (say in User's Program Menu), specify in the shortcut's properties, next to Arguments: [ProductCode]
.
回答3:
This is the script I wrote that creates an uninstall.cmd. It runs as a custom action during installation.
var fso, ts;
var ForWriting= 2;
fso = new ActiveXObject("Scripting.FileSystemObject");
var parameters = Session.Property("CustomActionData").split("|");
var targetDir = parameters[0];
var productCode = parameters[1];
ts = fso.OpenTextFile(targetDir + "uninstall.cmd", ForWriting, true);
ts.WriteLine("@echo off");
ts.WriteLine("goto START");
ts.WriteLine("=======================================================");
ts.WriteBlankLines(1);
ts.WriteLine(" Uninstall.cmd");
ts.WriteBlankLines(1);
ts.WriteLine("=======================================================");
ts.WriteBlankLines(1);
ts.WriteLine(":START");
ts.WriteLine("@REM The uuid is the 'ProductCode' in the Visual Studio setup project");
ts.WriteLine("%windir%\\system32\\msiexec /x " + productCode);
ts.WriteBlankLines(1);
ts.Close();
The result is a cmd file that always has the current ProductCode in it.
The downside of this is that ?the script that creates the uninstall.cmd remains in the installation directory. Not a huge problem but I don't like the rubbish in the install directory. I haven't yet tried to make the "createInstaller.js" self-deleting. That might work.
EDIT: yes, making the createInstaller.js self-deleting works fine.
I'm going to accept my own answer!
回答4:
a slight variation on the batch file approach. if you don't want to show a command window, use a wscript file. supply [ProductCode] as before in Arguments
<job>
<?job debug="true" error="true" ?>
<script language="JScript">
var arg = [];
for (var i=0; i<WSH.Arguments.length; i++) {
arg.push( WSH.Arguments.Item(i) );
}
if (arg.length>0) {
var productcode = arg[0];
var v = new ActiveXObject("Shell.Application");
v.ShellExecute("msiexec.exe", "/x "+productcode, "", "open", 10);
}
WSH.Quit(0);
</script>
</job>
回答5:
For removing the application I would use the [ProductCode] as a parameter, calling the msiexec from within the application itself - for a detailed guide as to creating the uninstaller please check this blog: http://endofstream.com/creating-uninstaller-in-a-visual-studio-project/
回答6:
I realize this question has already been answered, but what I did was create a batch file with the following content:
start msiexec.exe /x %1
Using "start" prevents the command prompt from staying open during the uninstallation process and the %1 is replaced by the first argument you pass to the batch file when executing it.
I added the batch file to the application folder and created a menu shortcut that points to the batch file. If you right click the shortcut and select Properties Window. In there, add the following text to the Arguments property:
[ProductCode]
After building and running the installer, you'll have a start menu shortcut that calls the batch file and passes the product code as it was when that version of the application was built. The user will then see a prompt asking if the product should be uninstalled.
The only downside of this solution is that if the user browses to the application folder and double clicks the batch file, the uninstaller will give an error that the install package does not exist.
回答7:
I did a combination of the accepted answer and Locksmith's answer to not see any flashes of command prompt or the command prompt itself. One pro of doing it like this is that you DONT HAVE to create a shortcut and set the arguments for it in order for it to work.
My createUninstaller.js file:
var fso, ts;
var ForWriting= 2;
fso = new ActiveXObject("Scripting.FileSystemObject");
var parameters = Session.Property("CustomActionData").split("|");
var targetDir = parameters[0];
var productCode = parameters[1];
ts = fso.OpenTextFile(targetDir + "Uninstall.js", ForWriting, true);
ts.WriteLine("var v = new ActiveXObject(\"Shell.Application\");");
ts.WriteLine("v.ShellExecute(\"msiexec.exe\", \"/x "+productCode+"\", \"\", \"open\",10);");
ts.Close();
This file is added as a custom action at the commit action 'directory'. In order to actually get to this custom actions:
right click your setup project>view>custom actions>right click commit 'directory'>add custom action. After you have to search for the createUninstaller.js file you created and add it.
Now to make the createUninstaller.js read the variables targetDir and productCode you have to
Right click the createUninstaller.js file in the setup project custom action
'commit' directory and go to properties window.
In properties you will see the 'CustomActionData' property. In there you just copy paste [TARGETDIR]|[ProductCode]
And VOILA! It should now add the Uninstall.js file which will work as soon as you double click it.
回答8:
every time when u generate setup then always change product code. create a uninstaller shortcut and there u will find command line argument passing technique to sort cut. there u will write always "/u product code" product code u need to write here always.
put this code in main method of program.cs file
[STAThread]
static void Main()
{
bool flag = true;
string[] arguements = Environment.GetCommandLineArgs();
foreach (string str in arguements)
{
if ((str.Split('='))[0].ToLower() == "/u")
{
if (MessageBox.Show("Do you want to uninstall job board", "Are you Sure?", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
flag = false;
RemoveRegSettings();
RemoveIniFile();
string guid = str.Split('=')[1];
string path = Environment.GetFolderPath(Environment.SpecialFolder.System);
ProcessStartInfo si = new ProcessStartInfo(path + @"\msiexec.exe", "/i" + guid);
Process.Start(si);
Application.Exit();
return;
}
}
}
//
//************************************************
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);