Windows Mobile ベースの移植可能なアプリケーションの構築

 

Paul Yao
The Paul Yao Company

July 2005

適用対象:
   Windows Mobile ベースのデバイス
   Visual Studio 2005
   eMbedded Visual C++
   Windows Mobile 5.0

要約: この記事では、Windows Mobile ベースのアプリケーションにバイナリ レベルの移植性を取り入れるための主要な概念と実践方法の概要について説明します。

目次

はじめに
Visual Studio 2005
コードの再利用
Windows Mobile での Uber 統合
プラットフォーム固有の UI オブジェクト
まとめ

はじめに

Microsoft の Windows Mobile 開発ツールでは、開発者がある特定のプラットフォームをターゲットにすると仮定しています(たとえば、Pocket PC と Smartphone のどちらかをターゲットにし、両方をターゲットにするのではない)。複数のプラットフォームをターゲットにする開発者にとって、1 つの解決策は、プラットフォームごとに別の実行可能ファイル セットをリリースすることです。しかし、もう少し努力するだけで、単独で複数のプラットフォームをサポートする実行可能ファイル セットを構築できます。この記事では、複数の Windows Mobile ベースのプラットフォームをターゲットにする単一の実行可能ファイル(またはそのセット)を構築する手順について説明します。

Microsoft の開発ツールは、1 つのプラットフォームをターゲットにするように適合されていることが多いですが、Microsoft は会社としてはより統合された方法を優先する傾向があります。言い換えれば、Microsoftの製品は、冗長性を最小限に抑える方法を提案しています。この方法は「Uber 統合」と呼ばれることもあります。

Visual Studio 2005

Microsoft の Uber 統合戦略は、Microsoft Visual Studio の古くからの伝統の一部です。Visual Studio は、最初のバージョンが設計されたとき、複数のプログラミング言語と複数のターゲット プラットフォームをサポートするように強化される予定でした。Visual Studio は、どこででも動作する単一のツールの基盤として構築されました。

この目標は、Microsoft Visual Studio .NET 2003 がリリースされたとき、モバイル デバイス開発者にとって半分だけ達成されました。Visual Studio .NET 2003 は、デバイス向けのマネージ コード開発をサポート(Microsoft .NET Compact Framework 1.0)しますが、ネイティブ コード開発はサポートしないバージョンでした。別のツールである Microsoft eMbedded Visual C++ がネイティブ コード開発をサポートしました。Microsoft Visual Studio 2005 によって、目標が完全に達成されました。Visual Studio 2005 は、Windows Mobile ベースのプラットフォーム向けのあらゆるアプリケーション プログラミング インターフェイス(API)とあらゆるアプリケーションの種類をサポートします。

  • ネイティブ アプリケーションの開発(*)
    • Microsoft Win32 API
    • Microsoft Foundation Class(MFC)8.0 ライブラリ
    • Microsoft ActiveX Template Library(ATL)8.0
  • マネージ アプリケーションの開発
    • .NET Compact Framework 1.0
    • .NET Compact Framework 2.0
    • ASP.NET モバイル コントロール

* ネイティブ アプリケーションの開発では、別の選択肢として、Microsoft Windows Template Library(WTL)を使用することもできます。Microsoft はサポートしていませんが、ネイティブ開発 API として広く支持されています。

eMbedded Visual C++ を使用してきた開発者にとって、Visual Studio 2005 への移行は簡単です。Visual Studio 2005 は、eMbedded Visual C++ と同一ではありませんが、大変似ているので、成果が上がるまでにさほど時間はかかりません。Visual Studio 2005 は、eMbedded Visual C++ が備えている機能のスーパーセットをサポートします。これは特に重要なことです。

Visual Studio 2005 は、大変成熟した完全な IDE(統合開発環境)です。経験のある eMbedded Visual C++ 開発者は、テキスト エディタ、状況依存のヘルプ、高機能なソース レベルのデバッガ、ビルド ツール、およびデバイス エミュレーションのサポートなど、あらゆる IDE ツールを使用して成果を上げるまでにほとんど時間を必要としません。Visual Studio 2005 は、統一的な開発環境を提供します。これは、モバイル デバイス向けのコードを作成するすべての C および C++ プログラマに役立ちます。

C++ クラス ライブラリ サポート: MFC、ATL、および WTL

C++ プログラマにとって、Microsoft が提供する Visual Studio 2005 の C++ クラス ライブラリは、これまでにない最も多機能なセットになります。これまで、モバイル デバイス ソフトウェアの開発者は、古いバージョンの MFC と ATL で作業する必要がありました。たとえば、Windows Mobile ベースのデバイスの ROM に搭載された MFC のバージョンは、すべて MFC 3.0 でした。したがって、eMbedded Visual C++ に付属する MFC も、このバージョンでした。しかし、MFC 3.0 は、デスクトップ コンピュータ向けにリリースされているMFCと比べると数年古いバージョンです。MFC のデスクトップ コンピュータ用バージョンとデバイス用バージョン間の違いが大きくなるにつれて、MFC アプリケーションのコードを、デスクトップ コンピュータとデバイスの間で移植することが難しくなってきています。

