Видалення файлів під час видалення WiX


84

Під час видалення моєї програми я хотів би налаштувати налаштування Wix, щоб видалити всі файли, додані після початкової інсталяції . Здається, програма видалення видаляє лише каталоги та файли, які спочатку були встановлені з файлу MSI, а все інше, що було додано пізніше, залишає у папці програми. Іншими словами, я хотів би очистити каталог під час видалення. Як це зробити?

Відповіді:


83

Використовуйте елемент RemoveFile з On = " uninstall ". Ось приклад:

<Directory Id="CommonAppDataFolder" Name="CommonAppDataFolder">
  <Directory Id="MyAppFolder" Name="My">
    <Component Id="MyAppFolder" Guid="*">
      <CreateFolder />
      <RemoveFile Id="PurgeAppFolder" Name="*.*" On="uninstall" />
    </Component>
  </Directory>
</Directory>

Оновлення

Це не спрацювало на 100%. Він видалив файли, проте жоден додатковий каталог - створений після встановлення - не був видалений. Будь-які думки з цього приводу? - прібейро

На жаль, інсталятор Windows не підтримує видалення каталогів з підкаталогами. У цьому випадку вам доведеться вдатися до нестандартних дій. Або, якщо ви знаєте, що таке підпапки, створіть купу елементів RemoveFolder та RemoveFile.


1
Дякую Павло. Однак це не спрацювало на 100%. Він видалив файли, проте жоден додатковий каталог - створений після встановлення - не був видалений. Будь-які думки з цього приводу?
прібейро

О, ані файли в цих каталогах не були видалені.
pribeiro

Коли ви будете зберігати файли (наприклад, конфігураційні файли) у 'MyAppFolder' на Основних оновленнях, ви отримаєте проблеми з цим підходом. Усі файли будуть видалені оновленням.
Саймон

1
Чи можливо за допомогою вашого коду створити каталог у MyAppFolder? Коли я додаю каталог після того, як у </Component>мене компіляція не вдаласяFound orphaned Component 'MyAppFolder'.
A.Pissicat

2
@PhilipRego Див. Msdn.microsoft.com/en-us/library/windows/desktop/aa367992.aspx щодо документування CommonAppDataFolder.
Павло Чучува

30

Використовуйте RemoveFolderExелемент з розширення Util у WiX.
При такому підході всі підкаталоги також видаляються (на відміну від безпосереднього використання RemoveFileелемента ). Цей елемент додає тимчасові рядки до RemoveFileта RemoveFolderтаблиці в базі даних MSI.


2
Попередження: При використанні RemoveFolderEx on = "uninstall" він також видаляє папку під час оновлення (Wix 3.9). Така ж поведінка на RemoveFileі RemoveFolder. Якщо ви хочете зберегти файли під час оновлення, ви не можете використовувати всі ці підходи.
Саймон

@Simon, який підхід ви б запропонували, якщо хочете тримати файли на оновлення?
Bijington

