28

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.

ProductCode

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?

Cheeso
  • 189,189
  • 101
  • 473
  • 713

8 Answers8

67

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)"

MPelletier
  • 16,256
  • 15
  • 86
  • 137
Ben
  • 845
  • 1
  • 8
  • 9
  • 1
    Now that's very handy and much more direct than the approach I took. – Cheeso Sep 02 '09 at 19:59
  • 8
    Awesome, works very well for me on WinXP/Vista & Win7. Worth noting that according to the article linked to, if you use a version of msiexec.exe HIGHER than the target platform there are issues. This is not an issue for me as I'm still intentionally using XP for building - but obviously if you want an installer built on Vista to run on XP that will be an issue. – Iain Collins Nov 24 '09 at 12:15
  • Great Post! Exactly what i was looking for. – Martin Dec 08 '11 at 05:34
  • 3
    Regarding the problem that arises when building the Installer under Vista/7, and the installer tries to overwrite msiexec on older, XP machines; this can be corrected by creating an empty .txt file, and renaming it to "msiexec.exe." Include that file in your installer, rather than the *actual* System32 version. Since the empty, fake file has no version information, it will not try to overwrite the XP msiexec. – BTownTKD May 17 '12 at 18:39
  • This is a good idea. But i have a problem. When i click on uninstall shortcut it throws me the error : "This installation package could not be opened. Verify that the package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer package." . Why it throws me this error. I know it's been a few years but now i am using it.... – NickName Jan 14 '15 at 10:36
  • 2
    @NickName I got the same error too. Set the Arguments property to /x{space}[ProductCode] isn't work for me ,but I change the Arguments property to /x [ProductCode],it works.I guess visual studio just can't recognize what's {space} means.by the way ,I tried in VS2005. – Rhain May 29 '15 at 02:56
10

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].

Community
  • 1
  • 1
MPelletier
  • 16,256
  • 15
  • 86
  • 137
  • 1
    You can get rid of the black window by using `start msiexec.exe /x %1`; but the black window still flashes. – moala Jul 13 '12 at 15:40
  • Probably `start /B msiexec.exe /x %1`. – MPelletier Jul 13 '12 at 15:58
  • Try `/min`, it should at least minimize it. – MPelletier Jul 13 '12 at 17:48
  • 4
    no, the windows which flashes is not the one of the start command, it is the one of the .bat, so an additional switch is not the solution; the solution is at the vdproj installation project: the ShowCmd property of the shortcut calling from the value vsdscNormal value to the vsdscMinimized value. Solved. – moala Jul 15 '12 at 15:12
4

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!

Cheeso
  • 189,189
  • 101
  • 473
  • 713
  • 1
    Fine solution but damn hacky, I'm wondering about Microsoft, Install-makers I tried before (such inno) was making unistall file automatically. – cnd May 26 '11 at 04:58
  • 1
    I know it's been a few years, but I for one would like to know how exactly you went about using this, Cheeso. Are you overriding the `OnAfterInstall`? If so, how are you inserting Script there? –  Jul 27 '11 at 15:32
2

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>
locksmith
  • 2,311
  • 1
  • 13
  • 4
1

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.

Jela
  • 562
  • 1
  • 6
  • 20
1

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/

Peter
  • 11
  • 1
1

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.

Merv
  • 1,039
  • 2
  • 12
  • 22
0

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);
Thomas
  • 33,544
  • 126
  • 357
  • 626