Microsoft のテクノロジの初心者のかたへ

MFC は、デスクトップ コンピュータ アプリケーションをビルドするために C++ クラス ライブラリとして開発されました。インターネットと Web ブラウザの発展に従って、Microsoft は、ブラウザ内部で実行できる軽量なコントロールの作成を可能にする ATL を作成しました。たとえば、MFC の ActiveX コントロールは、200 KB 以上になることもありますが、ATL ベースの同等のコントロールは 50 KB です。

Visual Studio 2005 には、MFC 8.0 と ATL 8.0 が付属します。これらのライブラリは共に長年強化され、MFC は一部の ATL テンプレートを使用するようになりました。これらのライブラリのデスクトップ コンピュータ用のバージョンが、デスクトップ コンピュータ開発とデバイス開発の両方をサポートするように変更されました。つまり、少ない移植作業で広範囲の統合が可能になりました。この 2 つのライブラリは、ニーズに応じて、一緒に使用したり、個別に使用したりできます。

Smartphone アプリケーションの開発者にとって嬉しいことに、MFC が Smartphone の開発をサポートするようになりました。実際のところ、これは、Smartphone をサポートする MFC の最初のバージョンです。各プラットフォームには独自の特性があるので、MFC コードをデスクトップ コンピュータや Pocket PC から Smartphone に移植するには、まだ特定の作業を行う必要があります。ただし、この移植に必要な作業は、MFC が Smartphone アプリケーションの開発をサポートしていなかったときより大幅に削減されました。

Microsoft は WTL を 2000 年に、ほとんど前宣伝なしでリリースしました。WTL は、ATL を作成した同じグループによって構築されました。つまり、これは ATL の拡張機能でした。本格的なデスクトップ コンピュータ アプリケーションの作成に必要ないくつかのウィンドウ化機能とその他の機能が追加されました。Microsoft は WTL にまだ公式のサポートをしておりませんが、WTL は支持を得てきています。2004 年 5 月、Microsoft は、WTL をオープン ソース プロジェクトとして sourceforge Web site にリリースしました。このリリースには、スマート デバイス向けの Visual Studio 2005 のサポートが含まれています。WTL をダウンロードしてインストールすると、Visual Studio 2005 のプラットフォーム作成ウィザードを使用して、Pocket PC 用、および Smartphone 用の両方の WTL ベースのプロジェクトを作成できます。

プラットフォーム固有のコード

どのようなソフトウェアを開発する場合でも、単一のコード ベースで作業することは重要です。ただし、固有の要件に適合させるには、特殊なコードで対応する必要があります。要件は、オペレーティング システムのバージョンやデバイス ドライバによって、また Windows Mobile の場合は Pocket PC か Smartphone かによって異なります。

使用できる標準のプリプロセッサ シンボルを表 1 に示します。シンボルは、Microsoft Windows CE のさまざまなインクルード ファイルで定義されています。シンボルを使用すると、ソフトウェアのビルド時に、コード ブロックを使用または除外したり、使用または除外を切り替える 2 つ以上の代替コード ブロックを記述できます。

表 1 標準のプリプロセッサ シンボル

シンボル 説明
_WIN32_WCE Windows CE のバージョン
  • Windows Mobile 2003 の Pocket PC 向けソフトウェア: 420
  • Windows Mobile 5.0: 501
WIN32_PLATFORM_PSPC Pocket PC(バージョン不問)向けにビルドします。
SMARTPHONE2003_UI_MODEL Smartphone 用ユーザー インターフェイス(UI)。Visual Studio は、ウィザードが生成するソースコードの移植をサポートするために、このシンボルを作成します。
POCKETPC2003_UI_MODEL Pocket PC 用 UI。Visual Studio は、ウィザードが生成するソースコードの移植をサポートするために、このシンボルを作成します。
WIN32_PLATFORM_WFSP Smartphone(バージョン不問)向けにビルドします。
_DEVICE_RESOLUTION_AWARE 画面のサイズまたは画面の向きの動的な変更に適応できる、Windows Mobile 2003 Second Edition ソフトウェア以降向けに作成されたアプリケーション
UNDER_NT Windows オペレーティング システムのデスクトップ コンピュータ向けバージョンとサーバー向けバージョンをターゲットにします。
UNDER_CE Windows CE をターゲットにします。
_WIN32 Win32 API をターゲットにします。
__cplusplus 現在のプログラムは、C++ コンパイラ構文に基づいてコンパイルされます。
_DEBUG デバッグ ビルドが有効になります。
SHELL_AYGSHELL AYGSHELL.DLL を組み込む Windows Mobile ベースのデバイスまたはすべての Windows CE 埋め込みデバイス。
UNICODE / _UNICODE 16 ビット Unicode 文字セットを使用します。

Visual Studio 2005 では、これらのプリプロセッサ シンボルの実際の値は、eMbedded Visual C++ より詳細な情報を提供します。どのシンボルを参照すべきかは知っておく必要があります。

