読者です 読者をやめる 読者になる 読者になる

ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

Windows ストアアプリの JS で文字列をエンコードするために Windows Runtime コンポーネントを作成する

Visual Studio Windows ストアアプリ Windows Runtime C# Windows

前置き: JS での Windows ストアアプリ開発時に C# の機能を使いたい

Windows ストアアプリを JS + HTML で開発する場合、たまに JS の非力さに困ることがあります。 例えば、文字列を UTF-8エンコードしてバイト列を得たいという場合。 JS だけでエンコードするのは難しいですよね。 JS での文字列のエンコードの現状としては、WHATWG の Encoding StandardTextEncoder インターフェイスが定義されていて、FirefoxChromeOpera では使えるようになっているようです。 しかし、残念ながら Windows ストアアプリでは使えません (Windows 8.1 時点)。

Windows ストアアプリで使える一つの方法として、エンコード処理を全て JS で記述するという方法があります。 JS の文字列を UTF-8エンコードして得られたバイト列を Uint8Array オブジェクトとして得る関数 (strToUTF8Arr 関数) のサンプルコードが MDN にあります。

このような関数を用意してもよいのですが、Windows ストアアプリ開発をする場合は C# の力を借りるということが簡単にできるので C# の力を借りるのが良いでしょう。 (C# だけでなく Visual BasicC++ も使用できますが、他の言語を選択する理由が特にないのであれば C# を使うのが楽だと思います。)

Windows Runtime コンポーネント (WinRT コンポーネント)

Windows ストアアプリの JS からは Windows Runtime API を触ることはできますが、ネイティブの C++ のライブラリを直接使用したり、.NET Framework のクラスライブラリを直接使用したりすることはできません。 JS から C++ .NET Framework の機能を使用するためには Windows Runtime を使ってコンポーネントを作成する必要があります。 Windows Runtime コンポーネントは、C#C++Visual Basic のいずれかの言語で作成できます。 作成された Windows Runtime コンポーネントは、JS からも使用できますし、当然他の言語 (C#C++Visual Basic) からも使用できます。

Windows Runtime コンポーネントの概要は次の記事が参考になります。

公式のドキュメントとしては次を見ると良いと思います。

MS によるブログエントリも参考になります。

実際の作り方

C#Windows Runtime コンポーネントを記述するには、次のチュートリアルを見るのが良いでしょう。

Visual Studio Professional (または Community) 2013 を使っていれば、上のチュートリアル通りに進めることで Windows Runtime コンポーネントを作成し、JS から使用するということができるはずです。

配列の扱いなどの注意すべき点は次の文書を読むと良いでしょう。 (日本語だとタイトルが 「C++ および〜」 となっていますが、正しくは 「C# および〜」 です。)

サンプル

例として、文字列を UTF-8 エンコーディングエンコードしたり、逆にデコードしたりするための Windows Runtime コンポーネントを作成して、JS から使用してみます。

まず、新たに C# 用の Windows Runtime Componenet プロジェクトテンプレートを使って、新しいプロジェクトを作成します。 今回は 「WindowsRuntimeComponentSample」 というプロジェクト名にしました。 そして、次のようなクラス (WindowsRuntimeComponentSample.Utf8Encoding クラス) を作成しました。

using System;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;

namespace WindowsRuntimeComponentSample
{
    public sealed class Utf8Encoding
    {
        public static byte[] encode(String str)
        {
            return Encoding.UTF8.GetBytes(str);
        }

        public static String decode([ReadOnlyArrayAttribute] byte[] bytes)
        {
            return decode(bytes, 0, bytes.Length);
        }

        public static String decode([ReadOnlyArrayAttribute] byte[] bytes, int index, int count)
        {
            return Encoding.UTF8.GetString(bytes, index, count);
        }
    }
}

そしてこのプロジェクトを JS のプロジェクト (プロジェクト名 「App1」) から参照するように設定します。 ソリューションの構成は次のようになりました。

f:id:nobuoka:20150329213852p:plain

これで JS から WindowsRuntimeComponentSample.Utf8Encoding クラスが使用できます。

// 文字列を UTF-8 でエンコードする。 (返り値は Uint8Array オブジェクト。)
WindowsRuntimeComponentSample.Utf8Encoding.encode("あ");
// バイト列 (Uint8Array オブジェクト) を UTF-8 でデコードする。
WindowsRuntimeComponentSample.Utf8Encoding.decode(new Uint8Array([0xE3, 0x81, 0x82]));

JS での string 型は C# では System.String 型になります。 また、C# での byte[] 型は JS では Uint8Array オブジェクトとして扱われます。

TypeScript で扱う際に型情報を自前で用意する必要があるのがちょっと面倒だなーと思いました。 *1

おわりに

UTF-8 での文字列エンコーディングを例にしましたが、文字列のエンコード・デコード処理以外でも JS では書きにくい処理を C# などで実装して JS から呼び出すということがさほど難しくなく実現できます。

Windows アプリ開発時にどの言語 (JS、C#C++Visual Basic) を選択するか考える際に 「基本的に JS で大丈夫だけど、JS で書きにくい処理を書く必要が出てきたらどうしよう」 と悩むこともあるかもしれません。 このエントリで見たように、そのような処理は C# などで Windows Runtime コンポーネントとして書いて、JS から呼び出す、ということが可能です。 言語選択の参考にしてください。

*1:もしかしたら自動で生成される機能があったりするかもしれないけど知らないです。