Search code examples
visual-studio-2005setup-projectdeployment-projectadvertised-shortcut

How Do I Prevent the Installer from Running when Application Data Files are Removed?


I have an application written in VB.Net with Visual Studio 2005. The application allows the user to create and save project files. When I distribute the application, I include some demo project files, which I install in the common application data folder.

XP - C:\Documents and Settings\All Users\Application Data

Vista & 7 - C:\Program Data

I have discovered an unexpected behavior -- if any file in the common application data folder is removed, and the application is run from the start menu, then the install procedure will start and attempt to restore the missing file(s). If the MSI file no longer exists at its original location or has been changed, then the application will fail to run. I perceive that this is a "feature", but it is one I don't want. Can anyone tell me what is going on and how I can avoid it?

Some more details:

  • I created the setup package by using a Visual Studio deployment project.

  • This behavior will not occur if I launch the EXE directly. I expect, therefore, that the behavior has something to do with the start menu shortcut. I've noticed that the shortcut isn't a normal shortcut -- it doesn't have a "Target Location".

All advice is appreciated.

-TC


Solution

  • I have learned that this behavior involves something called "Install-on-Demand" (aka "Self Heal"). The unusual shortcuts created by the setup package are called "Advertised Shortcuts". Now that I have a name for the problem, it is easy to find information on how to fix it. Notably:

    Those pages contain a wealth of information. For the convenience of others who may stumble upon this post, I will summarize what they say:

    Advertised shortcuts are special shortcuts which do some fancy things. Most notably, they reinstall damaged application before launching their target. There is some debate over whether they are good, evil, or harmless. In my opinion, they do something most users don't expect, and that makes them evil. Therefore, I'd like to disable them for my application.

    Visual Studio setup projects automatically create MSI packages which generate advertised shortcuts by default. It is easy to override that default when installing the MSI package by using DISABLEADVTSHORTCUTS=1 as a command-line argument for Setup.exe. Also, with a utility like Orca, you can manually change the default by inserting DISABLEADVTSHORTCUTS=1 as a property of the MSI. However, if you want Visual Studio to automatically create MSI packages which don't create advertised shortcuts, that is harder. I did it this way:

    1. First, I created a VBS file using the DisableAdvt code provided by Gary Chang in one of the links above (I've repeated that code below). Just create a text file, paste in the code. and save it as DisableAdvt.vbs.

    2. Then, create a post-build event for your setup project. The exact syntax will depend on your file locations. Because my DisableAdvt.vbs is in a "Tools" subfolder of the solution folder, my post-build event looks like this:

      • "$(ProjectDir)..\Tools\DisableAdvt\DisableAdvt.vbs" "$(BuiltOuputPath)"

    That's all I had to do. It works like a charm.

    -TC

    Some notes:

    In Visual Studio 2005, Build events are accessed differently for setup projects than they are for other types of projects. Click on the project name in the solution explorer, then look for PostBuildEvent in the Properties pane.

    Orca is a utility that can be used to manually insert the DISABLEADVTSHORTCUTS property into the MSI file. With my approach, Orca is not necessary. However, it is useful for verifying that the build event is making the expected change.

    In the build event, the misspelling "BuiltOuputPath" is intentional.

    Here is Gary Chang's DisableAdvt.vbs code (note that I fixed a typo on line 21 -- Very important!):

    Option Explicit
    
    Const msiOpenDatabaseModeTransact = 1
    Dim argNum, argCount:argCount = Wscript.Arguments.Count
    
    Dim openMode : openMode =  msiOpenDatabaseModeTransact
    
    ' Connect to Windows installer object
    On Error Resume Next
    Dim installer : Set installer = Nothing
    Set installer = Wscript.CreateObject("WindowsInstaller.Installer") :
    CheckError
    
    ' Open database
    Dim databasePath:databasePath = Wscript.Arguments(0)
    Dim database : Set database = installer.OpenDatabase(databasePath, openMode) : CheckError
    
    ' Process SQL statements
    Dim query, view, record, message, rowData, columnCount, delim, column
    
    query = "INSERT INTO Property(Property, Value) VALUES ('DISABLEADVTSHORTCUTS', '1')"  
    Set view = database.OpenView(query) : CheckError
    view.Execute : CheckError
    
    database.Commit
    
    If Not IsEmpty(message) Then Wscript.Echo message
    Wscript.Quit 0
    
    Sub CheckError
      Dim message, errRec
      If Err = 0 Then Exit Sub
      message = Err.Source & " " & Hex(Err) & ": " & Err.Description
      If Not installer Is Nothing Then
        Set errRec = installer.LastErrorRecord
        If Not errRec Is Nothing Then message = message & vbLf & errRec.FormatText
      End If
    Fail message
    End Sub
    
    Sub Fail(message)
      Wscript.Echo message
      Wscript.Quit 2
    End Sub