Office 2003 アプリケーションの Windows Installer (msi) による配布方法


2008/03 追記 : Office 2007 (及び VSTO v3) については、こちらの記事 を参照してください

環境:
Office Professional 2003 SP2 
Visual Studio 2005 Tools for the Microsoft Office system

こんにちは。

過去、10行以上の複雑な設定のため、「10行でずばり」に掲載できなかった当コンテンツを お困りの方のためにアップしておきます。

Orcas で VSTO プロジェクトの Click Once がサポートされる予定ですが、それまでの間、VSTO のプロジェクトでは CAS の設定をユーザに促す必要があるという配布の上での課題があるため、それをインストーラで克服するコードを後半(「補足」の章)で紹介しています。

==========================================================

目次

はじめに
作成するアプリケーションの概要
サンプルアプリケーションを作成する
セットアッププロジェクトを作成する
アプリケーションマニフェストを変更する
コードアクセスセキュリティを設定する
実行する
おわりに

(補足) コードアクセスセキュリティをインストーラから設定する方法について

 

はじめに

Visual Studio Tools for Office (Microsoft Visual Studio Tools for the Microsoft Office System、略して VSTO) を使用して作成したアプリケーションの配布方法には、「発行」による方法と、インストーラによる配布の大きく分けて2種類の配布方法があり、いずれの場合も、マニフェストの設定、Office アプリケーション実行のためのセキュリティの設定の双方を考慮した配布が必要となります。
ここでは、後者のインストーラによる配布方法を例として、こうした配布の方針(ポリシー)の設定方法について説明していきます。
(なお、「発行」を使用した配布については、「おわりに」でふれます。)

 

作成するアプリケーションの概要

ここでは、起動時にメッセージを表示する簡単なOfficeアプリケーションを作成し、これをインストールしてセットアップするためのセットアッププログラムを構築していきます。

 

サンプルアプリケーションを作成する

まずは、セットアッププログラムを作成する前の準備として、セットアップされるサンプルのOfficeアプリケーションを作成します。ここでは、起動時に 「Hello World」 のメッセージボックスを表示する簡単なアプリケーションを以下の手順で作成します。(なお、Office アプリケーションの作成方法詳細については、「10 行でズバリ !! Office アプリケーションの活用」 を参照してください。)

