MSIファイルのWindows Installerデータベースを編集する場合、通常はOrcaを使用します。しかし現実的な問題として、MSIファイルを作成するたびにOrcaを使って手作業で編集するのは面倒ですし、危険でもあります。ここではOrcaを使ってMSIファイルのデータベースを編集するのではなく、スクリプトやプログラムで自動的に編集するための方法を紹介します。
実はそのサンプルがPlatform SDK「Windows Installer Scripting Examples」にあります。ScriptsフォルダにあるVBScriptがそれです。多くのサンプルがあり、とても参考になります。
この内、「WiRunSQL.vbs」(Execute SQL Statements)はSQLクエリーによりWindows Installerデータベースを更新するスクリプトで、まさに求めているものです。
まずはWiRunSQL.vbsを使うことによりMSIファイルのデータベースを編集してみましょう。次のようなコマンドラインにより、PropertyテーブルにProperty=ALLUSERS、Value=2の行を追加できます。
cscript WiRunSQL.vbs
「「すべてのユーザー」がデフォルトになるようにする」と「「すべてのユーザー/このユーザーのみ」チェックボックスを隠す」にて、「すべてのユーザー/このユーザーのみ」チェックボックスを隠し、「すべてのユーザー」をデフォルトとする方法を紹介しましたが、下のURLの投稿では、WiRunSQL.vbsを使ってこれを実現する方法が紹介されています。
なおこの例ではWiRunSQL.vbsを何回も呼び出していますが、WiRunSQL.vbsは複数のSQLクエリーを引数に指定できるようなので、そのようにした方がより効率的でしょう。
次に「WiRunSQL.vbs」を参考にして、自分でスクリプトを書いてみます。このスクリプトではコマンドライン引数として渡されたMSIファイルのデータベースのPropertyテーブルにProperty=ALLUSERS、Value=2の行を追加しています。
{VBScript] Option Explicit Const msiOpenDatabaseModeTransact = 1 Dim msiPath : msiPath = Wscript.Arguments(0) Dim installer Set installer = Wscript.CreateObject("WindowsInstaller.Installer") Dim database Set database = installer.OpenDatabase(msiPath, msiOpenDatabaseModeTransact) Dim query query = "INSERT INTO Property(Property, Value) VALUES('ALLUSERS', '2')" Dim view Set view = database.OpenView(query) view.Execute database.Commit
もう一つサンプルを示します。この例では、PropertyテーブルにProperty=ALLUSERSの列があるか調べ、なければ追加し、あればValueを変更しています。
Option Explicit Const msiOpenDatabaseModeTransact = 1 Const msiViewModifyInsert = 1 Const msiViewModifyUpdate = 2 Dim msiPath : msiPath = Wscript.Arguments(0) Dim installer Set installer = Wscript.CreateObject("WindowsInstaller.Installer") Dim database Set database = installer.OpenDatabase(msiPath, msiOpenDatabaseModeTransact) Dim query query = "Select * FROM Property WHERE Property='ALLUSERS'" Dim view Set view = database.OpenView(query) view.Execute Dim record Set record = view.Fetch Dim viewModify viewModify = msiViewModifyUpdate 'ALLUSERSがない時 If record Is Nothing Then Set record = installer.CreateRecord(2) viewModify = msiViewModifyInsert End If record.StringData(1) = "ALLUSERS" record.StringData(2) = "2" view.Modify viewModify, record database.Commit
さて、これと同じことをVB.NETやC#で行うには、どのようにすればよいのでしょうか?
まずはじめに考えられる方法は、上と同様にCOMを使う方法でしょう。ところが、実際に「Microsoft Windows Installer Object Library」(msi.dll)を参照に追加してみると分かるのですが、事前バインディングではInstallerオブジェクトが取得できないため、なかなかうまくいきません(注)。VB.NETのCreateObjectを使って遅延バインディングにすれば、大丈夫のようです。
注:こちらのニュースグループの投稿によれば、次のような方法で可能のようです。
<System.Runtime.InteropServices.ComImport(), _ System.Runtime.InteropServices.Guid("000C1090-0000-0000-C000-000000000046")> _ Class Installer End Class
[System.Runtime.InteropServices.ComImport(),
System.Runtime.InteropServices.Guid("000C1090-0000-0000-C000-000000000046")]
class Installer { }
Dim inst As WindowsInstaller.Installer = _ CType(New Installer(), WindowsInstaller.Installer)
WindowsInstaller.Installer inst =
(WindowsInstaller.Installer)new Installer();
または、Windows Installer APIを直接呼び出してもよいでしょう。Windows Installer APIについては、次のリンク先で詳しく説明されています。
Windows Installer APIのラッパークラスがCode Projectの「Wrapping the Windows Installer 2.0 API」で紹介されていますので、このようなものを利用させていただくのもよいでしょう。
また、WiXに同梱されているwix.dllも役に立ちます。
(この記事は、「.NETプログラミング研究」の第62号で紹介したものを基にしています。)