プリプロセッサ シンボルのリストを検索する

  1. **[プロジェクト]メニューの[プロパティ]**をクリックします。

  2. プロパティ ページの左側で、[構成プロパティ][C/C++]、および**[プリプロセッサ]**を展開します。

  3. プロパティ ページの右側の中から、**[プリプロセッサの定義]をクリックします。[...]**ボタンが表示されます。

  4. **[...]ボタンをクリックして、[プリプロセッサの定義]**ダイアログ ボックスを開きます。

  5. **[マクロ]**をクリックします。次の図に示すように、ダイアログ ボックスに、すべてのプリプロセッサ シンボルの詳細を含むウィンドウ ペインが表示されます。

    クリックすると大きな画像を表示します

    プラットフォーム固有のリソース

Visual Studio 2005 が Windows Mobile ベースのアプリケーションの開発を容易にする方法の 1 つは、プラットフォーム固有のリソースを作成することです。スマート デバイス アプリケーション ウィザードで、Pocket PC 向けに 1 つのリソース セットを作成し、Smartphone 向けにもう 1 つのリソース セットを作成できます。特定のプラットフォーム向けにビルドすると、関連するリソース ファイルだけがインクルードされます。

Microsoft のテクノロジの初心者のかたへ

リソースとは、リソース ファイル(*.rc と *.rc2)に定義されている読み取り専用データのコレクションです。たとえば、メニューとダイアログ ボックスの定義がリソースとして格納されています。アプリケーションがビルドされると、リソースは、実行可能ファイルの特別な読み取り専用セクションに配置されます。リソースは変更されないので、メモリ マネージャは、必要な場合にリソースを読み取り、必要がなくなると破棄できます。これとは対照的に、読み書き可能なデータは、簡単に破棄できません。

リソースは、メモリ管理だけでなく、ソフトウェアのローカライズも容易にします。リソース ファイルには、UI オブジェクトのほかに、文字列テーブルが含まれていることがよくあります。アプリケーションの文字列をその他の種類のデータから分離することで、リソース ファイルにより、アプリケーションのすべての部分をローカライズするための作業が簡略化されます。

Pocket PC をターゲットにするファイルには、「ppc」というサフィックスが付きます。Smartphone をターゲットにするファイルには、「sp」というサフィックスが付きます。たとえば、test という名前のプロジェクトをビルドすると、プロジェクトには次の Pocket PC 固有のファイルが含まれます。

  • Testppc.rc
  • Testppc.rc2
  • Resourceppc.h

Smartphone ファイルもプロジェクトに含まれる場合、Visual Studio 2005 は次のファイルを追加します。

  • Testsp.rc
  • Testsp.rc2
  • Resourcesp.h

コードの再利用

生産性を向上させる最善の方法は、既存のコードを再利用することです。既存のコードに有用性があり、すでに設計、開発、およびテストが十分に行われていることが前提です。

ベストな状況のときには、既存のコードが生産性を大幅に向上させます。以前の成果物をもう一度使用できる場合です。これには、コードを作成する際に移植できるようにしておく必要があります。コードは、自動的にまたは偶然に移植可能になることはありません(マーフィーの法則に矛盾しますが)。移植は、次の手順で計画的に実行して組み込む必要があるものです。

再利用と、移植できないコード

コードの移植性を向上させるには「移植できないコード」に対処する必要があります。ほとんどすべての、アプリケーション、デバイス ドライバ、オペレーティング システムに、移植できないコードが含まれています。前述したように、最も簡単な方法は、移植可能にすべきコードを移植できないコード(プラットフォーム固有のコード)から明確に分離することです。

プラットフォーム固有のコードの 1 つの例は、特定の CPU 向けのコードで、もう 1 つの例は、プログラムの UI をサポートするコードです。次のセクションでは、この 2 種類のプラットフォーム固有のコードの例を紹介します。

プラットフォーム固有のコード: CPU のサポート

CPU の起動シーケンスは、CPU(または CPU ファミリ)固有の命令シーケンスの典型的な例です。CPU ファミリの異なる 2 つの CPU に同じ起動シーケンスを要求することは、有効ではありません。たとえば、AMD(Advanced Micro Devices, Inc.)の Athlon プロセッサと MIPS R5000 プロセッサはまったく異なるので、当然、(命令セットが完全に異なることに加えて)起動命令が異なります。

CPU の起動に必要な起動命令は、毎日起床してから食べる朝食に似ています。世界のある地域では、魚と米が朝食の標準であり、別の地域では、パンとコーヒーが普通です。文化が異なると、朝食の標準が異なるように、異なるプロセッサ ファミリの CPU では、起動命令が異なります。CPU の起動シーケンスは、その CPU のアーキテクチャの要件を満たすように設定されます。もちろん、そのような下位レベルの開発作業を行う開発者はわずかです(そのような開発者は、通常、朝食を食べるより、ソフトウェアを作成することに夢中でしょうが)。ハードウェア(CPU、ネットワーク、またはディスプレイ アダプタなど)に関係するコードは、まさにプラットフォーム固有です。

