使ったのはVersion 12のWindows版。
上書きインストールでファイルが置き替わらない
[編成] – [コンポーネント]で各要素ごとに 条件の再評価 の いいえ を はい に変更しないといけない(デフォルトはいいえ)
アンインストール->インストールがしたい
製品コードとバージョンを変更するとメジャーバージョン扱いになり、アンインストール&インストールのフローに入ることが可能。この際にアップデートコードは変更してはいけない。アップデートコードを変更すると、新規インストールになり旧バージョンと同居することになる。
どうやらアップデートコードを同じにしておくだけではだめで、メディア -> アップグレード -> アップグレードシナリオのセットアップの作成でメジャーアップグレードの設定を追加したところうまくいった。
アンインストール->インストールでファイルがインストールされない
メジャーアップグレード機能を使って、アンインストール->インストールした場合にファイルがアンインストールだけされて、インストールされないことがある。
アクションのシーケンスで、 RemoveExistingProducts が CostFinalize よりもあとにあると再現することがある。CstInitialize-CostFinalize間で、新バージョンのインストール情報の一覧を構築するがこの時点で更新が不要だと判断されると、インストールリストには追加されず、しかもアンインストールだけされてしまう。
この場合、RemoveExistingProductsをCostFinalizeよりも前に置くと解決することがある。
Ocxをインストールしたい
- インストール先はどこでもよく、COMの登録処理を追加すればいい
- 編成 – コンポーネントで対象モジュールを選択し、[詳細設定]で COM登録 を設定する
- COM登録で右クリックし Refresh COM Data for Key File を実行すれば適切な値が設定できる
NTサービスをインストールしたい
- 編成 – コンポーネントで対象モジュールを選択し、[詳細設定]で NTサービスのインストール を設定すればいい
- ここで重要なのはここで入力するサービス名をモジュール内部のものと正しく統一しておくこと
インストールシーケンスを見ると、
サービスの停止->サービスの削除->ファイルの削除->
ファイルのインストール->サービスのインストール->サービスの開始
といった順に実行されるようだ。
通常のシナリオでは問題なさそうだが、もしアンインストール開始前に別のサービスを起動したいという特殊な事情になるとカスタムアクションを使って自前で実行しないといけなさそうだ。
- …
- UnpublishFeatures
- StopServices
- DeleteServices
- UnregisterComPlus
- SelfUnregModules
- UnregisterTypeLibraries
- RemoveODBC
- UnregisterFonts
- RemoveRegistryValues
- UnregisterClassInfo
- UnregisterExtensionInfo
- UnregisterProgIdInfo
- UnregisterMIMEInfo
- RemoveIniValues
- RemoveShortcuts
- RemoveEnvironmentStrings
- RemoveDuplicateFiles
- RemoveFiles
- RemoveFolders
- CreateFolders
- MoveFiles
- InstallFiles
- PatchFiles
- DuplicateFiles
- BindImage
- CreateShortcuts
- RegisterClassInfo
- RegisterExtensionInfo
- RegisterProgIdInfo
- RegisterMIMEInfo
- WriteRegistryValues
- WriteIniValues
- WriteEnvironmentStrings
- RegisterFonts
- InstallODBC
- RegisterTypeLibraries
- SelfRegModules
- RegisterComPlus
- InstallServices
- StartServices
- RegisterUser
- …
.NETのアセンブリをグローバルアセンブリキャシュに登録したい
- 編成 – コンポーネントで対象モジュールを選択し、インストール先に [GlobalAssemblyCache] と設定すればいい
- ここで重要なのはここで入力するサービス名をモジュール内部のものと正しく統一しておくこと
インストール後に「いますぐアプリケーションを起動」をつけたい
ユーザインターフェース -> ダイアログを開き SetupCompleteSuccesss を開く
このダイアログの中には CheckLunchProgram(CheckBox), LaunchProgramText(StaticText) があり、デフォルトでVisibleがfalseなのでこれをtrueにして表示させる。
次にチェックされたときの動作をSetupCompleteSuccesssの 動作 で設定する。OKコントロールのイベント DoAction を追加し、アプリケーションを実行するためのカスタム関数を引数に指定し、条件に LAUNCHPROGRAM と入力する。
これでチェックが入ったときにカスタムアクションが実行できる。
チェックが入った場合に、exeをキックするというのはもう少し簡単に設定できる。ただし、指定できるexeがインストールするファイルに限られるようでPlug-inの追加だけのインストーラから本体のアプリをキックしたい場合にカスタムアクションを使う方法が有効だと考えた
MSIでカスタムアクションを自在に操りたい
MSIだとInstallScriptと違ってカスタムアクションを簡単にインストーラの中に実装できない。やり方としてはCのNativeなDLLを作成してMSIから適切なタイミングで呼び出すことになる。NativeのDLLと言ってもMsiのライブラリにリンクすることでMsi関係の操作が可能。MSIのデータにアクセスするために、MSIからDLLのFunctionを呼び出す際には自分のMSIハンドルが渡される。
たとえば以下のようなdllを作成し、動作とロジック->カスタムアクションでDLLと関数名を指定し、あとはどのシーケンスで実行するかを指定すればよい。
#include "stdafx.h"
#ifdef __cplusplus
extern "C" {
#endif
UINT __declspec(dllexport) CustomFunction(MSIHANDLE hInstall);
#ifdef __cplusplus
}
#endif
#ifdef _MANAGED
#pragma managed(push, off)
#endif
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
UINT __declspec(dllexport) CustomFunction(MSIHANDLE hInstall)
{
MessageBox(GetForegroundWindow(), _T("CustomFunction"), _T("Hello"), MB_OK | MB_ICONINFORMATION);
return ERROR_SUCCESS;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
↓がどっかに必要
#include <Msi.h>
#pragma comment (lib, "Msi.lib")
プログラムの追加と削除で表示されるアイコンの変更
一般情報 -> プログラムの追加と削除 -> アイコンの表示で変更できる
コマンドライン引数を使いたい
setup.exe /v"HOGEHOGE=\"1\""
と叩いて、MSIDLLの中で MsiGetProperty で取得する。
::MsiGetProperty(hInstall, _T("HOGEHOGE"), &strValue, &dwValueBuf);
64ビットOSにインストールできないようにしたい
インストール情報 -> 一般情報 -> 製品のプロパティ -> インストール条件にて Not VersionNT64 を追加する
アンインストール時に不明な発行元と言われないようにしたい
- 下記のforumを参照するとmsiの直接実行型では厳しいという見解