WIXを使ったWindows Installerの作成(ver3) ver5に移行予定
WiX (Windows Installer XML)ツールセットとは
WiX(Windows Installer XML)は、Windowsアプリケーションのインストールパッケージを作成するためのオープンソースツールセットです。XMLベースのソースファイルを使用して、Windows Installer(MSI)パッケージや、アプリケーションのアップデートやパッチを配布するためのパッチ(MSP)や、インストール前の条件チェックを行うためのセットアップバンドル(EXE)を生成します。
windowsアプリの開発経験が少ない筆者が、rustでwindowsアプリ開発するにあたって、インストーラの作成をどうするか調べていく中で、このツールを使うに至り調査した結果をメモしていきます。
本サイト
参考になるサイト
cliベースでmsiを構築するのはここが一番わかりやすかった
https://tauri.app/ )のテンプレートサンプル
tauri(rustによるwebviewを用いたデスクトップアプリ実装。
rustでの実装に役立ちそうな rust ツール(cargoに統合できる?)
その他参考サイト
上記サンプルサイトにあった例の要約
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*"
Name="My Software"
Language="1033"
Manufacturer="My Company"
Version="1.0.0.0"
UpgradeCode="8c7d85db-b0d1-4a9a-85ea-130836aeef67">
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<Feature Id="ProductFeature"
Title="The main feature"
Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER"
Name="My Software" />
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents"
Directory="INSTALLFOLDER">
<Component Id="cmpMyTextFileTXT"
Guid="{A4540658-09B6-46DA-8880-0B1962E06642}">
<File Source="MyTextFile.txt" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>
要約
このWiX (Windows Installer XML) コードは、"My Software" というアプリケーションのインストールパッケージを定義しています。
このコードは、"My Software" という名前のアプリケーションをインストールする際、ファイル "MyTextFile.txt" をProgram Filesフォルダ内の "My Software" フォルダに配置するインストールパッケージを作成します。
アプリケーションは、システムのProgram Filesフォルダに "My Software" という名前のフォルダを作成し、その中に"MyTextFile.txt"ファイルを配置します。
Windows Installer(MSI)パッケージが生成され、アプリケーションをインストールする際に使用できます。
主な要素
<Product>: アプリケーションの基本情報を定義しています。
<Package>: インストーラの設定を指定しています。
<MajorUpgrade>: ダウングレード時のエラーメッセージを設定しています。
<MediaTemplate>: メディア(インストールファイル)の設定を定義しています。
<Feature>: アプリケーションの主要機能を定義しています。
<Directory>: アプリケーションのディレクトリ構造を定義しています。
<ComponentGroup>: 関連するコンポーネント(ファイル、レジストリキー、ショートカットなど)の集合を定義しています。
<Fragment>: WiXプロジェクト内の独立した部分を表します。フラグメントは、再利用可能なコードの断片を作成するのに役立ちます。この例では、ディレクトリ構造とコンポーネントグループがフラグメントとして定義されています。
<Directory Id="INSTALLFOLDER" Name="My Software">: インストールフォルダを定義しており、Program Filesフォルダ内に"My Software"という名前のフォルダが作成されます。
<Component Id="cmpMyTextFileTXT" Guid="{A4540658-09B6-46DA-8880-0B1962E06642}">: コンポーネントを定義しており、このコンポーネントは"MyTextFile.txt"ファイルを含みます。
<File Source="MyTextFile.txt">: インストールするファイルを指定しています。この例では、"MyTextFile.txt"ファイルがインストール対象です。
日本語で、以下の要件を満たす設定ファイルを作成してみる
アプリ名:"AssetCare"
実行ファイル(exe)は、"it_agent.exe","update.exe"の2つです。
1.install時、フォルダにある以下3つのファイル、"it_agent.exe","update.exe",".env" の3つのファイルについて、フォルダ"Program Files\AssetCare"の直下に展開する
2.install時、次に、展開された"it_agent.exe"について、"it_agent.exe --mode install" を実行する
3.uninstall時、まず"it_agent.exe --mode uninstall"を実行する
4.uninstall時、次に"Program Files\AssetCare"を削除する
前提知識
・日本語のID:1041
言語IDは、NSIS (Nullsoft Scriptable Install System) : 昔からあるオープンソースのbundlerシステム で規定されている、以下のJapanese.nlfファイルのIDを利用している。こちらを参照。
最終版
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="AssetCare"
Language="1033"
Manufacturer="YourCompanyName"
Version="1.0.0.0" UpgradeCode="9c57f086-33f1-47f1-91a8-613bccdc88ba">
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<Feature Id="MainFeature" Title="Main Feature" Level="1">
<ComponentGroupRef Id="AssetCareComponents" />
</Feature>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="AssetCare">
<Component Id="it_agent.exe" Guid="{41f1f9b0-0315-42fa-90ce-aac00e9fe81f}">
<File Id="it_agent.exe" Source="it_agent.exe" KeyPath="yes" />
</Component>
<Component Id="update.exe" Guid="{731d5b59-c7d2-4ec2-8435-45abdf9ec036}">
<File Id="update.exe" Source="update.exe" KeyPath="yes" />
</Component>
<Component Id="dotEnv" Guid="{ea9645a6-6099-4de0-98d2-7a2b1a931a50}">
<File Id="dotEnvFile" Source=".env" KeyPath="yes" />
</Component>
</Directory>
</Directory>
</Directory>
<ComponentGroup Id="AssetCareComponents">
<ComponentRef Id="it_agent.exe" />
<ComponentRef Id="update.exe" />
<ComponentRef Id="dotEnv" />
</ComponentGroup>
<CustomAction Id="Install_it_agent" Directory="INSTALLFOLDER" ExeCommand='"[SystemFolder]cmd.exe" /C "it_agent.exe" --mode install > C:\temp\test.txt' Execute="deferred" Impersonate="no" Return="check" />
<InstallExecuteSequence>
<Custom Action="Install_it_agent" Before="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>
<CustomAction Id="Uninstall_it_agent" Directory="INSTALLFOLDER" ExeCommand='"[SystemFolder]cmd.exe" /C "it_agent.exe" --mode uninstall > C:\temp\test.txt' Execute="deferred" Impersonate="no" Return="check" />
<InstallExecuteSequence>
<Custom Action="Uninstall_it_agent" After="InstallInitialize">Installed AND REMOVE="ALL"</Custom>
</InstallExecuteSequence>
</Product>
</Wix>
wxs仕様 memo
[SystemFolder]について
[SystemFolder]は、Windowsのシステムフォルダを指します。システムフォルダは、通常、以下の場所にあります。
32ビットのWindows:C:\Windows\System32
64ビットのWindows:C:\Windows\SysWOW64(32ビットアプリケーション用)およびC:\Windows\System32(64ビットアプリケーション用)
ただし、WiXで[SystemFolder]を使うと、自動的に32ビットまたは64ビットのシステムフォルダに適切に展開されます。つまり、32ビット版のWindows上で実行される場合はC:\Windows\System32が使われ、64ビット版のWindows上で32ビットアプリケーションとして実行される場合はC:\Windows\SysWOW64が使われます。
その他の暗黙的なpath (by AI 未検証)
[WindowsFolder]:Windowsのインストールディレクトリ(通常はC:\Windows)。
[ProgramFilesFolder]:プログラムファイルのディレクトリ。32ビットシステムではC:\Program Files、64ビットシステムではC:\Program Files (x86)(32ビットアプリ用)。
[ProgramFiles64Folder]:64ビットシステムでのプログラムファイルのディレクトリ(C:\Program Files)。
[CommonFilesFolder]:共有プログラムファイルのディレクトリ。32ビットシステムではC:\Program Files\Common Files、64ビットシステムではC:\Program Files (x86)\Common Files(32ビットアプリ用)。
[CommonFiles64Folder]:64ビットシステムでの共有プログラムファイルのディレクトリ(C:\Program Files\Common Files)。
[TempFolder]:一時ファイル用のディレクトリ(通常はC:\Users[Username]\AppData\Local\Temp)。
[AppDataFolder]:現在のユーザーのアプリケーションデータディレクトリ(通常はC:\Users[Username]\AppData\Roaming)。
[LocalAppDataFolder]:現在のユーザーのローカルアプリケーションデータディレクトリ(通常はC:\Users[Username]\AppData\Local)。
[DesktopFolder]:現在のユーザーのデスクトップディレクトリ。
[MyPicturesFolder]:現在のユーザーのマイピクチャディレクトリ。
[MyDocumentsFolder]:現在のユーザーのドキュメントディレクトリ。
Impersonate 属性について
<CustomAction Id="Install_it_agent" Directory="INSTALLFOLDER" ExeCommand="it_agent.exe --mode install" Execute="deferred" Impersonate="no" Return="check" />
<InstallExecuteSequence>
<Custom Action="Install_it_agent" After="InstallFiles">NOT Installed</Custom>
</InstallExecuteSequence>
Impersonate属性は、カスタムアクションが実行される際のユーザーコンテキストに関する設定を制御します。Impersonate属性の値がyes(デフォルト)の場合、カスタムアクションは、インストールを実行しているユーザーの権限で実行されます。これは、通常のユーザーコンテキストで実行されるアクションや操作に適しています。
一方、Impersonate属性の値がnoの場合、カスタムアクションはシステムアカウント(LocalSystemアカウント)で実行されます。これは、管理者権限が必要な操作や、他のユーザーアカウントに影響を与える操作に適しています
msi実行時のエラーに対応する
msi実行時、以下のようなエラーが出て進まない事がある。
英語の場合
There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor.
これを検証するには、msi実行時にログを出力するようにする
msiexec /i "Installer.msi" /l*v "log.txt"
エラー発生時の実際のログ:
MSI (s) (C0:44) [17:15:07:368]: File: C:\Program Files (x86)\AssetCare\it_agent.exe; To be installed; Won't patch; No existing file
MSI (s) (C0:44) [17:15:07:368]: Source for file 'it_agent.exe' is compressed
MSI (s) (C0:44) [17:15:07:543]: Executing op: FileCopy(SourceName=update.exe,SourceCabKey=update.exe,DestName=update.exe,Attributes=512,FileSize=6053888,PerTick=65536,,VerifyMedia=1,,,,,CheckCRC=0,,,InstallMode=58982400,HashOptions=0,HashPart1=-1536252112,HashPart2=-1634207995,HashPart3=1633814810,HashPart4=2119473254,,)
MSI (s) (C0:44) [17:15:07:543]: File: C:\Program Files (x86)\AssetCare\update.exe; To be installed; Won't patch; No existing file
MSI (s) (C0:44) [17:15:07:543]: Source for file 'update.exe' is compressed
MSI (s) (C0:44) [17:15:07:656]: Executing op: CacheSizeFlush(,)
MSI (s) (C0:44) [17:15:07:656]: Executing op: ActionStart(Name=Install_it_agent,,)
MSI (s) (C0:44) [17:15:07:667]: Executing op: CustomActionSchedule(Action=Install_it_agent,ActionType=3106,Source=C:\Program Files (x86)\AssetCare\,Target=it_agent.exe --mode install,)
MSI (s) (C0:44) [17:15:07:676]: Note: 1: 1721 2: Install_it_agent 3: C:\Program Files (x86)\AssetCare\ 4: it_agent.exe --mode install
MSI (s) (C0:44) [17:15:07:676]: Note: 1: 2205 2: 3: Error
MSI (s) (C0:44) [17:15:07:676]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1721
MSI (c) (54:9C) [17:15:07:723]: Font created. Charset: Req=0, Ret=0, Font: Req=, Ret=Arial
Error 1721. There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. Action: Install_it_agent, location: C:\Program Files (x86)\AssetCare\, command: it_agent.exe --mode install
MSI (s) (C0:44) [17:15:09:184]: Note: 1: 2205 2: 3: Error
MSI (s) (C0:44) [17:15:09:184]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1709
MSI (s) (C0:44) [17:15:09:184]: Product: AssetCare -- Error 1721. There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. Action: Install_it_agent, location: C:\Program Files (x86)\AssetCare\, command: it_agent.exe --mode install
Action ended 17:15:09: InstallFinalize. Return value 3.
MSI (s) (C0:44) [17:15:09:210]: Note: 1: 2265 2: 3: -2147287035
MSI (s) (C0:44) [17:15:09:214]: User policy value 'DisableRollback' is 0
MSI (s) (C0:44) [17:15:09:214]: Machine policy value 'DisableRollback' is 0
MSI (s) (C0:44) [17:15:09:217]: Note: 1: 2318 2:
MSI (s) (C0:44) [17:15:09:218]: Executing op: Header(Signature=1397708873,Version=500,Timestamp=1451461092,LangId=1033,Platform=0,ScriptType=2,ScriptMajorVersion=21,ScriptMinorVersion=4,ScriptAttributes=1)
MSI (s) (C0:44) [17:15:09:218]: Executing op: DialogInfo(Type=0,Argument=1033)
MSI (s) (C0:44) [17:15:09:219]: Executing op: DialogInfo(Type=1,Argument=AssetCare)
MSI (s) (C0:44) [17:15:09:220]: Executing op: RollbackInfo(,RollbackAction=Rollback,RollbackDescription=Rolling back action:,RollbackTemplate=[1],CleanupAction=RollbackCleanup,CleanupDescription=Removing backup files,CleanupTemplate=File: [1])
MSI (s) (C0:44) [17:15:09:225]: Executing op: ActionStart(Name=Install_it_agent,,)
MSI (s) (C0:44) [17:15:09:226]: Executing op: ProductInfo(ProductKey={7CA75E4C-C0CF-4297-B7CF-229A2CE29FC9},ProductName=AssetCare,PackageName=CommandLineInstaller.msi,Language=1033,Version=16777216,Assignment=1,ObsoleteArg=0,,,PackageCode={832BF33B-CAFF-4128-A57B-F0E5AD0C5002},,,InstanceType=0,LUASetting=0,RemoteURTInstalls=0,ProductDeploymentFlags=3)
MSI (s) (C0:44) [17:15:09:228]: Executing op: ActionStart(Name=InstallFiles,Description=Copying new files,Template=File: [1], Directory: [9], Size: [6])
MSI (s) (C0:44) [17:15:09:230]: Executing op: SetTargetFolder(Folder=C:\Program Files (x86)\AssetCare\)
MSI (s) (C0:44) [17:15:09:231]: Executing op: FileRemove(,FileName=C:\Program Files (x86)\AssetCare\update.exe,,)
MSI (s) (C0:44) [17:15:09:243]: Note: 1: 2318 2:
MSI (s) (C0:44) [17:15:09:245]: Executing op: FileRemove(,FileName=C:\Program Files (x86)\AssetCare\it_agent.exe,,)
MSI (s) (C0:44) [17:15:09:258]: Note: 1: 2318 2:
MSI (s) (C0:44) [17:15:09:260]: Executing op: FileRemove(,FileName=C:\Program Files (x86)\AssetCare\.env,,)
MSI (s) (C0:44) [17:15:09:271]: Note: 1: 2318 2:
MSI (s) (C0:44) [17:15:09:284]: Executing op: ActionStart(Name=ProcessComponents,Description=Updating component registration,)
MSI (s) (C0:44) [17:15:09:285]: Executing op: ComponentUnregister(ComponentId={EA9645A6-6099-4DE0-98D2-7A2B1A931A50},ProductKey={7CA75E4C-C0CF-4297-B7CF-229A2CE29FC9},BinaryType=0,)
MSI (s) (C0:44) [17:15:09:287]: Executing op: ComponentUnregister(ComponentId={731D5B59-C7D2-4EC2-8435-45ABDF9EC036},ProductKey={7CA75E4C-C0CF-4297-B7CF-229A2CE29FC9},BinaryType=0,)
MSI (s) (C0:44) [17:15:09:288]: Executing op: ComponentUnregister(ComponentId={41F1F9B0-0315-42FA-90CE-AAC00E9FE81F},ProductKey={7CA75E4C-C0CF-4297-B7CF-229A2CE29FC9},BinaryType=0,)
MSI (s) (C0:44) [17:15:09:289]: Executing op: End(Checksum=0,ProgressTotalHDWord=0,ProgressTotalLDWord=0)
MSI (s) (C0:44) [17:15:09:289]: Error in rollback skipped. Return: 5
MSI (s) (C0:44) [17:15:09:299]: Note: 1: 2318 2:
MSI (s) (C0:44) [17:15:09:311]: Note: 1: 2318 2:
rustのbundlerでは、
これが有名
だが、iOS/windows supportはexperimentalとのことで、上記をforkして作られてる、tauriのbundlerを使った方が便利。
tauriでは、windows用にWIXが使われている。
WIX ver3→ver4 migration
migrationに関する参考URL
ver4では、nugetのみのdownloadになったので、nugetのダウンロードページのDownloadPackageからダウンロード。nugetファイルはzip圧縮ファイルなので、解凍ソフトで解凍しておく。
▼download
ver3で使っていた設定ファイルのwxsを、ver4用にconvert
"wix.4.0.0\tools\net6.0\any\wix.exe" build -o product.msi product.wxs
bundleは、ver3と異なり、コマンド1発でOK
"wix.4.0.0\tools\net6.0\any\wix.exe" build -o bin\product.msi product.wxs