IronPython, IronRuby での Silverlight 4 におけるブラウザー外実行と COM 連携 - WshShell でメモ帳を起動

IronPython, IronRuby で実装した Silverlight 4 にて、ブラウザー外実行時の COM オートメーション連携機能を試してみました。(ただし、IronRuby の方は正常動作しなかった)

使用した環境は以下の通り。

なお、COM オートメーション連携機能は WshShell(WScript.Shell)を使ったメモ帳の起動を試してみました。

サンプルのソースコードhttp://github.com/fits/try_samples/tree/master/blog/20101109/


個人的には、COM オートメーション連携が必要になっている時点でマルチプラットフォームを普通考慮しないだろうし、今回のようなケースで Silverlight にするメリットってそれほど無い気がしてますが・・・。

プロジェクトの雛形作成

まず、IronPythonIronRuby それぞれのホームディレクトリの Silverlight\script\sl.bat を使ってプロジェクトの雛形を作成します。

Silverlight\script\templates 内のファイルをコピーしてくるだけのようなので手動でコピーしてきてもいいと思います。

作成するプロジェクトのディレクトリを wsh_sample とすると以下のようになります。

IronPython の場合
> sl.bat python wsh_sample
IronRuby の場合
> sl.bat ruby wsh_sample

wsh_sample ディレクトリ内に index.html など Web 関係のファイルも作成されますが、ブラウザー外実行では app ディレクトリさえあればいいです。

COM オートメーション連携機能実装

app.py(もしくは app.rb)にボタンが押された際に WshShell を使ってメモ帳(notepad.exe)を起動する処理を実装します。

COM オートメーションの progID を AutomationFactory.CreateObject(もしくは GetObject)に指定して COM オブジェクトを取得し、メソッドを実行することになります。
また、AutomationFactory.IsAvailable を使って COM オートメーション連携機能が有効な状況か否かをチェックする事ができます。

なお、COM オートメーション連携を行うには、後述する AppManifest.xaml での昇格された信頼の設定が必要となります。(その設定が無いと IsAvailable が true にならない)

app.py(IronPython の場合)
from System.Windows import *
from System.Windows.Controls import UserControl
from System.Runtime.InteropServices.Automation import AutomationFactory

class App:
  def __init__(self):
    root = Application.Current.LoadRootVisual(UserControl(), "app.xaml")
    root.Message.Text = "Notepad Sample"

    root.NotepadButton.Content = "Run Notepad"
    root.NotepadButton.Click += self.button_click

  def button_click(self, sender, e):
    if AutomationFactory.IsAvailable:
      try:
        wsh = AutomationFactory.CreateObject("WScript.Shell")
        wsh.Run("notepad.exe")
      except Exception as e:
        MessageBox.Show("Error: " . e)
    else:
      MessageBox.Show("AutomationFactory: NG")

App()
app.rb(IronRuby の場合)
include System::Windows
include System::Windows::Controls
include System::Runtime::InteropServices::Automation

class App
  def initialize
    @root = Application.current.load_root_visual(UserControl.new, "app.xaml")
    @root.find_name('Message').text = "Notepad Sample"

    btn = @root.find_name('NotepadButton')
    btn.content = "Run Notepad"
    btn.Click {|sender, e|
        if AutomationFactory.IsAvailable
            begin
                wsh = AutomationFactory.CreateObject("WScript.Shell")
                #Run メソッドは正常に実行されない(例外も発生せず落ちている模様)
                r = wsh.Run("notepad.exe")
            rescue => e
                MessageBox.Show("Error: " + e)
            end
        else
            MessageBox.Show("AutomationFactory: NG")
        end
    }
  end
end

$app = App.new

IronRuby の方は正常に動作しなかったのですが、以下のようなコードだと問題なく動作するので COM オートメーション連携が全く機能しないという事では無さそうです。

IronRuby で実行に成功した COM オートメーション連携
wsn = AutomationFactory.CreateObject("WScript.Network")
MessageBox.Show(wsn.ComputerName)

ちなみに、app.xaml は以下のとおりです。

app.xaml
<UserControl x:Class="System.Windows.Controls.UserControl"
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <StackPanel x:Name="layout_root" Background="White">
    <TextBlock x:Name="Message" FontSize="30" />
    <Button x:Name="NotepadButton" Height="50" />
  </StackPanel>
</UserControl>

ブラウザー外実行用の AppManifest.xaml 作成

ブラウザー外実行の設定 Deployment.OutOfBrowserSettings を施した AppManifest.xaml ファイルを app ディレクトリに作成します。

注意点

ただし、ブラウザー外実行をしない場合や Chiron.exe.config ファイルでブラウザー外実行設定のコメントアウトを外した場合等では、AppManifest.xaml を自前で用意する必要はありません。(Chiron.exe で xap ファイルを作成する際に自動的に用意してくれる)


なお、COM オートメーション連携を行うには以下の設定が必要になります。

COM オートメーション連携を使う場合の昇格された信頼設定
<OutOfBrowserSettings.SecuritySettings>
  <SecuritySettings ElevatedPermissions="Required" />
</OutOfBrowserSettings.SecuritySettings>

IronPython の場合は以下のようになります。

AppManifest.xamlIronPython の場合)
<Deployment 
    xmlns="http://schemas.microsoft.com/client/2007/deployment" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    RuntimeVersion="2.0.31005.0" 
    EntryPointAssembly="Microsoft.Scripting.Silverlight" 
    EntryPointType="Microsoft.Scripting.Silverlight.DynamicApplication" 
    ExternalCallersFromCrossDomain="ScriptableOnly">
  <!-- Add assembly references here -->
  <Deployment.Parts>
    <AssemblyPart Source="Microsoft.Scripting.Silverlight.dll" />
    <AssemblyPart Source="System.Numerics.dll" />
    <AssemblyPart Source="Microsoft.Scripting.dll" />
    <AssemblyPart Source="Microsoft.Dynamic.dll" />
    <AssemblyPart Source="IronPython.dll" />
    <AssemblyPart Source="IronPython.Modules.dll" />
  </Deployment.Parts>
  ・・・
  <!-- ブラウザー外実行の設定 -->
  <Deployment.OutOfBrowserSettings>
      <OutOfBrowserSettings
            ShortName="DLR Application"
            EnableGPUAcceleration="False"
            ShowInstallMenuItem="True">
        <OutOfBrowserSettings.Blurb>
          DLR Application
        </OutOfBrowserSettings.Blurb>
        <OutOfBrowserSettings.Icons />
        <OutOfBrowserSettings.WindowSettings>
          <WindowSettings
              Title="DLR Application"
              Height="200" Width="300" />
        </OutOfBrowserSettings.WindowSettings>
        <OutOfBrowserSettings.SecuritySettings>
            <!-- COMオートメーション連携機能を使うための設定 -->
            <SecuritySettings ElevatedPermissions="Required" />
        </OutOfBrowserSettings.SecuritySettings>
      </OutOfBrowserSettings>
  </Deployment.OutOfBrowserSettings>
</Deployment>

IronRuby の場合は、基本的に上記の IronPython.dll・IronPython.Modules.dll が IronRuby.dll・IronRuby.Libraries.dll に変わるだけです。

AppManifest.xamlIronRuby の場合)
<Deployment ・・・>
  <!-- Add assembly references here -->
  <Deployment.Parts>
    ・・・
    <AssemblyPart Source="IronRuby.dll" />
    <AssemblyPart Source="IronRuby.Libraries.dll" />
  </Deployment.Parts>
  ・・・
</Deployment>

ビルド

ビルドは IronPythonIronRubySilverlight\bin\Chiron.exe を使って、xap ファイルを作成するだけです。

ビルド(IronPython, IronRuby 共通)
> Chiron.exe /d:app /z:wsh_sample.xap

動作確認

sllauncher.exe に /emulate オプションを指定すればインストールを行わずに動作確認が行えます。
なお、/origin で URI を指定する必要があるので適当に指定します。

sllauncher.exe は、C:\Program Files\Microsoft Silverlight(もしくは C:\Program Files (x86)\Microsoft Silverlight)にあると思います。

動作確認(IronPython, IronRuby 共通)
> sllauncher.exe /emulate:wsh_sample.xap /origin:file:///

IronPython の方は「Run Notepad」ボタンを押下するとメモ帳が起動しますが、
IronRuby の方は「Run Notepad」ボタンを押下した際にボタン表示等が消えてしまうと思います。

追記

以下のように Silverlight では無く通常の IronRuby スクリプトとしてメモ帳の起動を行ってみたところ正常に動作しました。

wsh_run.rb
include System

wsh = Activator.CreateInstance(Type.GetTypeFromProgID("WScript.Shell"))
wsh.Run("notepad.exe")
実行例
> ir wsh_run.rb