WiXをアンインストールするときにファイルを削除する


84

アプリケーションをアンインストールするときに、元のインストール後に追加されすべてのファイルを削除するようにWixセットアップを構成したいと思います。アンインストーラーは、MSIファイルから最初にインストールされたディレクトリとファイルのみを削除し、後で追加されたすべてのものをアプリケーションフォルダーに残すようです。つまり、アンインストール時にディレクトリを削除したいのですが。それ、どうやったら出来るの?

回答:


83

On = "アンインストール"でRemoveFile要素を使用します。次に例を示します。

<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
Pavelありがとう。しかし、それは100%機能しませんでした。ファイルは削除されましたが、追加のディレクトリ(インストール後に作成されたディレクトリ)は削除されませんでした。それについて何か考えはありますか?
pribeiro 2008年

ああ、それらのディレクトリの下のファイルはどちらも削除されませんでした。
pribeiro 2008年

メジャーアップグレード時に「MyAppFolder」にファイル(設定ファイルなど)を保持すると、このアプローチで問題が発生します。すべてのファイルはアップグレードによって削除されます。
サイモン

1
MyAppFolderでディレクトリを作成するコードで可能ですか?</Component>コンパイルに失敗した後にディレクトリを追加するとFound orphaned Component 'MyAppFolder'.
A.Pissicat 2016

2
@PhilipRego CommonAppDataFolderのドキュメントについては、msdn.microsoft.com / en-us / library / windows / desktop /aa367992.aspxを参照してください
Pavel Chuchuva 2017年

30

RemoveFolderExWiXのUtil拡張機能の要素を使用します。
このアプローチでは、(要素を直接使用RemoveFileするのではなく)すべてのサブディレクトリも削除されます。この要素は、一時的に行を追加RemoveFileし、RemoveFolderMSIデータベースのテーブル。


2
警告:RemoveFolderEx on = "uninstall"を使用すると、アップグレード時にフォルダーも削除されます(Wix3.9)。上と同じ動作RemoveFileRemoveFolder。アップグレード時にファイルを保持したい場合、これらすべてのアプローチを使用することはできません。
サイモン

@Simonアップグレード時にファイルを保持したい場合、どのようなアプローチを提案しますか?
Bijington 2016

@Bijington:アップグレード時にインストールフォルダーに特定のファイルを保持する場合は、カスタムコードを実行するカスタムアクションを使用します(例:c#で記述されたHandleSetup.exe)。カスタムコードは、インストール時にファイルを配信し、アップグレード時にファイルを保持し、アンインストール時にファイルを削除します。
サイモン

@Simonありがとう、これは現在機能していますが、私はそのアプローチを調べる必要があるかもしれません:stackoverflow.com/a/21383113/32348
Bijington 2016

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>

InstallerCustomActions.DLLのOnBeforeUninstallメソッドのコードは、(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

@Dennis INSTALLFOLDERを削除する方法、win 10では削除されますが、Windows Server2012では削除されません。
eomeroff 2016

素晴らしいソリューション。ありがとう!
Yurii Komarnytskyi 2017

私はいくつかのことを試みました-アンインストール中に単一のファイルを削除することはそれほど難しいとは思わないでしょう。これは私にとってはうまくいきました-ありがとう!
ラッキールーク

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>

そして、Product要素の下:

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

このアプローチでは、アンインストール時に削除するフォルダーの目的のパスを使用してレジストリ値を設定します。最後に、INSTALLFOLDERとレジストリフォルダの両方がシステムから削除されます。レジストリへのパスは、他のハイブや他の場所にある可能性があることに注意してください。


6

WIXの専門家ではありませんが、これに対する可能な(より簡単な?)解決策は、WIXの組み込み拡張機能の一部であるQuiet Executionカスタムアクション実行することでしょうか?

/ Sおよび/ Qオプションを指定してrmdirMSDOSコマンドを実行できます。

<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 2011

4
これをしないでください。1)cmd.exeインストーラーに埋め込みます。2)スクリプトの生成中にシステムに変更を加えています3)ロールバックオプションがありません4)ロックされたファイルを正しく処理しません
Nick Whaley 2015年

Windowsインストールからファイルを配布することが合法であるかどうか疑問があります。また、異なるバージョンのWindowsを実行している可能性のあるターゲットシステムで動作するかどうかも不明です。
ポールB.

ファイルは配布されていません。OSにインストールされているファイルを使用します。
トロンダ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.