NSISでインストーラを作ってみる その2

#はじめに
[その1](https://qiita.com/yuki_nishina/items/176d6d77911f2b54bd75)に引き続き、NSISのスクリプトをサンプルを用いてレクチャーします。
その1を読んでいない方は、以下から読んでください。
[NSISでインストーラを作ってみる その1](https://qiita.com/yuki_nishina/items/176d6d77911f2b54bd75)

#アンインストールに確認を設ける
アンインストーラを実行した時に確認を取らずにアンインストールすると、うっかり操作ミスでアンインストールしてしまう危険性があります。
アンインストール前に確認の一手間を置いて、意図しないアンインストールを防ぎます。

```NSIS:Install.nsi
# 日本語UI
LoadLanguageFile "${NSISDIR}\Contrib\Language files\Japanese.nlf"
# アプリケーション名
Name "サンプル アプリケーション"
# 作成されるインストーラ
OutFile "Install.exe"
# インストールされるディレクトリ
InstallDir "$PROGRAMFILES\NSISSample"
# ページ
Page directory
Page instfiles
# アンインストーラ ページ
UninstPage uninstConfirm
UninstPage instfiles

# デフォルト セクション
Section
  # 出力先を指定します。
  SetOutPath "$INSTDIR"
  # インストールされるファイル
  File "C:\Sample\Sample.exe"
  # 出力先を指定します。
  SetOutPath "$INSTDIR\docs"
  # インストールされるファイル
  File "C:\Sample\docs\readme.txt"
  # アンインストーラを出力
  WriteUninstaller "$INSTDIR\Uninstall.exe"
  # スタート メニューにショートカットを登録
  CreateDirectory "$SMPROGRAMS\NSISSample"
  SetOutPath "$INSTDIR"
  CreateShortcut "$SMPROGRAMS\NSISSample\サンプル アプリケーション.lnk" "$INSTDIR\Sample.exe" ""
  # レジストリに登録
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample" "DisplayName" "サンプル アプリケーション"
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample" "UninstallString" '"$INSTDIR\Uninstall.exe"'
SectionEnd

# アンインストーラ
Section "Uninstall"
  # アンインストーラを削除
  Delete "$INSTDIR\Uninstall.exe"
  # ファイルを削除
  Delete "$INSTDIR\Sample.exe"
  # ディレクトリを削除
  RMDir /r "$INSTDIR"
  # スタート メニューから削除
  Delete "$SMPROGRAMS\NSISSample\サンプル アプリケーション.lnk"
  RMDir "$SMPROGRAMS\NSISSample"
  # レジストリ キーを削除
  DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample"
SectionEnd
```

![001.png](https://qiita-image-store.s3.amazonaws.com/0/149140/5196bb0c-7122-5147-2291-99167bd1dc8a.png)
アンインストーラを実行すると、確認のウィンドウが表示されます。
アンインストールしたくない場合は"キャンセル"をクリックすれば取り消すことができ、
アンインストールしてもよい場合は"アンインストール"をクリックすると、アンインストールされます。
※注意: `UninstPage uninstConfirm`だけでなく、`UninstPage instfiles`も記述しないと、アンインストールが実行されません。
又、`Page uninstConfirm`と記述してもコンパイルできますが、正しく機能しません。

#LZMAで圧縮する
LZMAは7-Zipで用いられている非常に圧縮率の高い圧縮メソッドです。
大規模なアプリケーションをなるべく軽量にしたい時に効果を発揮しますが、
圧縮時間がトレードオフになっています。
又、解凍時のメモリ消費も大きめですが、現代的なスペックのマシンであれば特に問題にはならないでしょう。

```NSIS:Install.nsi
# 日本語UI
LoadLanguageFile "${NSISDIR}\Contrib\Language files\Japanese.nlf"
# アプリケーション名
Name "サンプル アプリケーション"
# 作成されるインストーラ
OutFile "Install.exe"
# インストールされるディレクトリ
InstallDir "$PROGRAMFILES\NSISSample"
# 圧縮メソッド
SetCompressor lzma
# ページ
Page directory
Page instfiles
# アンインストーラ ページ
UninstPage uninstConfirm
UninstPage instfiles

# デフォルト セクション
Section
  # 出力先を指定します。
  SetOutPath "$INSTDIR"
  # インストールされるファイル
  File "C:\Sample\Sample.exe"
  # 出力先を指定します。
  SetOutPath "$INSTDIR\docs"
  # インストールされるファイル
  File "C:\Sample\docs\readme.txt"
  # アンインストーラを出力
  WriteUninstaller "$INSTDIR\Uninstall.exe"
  # スタート メニューにショートカットを登録
  CreateDirectory "$SMPROGRAMS\NSISSample"
  SetOutPath "$INSTDIR"
  CreateShortcut "$SMPROGRAMS\NSISSample\サンプル アプリケーション.lnk" "$INSTDIR\Sample.exe" ""
  # レジストリに登録
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample" "DisplayName" "サンプル アプリケーション"
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample" "UninstallString" '"$INSTDIR\Uninstall.exe"'
SectionEnd

# アンインストーラ
Section "Uninstall"
  # アンインストーラを削除
  Delete "$INSTDIR\Uninstall.exe"
  # ファイルを削除
  Delete "$INSTDIR\Sample.exe"
  # ディレクトリを削除
  RMDir /r "$INSTDIR"
  # スタート メニューから削除
  Delete "$SMPROGRAMS\NSISSample\サンプル アプリケーション.lnk"
  RMDir "$SMPROGRAMS\NSISSample"
  # レジストリ キーを削除
  DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample"
SectionEnd
```

#スクリプトを分割する
プロジェクトが大きくなってくると、インストーラを1つのファイルで管理すると複雑になってきます。
スクリプトをモジュールで分割してみます。

```NSIS:Install.nsi
# 日本語UI
LoadLanguageFile "${NSISDIR}\Contrib\Language files\Japanese.nlf"
# アプリケーション名
Name "サンプル アプリケーション"
# 作成されるインストーラ
OutFile "Install.exe"
# インストールされるディレクトリ
InstallDir "$PROGRAMFILES\NSISSample"
# 圧縮メソッド
SetCompressor lzma
# ページ
Page directory
Page instfiles
# アンインストーラ ページ
UninstPage uninstConfirm
UninstPage instfiles

# デフォルト セクション
Section
  # 出力先を指定します。
  SetOutPath "$INSTDIR"
  # インストールされるファイル
  File "C:\Sample\Sample.exe"
  # 出力先を指定します。
  SetOutPath "$INSTDIR\docs"
  # インストールされるファイル
  File "C:\Sample\docs\readme.txt"
  # アンインストーラを出力
  WriteUninstaller "$INSTDIR\Uninstall.exe"
  # スタート メニューにショートカットを登録
  CreateDirectory "$SMPROGRAMS\NSISSample"
  SetOutPath "$INSTDIR"
  CreateShortcut "$SMPROGRAMS\NSISSample\サンプル アプリケーション.lnk" "$INSTDIR\Sample.exe" ""
  # レジストリに登録
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample" "DisplayName" "サンプル アプリケーション"
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample" "UninstallString" '"$INSTDIR\Uninstall.exe"'
SectionEnd

# アンインストーラ
!include Uninstall.nsi
```

```NSIS:Uninstall.nsi
# アンインストーラ
Section "Uninstall"
  # アンインストーラを削除
  Delete "$INSTDIR\Uninstall.exe"
  # ファイルを削除
  Delete "$INSTDIR\Sample.exe"
  # ディレクトリを削除
  RMDir /r "$INSTDIR"
  # スタート メニューから削除
  Delete "$SMPROGRAMS\NSISSample\サンプル アプリケーション.lnk"
  RMDir "$SMPROGRAMS\NSISSample"
  # レジストリ キーを削除
  DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample"
SectionEnd
```

Uninstall.nsiというファイルを新たに作成し、アンインストーラ部を分割しました。
大きくなりすぎると管理が複雑になってしまう部分は、分割すると管理しやすくなります。

#セクションの使い方
今までは`Section`という項目はデフォルト セクションとアンインストーラ セクションの2つが存在していました。
NSISはセクションを使いこなす事によりフレキシブルなインストーラが作成できます。
ここでは、インストールするファイルに"C:\Sample\utils\Utility.exe"というファイルを新たに用意してみます。

```NSIS:Install.nsi
# 日本語UI
LoadLanguageFile "${NSISDIR}\Contrib\Language files\Japanese.nlf"
# アプリケーション名
Name "サンプル アプリケーション"
# 作成されるインストーラ
OutFile "Install.exe"
# インストールされるディレクトリ
InstallDir "$PROGRAMFILES\NSISSample"
# 圧縮メソッド
SetCompressor lzma
# ページ
Page directory
Page components
Page instfiles
# アンインストーラ ページ
UninstPage uninstConfirm
UninstPage instfiles

# デフォルト セクション
Section
  # 出力先を指定します。
  SetOutPath "$INSTDIR"
  # インストールされるファイル
  File "C:\Sample\Sample.exe"
  # アンインストーラを出力
  WriteUninstaller "$INSTDIR\Uninstall.exe"
  # スタート メニューにショートカットを登録
  CreateDirectory "$SMPROGRAMS\NSISSample"
  SetOutPath "$INSTDIR"
  CreateShortcut "$SMPROGRAMS\NSISSample\サンプル アプリケーション.lnk" "$INSTDIR\Sample.exe" ""
  # レジストリに登録
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample" "DisplayName" "サンプル アプリケーション"
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample" "UninstallString" '"$INSTDIR\Uninstall.exe"'
SectionEnd

Section "ドキュメント"
  # 出力先を指定します。
  SetOutPath "$INSTDIR\docs"
  # インストールされるファイル
  File "C:\Sample\docs\readme.txt"
SectionEnd

Section /o "ユーティリティ"
  # 出力先を指定します。
  SetOutPath "$INSTDIR\utils"
  # インストールされるファイル
  File "C:\Sample\utils\Utility.exe"
SectionEnd

# アンインストーラ
!include Uninstall.nsi
```
`Page directory`の次の行に、`Page components`を追加します。
デフォルト セクションから"C:\Sample\docs\readme.txt"のインストールを削除し、新たに`Section "ドキュメント"`～`SectionEnd`を作成します。
又、`Section /o "ユーティリティ"`～`SectionEnd`も作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149140/fca4584a-34bf-91cf-38f8-3695d0de9557.png)
実行すると、インストール先の選択の次にインストール コンポーネントの選択が表示されます。
"ドキュメント"が既定でチェックされた状態になり、"ユーティリティ"は既定ではチェックされません。
`Section`に`/o`オプションを付与すると、そのセクションはオプション扱いとなります。
又、デフォルト セクションはこの一覧にリストされませんが、名前無しのセクションは必ず実行されるセクションになります。
そして、`Section "Uninstall"`と記述されたセクションは、アンインストーラが実行するセクションになります。

参考ドキュメント
[Scripting Reference](https://nsis.sourceforge.io/Docs/Chapter4.html#sections)
[Reference/Section - NSIS](https://nsis.sourceforge.io/Reference/Section)

##セクションのグループ化
セクションはその属性等でグループ化することができます。

```NSIS:Install.nsi
# 日本語UI
LoadLanguageFile "${NSISDIR}\Contrib\Language files\Japanese.nlf"
# アプリケーション名
Name "サンプル アプリケーション"
# 作成されるインストーラ
OutFile "Install.exe"
# インストールされるディレクトリ
InstallDir "$PROGRAMFILES\NSISSample"
# 圧縮メソッド
SetCompressor lzma
# ページ
Page directory
Page components
Page instfiles
# アンインストーラ ページ
UninstPage uninstConfirm
UninstPage instfiles

# デフォルト セクション
Section
  # 出力先を指定します。
  SetOutPath "$INSTDIR"
  # インストールされるファイル
  File "C:\Sample\Sample.exe"
  # アンインストーラを出力
  WriteUninstaller "$INSTDIR\Uninstall.exe"
  # スタート メニューにショートカットを登録
  CreateDirectory "$SMPROGRAMS\NSISSample"
  SetOutPath "$INSTDIR"
  CreateShortcut "$SMPROGRAMS\NSISSample\サンプル アプリケーション.lnk" "$INSTDIR\Sample.exe" ""
  # レジストリに登録
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample" "DisplayName" "サンプル アプリケーション"
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample" "UninstallString" '"$INSTDIR\Uninstall.exe"'
SectionEnd

SectionGroup "ドキュメント"
  Section "readme.txt"
    # 出力先を指定します。
    SetOutPath "$INSTDIR\docs"
    # インストールされるファイル
    File "C:\Sample\docs\readme.txt"
  SectionEnd
SectionGroupEnd

SectionGroup "ユーティリティ"
  Section /o "Utility.exe"
    # 出力先を指定します。
    SetOutPath "$INSTDIR\utils"
    # インストールされるファイル
    File "C:\Sample\utils\Utility.exe"
  SectionEnd
SectionGroupEnd

# アンインストーラ
!include Uninstall.nsi
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149140/d07bf7af-c268-79de-f43a-d64a406661f4.png)
"readme.txt"を"ドキュメント"グループに、"Utility.exe"を"ユーティリティ"グループにグループ化しました。
グループ化は`Section`を`SectionGroup`～`SectionEnd`間にネストします(インデントは必須ではありません)。
勿論、`SectionGroup`内には複数の`Section`を記述することができます。

##インストールされるコンポーネントの組み合わせを用意する
アプリケーションには、必ずインストールされなければならないファイルの他に、必要に応じてユーザーが取捨選択すべきファイルもある場合があります。
そのような場合にインストーラがあらかじめ組み合わせを提供することができます。

```NSIS:Install.nsi
# 日本語UI
LoadLanguageFile "${NSISDIR}\Contrib\Language files\Japanese.nlf"
# アプリケーション名
Name "サンプル アプリケーション"
# 作成されるインストーラ
OutFile "Install.exe"
# インストールされるディレクトリ
InstallDir "$PROGRAMFILES\NSISSample"
# 圧縮メソッド
SetCompressor lzma
# ページ
Page directory
Page components
Page instfiles
# アンインストーラ ページ
UninstPage uninstConfirm
UninstPage instfiles
# インストールの種類
InstType "推奨"
InstType "フル"
InstType "最小"

# デフォルト セクション
Section
  # 出力先を指定します。
  SetOutPath "$INSTDIR"
  # インストールされるファイル
  File "C:\Sample\Sample.exe"
  # アンインストーラを出力
  WriteUninstaller "$INSTDIR\Uninstall.exe"
  # スタート メニューにショートカットを登録
  CreateDirectory "$SMPROGRAMS\NSISSample"
  SetOutPath "$INSTDIR"
  CreateShortcut "$SMPROGRAMS\NSISSample\サンプル アプリケーション.lnk" "$INSTDIR\Sample.exe" ""
  # レジストリに登録
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample" "DisplayName" "サンプル アプリケーション"
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NSISSample" "UninstallString" '"$INSTDIR\Uninstall.exe"'
SectionEnd

SectionGroup "ドキュメント"
  Section "readme.txt"
    # 推奨・フル
    SectionIn 1 2
    # 出力先を指定します。
    SetOutPath "$INSTDIR\docs"
    # インストールされるファイル
    File "C:\Sample\docs\readme.txt"
  SectionEnd
SectionGroupEnd

SectionGroup "ユーティリティ"
  Section /o "Utility.exe"
    # フル
    SectionIn 2
    # 出力先を指定します。
    SetOutPath "$INSTDIR\utils"
    # インストールされるファイル
    File "C:\Sample\utils\Utility.exe"
  SectionEnd
SectionGroupEnd

# アンインストーラ
!include Uninstall.nsi
```
`InstType`の行で組み合わせとして用意する名前を記述します。
`Section`の中で`SectionIn`の後に組み合わせに含める番号を指定します。
1番目の`InstType`に"推奨"を指定し、セクションを"推奨"に含める場合はそのセクション内で`SectionIn 1`と記述します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149140/afbebec9-80f4-5e26-5a0d-91800de066c7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149140/6649e472-78a2-b0d2-3a7c-d845ec2de133.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149140/c7d4a566-f1e2-52e6-f4c8-aadc3d652bfc.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149140/bce7ef52-9c84-5fb2-1020-776355c4876e.png)
インストール オプションで"インストール タイプを選択"というコンボボックスが表示されます。
`InstType`で記述した組み合わせを選択できるようになっており、もう一つ"カスタム"という選択肢を選択すると、ユーザーが任意に組み合わせることができます。
"カスタム"を許容しない場合、`InstType /NOCUSTOM`を記述します。

```NSIS
# インストールの種類
InstType /NOCUSTOM
InstType "推奨"
InstType "フル"
InstType "最小"
```
#最後に
次回は、nsDialogsとModern UIを使用したより現代的なインストーラの作成について説明します。
※当初、その2(本ページ)でnsDialogsとModern UIの説明をしておりましたが、一般的なセクションの使い方の説明が浅かったため、順序を変更しました。