DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

MSIファイルのWindows Installerデータベースをプログラムで編集する

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 "INSERT INTO Property(Property,Value) VALUES('ALLUSERS','2')"

「すべてのユーザー」がデフォルトになるようにする」と「「すべてのユーザー/このユーザーのみ」チェックボックスを隠す」にて、「すべてのユーザー/このユーザーのみ」チェックボックスを隠し、「すべてのユーザー」をデフォルトとする方法を紹介しましたが、下のURLの投稿では、WiRunSQL.vbsを使ってこれを実現する方法が紹介されています。

なおこの例ではWiRunSQL.vbsを何回も呼び出していますが、WiRunSQL.vbsは複数のSQLクエリーを引数に指定できるようなので、そのようにした方がより効率的でしょう。

自分でVBスクリプトを作成する

次に「WiRunSQL.vbs」を参考にして、自分でスクリプトを書いてみます。このスクリプトではコマンドライン引数として渡されたMSIファイルのデータベースのPropertyテーブルにProperty=ALLUSERS、Value=2の行を追加しています。

VBScript
コードを隠すコードを選択
{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を変更しています。

VBScript
コードを隠すコードを選択
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

.NET Frameworkで行う

さて、これと同じことをVB.NETやC#で行うには、どのようにすればよいのでしょうか?

まずはじめに考えられる方法は、上と同様にCOMを使う方法でしょう。ところが、実際に「Microsoft Windows Installer Object Library」(msi.dll)を参照に追加してみると分かるのですが、事前バインディングではInstallerオブジェクトが取得できないため、なかなかうまくいきません(注)。VB.NETのCreateObjectを使って遅延バインディングにすれば、大丈夫のようです。

注:こちらのニュースグループの投稿によれば、次のような方法で可能のようです。
  1. msi.dll(Microsoft Windows Installer Object Library)を参照設定に追加します。
  2. 次のようなクラスを定義します。
    VB.NET
    コードを隠すコードを選択
    <System.Runtime.InteropServices.ComImport(), _
    System.Runtime.InteropServices.Guid("000C1090-0000-0000-C000-000000000046")> _
    Class Installer
    End Class
    
    C#
    コードを隠すコードを選択
    [System.Runtime.InteropServices.ComImport(),
    System.Runtime.InteropServices.Guid("000C1090-0000-0000-C000-000000000046")]
    class Installer { }
    
  3. 次のようにしてInstallerオブジェクトを作成します。
    VB.NET
    コードを隠すコードを選択
    Dim inst As WindowsInstaller.Installer = _
        CType(New Installer(), WindowsInstaller.Installer)
    
    C#
    コードを隠すコードを選択
    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 Tipsをご利用いただく際は、注意事項をお守りください。