プラットフォーム固有のコード: ユーザーとの対話処理

プラットフォーム固有のコードがよく使用される領域の 1 つは、プログラムの UI です。たとえば、Web ベースのインターフェイスとローカル クライアントの違いを見れば、明らかです。ブラウザは、使用されている Web サーバーに関係なく、HTML と変換済みスクリプトを取得します。対照的に、ローカル クライアントは、Win32、MFC、または .NET のような API を使用します。

ローカル クライアントに話を絞れば、プラットフォーム固有のハードウェアには、そのプラットフォーム固有の機能を利用するために、プラットフォーム固有のコードが必要です。たとえば、Tablet PC では、ディスプレイ画面に高解像度のデジタイザが搭載されています。デジタイザを最大限に利用するには、UI の部分をプラットフォーム固有にする必要があります。(Tablet PC は、Microsoft Windows XP のスーパーセットを実行します。多くの企業が、Pocket PC や Smartphone と共に Tablet PC の市場投入を開始しているので、取り上げました。)

ほとんど同一のプログラミング インターフェイスをサポートする Pocket PC と Smartphone の間にも、ハードウェア固有の違いが存在します。一方のデバイスはタッチ スクリーンを搭載していますが、他方は搭載していません。Pocket PC の画面は大きいですが(320x240 または 640x480)、Smartphone の画面は通常、小型です(176x220)。Pocket PC には入力ボタンが少ししかありませんが、Smartphone には電話特有のボタンがあります。このような違いから、プラットフォーム固有の UI コードが必要になります。

実際は、この違いにもかかわらず、API の共通サブセットにより、コードの共有とプラットフォーム間の移植は大変簡単です。Pocket PC と Smartphone 間、または Smartphone と Tablet PC 間でのコード共有を最大限に利用するには、固有の機能を特定し、共通の共有コードとは別のコード内でその機能をサポートする必要があります。

目標がコードの再利用である場合、移植性は重要な要件です。ただし、すべてのコードを再利用する必要はありません。移植可能なコードを作成するために、ソフトウェア開発者は、移植可能にすべきコードと移植できないコードの間の境界線をはっきりさせる必要があります。コードを再利用するには、ソフトウェア設計時に、この境界線をすべてのチーム メンバが理解できるように明確に定義する必要があります。

**ヒント   **移植可能なコードには、移植可能なコードとプラットフォーム固有のコードの間の明確な境界線が必要です。

コードの移植の検証

ただし、どのような移植性が必要かということをただ定義しただけでは、作業はうまくいきません。それは、良いスタートであり、必要な条件ですが、十分ではありません。開発者は、移植性の目標が満たされたかどうかをチェックする必要があります。つまり、移植性を検証する方法が必要です。検証が簡単なほど、移植性を達成する可能性が高くなります。この概念をより理解するために、移植性の実現に役立つ検証方法の例を次に示します。

最近、Microsoft Windows XP Professional x64 Edition がリリースされました。64 ビット ハードウェアの準備に数年かかりましたが、オペレーティング システムの 64 ビットへの移植は簡単でした。その理由は主に、最初の 32 ビット バージョンの Windows である Microsoft Windows NT 3.1 で導入された実践方法があったからです。

今日、Windows オペレーティング システムが実行するすべてのデスクトップ コンピュータおよびサーバー システムは、x86 アーキテクチャで動作します。以前は、常にそうだったわけではありません。32 ビット バージョンの Windows は、移植を考慮して設計されました。Windows NT は、次のプロセッサ アーキテクチャ上で実行できました。

  • Intel IA-32 x86
  • Digital Equipment Corporation(DEC)Alpha
  • MIPS R4000
  • PowerPC
  • Intergraph Clipper(一般にはリリースされていません)
  • SPARC(一般にはリリースされていません)

移植可能なオペレーティング システムをビルドできたのは、プラットフォーム固有の要素を HAL(ハードウェア アブストラクション レイヤ)に分離したからです。

Intel と MIPS の 2 つのプロセッサの並行開発作業を含む開発プロセスによって、移植性の実現が支援されました。両方のアーキテクチャを同時にビルドしてテストすることで、移植性の問題にできるだけ早く対応しました。早い時期の変更により、コード ベース全般の移植性が強化されました。したがって、それ以降の CPU への移植は大変簡単でした。オペレーティング システムは、大規模で一般的ではないプロジェクトですが、そこから重要な教訓を得ることができます。

**ヒント   **移植性を向上させるには、ターゲット プラットフォームを早期に、何度もテストします。

複数のプラットフォームをターゲットにする場合は、各プラットフォームについて早期に、何度もテストします。移植できないコードに対応して、早期に変更できます。

Windows Mobile 開発では、コードを Pocket PC と Smartphone の両方で実行するために、同時に両方のデバイス向けに開発し、両方のデバイスを定期的にテストする必要があります。エミュレータは便利ですが、開発作業をエミュレータ上だけに限定しないでください。ユーザーが実際のデバイスを使用することを考えて、実際のデバイス上でテストする必要があります。

さまざまなバージョンのプラットフォーム上でコードをテストしてください。Smartphone アプリケーションの場合は、Smartphone 用の Windows Mobile 2003 ソフトウェアを実行する Smartphone と、Windows Mobile 5.0 を実行する Smartphone の 2 種類でアプリケーションをテストしてください(2 種類の Smartphone がユーザーが使用する対象の場合)。この 2 つのプラットフォームには幅広い互換性がありますが、プラットフォームによって動作方法が異なる機能を使用しないでください。

目標は、移植できないコードを駆逐することではなく、移植できないコードを移植可能なコードから確実に分離することです。移植できないコードを、移植可能にすべきコードの本体内に配置することは、望ましくありません。移植できないコードを発見した場合、削除するのではなく、適切な場所(同様の移植できないコードを集めた場所)に移動します。

移植可能なコードを作成する最善の実践方法

成功から学ぶ人もいますが、失敗からより多くを学ぶ人もいます。ただし、さらによいのは、他人の失敗から学ぶことです。苦しむことなく知識を取得できます。Win16 コードの作成では、開発者は、Win32 への移植が非常に難しくなるような数々の失敗をしました。

Win16 から Win32 への移行期間に、オペレーティング システムの最下位レベルの部分が初めから作成されました。ただし、システム アプリケーションは、Windows 3.1 アプリケーションから移植されました。たとえば、Windows 3.1 のメモ帳は、32 ビット アプリケーションとして Windows NT 3.1 に移植されました。Win32 は、Win16 からの移植を考慮して設計されたので、ほとんどの移植が迅速に行われました。また、ほとんどのプログラムは、長年にわたって培われた移植方法を実践して開発されました。

しかし、すべてのプログラムがきれいに作成されていたわけではありません。たとえば、Windows 3.1 のプログラム マネージャです。これは、Windows 3.1 の主要な UI シェルでした(**[スタート]**メニューを導入したとき、Microsoft はプログラム マネージャの使用をやめました)。プログラム マネージャの移植は、数日で終わるはずでしたが、数週間かかりました。何が悪かったのでしょうか。

プログラム マネージャは簡単なプログラムでした。プログラムのアイコンを表示し、プログラムのグループを個別のウィンドウに表示しました。プログラム マネージャが行うタスクについては、本質的にプラットフォーム固有のものはありませんでした。つまり、低レベルの CPU コードとハードウェア固有の機能はありませんでした。Win16 から Win32 への移植は簡単なはずでした。しかし、簡単ではありませんでした。なぜでしょうか。これは、最初の開発者が標準の Windows API のコーディングの慣例に従わなかったためです。このような問題を避けるために、次に、Microsoft Windows ファミリのさまざまなオペレーティング システムが提供するプラットフォーム上で実行される移植可能なコードのビルドを構築するための、現在最善の実践方法の概要を示します。

  • 型の移植性: 大文字の型を使用し、ネイティブな C 言語である小文字の型を使用しません。つまり、WCHARLPWSTR を使用し、unsigned shortunsigned short * は使用しません。
  • 文字列型の移植性: 文字列型の T のバリエーションを使用して、Unicode プラットフォームと Unicode 以外のプラットフォーム間の移植性を実現します。TCHARLPTSTR を使用し、CHARLPSTR は使用しません。
  • C ランタイムの文字列関数の移植性: tchar.h 内に定義されている文字列関数の _t のバリエーションを使用します。たとえば、_tcslen_tcscpy、および _tcscat を使用し、strlenstrcpy、および strcat は使用しません。
  • 文字列定数と文字定数: _T() マクロを使用します。たとえば、_T("string")_T('s') を使用し、L"string"L's' は使用しません。
  • オペレーティング システムに依存しないソース: 特定のソース ファイルの移植性を向上させるために、windef.h をインクルードし、windows.h はインクルードしません。windef.h ファイルには、Win32 の基本型が含まれています。
  • 複数のプラットフォームのコード: 2 つ以上のプラットフォームをターゲットにする場合は、すべての開発者が各プラットフォームにアクセスして、必要に応じて各プラットフォームでビルドおよびデバッグすることができるようにします。
  • エミュレータと実際のハードウェア: エミュレータは大変便利ですが、必ず実際のハードウェアでコードをテストします。

**メモ   **Web で検索すると、移植可能なコードを作成するためのガイドラインが多数見つかります。ガイドラインを採用する前に、ガイドラインの目標が自分の目標と一致することを確認してください。最初のガイドラインと同様に、お互いに矛盾するガイドラインがすぐに見つかります。

Windows Mobile での Uber 統合

Windows Mobile をターゲットにする開発者は、次の点で、Uber 統合の成果を享受できます。

  • 共通の Windows Mobile API セット: Pocket PC と Smartphone の両方をターゲットにする共通のネイティブ実行可能ファイルの開発を可能にします。
  • 共通の .NET Compact Framework: Pocket PC と Smartphone の両方をターゲットにする共通のマネージ実行可能ファイルの開発を可能にします。
  • 共通の ARM 命令セット(すべての Windows Mobile プラットフォーム向け): エミュレータが ARM エミュレーションをホストできるようにするので、同一のバイナリを実際のデバイスとエミュレータの両方で実行できます。

Pocket PC と Smartphone の性能を最大限に引き出しながら、2 つの異なるデバイスが引き起こす混乱を最小限に抑えるために、この 2 つの Windows Mobile デバイスは同一のプログラミング インターフェイスを使用しています。外観上は、ハードウェアと UI が異なりますが、内部は、サポートされている API がまったく同じです。つまり、アーキテクチャは統一されています。(動作中の Uber 統合)

なぜこれが重要なのでしょうか。この統一アーキテクチャを使用すると、両方のプラットフォームをサポートするために、1 つのバイナリ(または、バイナリ セット)をビルドできるので、両方のプラットフォームのサポートにかかるコストが削減されます。このコスト削減は、すべてのインストール可能なコンポーネント(アプリケーションやデバイス ドライバなど)で実現されます。この規模の利益は、ソフトウェア開発に伴うすべての作業(設計、コーディング、テスト、および安定化)で利用されます。

この記事は、移植可能なアプリケーションのビルドに関するものなので、移植性とは何か?について述べることも意味があります。この記事が目的とする移植性は、ソース コードレベルの移植性とバイナリレベルの移植性 の 2 種類です。この記事では、バイナリの移植性を中心に述べていますが、より完全なものにするために、ソース コードの移植性についてもこれから簡単に説明します。

ソース コードの移植性

ソース コードの移植性とは、ビルド時の移植性ということを意味します。共通のソース コード ベースから始めて、さまざまなプラットフォームのための複数の実行可能ファイルをビルドします。Visual Studio 2005 の新規プロジェクト ウィザードは、この種の移植性を提供するためのコードを生成します。ソース コードの移植性は、コードの大幅な再利用を可能にするので、好ましいことです。この移植性は、次の 2 つによって実現されます。

  • プリプロセッサ シンボル
    このシンボルは、ソース コードの一部の条件付きコンパイルを制御します。2 つのシンボルがこの役割を果たします。つまり、Pocket PC 固有のコード用の WIN32_PLATFORM_PSPC と、Smartphone 固有のコード用の WIN32_PLATFORM_WFSP です。
  • リソース ファイル
    ユーザー インターフェイス オブジェクト(メニューやダイアログ ボックスなど)の基となる読み取り専用データです。また、文字列テーブルを集中管理します。ソース コードの移植性は、Pocket PC 用と Smartphone 用のリソース ファイルの 2 つの重複セットを用意することで、サポートされます。Windows Mobile プロジェクトがビルドされるときに、新規プロジェクト ウィザードによって提供される一方のセットともう一方のセットのどちらか(両方ではない)が、プロジェクトにインクルードされます。

プラットフォーム作成ウィザードは、この 2 つだけではなく、4 つのプラットフォームを暗黙にサポートしています。Windows Mobile プラットフォーム以外の 2 つは、デスクトップ コンピュータ上の Windows(Windows XP など)と、埋め込み型プラットフォームの Windows CE です。

バイナリの移植性

バイナリの移植性とは、実行時の移植性ということを意味します。つまり、1 つのバイナリ ファイル(または、ファイルのセット)を 2 つ以上のプラットフォームで実行できます。最下位レベルとして、ターゲット プラットフォームには共通の CPU 命令セットが必要です。ネイティブ コードの場合、すべての Windows Mobile プラットフォームは、同じ ARM4TI 命令セットをサポートする ARM コア用にビルドされるので、共通の命令セットの問題は簡単に解決します。

バイナリの移植性に必要な別の考慮事項は、プラットフォームの違いのために行われる微調整です。プラットフォーム作成ウィザードは、ソース レベルの移植性を提供するので、微調整には、このウィザードが行ったことを元に戻すことが含まれます。ウィザードが行った変更箇所を見つけることは簡単なので、元に戻すことは難しくありません。必要な変更は、次の 2 つのカテゴリのいずれかに当てはまります。

  • 条件付きでコンパイルされるコード
    バイナリの移植性を実現するには、条件付きでコンパイルされるコードを見つけて、ビルド時のチェックの代わりにランタイム時のチェックを実行するように変更します。
  • リソース
    リソース ファイルを変更して、サブセットだけではなく、すべてのリソースが実行可能ファイルに組み込まれるようにします。

ランタイム チェック

すべてのターゲット プラットフォーム上で正しく動作するように設定するには、条件付きでコンパイルされるコードをすべて見つけます。たとえば、次のコードは、プラットフォーム作成ウィザードが適切な場所に配置する Pocket PC ターゲット向けのコードです。

#ifdef WIN32_PLATFORM_PSPC
    SHInitExtraControls();
#endif // WIN32_PLATFORM_PSPC

バイナリの互換性を実現するには、これをランタイム時にテストするようにします。上のコードを次のように変更します。