Visual Studio 2005 を起動して、[ファイル] メニューの [新規作成] をポイントして、[プロジェクト] をクリックします。 [新しいプロジェクト] ダイアログ ボックスの、プロジェクトの種類ペインで [Visual C#] ノードを展開し、[Office] をクリックします。[テンプレート] ペインでは [Excelブック] をクリックします。[プロジェクト名] ボックスにプロジェクト名として 「SampleWorkbook」 と入力し、[場所] ボックスに適当なパスを指定したら、[OK] ボタンをクリックします。(図1)

図 1. Visual Studio Tools for Office の Excel ブック プロジェクト テンプレートの選択

[Visual Studio Tools for Office プロジェクト ウィザード] ダイアログ ボックスが表示されますので、既定の [新規ドキュメントの作成] オプションを選択し、[OK] をクリックします。これで、プロジェクトが作成されました。

表示されるソリューション エクスプローラ で ThisWorkbook.cs を右クリックして、[コードの表示] をクリックしてコードエディタを表示します。ブックの表示時に処理される StartUp イベントハンドラのコードが表示されますので、以下の通りコードを追加します。

private void ThisWorkbook_Startup(object sender, System.EventArgs e)
{
  MessageBox.Show("Hello World");
}

実行してみましょう。
[Ctrl] + [F5] キーを押すか、[デバッグ] メニューから [デバッグなしで開始] をクリックすると、図2のように表示されます。

図 2. サンプルアプリケーションの実行

 

セットアッププロジェクトを作成する

つぎに、以下の手順で、この簡単なサンプルアプリケーションのセットアップ用のプロジェクトを新規に作成します。上記のサンプルアプリケーションと同一のソリューションに別のプロジェクトとして作成していきます。
上記で作成したプロジェクトを開いたまま、Visual Studio の [ファイル] メニューの [追加] を選択して [新しいプロジェクト] をクリックします。[新しいプロジェクト] ダイアログ ボックスの、プロジェクトの種類ペインで [その他のプロジェクトの種類] ノードを展開し、[セットアップと配置] をクリックします。[テンプレート] ペインでは [セットアップ プロジェクト] をクリックします。[プロジェクト名] ボックスにプロジェクト名として 「TestSetup」 と入力し、[場所] ボックスに適当なパスを指定したら、[OK] ボタンをクリックします。(図3)

図 3. セットアップ プロジェクト テンプレートの追加

セットアップ用のプロジェクトが作成されましたので、つぎに、以下の手順で、作成したセットアップ プロジェクト (TestSetup) に上記で作成したサンプルアプリケーション (SampleWorkbook) を設定していきます。
ソリューション エクスプローラで [TestSetup] プロジェクト ノードを右クリックします。ショートカット メニューの [表示] をクリックし、[ファイル システム] をクリックすると、ファイル システムの設定画面が表示されます。(図4)

図 4. ファイルシステムの設定画面

画面左側のペイン上の [アプリケーション フォルダ] を右クリックし、ショートカット メニューの [追加] をポイントし、[プロジェクト出力] をクリックします。[プロジェクト] ボックスの [SampleWorkbook] を選択し、出力の種類として [プライマリ出力] を選択し、[OK] をクリックします。
これで、セットアップ対象となるプロジェクトの出力結果と、依存するアセンブリの一式が右ペインに表示されます。

つづけて、ソリューション エクスプローラで、[TestSetup] プロジェクト ノードの下にある [見つかった依存関係] を展開し、Microsoft .NET Framework を除く すべての依存関係をマウスで選択します ([Ctrl] キー、または [Shift] キーを押しながら複数選択をおこないます)。選択した領域を右クリックして、表示されるショートカット メニューの [除外] をクリックしてすべて除外します。

これで、セットアップのためのプログラムの配置の設定が完了しました。

 

アプリケーションマニフェストを変更する

つぎの手順の説明の準備として、ここで、Visual Studio Tools for Office (Microsoft Visual Studio Tools for the Microsoft Office System、略して VSTO) を使用して構築されたアプリケーションがどのように実行されるか、簡単に説明します。

VSTO で開発されたアプリケーションの処理(実装コード)は、ExcelブックやWordドキュメントなどのOfficeドキュメントに埋め込まれるのではなく、文書とは別のDLLファイルとしてマネージコードで保存されます。開かれるExcelブックやWordドキュメントにはカスタムプロパティの値が設定されており、文書ファイルを開く際に、文書ファイルに添付されているこのカスタムプロパティの内容をもとにドキュメントにマネージコードが添付されていることを知ると、ドキュメントに含まれるマニフェストと呼ばれる内容を参照して、DLLの名前や、バージョン、保管場所(パス) などの情報を取得してこのマネージコードを実行します。
Visual Studio で Officeアプリケーションを作成してビルドする際は、このマニフェストの情報を環境にあわせて自動的に更新してくれるため、そのままの状態で実行をする場合には問題なく動作します。しかし、インストーラを使用して配置する場合には、インストールされるフォルダの場所や状態 (例: ネットワークドライブか、ローカルか、など) に合わせ、このマニフェストの情報も更新する必要があります。このため、Officeアプリケーションの場合、セットアップ時にこの設定をおこなうためのカスタム動作をインストーラに設定する必要があるのです。

まず、以下の手順で、カスタム動作をおこなう処理を上記で作成したソリューションと同一のソリューションの中に新規のプロジェクトとして作成します。
上記のプロジェクトを開いたままで、Visual Studio の [ファイル] メニューの [追加] を選択して [新しいプロジェクト] をクリックします。[新しいプロジェクト] ダイアログ ボックスの、プロジェクトの種類ペインで [Visual C#] ノードを展開し、[Windows] をクリックします。[テンプレート] ペインでは [クラスライブラリ] をクリックします。[プロジェクト名] ボックスにプロジェクト名として 「CustomAction」 と入力し、[場所] ボックスに適当なパスを指定したら、[OK] ボタンをクリックします。(図5)

図 5. カスタム動作 プロジェクト テンプレートの追加

自動的に作成されるクラスファイル Class1.cs は使用しませんので、Class1.cs を右クリックし、[削除] をクリックしてファイルを削除します。代わりに、つぎの手順でインストーラ専用のクラスを追加していきます。
ソリューション エクスプローラで [CustomAction] プロジェクトを右クリックし、ショートカット メニューの [追加] を選択し、[新しい項目] をクリックします。[新しい項目の追加] ダイアログ ボックスが表示されますので、[インストーラ クラス] をクリックし、ファイル名に 「MyInstaller.cs」 と入力して[追加] をクリックします。(図6)

図 6. インストーラ クラス の追加

ソリューション エクスプローラで、CustomAction プロジェクトの[参照設定] を右クリックし、[参照の追加] をクリックします。表示される [参照の追加] ダイアログ ボックス の[.NET] タブから、[Microsoft.VisualStudio.Tools.Applications.Runtime] を選択して [OK] をクリックします。

ソリューション エクスプローラで、MyInstaller.cs ファイルを右クリックし、[コードの表示] をクリックして、コードエディタを表示します。表示されるファイル上部の宣言部分に、以下を追加します。

using Microsoft.VisualStudio.Tools.Applications.Runtime;

インストール時の処理としてマニフェストの更新をおこなうため、MyInstaller クラスのメソッドとして下記のコードを追加(及びオーバーライト) します。なお、下記で使用しているパラメータ値 targetdir、documentname、assemblyname については後ほど設定をおこないます。

// インストール処理のオーバーライト関数
// マニフェストの設定処理を追加
public override void Install(System.Collections.IDictionary stateSaver)
{
    SetupManifest();               /* 独自に追加された処理*/
    base.Install(stateSaver);
}
 
// マニフェストの設定処理
private void SetupManifest()
{
    // インストールディレクトリの取得
    string targetDir = this.Context.Parameters["targetdir"];
    // ドキュメント名(Excelブック) の取得
    string documentName = this.Context.Parameters["documentname"];
    // アセンブリ名 (DLL) の取得
    string assemblyName = this.Context.Parameters["assemblyname"];
 
    // VSTO のサーバドキュメントオブジェクトを取得
    ServerDocument serverDocument = new ServerDocument(
      System.IO.Path.Combine(targetDir, documentName),
      System.IO.FileAccess.ReadWrite);
 
    // マニフェストを取得し、AssemblyPath 属性を変更
    try
    {
        serverDocument.AppManifest.Dependency.AssemblyPath =
            System.IO.Path.Combine(targetDir, assemblyName);
        serverDocument.Save();
    }
    finally
    {
        if (serverDocument != null)
            serverDocument.Close();
    }
}

ソリューション エクスプローラで [CustomAction] プロジェクトを右クリックし、[ビルド] をクリックします。

これでカスタム動作が作成されましたので、以下の手順で、この作成したカスタム処理をセットアッププロジェクトに追加します。
ソリューション エクスプローラで [TestSetup] プロジェクト ノードを右クリックし、ショートカット メニューの [表示] を選択して、[カスタム動作] をクリックすると、カスタム動作エディタが表示されます。(図7)

図 7. カスタム動作エディタの表示

このエディタで、[インストール] ノードを右クリックし、[カスタム動作の追加] をクリックします。表示される ダイアログ ボックス の [検索対象] ボックスから [アプリケーション フォルダ] を選択し、[出力の追加] をクリックします。表示される ダイアログ ボックス の [プロジェクト] ボックスから [CustomAction] を選択し、出力の種類の一覧から [プライマリ出力] を選択し、[OK] をクリックします。項目の一覧に [CustomAction (アクティブ) のプライマリ出力] が追加されていることを確認し、[OK] をクリックします。(図8)

図 8. カスタム動作の項目追加

つぎに、以下の手順で、上記のコードで使用していたプロパティ (targetdir、documentname、assemblyname) の設定をおこないます。
表示しているカスタム動作エディタで、[インストール] を展開します。[CustomAction (アクティブ) のプライマリ出力] を右クリックし、[プロパティ ウィンドウ] をクリックして [プロパティ] ウィンドウを表示します。[プロパティ] ウィンドウで、CustomActionData プロパティの入力欄に以下の文字列を入力します。(下記をそのままコピー/ペーストして貼り付けてください。)

/targetdir="[TARGETDIR]/" /documentname="SampleWorkbook.xls" /assemblyname="SampleWorkbook.dll"

ソリューション エクスプローラで [TestSetup] プロジェクトを右クリックし、[ビルド] をクリックします。
これでセットアッププロジェクトへのカスタム動作の組み込みが完了しました。

 

コードアクセスセキュリティを設定する

では、以下の手順で、上記で作成したインストーラのインストール動作を実行して、動作を確認してみましょう。
ソリューション エクスプローラで [TestSetup] プロジェクトを右クリックし、[インストール] をクリックします。表示されるウィザードに従って、インストール先のディレクトリを適当に入力し、インストールを完了してください。

Visual Studio のプロジェクトを閉じて (プロジェクトを開いたままだと、SampleWorkbook.xls が開かれた状態になっていますので、一旦閉じてください)、インストールされた Excel ファイルをダブルクリックして実行してみてください。以下のエラーの ダイアログ ボックス が表示されますので、[詳細] ボタンを押してエラーの内容を確認してください。(図9)

図 9. セキュリティのエラー表示

このように、アクセス許可の違反が発生しているのがわかります。実は、VSTO で開発したOfficeアプリケーションを実行するには、利用者の環境で、コードアクセスセキュリティを明示的に設定する必要があります。
以下に、この設定方法を記載します。 (コードアクセスセキュリティの詳細については、「10 行でズバリ !! コード アクセス セキュリティ (C#)」 を参照してください。)
なお、この処理には、マシンの管理者の権限が必要です。

[コントロール パネル] の [管理ツール] を選択し、[Microsoft .NET Framework 2.0 構成] をクリックして、.NET の構成ウィンドウを表示します。(図10)

図 10. .NET Framework の構成ウィンドウ

インストール先のマシン環境で、以下の手順で、新しいコードグループの追加をおこないます。
構成ウィンドウで、[.NET Framework 2.0 Configuration] – [マイコンピュータ] – [ランタイムセキュリティポリシー] – [ユーザ] – [コードグループ] – [All_Code] のノードをクリックします。メニュー [操作] の [新規作成] をクリックして、[名前] 欄に 「Setup_Test」 と入力して、[次へ] をクリックします。[このコードグループの条件の種類を選択] グループで、[URL] を選択し、[URL] 入力欄に、[インストールしたディレクトリ]\* (例: C:\InsTest\TestSetup\*) を入力して、[次へ] をクリックします。設定するアクセス許可セットとして、[既存のアクセス許可セット] から [FullTrust] を選択して、[次へ] をクリックし、[完了] をクリックして確定します。
これで、コードアクセスセキュリティの設定は完了です。

なお、ここで実行した処理を caspol ユーティリティを使用して、コマンドプロンプトから以下の通り実行することもできます。(無論、この処理も、管理者の権限が必要となります。)

[.NET Framework のインストールディレクトリ]\caspol -u -ag All_Code -url [アプリケーションのインストールディレクトリ]\* FullTrust -n "Setup_Test"

注記 : [.NET Framework のインストールディレクトリ]、[アプリケーションのインストールディレクトリ] には導入環境にあわせて適当な値を設定してください。
(例) [.NET Framework のインストールディレクトリ] C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
(例) [アプリケーションのインストールディレクトリ] C:\InsTest\TestSetup

ここで示したセキュリティ設定の内容はあくまでもサンプルです。セキュリティの方針にあわせて、設定するアクセス許可セットや、コードグループ条件などは、適宜変更してください。

また、この設定をインストーラから自動的に設定する方法については、補足として後述します。

 

実行する

では、先ほどアクセス許可のエラーで実行できなかったOfficeアプリケーションを再度実行してみましょう。
こんどはセキュリティの設定がおこなわれているため、作成した処理を実行することが可能です。

図 11. Office アプリケーションの実行

アンインストールをおこなうには、[コントロール パネル] の [プログラムの追加と削除] からアンインストールをおこなうか、ソリューション エクスプローラから [TestSetup] プロジェクトを右クリックして、[アンインストール] をクリックします。

 

おわりに

「はじめに」 で記載したように、Officeアプリケーションの配布方法には上述のインストーラを使用した配布方法以外に、「発行」 の機能を使用した配布も可能です。「発行」 による配布は簡単で、上述のようなセットアッププロジェクトを作成する必要はなく、作成した Office プロジェクトをソリューション エクスプローラで右クリックして [発行] をクリックすることでネットワーク上のドライブなどに簡単に配置(及びセットアップ)をおこなうことができます。この「発行」の機能を使うと、共有フォルダなどに配置をおこなって、常に最新のバージョンを利用者に提供することが可能となります。

但し、この「発行」による仕組みで配布する場合でも、上述のように、「マニフェストの設定」 と 「コードアクセスセキュリティの設定」 の2つの方針を考慮する必要があるという点を憶えておいてください。
「発行」 により配布をおこなった場合、マニフェスト情報の設定は、発行ウィザードが環境にあわせて自動的に設定してくれますが、配置マニフェストとアプリケーションマニフェストがテキストファイルとしてドキュメントやアセンブリとは別で出力されますので、このテキストファイルの内容を編集することで、環境にあわせて、マニフェストの情報を独自にカスタマイズして配置することもできます。
またコードアクセスセキュリティについては、「発行」の際でも、上述のインストーラによる方法と同様に、各利用者の環境ごとに設定をおこなう必要があるという点に注意してください。

従来の VBA (Visual Basic for Application) と異なり、VSTOではこのマニフェストとセキュリティの仕組みを上手に使うことで様々な活用のシナリオが、安全かつ柔軟に実現できる仕組みになっています。例えば、Officeアプリケーションの場合、文書(ブック、ドキュメント、など)そのものは各利用者の環境に配置して自由な編集と保存を可能にしたい場合があります。このような場合でも、マニフェストとセキュリティの設定を適切におこなうことで、文書は各自の環境に保存し、アセンブリによる処理を共有フォルダ上などで共有するといった配置のシナリオが可能となっています。

 

(補足) コードアクセスセキュリティをインストーラから設定する方法について

さいごに、上記で設定したコードアクセスセキュリティを利用者に設定させるのではなく、インストーラのプログラムから自動的に設定する方法について、以下にサンプルを記載します。この処理は、利用者に設定させる場合や、あらかじめセキュリティ設定された所定のディレクトリにインストールさせる場合などは、必要ありません。必要に応じ実装をおこなってください。

上記で作成した[CustomAction] プロジェクトの [参照設定] を右クリックし、[参照の追加] をクリックします。表示される [参照の追加] ダイアログ ボックス の[.NET] タブから、[System.Security] を選択して [OK] をクリックします。

ソリューション エクスプローラで、MyInstaller.cs ファイルを右クリックし、[コードの表示] をクリックして、コードエディタを表示します。表示されるファイル上部の宣言部分に、以下を追加します。

using System.Security;

インストール時の処理としてマニフェストの更新をおこなうため、MyInstaller クラスの Install メソッドの処理として下記の処理を追加します。

public override void Install(System.Collections.IDictionary stateSaver)
{
    SetupManifest();
    AddCASecurityPolicy();      /* 今回、独自に追加した処理*/
    base.Install(stateSaver);
}
 
// コードアクセスセキュリティを追加する処理
private void AddCASecurityPolicy()
{
    string insdirTxt = this.Context.Parameters["targetdir"];
    string accessUrl = insdirTxt.Substring(0, insdirTxt.Length - 1) + "*";
 
    // User レベルのコードグループのルート (All_Code) を取得
    System.Collections.IEnumerator polLevEnum = SecurityManager.PolicyHierarchy();
    while (polLevEnum.MoveNext())
    {
        if (((System.Security.Policy.PolicyLevel) polLevEnum.Current).Label == "User")
            break;
    }
    System.Security.Policy.PolicyLevel polLev =
      (System.Security.Policy.PolicyLevel) polLevEnum.Current;
    System.Security.Policy.UnionCodeGroup allGroup =
      (System.Security.Policy.UnionCodeGroup) polLev.RootCodeGroup;
 
    // 新しいコードグループ (Setup_Test) を追加
    PermissionSet permSet = polLev.GetNamedPermissionSet("FullTrust");
    System.Security.Policy.UrlMembershipCondition urlCond =
      new System.Security.Policy.UrlMembershipCondition(accessUrl);
    System.Security.Policy.UnionCodeGroup newGroup =
      new System.Security.Policy.UnionCodeGroup(urlCond,
        new System.Security.Policy.PolicyStatement(permSet));
    newGroup.Name = "Setup_Test";
    allGroup.AddChild(newGroup);
 
    // セキュリティポリシーを保存
    SecurityManager.SavePolicy();
}

さらに、インストール時に追加したコードグループをアンインストール時にクリアするため、MyInstaller クラスのメソッドとして下記のコードを追加 (及びオーバーライト) します。

// アンインストール処理のオーバーライト関数
// インストール時に追加したコードグループを削除
public override void Uninstall(System.Collections.IDictionary savedState)
{
    RemoveCASecurityPolicy();
    base.Uninstall(savedState);
}
 
// コードグループを削除する処理
private void RemoveCASecurityPolicy()
{
    // “User”レベルのコードグループのルートを取得
    System.Collections.IEnumerator polLevEnum = SecurityManager.PolicyHierarchy();
    while (polLevEnum.MoveNext())
    {
        if (((System.Security.Policy.PolicyLevel) polLevEnum.Current).Label == "User")
            break;
    }
    System.Security.Policy.PolicyLevel polLev =
      (System.Security.Policy.PolicyLevel) polLevEnum.Current;
    System.Security.Policy.UnionCodeGroup allGroup =
      (System.Security.Policy.UnionCodeGroup) polLev.RootCodeGroup;
 
    // 削除する対象のコードグループを取得して削除実行
    System.Collections.IEnumerator childGroupEnum = allGroup.Children.GetEnumerator();
    while (childGroupEnum.MoveNext())
    {
        System.Security.Policy.CodeGroup childGroup;
        childGroup = (System.Security.Policy.CodeGroup) childGroupEnum.Current;
        if (childGroup.Name == "Setup_Test")
        {
            allGroup.RemoveChild(childGroup);
            SecurityManager.SavePolicy();
            break;
        }
    }
}

さいごに、インストール時と同様に、[TestSetup] プロジェクトのカスタム動作エディタを表示して、上述のCustomAction プロジェクトを TestSetup セットアッププロジェクトのアンインストール時のカスタム処理として追加設定します。アンインストール時の処理では TARGETDIR 等のプロパティは使用しませんので、インストール時のような CustomActionData プロパティの値の設定は必要ありません。

この処理を含んだインストーラを実行するには、手動で設定したときと同様に、管理者の権限が必要となる点に注意してください。

==========================================================

以上、墓場に捨てられた記事でした、、、

 

Comments (1)

  1. こんにちは。 現在、つぎなる技術訴求に向けて猛烈に準備中ですが、先日、福井で INETA & Microsoft 協賛のセミナーがあり、上記タイトルのご質問を頂きました。 通常、セミナーなどで頂くご質問はご本人に回答するのですが、このご質問、大変影響も大きく、そしてコツの居る内容ですので、ブログにて記載させていただくことにします。

Skip to main content