Windows Phone 8では、Win32 APIを利用してシフトJISのバイト列データをUnicode文字列に変換できるようになった。本TIPSでは、その実装方法を説明する。
powered by Insider.NET
前回、Windows Phone 8(以降、WP 8)では「GetEncoding("Shift-JIS")」というコードが動かず、シフトJISのデータを読み取れないと書いた。WP 7.xまでは実際にどうしようもなく、シフトJISでエンコードされたデータを読み取るには自前で変換テーブルを実装するしかなかった。だが、WP 8からはWin32 APIを利用してシフトJISのデータをUnicodeに変換することが可能になっている。本稿では、WP 8でWin32 APIを使う方法と、シフトJISをUnicodeに変換するコードを紹介する。本稿のサンプルは「Windows Store app samples:MetroTips #20」からダウンロードできる。
●事前準備
WP 8向けのアプリを開発するには、SLAT対応CPUを搭載したPC上の64bit版Win 8 Pro以上とWindows Phone SDK 8.0(無償)が必要となる。
●Win32 APIを使うには?
C++/CXで「Windows Phoneランタイム・コンポーネント」(以降、WinPRTコンポーネント)をARM CPU用に作成する(エミュレータで使うにはx86 CPU用にする)。
WP 8で利用できるWin32 APIは、MSDNの「MSDN: Windows Phone 8 でサポートされる Win32 API」に掲載されている。ただし、WP 8ではC#/VB(Visual Basic)のDllImport属性がサポートされておらず、C++/CXを使ってWinPRTコンポーネントを作らねばならない。
C++/CXとは「Visual C++ component extensions」(Visual C++ コンポーネント拡張)の略称であり、かつて「Metro」と呼ばれていたWindowsストア・アプリ/Windows Phoneアプリのための一連の拡張をC++言語に施したものだ。
WinPRTコンポーネントとは、Windows 8/RT用のWindowsストア・アプリのWindowsランタイム(WinRT)コンポーネントと大部分が同様のもの(=サブセット)だと思ってよいだろう。ただし、WinPRTコンポーネントはC#/VBでは作成できず、C++/CXのみがサポートされている。
また、WinPRTコンポーネントがサポートされているプラットフォームは「Win32」(=x86 CPU向け)と「ARM」(=ARM CPU向け)の2種類だけで、「Any CPU」はない。従って、WP 8エミュレータでテストするときは「Win32」でビルドし、実機にリリースするときは「ARM」でと作り分ける必要がある。
Windows Phone SDK 8.0に含まれているVisual Studio 2012(以降、VS 2012)でWinPRTコンポーネントを作るには、[新しいプロジェクト]ダイアログで「Visual C++」カテゴリを選び、次いで「Windows Phoneランタイム コンポーネント」テンプレートを選ぶ(次の画像)。
●C++/CXでコーディングするには?
この話題を本稿で詳しく解説している余裕はないので、MSDNの「Visual C++ の言語リファレンス (C++/CX)」を参照してほしい*1。
*1 このドキュメントはWindows 8/RTのWindowsストア・アプリ用に書かれているので、細部では異なる可能性がある。
Visual C++とC#での開発経験があるならば、「^」(ハット)と「ref new」を理解すればサンプル・コードなどが読めるようになるだろう。「^」はC++のauto_ptrに似ていて、「自動的に参照がカウントされるWindowsランタイム・オブジェクトへのポインタ」だ。また、「ref new」はWindowsランタイム・オブジェクトのインスタンスを作るが、ポインタではなくハットを返す。「ref new」して「^」で受けたオブジェクトはGC(ガベージ・コレクタ)が管理してくれるので、明示的にメモリを解放する必要がない。
●シフトJISをUnicodeに変換するには?
Win32 APIのMultiByteToWideChar関数を使う。先ほど作成したWinPRTコンポーネントのプロジェクトに、次のようなコードを記述する。
// WPRuntimeComponentSample.h
#pragma once
#include <ppltasks.h> // 型定義やWin32 APIの定義などを含む
#define CP_SJIS 932
namespace WPRuntimeComponentSample
{
public ref class Win32ApiSample sealed // WinPRTが公開できるのはsealedのみ
{
public:
static Platform::String^ MultiByteToWideChar(const Platform::Array<byte>^ buff);
};
}
// WPRuntimeComponentSample.cpp
#include "pch.h"
#include "WPRuntimeComponentSample.h"
using namespace WPRuntimeComponentSample;
using namespace Platform;
Platform::String^ Win32ApiSample::MultiByteToWideChar(const Platform::Array<byte>^ buff)
{
LPCSTR pBuff = (LPCSTR)(buff->Data);
if(pBuff == NULL)
return ref new Platform::String(); // 空文字を返す
const int nSize = ::MultiByteToWideChar(CP_SJIS, 0, pBuff, -1, NULL, 0);
BYTE* buffUtf16 = new BYTE[nSize * 2 + 2];
::MultiByteToWideChar(CP_SJIS, 0, pBuff, -1, (LPWSTR)buffUtf16, nSize);
Platform::String^ result = ref new Platform::String((LPWSTR)buffUtf16);
delete[] buffUtf16; // *で受けたオブジェクトは従来どおり自前で解放する
return result;
}
●C#/VBから呼び出すには?
普通の手順で利用できる。プロジェクトを参照し、名前空間名・クラス名・メソッド名を使って呼び出す。ただし、プラットフォームには要注意だ。
WP 8アプリのプロジェクトを作り、上記のWinPRTコンポーネントのプロジェクトへの参照を追加し、次のようなコードを試してみよう。
public MainPage()
{
……略……
// サンプル・データ
byte[] buff = new byte[] {
0x8E, 0x8E, 0x8C, 0xB1, 0x82, 0xC5, 0x82, 0xB7,
// “試験です”というシフトJIS文字列のバイト列データ(変換対象)
};
// Unicode形式データとしてUnicode文字列に変換
textBlock1.Text = Encoding.Unicode.GetString(buff, 0, 8);
// シフトJIS形式データとしてUnicode文字列に変換(WinPRTコンポーネント)
textBlock2.Text =
WPRuntimeComponentSample.Win32ApiSample.MultiByteToWideChar(buff);
}
Public Sub New()
……略……
' サンプル・データ
Dim buff() As Byte = { _
&H8E, &H8E, &H8C, &HB1, &H82, &HC5, &H82, &HB7 _
} ' “試験です”というシフトJIS文字列のバイト列データ(変換対象)
' Unicode形式データをUnicode文字列に変換
textBlock1.Text = Encoding.Unicode.GetString(buff, 0, 8)
' シフトJIS形式データをUnicode文字列に変換(WinPRTコンポーネント)
textBlock2.Text = _
WPRuntimeComponentSample.Win32ApiSample.MultiByteToWideChar(buff)
End Sub
バイト列データをUnicode形式として取り扱って文字列(※.NETでは文字はUnicode文字として処理されるため、厳密にはUnicode文字列)に変換した方は文字化けし、シフトJIS形式として変換した方は正しく表示されるはずだ。
なお、WinPRTコンポーネントのプロジェクトへの参照を追加すると、[構成マネージャー]ダイアログ(=メニューバーの[ビルド]−[構成マネージャー]で表示される)は次の画像のようになっているはずだ。
WinPRTコンポーネントのプラットフォームは、デフォルトの「Win32」になっている。それを参照するWP 8アプリの[プラットフォーム]は「x86」でなければならないので、自動的に「Any CPU」から「x86」に変更されているのだ。エミュレータで実行する場合は、この設定のままでよい。
実機にインストールするパッケージを作る場合には、次の画像のように[プラットフォーム]を「ARM」にする。
●実行結果
次の画像に示すように、シフトJIS形式のバイト列データを文字化けせずに表示できた。
なお、ほぼ同じC++/CXのコードを使ったWP 8アプリを筆者はWindows Phoneストアで公開している。もちろんストアの審査も問題なく通っている。また、知人の協力により実機HTC 8X(国内未発売)で実際に動作することも確認できた。
●まとめ
C++/CXでWinPRTコンポーネントを作れば、Win32 APIが利用できる。Win32 APIのMultiByteToWideChar関数を使って、シフトJIS文字列のバイト列データを文字列(※.NETでは文字はUnicode文字として処理されるため、厳密にはUnicode文字列)に変換できる。
WinPRTコンポーネントの資料はまだ少ないのが現状だが、次のドキュメントを参考にしてほしい。
※ 以下のドキュメントはWindows 8/RT用なので、細部では異なる可能性がある。
Copyright© Digital Advantage Corp. All Rights Reserved.