if (bPocketPC)
{
    SHInitExtraControls();
}

このコードが正しく動作するには、プログラムが Pocket PC 上で実行されるとき、フラグ bPocketPC が設定されている必要があります。次のコードは、さまざまな Windows Mobile ベースのデバイスとさまざまなバージョンの Windows CE を検出します。

// プラットフォーム用のフラグ
BOOL bPocketPC     = FALSE;
BOOL bSmartphone   = FALSE;
BOOL bWinMoFiveOh  = FALSE;
BOOL bWinMo2003    = FALSE;
BOOL bWinMo2003_SE = FALSE;

// InitPlatformFlags - システムの問い合わせ、フラグの設定。
void InitPlatformFlags(HWND hwnd)
{
    // プラットフォーム名の問い合わせ
    TCHAR atchPlat[64];
    SystemParametersInfo(SPI_GETPLATFORMTYPE, 64, (PVOID)atchPlat, 0);

    if (_tcsncmp(atchPlat, L"PocketPC", 64) == 0)
    {
        bPocketPC = TRUE;
    }

    if (_tcsncmp(atchPlat, L"SmartPhone", 64) == 0)
    {
        bSmartphone = TRUE;
    }

    OSVERSIONINFO osvi;
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionEx(&osvi);
    if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 01)) 
        bWinMoFiveOh = TRUE;
    if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 20)) 
        bWinMo2003 = TRUE;
    if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 21)) 
        bWinMo2003_SE = TRUE;
}

すべてのリソースの組み込み

バイナリの移植性を備えた Windows Mobile アプリケーションをビルドするための 2 番目の手順は、必要なリソースのすべてをインクルードすることです。必ずしも必要ではありませんが、複数の種類のプラットフォームを指定することで、Smart Device Project Wizard のプロセスを簡略化できます。たとえば、図 1 では、ターゲットの SDK(ソフトウェア開発キット)として、Pocket PC プラットフォームと Smartphone プラットフォームの両方を含むように選択しています。

ms838140.build_portable_wm_apps_02(ja-jp,MSDN.10).gif

図 1. 複数のターゲット プラットフォームを作成する Smart Device Project Wizard

両方の種類の Windows Mobile プラットフォームをターゲットにする場合、新規プロジェクト ウィザードは 2 つのリソース ファイル セットを作成します。図 2 は、Pocket PC と Smartphone の両方をターゲットにするプロジェクトのソリューション エクスプローラです。リソース ファイルのうち 2 つは、Pocket PC 向けで(testppc.rc と testppc.rc2)、2 つは Smartphone 向けです(testsp.rc と testsp.rc2)。この図の赤にマイナスの記号は、Pocket PC リソース ファイルがビルドから除外されていることを示します。

ms838140.build_portable_wm_apps_03(ja-jp,MSDN.10).gif

図 2. リソース ファイルの 2 つのセットが表示されているソリューション エクスプローラ

両方のリソース(*.rc)ファイルを単純に有効にすると、エラー メッセージが表示されます。問題は、Pocket PC リソース(testppc.rc)と Smartphone リソース(testsp.rc)の間に多くの余分なリソースがあることです。ただし、リソース自体を詳しく調べると、ほとんどのリソースは、特定のプラットフォームに最小限しか依存していないことがわかります。2 つの例外は、メニューとダイアログ ボックスです。これは、次で説明します。

プラットフォーム固有の UI オブジェクト

図 3 に示すように、Visual Studio 2005 の**[リソースの追加]**ダイアログ ボックスは、9 種類のリソースを表示します。ほとんどはプラットフォームに依存しません。これは、Pocket PC と Smartphone の間で共有できる 1 つのセットを作成できることを意味します。2 つの例外は、メニューとダイアログ ボックスです。

ms838140.build_portable_wm_apps_04(ja-jp,MSDN.10).gif

図 3. 9 種類のリソースを表示する[リソースの追加]ダイアログ ボックス

メニュー

Smartphone と Pocket PC のメニューは、本質的に異なります。Smartphone は、最上位のメニュー項目を 2 つしか表示できません。規約により、左側のメニューは、ポップアップ メニュー項目ではなく、スタンドアロン メニュー項目です。一方、Pocket PC は、メニュー バーに複数のメニューを表示できます。さらに、Pocket PC は、メニュー バーにボタンを表示できます。2 つのプラットフォームのユーザー インターフェイスは、それぞれのプラットフォームを最大限に利用できるように設計されました。

しかし、両方のプラットフォームで同一のメニューを作成することは可能です。この記事の文脈では、両方のプラットフォーム向けに 1 つのバイナリをビルドすると、両方のプラットフォームに同じメニューを表示できます。これは、Pocket PC でも簡単なメニューで済ませることを意味します。この方法にはいくつかの利点があります。最も明らかな利点は、一方のプラットフォーム上のアプリケーションに慣れている人は、他方のプラットフォーム上のアプリケーションにすぐに慣れることです。別の利点は、より簡単なメニュー構造により、片手での操作がより簡単になることです。

