ぷろじぇくと、みすじら。

ChakraCoreをビルドしてC#から使うはじめの一歩

Created at:

ついにChakraCoreが公開されたので、早速ビルドしてC#からとりあえずハローしてみます。

ChakraCore is 何

とその前にChakraCoreのおさらいです。

まずChakraCoreはInternet ExplorerやEdgeで使われているJavaScriptエンジン ChakraのWindows固有の機能を外したライブラリです。要するにV8とかJavaScriptCoreみたいなものです。

オープンソースになった後のロードマップが公開され、いろいろ書いてあります。

ChakraCoreのメリット

従来のChakraはWindowsまたはInternet Explorerと共にバージョンが管理されていました。
つまり現在、ChakraにはInternet Explorer 9, 10, 11(Windows Vista/7/2008/2008 R2)、Windows 8.1、10、10 Version 1511というバリエーションがあることになり、
それをアプリケーションに組み込んで利用したい場合にバージョンの差異が発生することになります。

そこでChakraCoreはWindowsやブラウザから分離したJavaScriptのエンジンとなったので、
アプリケーションに独立して組み込むことができるようになり、環境ごとのバージョンの差異に悩まされないで済むようになります。

そもそも従来のWindowsではWindows Scripting Hostを経由してエンジンを組み込むことができましたが、APIもCOMベースでJavaScriptのエンジンを使うということ以外を考慮していたりして使いづらく、エンジンも古いのでモダンなJavaScriptを動かすことができなかったという話もあります。

ChakraCoreをビルドする

2016年1月14日現在、WindowsサポートのみなのでGitHubのリポジトリをcloneし、BuildディレクトリにあるChakraCore.slnをVisual Studio 2015で開いてビルドすればよいです。

と、簡単そうな気がしたのですが日本語環境(CP932がデフォルト環境)ではソースコードがUnicodeじゃないよというWarning(C4819)が出て、WarningがErrorとして扱われてビルドが失敗します。幸い数は少ないのでBOM付きUTF-8で適当に保存しなおしましょう。

ビルドすると Build\VcBuild\bin\x64_debug などに ChakraCore.dll が生成されます。

ChakraCoreをC#から使う

ChakraCoreを無事ビルドできたらC#からChakraCoreを使ってみます。

ChakraCoreはJSRT API(JavaScript Runtime API)というAPIを持っているのでそれを利用してChakraCoreの機能を呼び出します。ちなみにJSRTはChakraCoreよりも以前からWindows 10以降(またはInternet Explorer 11以降)ではChakraを利用する手段として提供されています。

詳しくはMSDNのJavaScript ランタイムのホスト処理に書いてあります。

ただしJSRTは.NET Framework向けのAPIではないアンマネージドなAPIなため、P/Invokeでの呼び出しを行う必要があります。
幸いにもGitHubにChakra-Samples@Microsoftというリポジトリがあり、JSRTのC#のバインディングがすでに作られているのでこれを使います(自分で書こうとするとだいぶ大変です)。

というわけでChakra-Samplesをcloneやダウンロードしておきます。Chakra-SamplesにはHello WorldやHostingサンプルがあるのでまあそれでいいという話もあるのですが、最小限の構成を作ってみることにします。

準備

まず初めに適当にコンソールアプリケーションのプロジェクトを作ります。

プロジェクトを作ったら先ほどビルドしたChakraCore.dllをプロジェクトに追加し、プロパティでビルド時にコピーされるように設定します。

ちなみに普通にプロジェクトを作るとPrefer 32bitということで32bitプロセスとして起動されるのでx86版DLLをコピーしておきましょう。

次にChakra-SamplesからChakraCore Samples\JSRT Hosting Samples\C#\ChakraCoreHostにあるHostingフォルダをプロジェクトにコピーします。これがJSRTのバインディングです。

プロジェクト構成

ChakraCoreを実行してみる

というわけでまずはランタイム(=実行エンジン)を作り、実行用のコンテキストを作って実行に備えます。

// ランタイムを作る
JavaScriptRuntime runtime;
Native.JsCreateRuntime(JavaScriptRuntimeAttributes.None, null, out runtime);

// 実行コンテキストを作る
var context = runtime.CreateContext();

// 現在のスレッドの実行コンテキストをセットする
Native.JsSetCurrentContext(context);

次に実際にJavaScriptのコードを実行します。

// 実行するスクリプト
var script = @"
    class Greeter {
        hello() { return 'コンニチハ!'; }
    }

    new Greeter().hello();
