Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The <a href="http://wix.sourceforge.net/manual-wix3/wix_xsd_removefile.htm" rel="nofollow">RemoveFile element</a> is designed to do exactly this. You use this to teach MSI to remove application data it didn't install. The advantage is during a rollback the files will be put back in place.</p> <p>You can also use the RemoveFolder element to delete the entire directory. Generally the concept is to * the file removal and specify the folder also. This isn't recursive so you need to do this for any subdirectories that might have got created also.</p> <p>Writing custom actions is just reinventing the wheel and increases installer fragility. It should only be used when the subdirectories cannot be known in advance. In that situation the ideal story is to use temp rows in MSI to dynamically emit the rows into the MSI at install time and let MSI handle thea actual delete. This allows the rollback functionality to still work.</p> <p>Here is a really simple version of what that would look like. It could be improved by making it data driven from a custom table instead of constant strings for ComponentID and DirectoryID.</p> <pre><code> public class RecursiveDeleteCustomAction { [CustomAction] public static ActionResult RecursiveDeleteCosting(Session session) { // SOMECOMPONENTID is the Id attribute of a component in your install that you want to use to trigger this happening const string ComponentID = "SOMECOMPONENTID"; // SOMEDIRECTORYID would likely be INSTALLDIR or INSTALLLOCATION depending on your MSI const string DirectoryID = "SOMEDIRECTORYID"; var result = ActionResult.Success; int index = 1; try { string installLocation = session[DirectoryID]; session.Log("Directory to clean is {0}", installLocation); // Author rows for root directory // * means all files // null means the directory itself var fields = new object[] { "CLEANROOTFILES", ComponentID, "*", DirectoryID, 3 }; InsertRecord(session, "RemoveFile", fields); fields = new object[] { "CLEANROOTDIRECTORY", ComponentID, "", DirectoryID, 3 }; InsertRecord(session, "RemoveFile", fields); if( Directory.Exists(installLocation)) { foreach (string directory in Directory.GetDirectories(installLocation, "*", SearchOption.AllDirectories)) { session.Log("Processing Subdirectory {0}", directory); string key = string.Format("CLEANSUBFILES{0}", index); string key2 = string.Format("CLEANSUBDIRECTORY{0}", index); session[key] = directory; fields = new object[] { key, ComponentID, "*", key, 3 }; InsertRecord(session, "RemoveFile", fields); fields = new object[] { key2, ComponentID, "", key, 3 }; InsertRecord(session, "RemoveFile", fields); index++; } } } catch (Exception ex) { session.Log(ex.Message); result = ActionResult.Failure; } return result; } private static void InsertRecord(Session session, string tableName, Object[] objects) { Database db = session.Database; string sqlInsertSring = db.Tables[tableName].SqlInsertString + " TEMPORARY"; session.Log("SqlInsertString is {0}", sqlInsertSring); View view = db.OpenView(sqlInsertSring); view.Execute(new Record(objects)); view.Close(); } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload