C++/CLIからIronPythonModを使う場合

  • 概要

    ここでは、C++/CLIからIronPythonModを利用する例を記載しています。

    一足飛びにScenarioModで利用すると、本質が見えにくくなるかもしれません。
    ここでは一旦汎用的なC++/CLIでの最小サンプルで雰囲気をつかんでみましょう。

    プロジェクトの作成

    適当にC++/CLI(CLR)のコンソールアプリケーションを作成してみましょう。
    .NET FrameWorkのバージョンは、ScenarioModと合わせて4.0としておきましょう。

    C#の時と同様に、IronPythonMod.dllを参照に加えてください。

    ScenarioModと類似の環境を想定するため、文字コードを「マルチバイト」の設定としましょう。

  • C++/CLI側

    C++/CLIのソース

    #include "stdafx.h"
    
    using namespace System;
    
    using namespace IronPython::Hosting;
    using namespace System::Collections;
    
    
    int main(cli::array<System::String ^> ^args)
    {
      auto pe = Python::CreateEngine();
    
      // その場で式を実行。
      int result32 = pe->Execute<int>("2 ** 5");
      Console::WriteLine(result32);
      Console::WriteLine();
    
    
      // ファイルを実行。
      auto scope = pe->ExecuteFile("script.py");
    
      // 変数 abc を intとして取得
      int val = scope->GetVariable<int>("abc");
    
      // 変数 name を String^として取得
      String^ str = scope->GetVariable<String^>("name");
    
      // 変数 ret_valを「ArrayList^」型として取得
      ArrayList^ arr1 = scope->GetVariable<ArrayList^>("ret_val");
      for each (int l in arr1) {
        Console::WriteLine(l);
      }
    
      // 関数を呼び出し
      pe->Execute("hello('world')", scope);
    
      // 関数を呼び出すが、返り値は、String^型とみなす
      String^ ret1 = pe->Execute<String^>("get_hello('world')", scope);
      Console::WriteLine(ret1);
    
      // 日本語名の関数を呼び出すが、返り値は、String^型とみなす
      String^ retstr = pe->Execute<String^>("ハロー('world')", scope);
      Console::WriteLine(retstr);
    
      // 関数を呼び出す。返り値はArrayList^型
      ArrayList^ arr2 = pe->Execute<ArrayList^>("get_ret_val()", scope);
      for each (int l in arr2) {
        Console::WriteLine(l);
      }
    
      // intを引数に取って、boolを返す関数
      auto funcIsOdd = pe->Operations->GetMember<Func<int, bool>^>(scope, "is_odd");
      bool b1 = funcIsOdd(3);
      Console::WriteLine(b1);
      bool b2 = funcIsOdd(4);
      Console::WriteLine(b2);
    
      return 0;
    }
    
  • Python側

    スクリプト側となるPython側のソースも用意します。
    Pythonは「空白やインデント」も文法に含まれますので、注意してください。

    C++/CLIの「マルチバイト」から呼ばれますので、「script.pyのソースコードの文字コードをShitJIS(=cp932)」で保存してください。
    (テキストエディタなどで実際に確認してください。間違っているとSyntax Errorが出ます)

    IronPythonのソース:script.py

    # coding: cp932
    
    
    from System.Collections import *
    
    abc = 3
    
    name = "武田信玄"
    
    def hello( x ) :
      print "hello, " + x
    
    def ハロー( x ) :
      print "ハロー, " + x
      return "ハロー" + x
    
    
    def get_hello( x ) :
      return "hello, " + x
    
    
    a = [10,20,30]
    ret_val = ArrayList(a)
    
    def get_ret_val() :
      return ret_val
    
    
    def is_odd(num):
      if num % 2 == 1:
        return True
      else:
        return False
    
    

    以上となります。

    IronPythonがそのままcp932を取り扱えることは、ScnearioModで利用する上では
    非常に大きなポイントとなります。

    C++/CLIには残念ながら、C#のdynamicに相当するものがありません。
    よって、C#ほどには、自然な記述でIronPythonを取り扱うことは出来ません。

    しかし、pe->Execute<返り値の型>("IronPythonのコード", scope);
    を取り扱うことで、文字列ベースで引数や関数などを操作し、
    返り値は、.NET FrameWorkの型を介することで、比較的便利に情報をやり取りすることができます。