実際、両方のプラットフォームの共通メニュー スタイルは、現在 Microsoft が推進している方法です。図 4 は、Smartphone 向けの Windows Mobile 5.0 ソフトウェアを実行中の Smartphone の画面です。図 5 は、Pocket PC 向けの Windows Mobile 5.0 ソフトウェアを実行中の Pocket PC の画面です。Windows Mobile 5.0 の導入により、UI ロゴのガイドラインが変更されて、2 つのメニュー項目を備えたコマンド バーが両方のデバイスに表示されるようになりました。左側に 1 つのレベルのボタン、右側にポップアップ メニューが表示されます。

クリックすると大きな画像を表示します

図 4. Smartphone 向けの Windows Mobile 5.0 ソフトウェアが実行されている Smartphone。クリックすると大きな画像を表示します。

クリックすると大きな画像を表示します

図 5. Pocket PC 向けの Windows Mobile 5.0 ソフトウェアが実行されている Pocket PC。クリックすると大きな画像を表示します。

ダイアログ ボックス

目標が Pocket PC と Smartphone の間のバイナリの移植性であると仮定すると、開発時間のほとんどは、さまざまな画面解像度と画面の向きの調整に費やされます。また、1 つの UI オブジェクトだけが画面解像度と画面の向きに密接に関連付けられていることがわかります。それは、ダイアログ ボックスです。

初期の Pocket PC の画面は、縦長モードで、240 x 320 でした。また、初期の Smartphone の画面は、縦長モードで、176 x 220 でした。これらの解像度は、Windows Mobile 2003 Second Edition から変更され始めました。現在および予想される将来の Windows Mobile 5.0 デバイス上で実行されるために、プログラムは、フル VGA(640 x 480)と、縦横同サイズの画面(240 x 240)を含む幅広い解像度に対応する準備をしておく必要があります。

この問題に対応する方法がいくつかあります。1 つの方法は、ダイアログ ボックスを使用しないことです。ただし、これは、非常に UI が簡単なアプリケーションでしか現実的ではありません。2 番目の方法は、プログラムから、画面のサイズと向きに基づいて、コントロールの位置とサイズを変更することです。この方法の欠点は、時間と労力が必要なことです。

最も簡単な方法は、複数のダイアログ ボックス テンプレートを使用することです。各ダイアログ ボックスに必要なテンプレート セットの数は、現在のところ、6 つです。次にその 6 つを示します。

  • 176 x 220   Smartphone
  • 240 x 320   Smartphone、Pocket PC 縦長
  • 320 x 240   Pocket PC 横長
  • 240 x 240   Pocket PC 正方形
  • 640 x 480   Pocket PC 横長
  • 480 x 640   Pocket PC 縦長

このリストには、縦長と横長の両方の向きが含まれています。この問題の処理方法の詳細については、「Developing DPI-Aware Applications」(英語) を参照してください。

入力処理の違い

Pocket PC と Smartphone の両方で動作する 1 つの実行可能ファイルをビルドする場合は、入力が処理される方法の違いを考慮します。Pocket PC は、タッチ スクリーンを搭載していますが、Smartphone は搭載していません。Pocket PC は、テンキーおよび Smartphone の**[Call]ボタンと[Disconnect]**ボタンのどちらも搭載していません。

物理的なハードウェアの違いのほかに、標準のアプリケーション内でそのハードウェアが使用される方法に関する問題があります。Pocket PC の共通アクションには、ユーザーがデバイスをタップして選択する動作が含まれています。Smartphone では、タップと同等の動作がないので、別の方法が必要です。ユーザーが矢印キーを使用して選択肢を移動することが必要になる可能性もあります。必要なのは、プラットフォームに関係なくプログラムのユーザーに同等の機能を提供する代替手段です。

Pocket PC 上で行う別の共通アクションは、タップしたまま押さえてポップアップ メニューを開く動作があります。これは、ショートカット メニューと呼ばれることもあります。これも、Pocket PC 上のプログラムと等しい機能を、Smartphone 上の同じプログラムでも使用できるような手段を見つける必要があります。この場合は、追加のメニュー項目やダイアログ ボックスを使用すると、問題に対応できる可能性があります。

まとめ

この記事は、2005 年 7 月 22 日時点の情報です。私は Walter Cronkite ではありません。おやすみ(グレーシー...)。(こういうのは好きではないですか。次のようなのはどうですか)

この記事では、Windows Mobile アプリケーション開発の移植性について説明しました。移植可能なコードを作成すると、生産性が向上します。ただし、ソース コードの移植性とバイナリの移植性のどちらが必要かを決めなければなりません。ネイティブ アプリケーションをビルドする場合は、Visual Studio 2005 のさまざまなウィザードとコード ジェネレータを使用すると、ソース コードの移植性が簡単に実現できます。少し努力すると、スマート デバイス アプリケーションのバイナリの移植性を実現できます。複数のプラットフォームをターゲットにする開発者は、バイナリの移植性により、スマート デバイス向けの開発、配置、およびサポートの作業のほとんどすべての面を合理化できることがわかります。