はじめに
2006年2月25日に PASSJ Conference with VSUG というカンファレンスが開催されました。その中で、Ask the VSUGというブースに立たせていただいたのですが、そこでいただいた質問が以下のようなものでした。
|
すでに完成している.NET Framework 1.1上で動作するアプリケーションが存在するが、ノータッチ デプロイメントでの配布では、セキュリティ制約に引っかかってしまう。クライアント上のセキュリティ設定を変更するのが難しいため、ClickOnceで配布できないか。 |
持ち帰って調べた結果は、すでにご報告していますが、掲示板形式では解説仕切れない部分がありましたので、コラムという形で再度解説していきたいと思います。
本稿は前回の記事の内容を踏まえて記述しています。もし、ClickOnceで展開されるファイルについて、わからない場合は、前回の記事も併せてご参照ください。
■ ClickOnce のファイル構成
とはいえ、前回の記事も長いので、簡単におさらいしておきましょう。

前回の解説でも触れましたが、デプロイメント マニフェスト(.application)が、アプリケーションマニフェスト(.manifest)ファイルを参照していて、アプリケーション マニフェストが、アプリケーションに必要なファイルの情報を持っています。
つまり、アプリケーションに必要なファイルと、アプリケーション マニフェスト、デプロイメント マニフェストを作成すれば、ClickOnceによる配布ができるということになります。そして、これらのマニフェスト ファイルを作成するツールが mage.exe (mageUI.exe) というツールになります。
では、以上の内容を踏まえて解説していきたいと思います。
アプリケーションを作る
ノータッチ デプロイメントは、デフォルトではゾーンによるセキュリティ制約を採用しています。そのため、ローカル コンピュータ(マイコンピュータ ゾーン)では実行できるアプリケーションが、Web サーバーやファイルサーバーを経由したイントラネット ゾーンでは実行できなくなることがあります。今回の要件は、ノータッチデプロイメントで実行できないアプリケーションということなので、以下のように、イントラネット ゾーンでは許可されていない、Process.Start()メソッドを呼び出して、メモ帳を起動してみます。
.NET Framework 1.1で動作するアプリケーションなので、開発環境はVisual Studio .NET 2003になります。
作成するアプリケーションは、以下のように、メモ帳を起動するためのボタンと、ラベルに起動している.NET Framework のバージョンを表示するだけのシンプルなものです。

では、実際のコードを見てみましょう。
|
[C#] private void Form1_Load(object sender, System.EventArgs e) { try { label1.Text = RuntimeEnvironment.GetSystemVersion(); }catch(Exception){} }
private void button1_Click(object sender, System.EventArgs e) { Process.Start(@"C:\Windows\Notepad.exe"); }
|
|
[VB] Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MyBase.Load label1.Text = RuntimeEnvironment.GetSystemVersion() End Sub
Private Sub button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Try Process.Start("C:\Windows\Notepad.exe") Catch End Try End Sub |
フォーム読み込み時(Form1_Load))に、RuntimeEvironment.GetSystemVersion() メソッドを使用して、実行中の .NET Framework ランタイム バージョンをlabel1に表示しています。ただし、ノータッチデプロイメントでイントラネット ゾーンでは、この部分が実行できないため、例外をハンドリングしています。
ボタン クリック時(button1_Click)に、Process.Start() メソッドを使用して、メモ帳(Notepad.exe)を起動しています。この部分ももちろんイントラネットゾーンでは実行できませんが、例外を発生させるためにあえて例外のハンドリングはしていません。
このアプリケーションをデバッグ実行してみると、ボタンのクリックでメモ帳が起動することが確認できます。
ノータッチ デプロイメントで実行してみる
では、まず試しにノータッチ デプロイメントで配布してみましょう。ノータッチ デプロイメントでの配布は、実行ファイルや関連するファイルをWeb サーバー上にコピーして、Web ブラウザからアクセスするだけです。
Web サーバー上にファイルをコピーして、Internet Explorer から実行ファイルにアクセスすると、アプリケーションが起動します。次に、ボタンをクリックすると以下の図ように SecurityException が発生します。

このように、ノータッチ デプロイメントではデフォルトでは、ゾーンによるアクセス許可が与えられるため、イントラネット ゾーンで多くの制限がかかってしまいます。[管理ツール]にある[Microsoft .NET Framework 1.1 構成]を使用して制限を緩和することも可能ですが、構成の複雑なため実際に使用したことがない読者も多いのではないでしょうか。
ClickOnce では、様々な場所で紹介されているとおりセキュリティの制約を緩和してアプリケーションを配布することが容易にできるようになっています。
では、このアプリケーションをClickOnceで配布することができないか試してみましょう。
ClickOnceで配布する準備をする
ClickOnceで配布するためには、先ほど書いたようにアプリケーションマニフェスト ファイル(.manifest)とデプロイメント マニフェスト ファイル(.application)を作成して、必要なファイルを IIS の仮想ディレクトリに配置するだけで実現できます。では、mage.exe(mageUI.exe) を使用してマニフェスト ファイルを作成してみましょう。
アプリケーション マニフェストを作成する
まずは、アプリケーション マニフェストを作成します。[File]–[New]–[Application Manifest]をクリックします。
まず、[Name] パネルでアプリケーション名とバージョンを入力します。