";

// スクリプトのソースの位置を記録するためのコンテキスト
var currentSourceContext = JavaScriptSourceContext.FromIntPtr(IntPtr.Zero);
// スクリプトを実行する
JavaScriptValue result;
Native.JsRunScript(script, currentSourceContext++, "", out result);

JsRunScriptメソッドはランタイムもコンテキストも渡さず、現在のスレッドのコンテキストから良しなに実行するので少し不思議な感じがしますね。

正常に実行できれば戻り値がresult変数に格納されます。戻り値はJavaScriptの値となっているのでそこからさらにCLRオブジェクトへ変換します。ToStringメソッドがお手軽に変換してくれるので任せましょう。

// 戻り値をJavaScriptの値からCLRのStringに変換する
// ちなみにConvertToStringメソッドはJavaScriptのStringなので注意。
var resultString = result.ToString(); // Native.JsStringToPointer + Marshal.PtrToStringUni

// 出力
Console.WriteLine(resultString);

最後はお片付けです。

// 後片付け
Native.JsSetCurrentContext(JavaScriptContext.Invalid);
runtime.Dispose(); // IDisposableなのでusingでもいい

というわけでここまでのコードをまとめるとこんな感じ。

実行すると「コンニチハ!」という出力が出てくるかと思います。割とお手軽ですね。

なお実行してBadImageFormatExceptionAn attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)と言われたらそれはx86/x64のDLLを間違えている可能性があります。

まとめ

もちろんエラーハンドリングや.NETからJavaScript側へオブジェクトの公開などもありますがとりあえず今回はここまでです。

意外と簡単に動かせるようになっているのでアプリケーションに組み込み用途にはいいかなと思うものの、ホストとChakraCoreとのやり取りが増えると割と高度なことを必要とするのでちょっと難易度高いかもという感じもします。

Visual Studio CodeのシンタックスハイライトをWebページで使う

Created at:

Visual Studio Codeのエディタ部分はVisual Studio Codeがリリースされるよりも前からいろいろなところで使われていて、
最初はVisual Studio Online “Monaco”のエディタ部分として公開されていました。

それから徐々にMicrosoftの中での利用範囲が広がりTypeScriptのPlaygroundやWinJSのPlayground、
ちょっと変わったところではInternet Explorer/EdgeのF12開発者ツールの中でも使われていたりします。

そして月日は流れて、Visual Studio Codeがオープンソースになってついにエディタ部分(Monaco Editor)が公開されました。

ということでそれを使う方法を調べていたのですが、たまたまシンタックスハイライトの機能が備わっているのを発見したので単体でも使えるようにするライブラリを作りました。

mayuki/Mimosa - GitHub

使い方

GitHubのReleasesに一式を固めたものがあるのでそれをとってきて適当に展開します。

<script src="/shared/js/mimosa/vs/loader.js"></script>
<script src="/shared/js/mimosa/mimosa.min.js"></script>
<script>
    require.config({
        baseUrl: '/shared/js/mimosa/', // MimosaとMonacoの入っているディレクトリへのパス
    });

    // 自動で pre.vs[data-lang] な要素を探してシンタックスハイライトを適用する
    Mimosa.initialize();
</script>

こんな感じでMimosaを読み込ませるものをページに書いておきます。
loaderはVSCode Loaderなのですが、これがほかのrequire機構と被ると何が起きるのかは謎です。

そして以下のように対象となるソースコードを pre 要素にして vs クラス (とスタイルのために monaco-editor)をつけておきます。
あと data-lang 属性に言語名を指定する必要があるのでそれも指定します。
対応している言語名はcss, html, javascript,…csharp, bat, powershell, …といった感じです。

<pre data-lang="csharp" class="monaco-editor vs">
class A
{
    public async Task<int> Hoge()
    {
        await Task.Delay(1000);
        return 10;
    }
}</pre>

そうすると以下のような感じでシンタックスハイライトが適用されます。

class A
{
    public async Task<int> Hoge()
    {
        await Task.Delay(1000);
        return 10;
    }
}

ちなみに vs-dark クラスをつけておくと黒背景になじむカラーリングになります。

class A
{
    public async Task<int> Hoge()
    {
        await Task.Delay(1000);
        return 10;
    }
}

備考

まとめ

どうぞご利用ください。

次回はMonaco Editorを使う方法について書く予定があるとかないとか(ビルド方法とかはそっちで…)。