@Bijington: Коли ви хочете зберегти певні файли у вашій інсталяційній папці під час оновлення, використовуйте спеціальну дію, яка виконує користувацький код (наприклад, c # написаний HandleSetup.exe). Спеціальний код доставляє ваші файли під час встановлення, зберігаючи їх на оновлення та видаляє файли при видаленні.
Саймон

@Simon спасибі, я , можливо , доведеться заглянути в цей підхід , хоча це один в даний час працює: stackoverflow.com/a/21383113/32348
Bijington

13

Для цього я просто створив власну дію, яку потрібно викликати при видаленні.

Код WiX буде виглядати так:

<Binary Id="InstallUtil" src="InstallUtilLib.dll" />

<CustomAction Id="DIRCA_TARGETDIR" Return="check" Execute="firstSequence" Property="TARGETDIR" Value="[ProgramFilesFolder][Manufacturer]\[ProductName]" />
<CustomAction Id="Uninstall" BinaryKey="InstallUtil" DllEntry="ManagedInstall" Execute="deferred" />
<CustomAction Id="UninstallSetProp" Property="Uninstall" Value="/installtype=notransaction /action=uninstall /LogFile= /targetDir=&quot;[TARGETDIR]\Bin&quot; &quot;[#InstallerCustomActionsDLL]&quot; &quot;[#InstallerCustomActionsDLLCONFIG]&quot;" />

<Directory Id="BinFolder" Name="Bin" >
    <Component Id="InstallerCustomActions" Guid="*">
        <File Id="InstallerCustomActionsDLL" Name="SetupCA.dll" LongName="InstallerCustomActions.dll" src="InstallerCustomActions.dll" Vital="yes" KeyPath="yes" DiskId="1" Compressed="no" />
        <File Id="InstallerCustomActionsDLLCONFIG" Name="SetupCA.con" LongName="InstallerCustomActions.dll.Config" src="InstallerCustomActions.dll.Config" Vital="yes" DiskId="1" />
    </Component>
</Directory>

<Feature Id="Complete" Level="1" ConfigurableDirectory="TARGETDIR">
    <ComponentRef Id="InstallerCustomActions" />
</Feature>

<InstallExecuteSequence>
    <Custom Action="UninstallSetProp" After="MsiUnpublishAssemblies">$InstallerCustomActions=2</Custom>
    <Custom Action="Uninstall" After="UninstallSetProp">$InstallerCustomActions=2</Custom>
</InstallExecuteSequence>

Код методу OnBeforeUninstall у InstallerCustomActions.DLL буде виглядати так (у VB).

Protected Overrides Sub OnBeforeUninstall(ByVal savedState As System.Collections.IDictionary)
    MyBase.OnBeforeUninstall(savedState)

    Try
        Dim CommonAppData As String = Me.Context.Parameters("CommonAppData")
        If CommonAppData.StartsWith("\") And Not CommonAppData.StartsWith("\\") Then
            CommonAppData = "\" + CommonAppData
        End If
        Dim targetDir As String = Me.Context.Parameters("targetDir")
        If targetDir.StartsWith("\") And Not targetDir.StartsWith("\\") Then
            targetDir = "\" + targetDir
        End If

        DeleteFile("<filename.extension>", targetDir) 'delete from bin directory
        DeleteDirectory("*.*", "<DirectoryName>") 'delete any extra directories created by program
    Catch
    End Try
End Sub

Private Sub DeleteFile(ByVal searchPattern As String, ByVal deleteDir As String)
    Try
        For Each fileName As String In Directory.GetFiles(deleteDir, searchPattern)
            File.Delete(fileName)
        Next
    Catch
    End Try
End Sub

Private Sub DeleteDirectory(ByVal searchPattern As String, ByVal deleteDir As String)
    Try
        For Each dirName As String In Directory.GetDirectories(deleteDir, searchPattern)
            Directory.Delete(dirName)
        Next
    Catch
    End Try
End Sub

11

Ось варіація пропозиції @ tronda. Я видаляю файл "install.log", який створюється іншою спеціальною дією під час Видалення:

<Product>
    <CustomAction Id="Cleanup_logfile" Directory="INSTALLFOLDER"
    ExeCommand="cmd /C &quot;del install.log&quot;"
    Execute="deferred" Return="ignore" HideTarget="no" Impersonate="no" />

    <InstallExecuteSequence>
      <Custom Action="Cleanup_logfile" Before="RemoveFiles" >
        REMOVE="ALL"
      </Custom>
    </InstallExecuteSequence>
</Product>

Наскільки я розумію, я не можу використовувати "RemoveFile", оскільки цей файл створюється після встановлення і не є частиною групи компонентів.


4
Я використав це рішення, з деякими змінами, щоб видалити весь каталог: ExeCommand = "cmd / C RD & quot; [INSTALLFOLDER] & quot; / s / q"
Денніс,

@Dennis як видалити INSTALLFOLDER, при виграші 10 він видаляється, а на сервері Windows 2012 - ні.
eomeroff

Чудове рішення. Дякую!
Юрій Комарницький

Я спробував кілька речей - не можна подумати, що видалити один файл під час видалення може бути настільки складно. Це все ж спрацювало для мене - дякую!
Lucky Luke

7

Це було б більш повною відповіддю на пропозицію @Pavel , для мене це працює на 100%:

<Fragment Id="FolderUninstall">
    <?define RegDir="SYSTEM\ControlSet001\services\[Manufacturer]:[ProductName]"?>
    <?define RegValueName="InstallDir"?>
    <Property Id="INSTALLFOLDER">
        <RegistrySearch Root="HKLM" Key="$(var.RegDir)" Type="raw" 
                  Id="APPLICATIONFOLDER_REGSEARCH" Name="$(var.RegValueName)" />
    </Property>

    <DirectoryRef Id='INSTALLFOLDER'>
        <Component Id="UninstallFolder" Guid="*">
            <CreateFolder Directory="INSTALLFOLDER"/>
            <util:RemoveFolderEx Property="INSTALLFOLDER" On="uninstall"/>
            <RemoveFolder Id="INSTALLFOLDER" On="uninstall"/>
            <RegistryValue Root="HKLM" Key="$(var.RegDir)" Name="$(var.RegValueName)" 
                    Type="string" Value="[INSTALLFOLDER]" KeyPath="yes"/>
        </Component>
    </DirectoryRef>
</Fragment>

І в розділі Елемент продукту:

<Feature Id="Uninstall">
    <ComponentRef Id="UninstallFolder" Primary="yes"/>
</Feature>

Цей підхід встановлює значення реєстру з бажаним шляхом до папки, яку потрібно видалити під час видалення. Наприкінці з системи видаляються як INSTALLFOLDER, так і папка реєстру. Зверніть увагу, що шлях до реєстру може бути в інших вуликах та інших місцях.


6

Не фахівець з WIX, але чи можливим (простішим?) Рішенням цього може бути запуск спеціальної дії Quiet Execution, яка є частиною вбудованих розширень WIX?

Можна запустити команду rmdir MS DOS із параметрами / S та / Q.

<Binary Id="CommandPrompt" SourceFile="C:\Windows\System32\cmd.exe" />

А спеціальна дія, яка робить роботу, проста:

<CustomAction Id="DeleteFolder" BinaryKey="CommandPrompt" 
              ExeCommand='/c rmdir /S /Q "[CommonAppDataFolder]MyAppFolder\PurgeAppFolder"' 
              Execute="immediate" Return="check" />

Тоді вам доведеться змінити InstallExecuteSequence, як це задокументовано в багатьох місцях.

Оновлення: Були проблеми з цим підходом. Закінчило робити власне завдання натомість, але все ще вважає це життєздатним рішенням, але не змушуючи деталі працювати.


Мені подобається ця опція, що ви включаєте cmd.exe до програми встановлення. Напевно, це буде у кожної машини, вам просто потрібно використовувати DirectorySearch, щоб знайти його! :)
caveman_dick

4
Не роби цього. 1) ви вбудовуєтесь cmd.exeу свій інсталятор. 2) Ви вносите зміни в систему під час генерації сценарію 3) Немає можливості відкоту 4) Неправильно справляється із заблокованими файлами
Нік Уейлі

Я сумніваюся, що законно розповсюджувати файл із інсталяції Windows. Також незрозуміло, чи буде це працювати в цільовій системі, яка може працювати з іншою версією Windows.
Пол Б.

Файли не розповсюджені. Тут використовуються файли, встановлені в ОС.
тронда
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.