ここでは、アプリケーション名を [NotepadLauncher]、バージョンを[1.0.0.0]にします。
次に、[Files] パネルを編集します。

[Application directory] に先ほどファイルを配置したフォルダのフルパスを入力して、[Populate]ボタンをクリックすると、フォルダ内のファイルが[Application files]に一覧表示されます。
ここでは、先ほど作成したNotepadLauncher.exeのみが表示されていて、[File Type]には、起動ファイルを意味する[Entry Point]が表示されています。
最後に、[Permissions Required] パネルを設定します。

Permission set type(アクセス許可セット)を[FullTrust]にして保存します。
保存しようとすると、署名ダイアログが表示されるので、署名ファイルがない場合は[New]ボタンをクリックして、キーペアファイル (.pfx) を作成して署名します。NotepadLauncher.exe.manifestというファイル名で保存します。

デプロイメント マニフェストを作成する
次にデプロイメント マニフェスト ファイルを作成します。
同じように[File]–[New]–[Deployment Manifest]をクリックします。
まず、[Name] パネルが開きます。ここでは、アプリケーション マニフェストと同じように名前とバージョンを入力します。

次に [Description] パネルを開いて、発行者名と製品名を入力します。

[Deployment Option]では、[Start Location]に、デプロイメント マニフェストのURLを入力します。

[Update Options]は、デフォルトのままなので省略します。
[Application Reference]パネルでは、先ほど作成したアプリケーション マニフェストへの参照を設定します。[Select Manifest]ボタンをクリックするとファイル選択ダイアログが表示されるので、先ほど作成したNotepadLauncher.exe.manifest を選択します。

以上の設定をして、ファイルの保存をクリックすると、アプリケーション マニフェストと同じように署名ダイアログが表示されるのでキーペアファイル(.pfx)を選択して、署名を行います。NotepadLauncher.applicationというファイル名で保存します。
これでアプリケーションをClickOnce で配布する準備が完了しました。では、クライアントから呼び出してみましょう。
.NET Framework 1.1 アプリケーションを ClickOnce で配布
Internet Explorerを開いて、アドレスにデプロイメント マニフェストファイル(NotepadLauncher.application) のURLを入力します。
[アプリケーションの起動中]ダイアログが表示されます。

しばらく待つと、以下のように起動失敗ダイアログが表示されます。

[詳細]ボタンをクリックして、エラー詳細を確認すると、以下のようなメッセージが表示されます。
|
(省略)
エラーの概要
以下はエラーの概要です。これらのエラーの詳細はログに一覧表示されています。
* http://localhost/NotepadLauncher/NotepadLauncher.application のライセンス認証により例外が発生しました。 次の失敗メッセージが検出されました:
+ http://localhost/NotepadLauncher/NotepadLauncher.exe.manifest からマニフェストを読み取っているときに例外が発生しました。マニフェストが無効であるか、ファイルを開くことができなかった可能性があります。
+ アプリケーション マニフェストが意味的に無効です。
+ 指定された <entryPoint> は無効です。エントリポイントへのパスが整形式で、エントリポイントが配置に存在することを確認してください。
(省略)
エラーの詳細
この操作中に次のエラーが検出されました。
* [2006/03/06 23:58:33] System.Deployment.Application.InvalidDeploymentException (ManifestParse)
- http://localhost/NotepadLauncher/NotepadLauncher.exe.manifest からマニフェストを読み取っているときに例外が発生しました。マニフェストが無効であるか、ファイルを開くことができなかった可能性があります。
- ソース: System.Deployment
- スタック トレース:
場所 System.Deployment.Application.ManifestReader.FromDocument(String localPath, ManifestType manifestType, Uri sourceUri)
(省略)
|
「指定された <entryPoint> は無効です。」というメッセージから、NotepadLauncher.exeファイルの実行に失敗していることがわかります。試しに、同様のアセンブリを.NET Framework 2.0で作成して、同じようにマニフェスト ファイルを作成してみると配布が成功して、正常にアプリケーションが起動できることが確認できます。
このことから、.NET Framework 1.1 のアプリケーションは、ClickOnceで配布することができないことがわかります。
では、他の方法で配布できないか試してみましょう。
.NET Framework 2.0 アプリケーションから起動(Process.Start)
EntryPoint にしようとして失敗していたので、EntryPoint を.NET Framework 2.0 で作成したアセンブリに変えてみて、そこから.NET Framework 1.1 で作成した NotepadLauncher.exe を呼び出してみたらどうなるでしょうか?
Visual Studio 2005 で以下のようなコンソール アプリケーションを作成します。このアプリケーションは、NotepadLauncherLauncher という名前で作成します。
|
[C#] [STAThread] static void Main() { Console.WriteLine(RuntimeEnvironment.GetSystemVersion()); Process.Start("NotepadLauncher.exe"); Console.Read(); }
|
|
[VB] Sub Main() Console.WriteLine(RuntimeEnvironment.GetSystemVersion()) Process.Start("NotepadLauncher.exe") Console.Read() End Sub |
先ほどと同じようにアプリケーション マニフェスト ファイル、デプロイメント マニフェスト ファイルを作成します。アプリケーション マニフェストでは、[Files] パネルで作成したアプリケーション(NotepadLauncherLauncher.exe)を追加して、EntryPoint に設定します。

Internet Explorerを起動して、デプロイメント マニフェストファイル (http://localhost/NotepadLauncher/NotepadLauncherLauncher.application) のURLを入力します。しばらく待つと、以下のようなインストール確認ダイアログが表示されます。

前進しました!では、[インストール]ボタンをクリックしてクライアントにインストールしてみます。
コマンドプロンプトが起動して、フォームが表示されました。フォーム上のボタンをクリックすると、メモ帳が起動しました。成功です!

画像を見ていただくとわかりますが、コマンドプロンプトは、.NET Framework 2.0 が使用されていますが、フォームの方は、.NET Framework 1.1 上で実行していることがわかります。Process.Start() メソッドで起動しているため、全く別のプロセスとして起動しています。つまり、ClickOnce で設定されたセキュリティの制約は関係なく、クライアントに配布されたアプリケーションを起動していることになります。
この方法で、アプリケーションの起動はできましたが、セキュリティ上の問題が発生する可能性があります。アプリケーションの起動イメージを以下の図を使って解説します。

ここでは、NotepadLauncherLauncher が、Process.Start()メソッドを使用して、全く新しいアプリケーションを起動しています。つまり、NotepadLauncherLauncher 起動時に.NET Framework 2.0 が作成したサンドボックスの外で NotepadLauncher が起動されているため、たとえ、ClickOnceで適切なセキュリティを設定していたとしても、これが無視されてアプリケーションが実行されることになってしまいます。
では、サンドボックスの中で起動できないか試してみましょう。
.NET Framework 2.0 アプリケーションから起動(Assembly.LoadFrom)
.NET Framework 2.0 によって作成されたサンドボックスの中でアプリケーションを実行するためには、アセンブリを読み込んで実行する必要があります。そのために使用するのがAssembly.LoadFrom()メソッドです。
では、コンソール アプリケーションを作成して、以下のようなコードを記述します。このアプリケーションは、NotepadLauncherLoader という名前で作成します。
|
[C#] [STAThread] static void Main() { Console.WriteLine(RuntimeEnvironment.GetSystemVersion()); Assembly asm = Assembly.LoadFrom("NotepadLauncher.exe"); Form frm = (Form)asm.CreateInstance("NotepadLauncher.Form1"); frm.ShowDialog(); Console.Read(); }
|
|
[VB]
Sub Main() Console.WriteLine(RuntimeEnvironment.GetSystemVersion()) Dim asm As Assembly = Assembly.LoadFrom("NotepadLauncher.exe") Dim frm As Form = DirectCast(asm.CreateInstance("NotepadLauncher.Form1"), Form) frm.ShowDialog() Console.Read() End Sub
|
アプリケーションのビルドが完了したら、これまでと同様にマニフェスト ファイルを作成して、ブラウザから呼び出してみます。
以下のようなインストール確認ダイアログが表示されるので、[インストール]をクリックして、インストールしてみます。

すると、コマンドプロンプトが起動して、つづけてフォームが表示されます。フォーム上のボタンをクリックすると、メモ帳が起動することが確認できました。

ここで注目したいのは、フォーム (NotepadLauncher) が.NET Framework 2.0 上で起動しているということです。アセンブリを読み込んで実行しているためサンドボックスの中で実行されていることになります。

これによって、マニフェスト ファイルで指定したセキュリティで実行されることになります。ただし、.NET Framework 1.1 上で動作させるために作成したアプリケーションが、.NET Framework 2.0 上で実行されるため、下位互換性のない処理を行った場合、予期しない動作をする可能性があります。
まとめ
ここまでに解説してきたように、.NET Framework 1.1 で作成したアプリケーションを ClickOnce で配布するためには、.NET Framework 2.0 で作成したアプリケーションが必要だということがわかりました。ただし、セキュリティを犠牲にするか、実行するランタイムのバージョンが2.0になるのをあきらめるかを選択する必要があります。
実際に利用する機会は非常に少ないと思いますが、ClickOnce の内部動作に触れることができたのではないでしょうか。
今回のコラムにご意見・ご要望がございましたら、モバイル・スマートクライアント フォーラムにトピックを立ててありますのでご活用ください。 |