Quantcast
Channel: Windows CE Blog »付属機能の使い方
Viewing all 14 articles
Browse latest View live

WinCE/WEC でシリアルコンソール

$
0
0

Windows Embedded CE/Compact には、PC 用の Windows と同様のコマンドプロセッサ(cmd.exe)が付属しているのは、皆さんご存じの通りです。今回は、このコマンドプロセッサをシリアルケーブル経由で PC から操作する手順について述べます。

さて、Platform Builder のカタログ項目ビューで依存項目を見ると、コマンドプロセッサには、コンソールウィンドウと Telnet サーバーが依存していることが分かります。コンソールウィンドウは、「コマンドプロンプト」のウィンドウですが、コンソールアプリケーションから printf() などで標準出力に出力した場合も、コンソールウィンドウが開いて出力内容が表示されます。PC 用の Windows でも、同様にコンソールウィンドウが開きますよね。つまり、コンソールウィンドウは、標準出力と結びつく(同様に、標準入力とも結びつく)コンソールデバイスとして機能するというわけです。Telnet サーバについては、後で述べます。

■コンソールの出力先に対するレジストリ設定
コマンドプロセッサを、シリアルケーブル経由で PC から操作するには、コンソールの出力先の設定を変更します。この設定は、リファレンスの次のページで説明されています:

 Command Processor Registry Settings (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-US/library/ee506287(v=winembedded.60).aspx

 Command Processor Registry Settings (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee506287.aspx

上のページで説明されているように、[HKEY_LOCAL_MACHINE\Drivers\Console] キー直下の OutputTo の値により、コンソールの出力先を、コンソールウィンドウ以外に設定できるのです。たとえば、2番のシリアルポート(COM2)であれば、次のような設定になります。


[HKEY_LOCAL_MACHINE\Drivers\Console]
    "OutputTo"=dword:2
    "COMSpeed"=dword:1C200

上の例は、COM2 をコンソールの出力先とし、COM2 のボーレートを 115200 としています。

上記のように設定することで、シリアルケーブルで接続した PC から、ターミナルソフトを使ってコマンドプロセッサを操作できます。このように設定しておくと、コマンドプロセッサ(cmd.exe)を起動すると、コンソールウィンドウは開かず、代わりに、シリアルケーブルで接続した PC のターミナルソフトのウィンドウに、コマンドプロセッサのプロンプトが出力されます。そして、コマンドプロセッサのプロンプトに対して、コマンド名やプログラム名をタイプ入力すれば、Windows Embedded CE/Compact 上のコンソールウィンドウの場合と同様、コマンドやプログラムを実行できます。

なお、コンソール出力をデフォルト(0)以外に設定すると、「コマンドプロンプト」を起動しても、ウィンドウが開かず、コンソール出力に設定したデバイスにプロンプトが出力されます。この点は、注意して下さい。

■シリアルコンソールに関する注意点
シリアルケーブル経由でコマンドプロセッサを使う設定については、たとえば、次の Blog エントリでも紹介されています:

 Command line (Console) over serial
 http://ce4all.blogspot.com/2007/06/command-line-console-over-serial.html

このエントリには、いくつか読者コメントが付いており、最後のコメントにある「入力がエコーバックされない」という質問には、回答が付いていないままです。実は、エコーバックされないのが通常動作です。コマンドプロセッサ(cmd.exe)のソースを見ると分かりますが、cmd.exe 自身は、コンソールに対して入力をエコーバックしません。バッチファイル(.bat, .cmd)の中で、echo コマンドによるエコーバックの ON/OFF 切り替えは出来ますが、コンソールに対しては、echo コマンドの実行有無とは関係無く、エコーバック動作は行いません。

cmd.exe のソースコードは、WinCE/WEC のソースツリーの、以下の場所にあります:

 %_WINCEROOT%/private/winceos/UTILS/cmd2/

コンソールに対する入力処理は、cmd.cxx にある cmd_GetInput() で実装されていますが、バッチファイル(.bat, .cmd)の実行ではなく、コンソールからの入力、つまり標準入力に対する入力処理では、エコーバックは行いません。そもそも、コマンド入力を _fgetts() で取得していますので、タイプ入力の1文字ごとにエコーバックする仕組み自体がないのです。従って、シリアルコンソールで入力のエコーバックを実現するには、自前でエコーバック処理を実装する必要があります。

■タイプ入力に対するエコーバック動作
コマンドプロセッサのプロンプトに対してエコーバックする処理は、コマンドプロセッサが標準入出力を行う先の、「コンソールデバイス」が担当する役割です。たとえば、コンソールウィンドウは、コマンドプロセッサがデフォルトで使用するコンソールデバイスであり、コンソールウィンドウにおけるタイプ入力のエコーバック処理は、コンソールウィンドウが行います。

もう一つの例は、Telnet サーバです。以下のページでも言及されていますが、Telnet サーバは、自身をコンソールデバイスとして登録したうえで、コマンドプロセッサ(cmd.exe)を起動します。

 http://msdn.microsoft.com/en-us/library/aa446909.aspx (Implementing a Network Service on Windows CE)

そして、Telnet クライアントでのタイプ入力を受け取り、それを、コンソールデバイスのインタフェースを介してコマンドプロセッサへ渡し、コマンドの実行を依頼します。コマンドプロセッサがコマンドを実行し、標準出力へ出力を行うと、それが(入力とは逆の向きに)コンソールインタフェースを介して Telnet サーバに渡され、Telnet クライアントに送信される、というわけです。なお、Telnet の場合には、Telnet クライアントでのタイプ入力のエコーバック処理は、Telnet クライアント自身が行うことになるはずです。

コンソールウィンドウのソースコードは、開示されていないため、コンソールデバイスとしての振る舞いの詳細を見ることができません。一方、Telnet サーバの方は、
 %_WINCEROOT%/public/servers/sdk/samples/telnetd/
にソースコードが収録されていますので、興味のある方は、ご覧になってみて下さい。telndev.cpp において、Stream Interface Driver のインタフェース(TEL_Init(), TEL_Deinit(), TEL_Open(), TEL_Close(), TEL_Read(), TEL_Write(), TEL_Seek(), TEL_IOControl(), TEL_PowerUp(), TEL_PowerDown() 関数)を実装しており、TEL_Read() と TEL_Write() で、コンソール入出力の処理を行います。

Telnet サーバが cmd.exe を起動する処理は、telnetd.cpp にある TelnetLaunchCmd() ですが、ここでは、cmd.exe を起動する前に、SetStdioPathW() を呼び出して標準入出力を変更します。この時、コンソールデバイスとして、自分自身を実体に割り当てたデバイス(”TEL:” というデバイス名)を設定することにより、cmd.exe の標準入出力先として自身を設定します。Telnet サーバは、Windows の流儀でいう「サービス」、つまり、ユーザモードのデバイスドライバとして動作しますから、このような動作が可能なのです。

■エコーバック動作の実現方策
では、シリアルコンソールの場合に、タイプ入力のエコーバック動作を実現するには、どうすればよいのでしょうか?

方策は、二つ考えられます。一つは、Telnet サーバのように、自前でコンソールデバイス機能を実装し、コマンドプロセッサとシリアルポートの間に介在することにより、シリアルポートからの入力を、一文字ごとにエコーバックする、という方策です。

もう一つは、シリアルポートに対して直接入出力を行い、シリアルポートから文字列が入力されたら、入力された文字列をコマンド名として、都度コマンドプロセッサ(cmd.exe)を起動する、という方策です。

二つの方策のうち、後者の方が、より簡単に実装できます。cmd.exe にコマンドを実行させるには、/Q と /C オプション付きで cmd.exe を実行すればよいのです。つまり、
 ”/Q /C [ コマンド引数]”
という文字列を、CreateProcess() の第二引数として渡し、第一引数に “cmd.exe” を渡して呼び出せば、cmd.exe がコマンドを実行し、その結果が、レジストリで設定したコマンドプロセッサのコンソール、つまりシリアルポートへ出力されます。その際、CreateProcess() が返したプロセスハンドルに対して WaitForSingleObject() を呼び出せば、コマンド実行の完了を待つことが出来ます。

ただし、二番目の方策については、次の点を注意して下さい:

・コマンド実行のたびに、都度 cmd.exe を起動するので、シリアルコンソールから cd コマンドが実行されても、その結果が保持されない。
 (cd コマンドに対応するとしたら、移動先に指定されたディレクトリを、cmd.exe を起動するプログラム自身が記録することによって、履歴動作を実現する必要がある。)

・cmd.exe を実行している間は、シリアルポートを閉じて、cmd.exe がシリアルコンソールを使用できるようにしなければならない。

二番目の注意点ですが、これは、シリアルポートのデバイスドライバの制約によるものです。シリアルポートは、一つの実体に対し、デバイスを一つしかオープンできないのです。たとえば、COM1 であれば、”COM1:” を指定して CreateFile() を呼び出すことにより、シリアルポートのデバイスをオープンします。この時、”COM1:” のデバイスをオープンしたままの状態で、同じシリアルポート(”COM1:”)に対して CreateFile() を呼び出すと、エラーとなり、オープンできません。この制約は、シリアルポートのデバイスドライバの、MDD レイヤの実装によるものです。

シリアルポートのデバイスドライバの MDD レイヤのソースコードは、
 %_WINCEROOT%/public/COMMON/oak/drivers/serial/com_mdd2/
に収録されています。このディレクトリにある mdd.c で実装されている COM_Open() を見ると、既にオープン済みのシリアルポートに対して呼び出された場合は、ERROR_INVALID_ACCESS をエラーコードとしてセットして、NULL を返すことが分かります。

ところで、シリアルコンソールにバックスペース(’\b’)が入力された場合、エコーバック処理では、入力を一文字消さなければいけません。単純に ‘\b’ をエコーバックしただけでは、PC のターミナルソフトでは、カーソルが一文字戻るだけで、文字が消えないのではないかと思います。カーソルを戻すだけでなく、直前にあった文字を消したい場合には、’\b’ を単純にエコーバックする代わりに、”\b \b” という文字列を出力すればよいでしょう。つまり、カーソルを一文字分戻した後、空白文字を出力することにより、直前にあった文字を消し、再度 ‘\b’ を出力してカーソルを戻す、というわけです。

■シリアルコンソールを利用した管理機能の実現
上で述べた、シリアルコンソールのタイプ入力に対するエコーバック動作の二つの実現方策のうち、後者の方は、シリアルコンソールを使った管理機能を実装する際には、却って向いているかも知れません。前者の方策の場合、OS (WinCE/WEC) の起動完了直後にコマンドプロセッサを起動するように設定すれば、シリアルコンソールにコマンドプロセッサのプロンプトが出力されて、Linux などと同じ感覚で使うことが可能です。しかし、そのようにしてしまうと、全てのプログラムをコマンドプロセッサから実行できてしまいます。

シェルをカスタマイズして、特定の操作しかできないようにしたデバイスや、あるいは、ヘッドレスのデバイスの場合には、限られたコマンドだけをシリアルコンソールから実行できるように制限したり、また、ログイン動作を実装してセキュリティを確保する必要があるでしょう。そのような場合は、単純にコマンドプロセッサをシリアルコンソールへ割り当てるのではなく、コマンドプロセッサを呼び出す「ラッパー」/「ドライバ」プログラムを割り当てて、そのプログラムが、ログイン動作や、シリアルコンソールから実行可能なプログラムの名前だけを受け付けて実行する、という仕組みにするのが良いと思います。


WEC/WinCE から共有ディレクトリ(ファイルサーバ)をアクセス

$
0
0

前回のエントリで、.NET CF アプリケーションから WNetAddConnection3() を呼び出す例を述べました。その例の説明で書いたように、WNetAddConnection3() は、Windows フィルサーバとの接続などを行う API です。

■Windows ファイルサーバに対するクライアント機能
Windows ファイルサーバ(CIFS サーバ)をアクセスする機能、つまり、Windows ファイルサーバに対するクライアント機能は、”Windows Networking API/Redirector” というコンポーネントになっており、SYSGEN 変数の SYSGEN_REDIR を設定することにより、OS イメージに組み込まれます。詳細については、リファレンスの次のページをご覧ください。

 Windows Networking API/Redirector Reference (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee495264.aspx

 Windows Networking API/Redirector (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-US/library/ee494246(v=winembedded.60).aspx

Platform Builder のカタログ項目ビュー(Catalog Items View)の階層で言うと、次の項目を選択すると、SMB/CIFS クライアント機能が OS Design に組み込まれます(※WEC 7 の場合):

 <OS Design 名>
 Core OS
  Windows Embedded Compact
   Communication Services and Networking
    Networking – General
★    Windows Networking API/Redirector (SMB/CIFS)

ここで、”Redirector” という Windows の用語に馴染みのない方は、たとえば、次の解説記事が参考になるのではないかと思います。

 「基礎から学ぶWindowsネットワーク 第20回」
 http://www.atmarkit.co.jp/fwin2k/network/baswinlan020/baswinlan020_03.html

 「基礎から学ぶWindowsネットワーク」
 http://www.atmarkit.co.jp/fwin2k/network/baswinlan002/baswinlan002_03.html

なお、CIFS クライアントだけでなく、CIFS サーバ機能も WEC/WinCE に付属しています。こちらは、カタログ項目ビューの階層の、次の場所にあります:

 <OS Design 名>
 Core OS
  Windows Embedded Compact
   Communication Services and Networking
    Servers
     File Server (SMB/CIFS)

CIFS サーバに関する記述は、なぜか WEC 7 のリファレンスに見当たりません。興味のある方は、WinCE 6.0 のリファレンスをご覧ください。

 File Server (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-us/library/ee500573(v=winembedded.60).aspx

■SMB/CIFS クライアント機能を組み込む場合の注意点
さて、SMB/CIFS クライアント機能(Windows Networking API/Redirector)を組み込む場合、一つ注意しなければいけません。WEC/WinCE のリファレンスには、このコンポーネントが依存するのは、TCP/IP (SYSGEN_TCPIP) と Winsock (SYSGEN_WINSOCK)、および NDIS (SYSGEN_NDIS) とだけ書かれているのですが、それらのコンポーネントだけでは、SMB/CIFS サーバにアクセスすることは、できません。

CIFS サーバに接続する場合は、認証処理が必要ですが、認証処理に必要なコンポーネントは、SMB/CIFS クライアント機能を組み込んでも自動的に組み込まれないため、明示的に組み込む必要があるのです。認証処理に必要なコンポーネントは、WEC 7 ですと、カタログ項目ビューの階層の、次の場所にあります:

 <OS Design 名>
 Core OS
  Windows Embedded Compact
   Security
    Authentication Services (SSPI)
★    Kerberos
★    NTLM

通常は、NTLM だけを選択しても CIFS サーバに接続できるでしょう。お手元の環境で、試してみて下さい。これらのコンポーネントについては、リファレンスの次のページで説明されています(※WEC 7 の場合)。

 NTLM Security Support Provider (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee498104.aspx

 Kerberos Security Support Provider (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee498711.aspx

 Authentication Services (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee498877.aspx

デバイスエミュレータで WEC 7 を動かす

$
0
0

最初にことわっておきますが、今回の内容は、WinCE 6.0 (Windows Embedded CE 6.0) と WEC 7 (Windows Embedded Compact 7 ) を両方お使いの方が主な対象です。WinCE 6.0 しか使っていらっしゃらない方には、特に関係ない内容ですし、また、WEC 7 だけをお使いの方にも、必要性は低い内容だと思います。もし、あなたが、WinCE 6.0 の ARM ベースのデバイスエミュレータをご利用になっていて、同じものを WEC 7 でも使えないだろうか?と思ったことがあるのなら、今回の内容は、あなたのためのものです。お急ぎなら、途中を飛ばして、今回のエントリの最後の方にある「DeviceEmulator BSP を WEC 7 へ移植する」を読んでみて下さい。

■WinCE 6.0 と Windows Mobile のデバイスエミュレータ
Visal Studio 2008 までは、Pro 以上の版に含まれる Smart Device Development 機能の一部として、ARM ベースのデバイスエミュレータが付属しています。このデバイスエミュレータは、単体でも提供されており、最新版の 3.0(VS 2008 付属のものと同じ版)を、以下のページからダウンロードできます:

 Microsoft Device Emulator 3.0
 http://www.microsoft.com/ja-jp/download/details.aspx?id=5352

デバイスエミュレータがエミュレートしているのは、Samsung 製の、S3C2410 という ARM9 コアのプロセッサを搭載したリファレンスボードです。WinCE 6.0 の Platform Builder をお使いの方ならご存知の通り、WinCE 6.0 には、デバイスエミュレータの BSP が付属しています。そのため、WinCE 6.0 を動かす実機がなくても、デバイスエミュレータの BSP を使って OS イメージをビルドすれば、その OS イメージをデバイスエミュレータで動かし、実機に依存しない部分の開発が可能です。

WinCE 5.0 までは、デバイスエミュレータには Virtual PC が使われていました。つまり、ターゲットプロセッサは x86 でした。WinCE 6.0 では、それが ARM プロセッサになった、というわけです。しかし、後述するように、WEC 7 では、再び Virtual PC がデバイスエミュレータとして採用されました。

以下に、WinCE 6.0 のデバイスエミュレータ、つまり、S3C2410 リファレンスボードのエミュレータの特徴をまとめます:

  • Windows Mobile のエミュレータとしても利用されている。
  • 設定ファイルを作成することにより、スキン画像と入力ボタン/キーパッドを設定できる。
  • ARM プロセッサをエミュレートしている。

どれも、Virtual PC ベースのエミュレータには無いものです。専用の BSP を使って作成した OS イメージをロードして動かせるのは、どちらのエミュレータも同じです。一方、エミュレータから利用できるホスト PC の周辺機器機能は、Virtual PC ベースのエミュレータの方が豊富です。WinCE 6.0 のデバイスエミュレータの方は、実質、Ethernet とシリアルポートのみです。

WinCE 6.0 のデバイスエミュレータでは、周辺機器のエミュレート機能として、ホスト PC のマウス入力に対する、タッチパネル入力のエミュレートや、ホスト PC のディレクトリをメモリカードとしてマウント/エミュレートする、というものがあります。Virtual PC に比べると、利用できるホスト PC の周辺機器機能は貧弱ですが、入力ボタン/キーパッドのエミュレートが可能なことと、ARM プロセッサをエミュレートしているのは、便利な場合があります。

さて、WinCE 6.0 のデバイスエミュレータがエミュレート(シミュレート)しているのは、上述したように、Samsung の ARM9 コアのプロセッサ(S3C2410)のリファレンスボードです。S3C2410 の ARM9 コアは、ARM920T、つまり、命令セットが v4T である ARM9TDMI ファミリです。WinCE 6.0 までの ARM コンパイラは、ARMv4 の命令セットにしか対応していませんでしたので、それで十分でした。しかし、WEC 7 の ARM コンパイラでは、ARMv5/v6/v7 のサポートが追加された代わりに、ARMv4 には対応していません。このことは、このデバイスエミュレータで WEC 7 を動かそうとする場合に、問題となるように思われます。

しかし、心配はいりません。VS 2008 の Smart Device Development 機能に付属する、最新版(3.0)のデバイスエミュレータ(※上述したページから、単体でダウンロードできます)では、ARMv5 の命令セットにも対応しています。デバイスエミュレータのコマンドラインオプションのリファレンスを見ると、/cpucore オプションで ARMv5 を指定することにより、ARMv5 命令セットが有効になると説明されています(デフォルトは、ARMv4):

 デバイス エミュレータのコマンド ライン リファレンス
 http://msdn.microsoft.com/ja-jp/library/aa188169(v=VS.90).aspx

ちなみに、VS 2005 に付属していた版(1.0)、つまり、WinCE 6.0 用としても使われるデバイスエミュレータは、ソースコードを入手可能です:

 Shared Source Microsoft Device Emulator 1.0 Release
 http://www.microsoft.com/en-us/download/details.aspx?id=10865

デバイスエミュレータ 1.0 のソースコードは、上のページに書かれているように、Shared Source ライセンスで提供されていますので、興味がある方は、ご覧になってみて下さい。QEMU など、他のエミュレータと同様なところはあると思いますので、両者を比較しながら読んでみるのも、面白いでしょう。

■WEC 7 での Virtual PC 対応
WEC 7 では、WinCE 6.0 にあった ARM ベースのデバイスエミュレータの BSP は付属せず、代わりに、Virtual PC 用の BSP が付属しています。この BSP に対応した、Virtual PC の仮想マシンイメージ(cevm.vmc)も付属しており、BSP を使って OS イメージを作成すれば、すぐに動かせるようになっています。この仮想マシンイメージを有効にすると、Windows 7 で Windows XP Mode をお使いの場合、Windows Virtual PC の仮想マシンとして、Windows XP Mode に加えて cevm が表示されるようになる筈です。cevm には、WEC 7 のブートローダが組み込まれていますので、起動してブートローダのメニュー画面を表示させ、ネットワーク設定を行えば、Platform Builder を使って OS イメージをダウンロードできます。

WEC 7 での Virtual PC ベースのデバイスエミュレータを使う手順については、リファレンスの次のページをご覧下さい。

 Develop with Virtual CEPC (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/jj200433

お使いの PC に WEC 7 をインストール済みの方であれば、
 C:/Program Files/Windows Embedded Compact 7/Documentation/
ディレクトリの中に入っている
 Getting Started with Virtual CEPC.pdf
というドキュメントも、参考になるでしょう。

Virtual PC ベースのデバイスエミュレータを、WinCE 6.0 のデバイスエミュレータと比べると、上述したように、エミュレータから利用できるホスト PC の周辺機器機能は、Virtual PC ベース(前者)の方が豊富です。また、原理上、前者の方が高速でもあります。一見すると、Virtual PC ベースのエミュレータの方が良いことずくめで、WinCE 6.0 のデバイスエミュレータ(ARM ベースのエミュレータ)を使う理由は、ありません。

しかし、ARM ベースのエミュレータの方が便利な場合も、あります。たとえば、次の場合です。

  • 実機のプロセッサが ARM の場合。
  • 実機にハードウェアボタンを搭載予定であり、そのモック動作を、エミュレータで行いたい場合。

ハードウェアボタンのシミュレートについては、上述したように、設定ファイル(スキンファイル)へ記述することにより任意に設定できます。ARM ベースのデバイスエミュレータの設定ファイルの記述仕様は、リファレンスの次のページで説明されています:

 デバイス エミュレータのスキンの XML スキーマ リファレンス
 http://msdn.microsoft.com/ja-jp/library/aa188144(v=vs.90)

 デバイス エミュレータ構成の XML スキーマ リファレンス
 http://msdn.microsoft.com/ja-jp/library/bb531167(v=vs.90)


2012-09-05 追記:
デバイスエミュレータのスキン設定ファイルにおいて、ボタン/キーパッドに割り当てるキーコードについて、上記のリファレンスでは、特に説明されていません。割り当て可能なキーコードの説明は、WinCE 5.0 のリファレンスにある、次のページをご覧下さい:

 http://msdn.microsoft.com/en-us/library/ms905130.aspx

実機のプロセッサが ARM の場合ですが、Virtual PC ベースのデバイスエミュレータ、つまり、x86 のエミュレータで開発すると、エミュレータでの動作中には起きなかった例外送出が、実機の ARM プロセッサでは発生する、という可能性があります。これが起きる典型的なケースは、TCP/IP 通信や USB 通信でデータ転送を行う際に、転送プロトコルのパケットのペイロードを、構造体に cast して、構造体のメンバにアクセスする場合です。この時、構造体のメンバが 2Byte 以上のサイズの整数値型([unsigned] short, [unsigned] long など)であり、かつ、構造体に cast したメモリ領域のアドレスのアラインメントが、それらの整数値型のサイズに対して揃っていなければ、ARM プロセッサの場合は例外が発生します。しかし、x86 の場合には、アラインメントが揃っていなくても、例外が発生しません。

従って、Virtual PC ベースのデバイスエミュレータでは起きなかった、アプリケーションや汎用デバイスドライバ(USB のクラスドライバなど)の不具合が、ARM プロセッサの実機へ移植すると発生する、という可能性があります。同様のことは、x86 PC でしかテストされていないソフトウェアを、ARM や MIPS などのプロセッサへ移植する場合にも問題となります。これら、ワードアラインメントに関わる不具合を、デバイスエミュレータでの開発時に検出することができるのは、WinCE 6.0 において、ARM ベースのエミュレータが導入された利点の一つだったと思います。

ちなみに、WEC 7 の ARM コンパイラでは、WinCE 6.0 までの ARM コンパイラに比べて Compiler Intrinsics が強化されているため、WinCE 6.0 では発生しなかった例外送出が、WEC 7 では発生する、というケースもあります。つまり、WinCE 6.0 では、バイト単位のアクセス実行にしかコンパイルされなかったソースコードが、ワード単位でのアクセス実行にコンパイルされる場合がある、ということです。同じソースコードから生成されるバイナリの実行効率が上がるようにコンパイラが改善された一方で、その「副作用」として、不用意に書かれたソースコードによって新たに例外送出が発生する場合もある、というわけですね。

ところで、WEC 7 のデバイスエミュレータが、WinCE 6.0 での ARM ベースから Virtual PC ベースに戻ったのは、使用できるホスト PC の周辺機器や実行速度の違いが、主な要因だと思われます。それに加えて、WEC 7 からは PCMCIA がサポートされなくなったことも、要因の一つではないかと思います。WinCE 6.0 のデバイスエミュレータは、NE2000 互換の PCMCIA カードをエミュレートしているのですが、WEC 7 では PCMCIA がサポートされないため、その PCMCIA カード(NE2000 互換のネットワークカード)を利用できないのです。

このことは、Device Emulator の BSP を WinCE 6.0 から WEC 7 へ移植する際に、問題となります。さて、いよいよ、今回のエントリの本題です。

■Device Emulator BSP を WEC 7 へ移植する
これまでの説明で、WinCE 6.0 と WEC 7 では、デバイスエミュレータが異なっており、一方は、ARM プロセッサベース(Samsung S3C2410 のリファレンスボード)、他方は、Virtual PC ベースだということを述べました。また、WinCE 6.0 には付属していた、ARM プロセッサベースのデバイスエミュレータの BSP が、WEC 7 には付属していないことも述べました。そのため、Visual Studio 2008 の Smart Device Development 機能に含まれる、ARM ベースのデバイスエミュレータ(3.0; ARMv5 対応)で WEC 7 を動かそうとしても、OS イメージを作成する手段がないということについても、お分かり頂けたのではないかと思います。

では、Visual Studio 2008 付属のデバイスエミュレータで WEC 7 を動かすには、どうすればよいのでしょうか?答えは簡単です。WinCE 6.0 に付属するデバイスエミュレータの BSP を、WEC 7 に移植して、移植した BSP を使って OS イメージを作成すればよいのです。必要な作業は、以下の通りです:

  1. WinCE 6.0 の %_WINCEROOT%/platform/DEVICEEMULATOR/ ディレクトリを、WEC 7 の %_WINCEROOT%/platform/ ディレクトリへコピーする。
  2. WinCE 6.0 の %_WINCEROOT%/PUBLIC/COMMON/OAK/DRIVERS/PCCARD/ ディレクトリを、WEC 7 にコピーした DEVICEEMULATOR/ ディレクトリの中の SRC/DRIVERS/ ディレクトリへコピーする(※その際、DRIVERS/ の下に PCMCIA/ というディレクトリを作り、その中に PCCARD/ ディレクトリの内容をコピーするのが良いでしょう)。
  3. コピーした DEVICEEMULATOR/ ディレクトリと PCCARD/ ディレクトリの内容、つまり、WinCE 6.0 のデバイスエミュレータの BSP と PCMCIA スタックに対して、WEC 7 への移植(必要な改訂)を施す。
  4. WinCE 6.0 の %_WINCEROOT%/PUBLIC/COMMON/DDK/INC/ ディレクトリから、PCMCIA 関連のヘッダファイル(tuple.h, cardsv2.h, socksv2.h, cardserv.h)を、WEC 7 にコピーした DEVICEEMULATOR/ ディレクトリの中の SRC/INC/ へコピーする。
  5. WinCE 6.0 の %_WINCEROOT%/PUBLIC/COMMON/OAK/files/common.reg ファイルから、PCMCIA の NE2000 互換カードに関するレジストリ項目を、WEC 7 にコピーしたデバイスエミュレータの platform.reg へコピーする。

上で述べたように、デバイスエミュレータがエミュレートするネットワークインタフェースは、NE2000 互換の PCMCIA カードなのですが、WEC 7 では PCMCIA がサポートされず、PCMCIA スタックが付属していません。そのため、WinCE から PCMCIA スタックを移植する必要があります。PCMCIA スタックを移植するにあたっては、%_WINCEROOT%/PUBLIC/COMMON/OAK/DRIVERS/ ディレクトリへコピーせず、デバイスエミュレータ専用のコンポーネントとして、デバイスエミュレータの BSP ディレクトリへコピーするのが良いでしょう。そうすれば、WEC 7 のソースツリー全体を「汚さずに」済みます。なお、デバイスエミュレータの BSP では、DRIVERS/ の下に PCCARD/ というディレクトリがあります。そのため、WinCE 6.0 の PCMCIA スタックのディレクトリ(PCCARD/)を、そのまま DRIVERS/ の下にコピーするのではなく、DRIVERS/ の下に PCMCIA/ というディレクトリを作って、その下に、WinCE 6.0 の PCARD/ ディレクトリの内容をコピーするのが良いでしょう。

デバイスエミュレータの BSP の移植作業は、他の BSP を WinCE 6.0 から WEC 7 へ移植する場合と同様です。中間ディレクトリのパスが WEC 7 で変わったことに伴う、各コンポーネントの sources ファイルの修正や、WinCE 6.0 時点で古くなっていた型定義が WEC 7 では削られてしまったことへの対応などが必要です。たとえば、デバイスエミュレータのディスプレイドライバでは、GPERotate や GPESurfRotate という型を参照していますが、これらは、WEC 7 のヘッダファイルでは削られてしまっているため、WinCE 6.0 のヘッダファイルからドライバのソースファイルへコピーする必要があります。

また、PCMCIA スタックの移植では、%_WINCEROOT%/PUBLIC/COMMON/DDK/INC/ にある devload.h や cebuscfg.h において、PCMCIA 関連の定数の定義が削られてしまっていることへの対応(WinCE 6.0 の同じ名前のファイルから、PCMCIA 関連の定数の定義を PCMCIA スタックのソースファイルへコピーする)も必要です。

上記のように、それなりの移植の手間は必要ですが、WEC 7 のコアのソース(PRIVATE/ および PUBLIC/ ディレクトリ配下)に手を加えずに、BSP および BSP 固有のコンポーネントとして追加するだけで済みます。これは、Windows Embedded Compact が、明確にモジュール化されていることの証だと思います。

移植後の BSP の品質を確保するためには、より多くの作業が必要ですが、「とりあえず動かす」レベルであれば、それほど大変な作業では、ありません。今回は、デバイスエミュレータで WEC 7 が起動して、ホスト PC でのマウス操作でタッチパネル入力をシミュレートでき、さらに、デバイスエミュレータのネットワークアダプタを使えるようになるまでの作業で分かったことを書いています。

最後に、デバイスエミュレータのネットワークアダプタを使えるようにするための移植作業に関して、注意点を二つ書きます。移植作業の細かい説明は省きましたが、次の二点は、見落としがちな要点なので、自分でも移植してみようと思った方のために書いておきます。

  • PCMCIA の NE2000 互換カードに関するレジストリ項目を、WinCE 6.0 の common.reg からコピーする際、BusType を 0 に変更する。
  • PCMCIA ホストコントローラのドライバ(pcc_smdk2410.dll)のロード順序を、後にする。

一番目の注意点ですが、[HKEY_LOCAL_MACHINE\Comm\NE20001\Parms] キーの下にある BusType キー値のことです。WinCE 6.0 の common.reg では、8、つまり PCMCIA の bus type 値が設定されています。しかし、WEC 7 では、PCMCIA がサポートされないため、この値を指定すると、「未知/未定義の bus type」というエラーになってしまい、NE2000 ミニポートドライバの初期化に失敗します。このキー値は、NE2000 ミニポートドライバがロードされた際に、初期化動作の一つとして NdisMRegisterIoPortRange() を呼び出す際に参照されるのですが(※NdisMSetAttributes() を使って、NDIS_HANDLE に対して bus type を設定したのち、NdisMRegisterIoPortRange() を呼び出します)、その呼び出しがエラーとなってしまいます。

このエラーは、bus type を 0 (Internal) に変更することで回避できます。今回、デバイスエミュレータで WEC 7 を動かすために上記の移植を行った際、当初は、NE2000 ミニポートドライバを自前実装し、NdisMRegisterIoPortRange() を呼び出さない仕組みで実装し直す必要があるのではないかと考えました。しかし、分析してみたところ、bus type の設定変更だけで済むことが分かり、移植の手間を減らすことができました。

最後に、二番目の注意点です。オリジナルの実装では、[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\PCC_SMDK2410] キーの下にある Order キー値が 1 になっています。しかし、その設定では、デバイスエミュレータの PCMCIA ホストコントローラがネットワークカードを認識して、NE2000 ミニポートドライバをロードする際に、エラーになってしまうのです。その原因は、解明できていないのですが、pcc_smdk2410.dll がロードされる順序を遅らせることにより、エラーを回避できるようです。設定する値は、dword:10 などにしてみて下さい。

二番目の点については、今後、もし調査の時間がとれたら、さらに追ってみたいと思います。もし、正確な原因や、より根本的な対処策をご存じの方がいらしたら、ぜひ教えて下さい。

WEC 7 の Meiryo フォント

$
0
0

WEC 7 (Windows Embedded Compact 7) で、日本語フォントに Meiryo が追加されたのをご存じの方は、少なくないと思います。WEC 7 に標準で付属するフォントについては、リファレンスの次のページをご覧下さい。

 Fonts Catalog Items and Sysgen Variables (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee489874

上のページに書かれていますが、WEC 7 の Meiryo フォントは、Windows 7 のものと同じバージョンだそうです。Windows 7 と同様に、ClearType を有効にすることで、従来の MS ゴシックに比べて、より綺麗な文字表示が可能となります。ディスプレイドライバに対して ClearType の有効/無効を設定するためのレジストリキーは、次のページにある “ClearType Registry Keys” をご覧下さい。

 Display Driver Registry Settings (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee482851

さて、Meiryo フォントを使う場合に、注意しなければいけないことがあります。それは、”Monotype Imaging AC3 Font Compression” です。以前のエントリ(「圧縮フォント」)で書いたように、このカタログ項目を選択すると、MS ゴシックなどのアジア言語圏用のフォントファイルとして、通常の .ttc ではなく圧縮版の .ac3 が OS イメージに組み込まれます。ところが、OS イメージが小さくなるようにしたいと思って、Meiryo フォントを組み込む場合にも、この “Monotype Imaging AC3 Font Compression” を選択すると、ウィンドウのタイトルバーやメニュー項目、ボタンのラベルなど、標準の GUI 部品の日本語文字列が表示されなくなるのです。

そうなってしまう理由は、%_WINCEROOT%/public/COMMON/oak/files/ ディレクトリにある common.reg と common.bib を見ると分かります。まず、common.reg で “[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\FontLink\SystemLink]” を検索してみて下さい。すると、このキーに対して、MS UI Gothic を代表的なフォントに関連づけるブロックがあって、その次に、Meiryo UI を、代表的なフォントおよび、MS ゴシック系統のフォントファミリに関連づけるブロックがあります。以下に、当該個所を引用します。


; @CESYSGEN IF FONTS_MSGOTHIC || FONTS_MSGOTHIC30 || FONTS_MSGOTHIC30_1_19 || FONTS_MSGOTHIC_1_50 || FONTS_MSGOTHIC_1_60 || FONTS_MSGOTHIC_1_70 || FONTS_MSGOTHIC_1_80 || FONTS_MSGOTHIC_1_90 || FONTS_MSGOTHIC_1_48
[HKEY_LOCAL_MACHINE\SYSTEM\GDI\GLYPHCACHE]
    "limit"=dword:5000
[HKEY_LOCAL_MACHINE\SYSTEM\GDI]
   "FontLinkMethods"=dword:1
; @CESYSGEN IF !FONTS_AC3_VERSIONS
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\FontLink\SystemLink]
      "Arial"="\\Windows\\msgothic.ttc,MS UI Gothic"
      "Courier New"="\\Windows\\msgothic.ttc,MS UI Gothic"
      "Segoe UI"="\\Windows\\msgothic.ttc,MS UI Gothic"
      "Symbol"="\\Windows\\msgothic.ttc,MS UI Gothic"
      "Tahoma"="\\Windows\\msgothic.ttc,MS UI Gothic"
      "Times New Roman"="\\Windows\\msgothic.ttc,MS UI Gothic"
; @CESYSGEN ENDIF !FONTS_AC3_VERSIONS
; @CESYSGEN IF FONTS_AC3_VERSIONS
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\FontLink\SystemLink]
      "Arial"="\\Windows\\msgothic.ac3,MS UI Gothic"
      "Courier New"="\\Windows\\msgothic.ac3,MS UI Gothic"
      "Segoe UI"="\\Windows\\msgothic.ac3,MS UI Gothic"
      "Symbol"="\\Windows\\msgothic.ac3,MS UI Gothic"
      "Tahoma"="\\Windows\\msgothic.ac3,MS UI Gothic"
      "Times New Roman"="\\Windows\\msgothic.ac3,MS UI Gothic"
; @CESYSGEN ENDIF FONTS_AC3_VERSIONS
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\FontLink\SkipTable]
      "Tahoma"="005c,00a5,007e,0391-03c9,2026,2116,221a,25a0-25ff"
; @CESYSGEN ENDIF FONTS_MSGOTHIC

; @CESYSGEN IF FONTS_MEIRYO
[HKEY_LOCAL_MACHINE\SYSTEM\GDI\GLYPHCACHE]
    "limit"=dword:5000
[HKEY_LOCAL_MACHINE\SYSTEM\GDI]
        "FontLinkMethods"=dword:1
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\FontLink\SystemLink]
      "Arial"="\\Windows\\meiryo.ttc,Meiryo UI"
      "Courier New"="\\Windows\\meiryo.ttc,Meiryo UI"
      "MS Gothic"="\\Windows\\meiryo.ttc,Meiryo UI"
      "MS PGothic"="\\Windows\\meiryo.ttc,Meiryo UI"
      "MS UI Gothic"="\\Windows\\meiryo.ttc,Meiryo UI"
      "Segoe UI"="\\Windows\\meiryo.ttc,Meiryo UI"
      "Symbol"="\\Windows\\meiryo.ttc,Meiryo UI"
      "Tahoma"="\\Windows\\meiryo.ttc,Meiryo UI"
      "Times New Roman"="\\Windows\\meiryo.ttc,Meiryo UI"
; @CESYSGEN ENDIF FONTS_MEIRYO

この記述があるために、MS ゴシックと Meiryo のカタログ項目を両方選択した場合、デフォルトのフォントとして Meiryo が設定されます。ここで、FONTS_AC3_VERSIONS が設定されているか否か、つまり、”Monotype Imaging AC3 Font Compression” が選択されているか否かに関わらず、meiryo.ttc が設定されることにも注意して下さい。実は、msgothic とは違い、meiryo には、.ac3 ファイルが存在せず、meiryo.ttc しかありません。興味のある方は、%_WINCEROOT%/public/COMMON/oak/files/ ディレクトリをご覧になってみて下さい。

なお、レジストリの [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\FontLink\SystemLink] キーについては、リファレンスの次のページに説明があります:

 Fonts Linking Registry Settings (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee489864

さて、MS ゴシックと Meiryo のカタログ項目を両方選択した場合、common.reg の記述により、Meiryo がデフォルトのフォントとして設定されることが分かりました。次は、common.bib を見てみましょう。common.bib で “; @CESYSGEN IF FONTS_AC3_VERSIONS” を検索してみて下さい。この行の以下、つまり、FONTS_AC3_VERSIONS が設定されている場合の条件ブロック内には、Meiryo に関する行が存在しないのです。FONTS_AC3_VERSIONS が設定されていない場合の条件ブロック(ELSE ブロック)には、meiryo.ttc が記述されています。

これで、お分かりでしょうか。OS Design で、MS ゴシックと Meiryo のカタログ項目を両方選択すると、Meiryo (meiryo.ttc) がデフォルトのフォントとして設定される一方、”Monotype Imaging AC3 Font Compression” が選択されていると、common.bib の記述により、meiryo.ttc が OS イメージに組み込まれないのです!

というわけで、Meiryo フォントを OS イメージに組み込む場合は、カタログ項目の “Monotype Imaging AC3 Font Compression” を選択しては、いけません。

さて、”Monotype Imaging AC3 Font Compression” については、Silverlight for Windows Embedded アプリケーションの場合も注意が必要です。リファレンスの次のページにある、”Monotype Imaging AC3 Font Compression” の説明をご覧になってみて下さい。

 Japanese Catalog Items and Sysgen Variables (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee491212.aspx

上のページには、AC3 フォント圧縮が、Silverlight for Windows Embedded ではサポートされておらず、そのため、AC3 フォント圧縮を有効にした OS Design では、非圧縮版のフォントファイルをアプリケーションに埋め込む必要がある、と書かれています。ちなみに、WinCE 6.0 のリファレンスにある AC3 フォント圧縮のカタログ項目の説明には、このような注意書きが、見当たりません(※もし、僕が見落としているのであれば、教えて下さい):

 Japanese OS Design Development (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-US/library/ee491212(v=winembedded.60)

WEC 7 において、Meiryo フォントおよび Silverlight for Windows Embedded アプリケーションが AC3 フォント圧縮をサポートしていない理由は、分かりません。もしかすると、Meiryo フォントが AC3 フォント圧縮に向かない仕組みなのかも知れません。Silverlight for Windows Embedded アプリケーションでは、表示を綺麗にするために Meiryo フォントを使うようになっており、そのため、上述したように、AC3 フォント圧縮が有効になっていると日本語が表示されない(meiryo.ttc が OS イメージに組み込まれないため)、ということなのかも知れません。

CeLogFlush.exe と Kernel Tracker

$
0
0

WEC 7 や WinCE 6.0 のデバイスドライバや、アプリケーションの開発を行っていて、期待しているパフォーマンスが達成されなかったり、予想していたタイミングでスレッドが実行されない、などの問題が生じた場合、どこに要因があるのかを調べるには、カーネルのログ機能と Kernel Tracker を使うのが便利です。WEC/WinCE カーネルのログ機能は、デバッグメッセージを出力するなどの単純なものではなく、スレッドの切り替わりや、各種同期オブジェクトの獲得や解放、および、割り込み処理の発火など、OS 内部の詳細な動きを記録できるようになっています。

WEC/WinCE カーネルが出力したログの内容は、Kernel Tracker を使って、グラフィカルに表示できます。以下に、WEC 7 をデバイスエミュレータで動かして取得したログの内容を、Kernel Tracker で表示した様子を示します。

Kernel Tracker の画面キャプチャ

Kernel Tracker の画面キャプチャ

上の画面キャプチャを見ると、標準シェル(explorer.exe)のスレッドが 100ms の Quantum を使い果たし、servicesd.exe 内の同じ優先度を持つスレッドに切り替わった様子が分かります。また、ほぼ一定間隔で割り込み応答動作が起きていることも分かります。これは、1ms おきに発生するタイマ割り込みに対するものです。

このように、WEC/WinCE カーネルのログ機能を使うと、1ms より細かい時間精度でスレッドの動きを知ることができ、OS 内部の動作を分析するのに役立ちます。カーネルデバッガを使ってステップ実行する場合とは異なり、通常の動作での OS 内部の振る舞いを知ることができますので、うまく使えば、強力なツールとなります。また、後述するように、出荷後のデバイスに搭載されているものなど、ログ機能を有効にしない OS イメージに対しても、一時的にログ機能を有効にしてログ採取できるのも、非常に便利な点でしょう。

■CeLogFlush.exe によるログ採取(標準設定)
WEC/WinCE カーネルのログ機能については、リファレンスの次のページで説明されています:

 CeLog Event Tracking (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee479601

 CeLog Event Tracking Overview (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-us/library/ee480432(v=winembedded.60)

このログ機能を使って、WEC/WinCE カーネルが出力するログをファイルに保存する手順は、次の通りです。以下の説明は WEC 7 の場合ですが、WinCE 6.0 でも同様です。

  1. OS Design のカタログ項目で、Target Control Support (Shell.exe) を選択する(SYSGEN_SHELL を有効にする)。
  2. OS Design の「構成プロパティ」の Build Options で、Enable KITL を Yes に設定する。
  3. 同じく Build Options で、Flush tracked events to release directory を Yes (IMGAUTOFLUSH=1) に設定する。

ただし、WinCE 6.0 の場合は、次のいずれかの手順が追加で必要です。

  • OS Design の「構成プロパティ」の Build Options で、Enable event tracking during boot を Yes (IMGCELOGENABLE=1) に設定する。
  • project.bib の FILES セクションに、celog.dll を追加する。

つまり、WinCE 6.0 の場合は、IMGAUTOFLUSH に加えて IMGCELOGENABLE も1に設定しなければ(または、明示的に celog.dll を .bib ファイルに記述しなければ)、カーネルのログ出力が起きません。一方、WEC 7 の方は、IMGCELOGENABLE は設定しなくても、IMGAUTOFLUSH を1に設定すればカーネルのログ出力が起きるのです。実際、リファレンスを見ても、そのように説明されています:

 Including CeLogFlush in a Run-Time Image (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-us/library/ee481413(v=WinEmbedded.60).aspx

 Enable CeLog Event Tracking (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee480716

WinCE 6.0 と WEC 7 の、この違いは、%_WINCEROOT%/public/COMMON/oak/files/common.bib の記述内容の違いによるものです。WinCE 6.0 の common.bib には、IMGCELOGENABLE が1の場合に celog.dll を MODULES セクションに追加する行があるだけです。一方、WEC 7 の common.bib では、次のようになっています。

MODULES
;  Name            Path                                           Memory Type
;  --------------  ---------------------------------------------  -----------
…
IF IMGCELOGENABLE
   celog.dll       $(_FLATRELEASEDIR)\celog.dll                NK  SHK
ENDIF IMGCELOGENABLE
…

; ====================================================================
; FILES section
;
; ====================================================================

FILES
…
; Setting IMGAUTOFLUSH or IMGOSCAPTURE without IMGCELOGENABLE will include
; celog.dll in the FILES section instead of MODULES, so that the DLL will
; be loaded late enough to read settings from the device registry.
IF IMGCELOGENABLE !
IF IMGAUTOFLUSH
   celog.dll       $(_FLATRELEASEDIR)\celog.dll                NK  SH
ENDIF IMGAUTOFLUSH
IF IMGOSCAPTURE
   celog.dll       $(_FLATRELEASEDIR)\celog.dll                NK  SH
ENDIF IMGOSCAPTURE
ENDIF IMGCELOGENABLE


WEC 7 の場合は、common.bib の内容が上のようになっているため、IMGCELOGENABLE を設定せずに IMGAUTOFLUSH だけを1に設定した場合は、celog.dll が .bib ファイルの FILES セクションに追加されますので、OS イメージに celog.dll が収録されます。これに対して、WinCE 6.0 では、IMGCELOGENABLE が1に設定されなければ celog.dll が OS イメージに収録されません。そのため、IMGCELOGENABLE も1に設定するか、または、project.bib の FILES セクションに celog.dll の行を追加する必要があるのです。

上記の設定を行った OS Design をビルドして、ターゲットデバイスにダウンロードして動かすと、Flat Release Drectory、つまり環境変数 _FLATRELEASEDIR が指すディレクトリに celog.clg というファイルが作られて、カーネルが出力したログが書き込まれます。ターゲットデバイスと Platform Builder との接続を切れば、celog.clg ファイルを開くことができるようになりますので、Kernel Tracker で開いてみて下さい。

WEC 7 の場合は、.clg ファイルが Kernel Tracker と関連づけられているため、.clg ファイルのアイコンをダブルクリックすると、Kernel Tracker が起動します。WinCE 6.0 の場合は、Kernel Tracker を起動した後、File メニューで .clg ファイルを開く必要があります。詳細は、次のページをご覧下さい:

 Remote Timeline Viewer (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/gg156030

 Starting Kernel Tracker in File Mode (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-US/library/ee480674(v=winembedded.60)

■CeLogFlush.exe によるログ採取(設定のカスタマイズ)
さて、KITL と Target Control Support (Shell.exe) を有効にした OS イメージで、Flat Release Directory に WEC/WinCE カーネルのログを出力できることは分かりました(Target Control Support (Shell.exe) ではなく、Release Directory File System を有効にするのでも構いません)。これらを有効にしない限り、カーネルのログをファイルへ出力することは、できないのでしょうか?

Flat Release Directory 以外のディレクトリへファイルを出力することは、レジストリ設定により可能です。WEC/WinCE カーネルのログは、celog.dll によって RAM 上のリングバッファへ格納され、その内容を、CeLogFlush.exe がファイルへ出力する、という仕組みになっています。CeLogFlush.exe および celog.dll に対するレジストリ設定は、リファレンスの次のページで説明されています。

 CeLog Registry Settings (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee480468

 CeLogFlush Registry Settings (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-US/library/ee481192(v=winembedded.60)

ログを出力するファイルは、上のページの説明にある通り、[HKEY_LOCAL_MACHINE\System\CeLog] キーの FileName で設定できます。たとえば、SD カードにログファイルを出力する場合は、次のような行を .reg ファイルへ追加すればよいでしょう。

[HKEY_LOCAL_MACHINE\System\CeLog]
    "BufferSize"=dword:20000
    "FileName"="\\Storage Card\\celog.clg"
    "FileSize"=dword:0
    "FileFlags"=dword:0
    "FlushTimeout"=dword:2710
    "ThreadPriority"=dword:F8
    "Transport"="LocalFile"
    "UseUI"=dword:0
    "ZoneCE"=dword:c003e2


なお、BufferSize や FlushTimeout の値は、デフォルトよりも小さくしないで下さい。これらを小さくすると、celog.dll が確保するリングバッファがすぐに満杯になったり、あるいは、ログが出力されていなくてもすぐにバッファのフラッシュ時間に達してしまい、必要以上にログ出力が増えます(CeLogFlush.exe によるファイルへのログ書き込みによっても、カーネルのログ出力が発生することに留意して下さい)。その結果、OS の実効速度が実用にならないものになってしまう場合もあるからです。

もう一点注意です。[HKEY_LOCAL_MACHINE\System\CeLog] キーの FileName 値の設定で、ログの出力先を外部ストレージにする場合、そのストレージデバイスがマウントされるよりも前に CeLogFlush.exe が起動されないようにしなければいけません。IMGAUTOFLUSH を1に設定した場合、common.reg ファイルの記述により、[HKEY_LOCAL_MACHINE\init] キーに対する以下の設定が追加されます:

[HKEY_LOCAL_MACHINE\init]
        "Launch05"="CeLogFlush.exe"


この設定では、デバイスマネージャ(device.dll)よりも先に CeLogFlush.exe がロード・起動されてしまうため、CeLogFlush.exe が初期化時に出力ファイルを作成できず、エラーで終了してしまいます。従って、device.dll の起動順序(Launch20)よりも後の起動順序を設定する必要があります。デバイスマネージャが起動してストレージがマウントされるまでに若干の時間がかかることを考慮すると、gwes.dll(Launch30)の後にする方が、より確実だと思われます。

■ログ機能を有効にしていない OS イメージでのログ採取
ここまでの説明で、celog.dll と CeLogFlush.exe を OS イメージに組み込んでいれば、WEC/WinCE カーネルのログをファイルへ出力できることが分かりました。しかし、カーネルのログが常にファイルへ出力されると、若干のオーバーヘッドを生みますし、また、セキュリティの観点からも、好ましいことでは、ありません。このことは、上で紹介した WEC 7 のリファレンスページにも注意書き(Note)として記載されています。

さて、今回のエントリの冒頭で、次のように書きました:

また、後述するように、出荷後のデバイスに搭載されているものなど、ログ機能を有効にしない OS イメージに対しても、一時的にログ機能を有効にしてログ採取できるのも、非常に便利な点でしょう。

実は、celog.dll と CeLogFlush.exe を OS イメージに組み込んでいなくても、OS の起動後に celog.dll をカーネルにロードさせて、ログ機能を有効にできるのです。従って、USB メモリなどの外部ストレージに celog.dll と CeLogFlush.exe を入れておき、OS の起動後に、手動で CeLogFlush.exe を始動すれば、必要な時にだけログを採取できます。このことは、リファレンスの次のページでも説明されています:

 Collecting Data On A Standalone Device With CeLogFlush (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-US/library/ee480886(v=winembedded.60)

CeLogFlush.exe は、起動すると終了要求されるまで、celog.dll が出力したログをリングバッファから読み出してファイルへ出力するループ動作を実行します。”SYSTEM/CeLogFlush Quit” という名前の event に対して SetEvent() を呼び出すことにより、CeLogFlush.exe に終了要求できます。または、CeLogFlush.exe のソースファイルと同じ場所に収録されている、CeLogStopFlush というサンプルプログラムも参考になります。CeLogStopFlush は、CeLogFlushCommon.lib というライブラリを CeLogFlush.exe と共用しており、CeLogFlushCommon.lib の FLUSH_SignalStopFlush() という関数を呼び出します。FLUSH_SignalStopFlush() は、”SYSTEM/CeLogFlush Quit” という名前の event を OpenEvent() でオープンして、SetEvent() を呼び出すだけです(※SetEvent() の後、CloseHandle() を呼び出します)。

■おまけ
いかがでしょうか?ここまでの説明で、WEC/WinCE カーネルのログ機能が、出荷用の OS イメージに対する障害解析ツールとしても利用可能な、強力なものであることを、お分かり頂けたのではないかと思います。以下に、このログ機能について、いくつか補足します。

(1)CeLogFlush.exe と celog.dll のソースコード
 CeLogFlush.exe と celog.dll のソースコードは、それぞれ次の場所にあります:

 CeLogFlush.exe
 %_WINCEROOT%/public/COMMON/sdk/samples/celog/flush/CeLogFlush/

 celog.dll
 %_WINCEROOT%/private/winceos/COREOS/nk/celog/celogdll/

 CeLogFlush.exe と celog.dll は、”SYSTEM/CeLog Data” という名前の共有メモリ領域(CreateFileMapping() によって生成されるメモリマップドオブジェクト)上に配置したリングバッファを介して、WEC/WinCE カーネルが出力したログデータを受け渡しします。リングバッファが満杯に近付くと、celog.dll が event オブジェクトを使って CeLogFlush.exe に通知して、リングバッファの内容をファイルへ出力させる、という連携です。リングバッファのサイズは、celog.dll が共有メモリ領域を生成する際に、レジストリの設定値に従って決定します。celog.dll は、共有メモリ上のリングバッファ構造体のヘッダにバッファサイズを書き込むことにより、CeLogFlush.exe にサイズを伝えます。CeLogFlush.exe は、リングバッファが満杯に近付かなくとも(つまり、celog.dll から event オブジェクトで通知されなくとも)、レジストリで設定されたタイムアウト時間が経過すると、リングバッファの内容をファイルへ出力します。従って、ログ出力の量が少ない場合でも、一定周期でログファイルへの書き出しが行われます。

(2)”Enable event tracking during boot” を設定しない場合の動作
 OS Design の「構成プロパティ」の Build Options で、”Enable event tracking during boot” を Yes (IMGCELOGENABLE=1) に設定しない場合とする場合の違いについて、もう少し詳しく述べておきます。

  IMGCELOGENABLE を1に設定した場合としない場合の違いは、WEC/WinCE カーネルの初期化が完了した後から、カーネルの起動が完了するまでの間のログ出力を採取するかどうかです。つまり、IMGCELOGENABLE を1に設定した場合は、CeLogFlush.exe が起動する前に出力されたログも採取できるのに対し、IMGCELOGENABLE を1に設定しない場合は、CeLogFlush.exe が起動した以降のログのみ採取可能となります。この違いは、celog.dll がロードされるタイミングの違いによって生じます。そのタイミングの違いを引き起こすのは、.bib ファイルの設定です。

  WEC 7 の場合、common.bib の設定で、IMGAUTOFLUSH のみ1に設定した場合(IMGCELOGENABLE は1に設定しない場合)は、celog.dll が .bib ファイルの MODULES セクションではなく、FILES セクションに配置されると述べました。この結果、WEC/WinCE カーネルの初期化が完了した直後のタイミングでは、celog.dll がロードされず、CeLogFlush.exe によって初めてロードされるのです。これについて、もう少しだけ詳しく述べます。

  WEC/WinCE カーネルの初期化が終わり、マルチスレッドモードへ遷移して最初に起動されるスレッドが実行する関数である SystemStartupFunc() の中で、LoggerInit() という、ログ機能の初期化関数を呼び出します。この LoggerInit() は、”CeLog.dll” を引数として LoadKernelLibrary() を呼び出し、celog.dll をカーネルにロードすることを要求します。しかし、この時点では、filesys.dll がロードされておらず、ファイルシステム機能が初期化されていません。そのため、カーネルの loader は、OS イメージの中の modules、つまり、.bib ファイルの MODULES セクションに配置された DLL しかロードできないのです(※ちなみに、SystemStartupFunc() は、LoggerInit() を呼び出す前に、LoaderInit() を呼び出してカーネルの loader を初期化します)。そのため、LoggerInit() による CeLog.dll のロードは成功せず、その時点では、ログ出力が有効になりません。その後、CeLogFlush.exe が起動すると、CeLogFlush.exe の初期化処理において、再び “CeLog.dll” を引数として LoadKernelLibrary() が呼び出されます。この時点では、filesys.dll が動作していますので、FILES セクションに配置された DLL もロードできる、というわけです。

  さて、celog.dll は、ロードされると、InitLibrary() という初期化関数を呼び出します。この関数の中で、IOCTL_CELOG_REGISTER を ioctl コードとする KernelLibIoControl() 呼び出しを行い、ログ出力関数群の関数テーブル(CeLogExportTable 構造体)をカーネル本体に登録します。これらの関数は、カーネル本体の中にあるログ出力部に登録されます。カーネル本体の中にあるログ出力部は、登録された関数テーブルの中の pfnCeLogQueryZones というメンバを使って、ログ出力 DLL から、出力対象とする zone の組み合わせを示すマスクビット列を得て、ログ出力の有無判定に使う、という仕組みになっています。

  上で述べた、カーネル本体の処理のソースコードは、それぞれ次の場所にあります:

  SystemStartupFunc()
  %_WINCEROOT%/private/winceos/COREOS/nk/celog/schedule.c

  カーネル本体の中のログ出力部
  %_WINCEROOT%/private/winceos/COREOS/nk/logger/logger.c

(3)Readlog
  Kernel Tracker を使うと、WEC/WinCE カーネルのログ機能が出力したログデータをグラフィカルに表示できることを、冒頭で紹介しました。このログデータ、つまり .clg ファイルの内容を解析する付属のツールは、他にもあります。それが Readlog です。Readlog について、リファレンスの次のページをご覧下さい:

  Readlog Viewing Tool (Windows Embedded Compact 7)
  http://msdn.microsoft.com/en-us/library/ee481220.aspx

  Readlog Viewing Tool (Windows Embedded CE 6.0)
  http://msdn.microsoft.com/en-US/library/ee481220(v=winembedded.60)

  スレッドの切り替わりの様子などを直観的に見るには、Kernel Tracker が便利ですが、Kernel Tracker には表示されないログ内容をチェックしたり、ログ全体の分析結果などを手早く表示するには、Readlog の方が便利です。ちなみに、WinCE 6.0 の Kernel Tracker では、”Thread Migrate” のログを表示できませんが、WEC 7 のものでは表示できます。この “Thread Migrate” は、システムコールの発生、つまり、プロセス(カーネルである nk.exe 以外のプロセス)中のスレッドの、カーネル呼び出しによる、ユーザモードとカーネルモードの間の遷移に伴うコンテキストスイッチを示します。

(4)ログ機能のカスタマイズ
  ここまでの説明では、WEC/WinCE カーネルのログ出力は、celog.dll によって実行されると述べました。しかし、celog.dll を使わず、独自のログ出力 DLL を実装して使うことが可能です。また、独自のログ出力 DLL を celog.dll と共存させることも可能です(複数のログ出力 DLL を共存させることに意味があるかどうかは、別としてですが)。

  独自のログ出力 DLL を実装する方法について、リファレンスの次のページで説明されています。今のところ、WinCE 6.0 向けのものしかありませんが、WEC 7 でも同様の筈です。興味のある方は、カーネル本体のログ出力部や celog.dll のソースコードと併せ、ご覧になってみて下さい。

  CeLog Tool Customization (Windows Embedded CE 6.0)
  http://msdn.microsoft.com/en-us/library/ee480013(v=winembedded.60)

  Implementing a Custom Event Tracking Library (Windows Embedded CE 6.0)
  http://msdn.microsoft.com/en-US/library/ee480279(v=winembedded.60)

  Implementing an Event Tracking Library (Windows Embedded CE 6.0)
  http://msdn.microsoft.com/en-US/library/ee480272(v=winembedded.60)

telnetd と ftpd のユーザ認証

$
0
0

WEC 7/WinCE 6.0 には、皆さんお馴染みの Telnet サーバ(telnetd)と FTP サーバ(ftpd)が付属しています。どちらも、ユーザ認証なしで動かすことができ、開発中のデバイスを、ネットワーク経由で遠隔操作する際に便利です。しかし、ユーザ認証なしのままの設定では、セキュリティ面で大きなリスクがあります。今回は、WEC 7/WinCE 6.0 付属の telnetd と ftpd について、ユーザ認証を有効にする場合に必要な手順を述べます。

■はじめに
telnetd と ftpd は、OS Design のカタログビューでは、次の場所にあります:

・WEC 7 のカタログ項目
 <OS Design 名>
  Core OS
   Windows Embedded Compact
    Communication Services and Networking
     Servers
★     FTP Server
★     Telnet Server

・WinCE 6.0 のカタログ項目
 <OS Design 名>
  コア OS
   CEBASE
    通信サービスおよびネットワーク
     サーバー
★     FTP サーバー
★     Telnet サーバー

これらのカタログ項目を選択することにより、telnetd と ftpd が OS イメージに組み込まれます。

■ユーザ認証無しで動かす場合の設定
冒頭で述べたように、telnetd と ftpd のどちらも、レジストリ設定により、ユーザ認証無しで動かすことができます。次の行を、OS Design のレジストリ設定ファイル、つまり、OSDesign.reg(WEC 7 の場合)や project.reg(WinCE 6.0 の場合)に記述すれば、ユーザ認証無しで動作します。

[HKEY_LOCAL_MACHINE\Comm\TELNETD]
    "IsEnabled"=dword:1
    "UseAuthentication"=dword:0

[HKEY_LOCAL_MACHINE\Comm\FTPD]
    "IsEnabled"=dword:1
    "AllowAnonymous"=dword:1
    "AllowAnonymousUpload"=dword:1
    "NoSystemInfo"=dword:0


telnetd は、UseAuthentication に0を指定すると、接続時にユーザ認証を行いません。ftpd は、AllowAnonymous に1を指定すると、匿名アクセスを許可します。telnetd と ftpd に対するレジストリ設定項目の詳細については、リファレンスの次のページをご覧下さい。

 
 Telnet Server Registry Settings (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee499490

 FTP Server Registry Settings (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee498908

上のページは、WEC 7 のリファレンスですが、WinCE 6.0 の場合も同じです。なお、FTP サーバのレジストリ設定のページ(上の二番目のページ)にある DefaultDir の説明にあるように、デフォルトでは、FTP アカウントのルートディレクトリは /Temp に設定されます。WEC 7/WinCE のルートディレクトリを FTP アカウントでもルートディレクトリとしたい場合は、DefaultDir の値を “\\” にして下さい。

■ユーザ認証を有効にするための設定
telnetd と ftpd のユーザ認証無しのアクセスを禁止して、必ずユーザ認証を行わせるには、レジストリ設定を次のようにして下さい。

  • telnetd のレジストリ設定で、UseAuthentication を指定しないか(デフォルト値は0)、または、明示的に0を指定する。
  • ftpd のレジストリ設定で、AllowAnonymous と AllowAnonymousUpload を指定しないか(デフォルト値は0)、または、明示的に0を指定する。
  • アクセスを許可するユーザを、UserList で指定する。

たとえば、’Administrator’ というユーザにのみアクセスを許可する場合は、レジストリ設定ファイルに次の記述を入れて下さい。

[HKEY_LOCAL_MACHINE\Comm\TELNETD]
    "IsEnabled"=dword:1
    "UseAuthentication"=dword:1
    "UserList"="Administrator"

[HKEY_LOCAL_MACHINE\Comm\FTPD]
    "IsEnabled"=dword:1
    "NoSystemInfo"=dword:1
    "UserList"="Administrator"


上の記述例では、ftpd のレジストリ設定で NoSystemInfo に1を設定することにより、FTP クライアントがシステム情報を要求しても返さないようにしています。telnetd と ftpd のどちらも、平文でパスワードを受け取りますので、セキュリティが高くありません(※そのため、OS Design のこれらのカタログ項目を選択すると、Platform Builder がセキュリティリスクの警告ダイアログを表示します)。多少ともセキュリティを高める方策として、NoSystemInfo に1を指定するのは、悪くない考えだと思います。

さて、これだけでは、telnetd と ftpd にユーザ Administrator で接続することは、できません。次の二つの手順が、追加で必要です:

  1. OS Design に、ユーザ認証のカタログ項目を追加する。
  2. ユーザ登録を実行する。

以下、これらについて順に述べます。

(1)ユーザ認証のカタログ項目
以前に書いたエントリ(「WEC/WinCE から共有ディレクトリ(ファイルサーバ)をアクセス」)で、SMB/CIFS クライアントを組み込む場合には、認証処理に必要なコンポーネントも組み込む必要があると書きました。これと同様に、telnetd と ftpd のユーザ認証機能を有効にする場合も、認証処理用のコンポーネントを組み込まなければいけません。

telnetd と ftpd のユーザ認証では、認証処理用のコンポーネントとして必要なのは NTML です。WEC 7 の場合であれば、次のカタログ項目を選択して下さい。

 <OS Design 名>
  Core OS
   Windows Embedded Compact
    Security
     Authentication Services (SSPI)
★     NTLM

(2)ユーザ登録
ユーザ登録を行うには、アプリケーションから NTLMSetUserInfo() を呼び出して下さい。この関数で、ユーザのアカウント名とパスワードを設定できます。たとえば、OS の起動完了後に自動実行されるアプリケーションを実装し、そのアプリケーションが、NTLMSetUserInfo() を呼び出して telnetd と ftpd のユーザアカウントを登録する、というのが、お手軽な方策でしょう。NTLMSetUserInfo() については、リファレンスの次のページをご覧下さい:

 NTLMSetUserInfo (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee498121

ところで、telnetd と ftpd のレジストリ項目の UserList では、アクセスを許可するユーザを複数指定できるのですが、リファレンスの説明に間違いがありますので、注意して下さい。リファレンスには、許可対象のユーザが複数ある場合、カンマ区切りで指定すると書かれていますが、これはセミコロン区切りの間違いです。WinCE 6.0 のリファレンスの Telnet サーバに関するページには、この間違いを指摘するコメントが寄せられています:

 Telnet Server Registry Settings (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-US/library/ee499490(v=winembedded.60)

上のページの末尾にある Community Content の欄に、”Telnet Server Registry Settings corrections” というコメントがあり、上記の間違いを指摘しています。

UserList の記法の、より正確な説明は、telnetd と ftpd がユーザ認証時に利用している AuthHelpValidateUser() という API 関数を宣言したヘッダファイルに記載されています。この API 関数は、リファレンスに載っていないのですが、
 %_WINCEROOT%/public/common/sdk/inc/authhlp.h
で宣言されており、この authhlp.h の冒頭のコメント中に、より正確な記法の説明があります。その説明によれば、許可するユーザに加えて、拒否するユーザの指定も可能です。

■telnetd と ftpd のソースコード
今回のエントリの最後に、telnetd と ftpd のソースコードの場所を紹介しておきます。リファレンスページにも記載されているのですが、これらのソースコードは、次の場所にあります:

 telnetd
 %_WINCEROOT%/public/servers/sdk/samples/telnetd/

 ftpd
 %_WINCEROOT%/public/servers/sdk/samples/ftpd/

samples というディレクトリの配下に収録されていることからも分かるように、これらは、どちらかといえばサンプルコードという扱いです。実装上の制限が加えられている個所もありますので(たとえば、telnted は、同時接続数は最大9です)、必要であれば、カスタマイズを加えて利用するのが良いでしょう。telnetd のソースコードを改変し、限られたコマンドしか受け付けないようにすることでセキュリティを高める、というのは、その一例だと思います。

IME と、ソフトウェアキーボードに関する tips

$
0
0

■はじめに
ご存じの方も多いと思いますが、WEC/WinCE には、日本語入力の IME (Input Method Editor) が付属しています。WEC 7 ですと、Platform Builder の Catalog Items View で次のカタログ項目を選択して OS Design をビルドすることにより、日本語 IME 3.1 が OS イメージに組み込まれます。

 Core OS
  International
   Language
    Japanese
     Input Method Editor (Choose 1)
★     IME 3.1

日本語入力用の IME として、IME 3.1 に加えて Pocket IME 2.0 も付属しており、Catalog Items View には、IME 3.1 と同じ階層に表示されます。今回は、Pocket IME ではなく、IME についての tips を紹介します。

■IME の初期入力モードの設定
IME の入力モードは、IME ツールバーの入力モードアイコンをクリックして表示されるポップアップメニューで変更できます。これは、WinXP/Vista/Windows 7 と同様です。ただし、WEC/WinCE 付属の IME では、プロパティダイアログで初期入力モードを設定することができません。初期入力モードは、レジストリでのみ設定可能なようです。

IME のレジストリ設定項目は、リファレンスの次のページで説明されています:

 Japanese IME 3.1 Registry Settings (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee491573.aspx

 Japanese IME 3.1 Registry Settings (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-US/library/ee491573(v=winembedded.60).aspx

なお、WinCE 6.0 の方のリファレンスには、”Japanese IME 3.1 Architecture” というページや、”Japanese IME 3.1 Customizable User Interface” というセクションがあり、IME のカスタマイズを行う際に必要となる情報が記載されています。興味のある方は、そちらも御覧になってみて下さい。

さて、初期入力モードを設定するレジストリ項目は、上のページで説明されている、HKEY_LOCAL_MACHINE\Software\Microsoft\IMEJP\3.1\MSIME キーの下の option3 です。この値は、デフォルトでは「ひらがな」入力モードになっています。これを変更して、たとえば「半角英数」入力モードにしたい場合は、0×0000000C を指定します。ただし、0×0000000C そのものを設定すると、「かな入力」になってしまいます。「ローマ字入力」にしたい場合は(※上のページに説明がある通り、デフォルトは「ローマ字入力です)、ローマ字入力を指定する 0×00000001 と組み合わせた値(論理 OR 結合した値)の 0×0000000D を指定して下さい。

つまり、OS Design のレジストリ設定ファイル(OSDesign.reg や project.reg)に次の行を追加して OS イメージをビルドすると、日本語 IME の初期入力モードが「半角英数」になります。

[HKEY_LOCAL_MACHINE\Software\Microsoft\IMEJP\3.1\MSIME]
    "option3"=dword:0000000D

■ソフトウェアキーボードの設定
次に、ソフトウェアキーボード(Software-based Input Panel; SIP)に関する tips です。デフォルトの振る舞いでは、エディットフィールドなど、テキスト入力の GUI 部品にフォーカスが当たると、自動的に SIP が表示されますが、WEC 7 では、この振る舞いを変更できます。

WEC 7 の SIP のレジストリ設定項目のリファレンスは、次のページです:

 Input Panel Registry Settings (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee504097.aspx

このページにある HKEY_CURRENT_USER\ControlPanel\SIP キーの説明を見て下さい。TurnOffAutoDeploy という値を 1 にすると、SIP が自動的に表示されない(are not auto deployed)と書かれています。実際、OSDesign.reg に次の行を追加して OS イメージをビルドすると、SIP が自動表示されません:

[HKEY_CURRENT_USER\ControlPanel\Sip]
    "TurnOffAutoDeploy"=dword:1


注意:リファレンスでは、キーの名前は ‘HKEY_CURRENT_USER\ControlPanel\SIP’ となっていますが、実際は、上の設定例のように、末尾は ‘Sip’ (先頭のみ大文字)が正しいようです。WINCE700\public\COMMON\oak\files/common.reg の記述を見ても、そうなっています。

なお、WinCE 6.0 のリファレンスを見ると、HKEY_CURRENT_USER\ControlPanel\SIP キーに TurnOffAutoDeploy という値がありません:

 Input Panel Registry Settings (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-US/library/ee504097(v=winembedded.60).aspx

WinCE 6.0 の OS Design に上記の TurnOffAutoDeploy の設定を追加して OS イメージをビルドしてみても、SIP が自動表示される動作は変わりません。つまり、WinCE 6.0 までは undocumented だったが実は使えた、という機能ではなく、WEC 7 になって初めて使えるようになった機能のようです。

しかし、Windows Mobile では、TurnOffAutoDeploy の設定が有効だったようで、’TurnOffAutoDeploy’ で Web を検索すると、Windows Mobile の tips として紹介しているページがヒットします。たとえば、次のページです。

 How To Stop Your SIP From Automatically Popping Up
 http://pocketnow.com/tweaks-hacks/how-to-stop-your-sip-from-automatically-popping-up

 Windows Mobile Registry Tricks
 http://www.ehow.com/list_7200029_windows-mobile-registry-tricks.html

Windows Mobile(6.x)のカーネルは WinCE 5.0 だったようですから、念のためにと思い、WinCE 5.0 のリファレンスも見てみましたが、WinCE 6.0 と同様、TurnOffAutoDeploy の記述は、ありません:

 Input Panel Registry Settings (Windows CE 5.0)
 http://msdn.microsoft.com/en-us/library/aa452674.aspx 

真相は分かりませんが、Windows Mobile でのみ提供されていた機能が、ユーザや開発者からの要望により WEC 7 にも追加された、ということなのかも知れません。

タスクバーの電源状態アイコンとバッテリドライバ

$
0
0

■電源管理ドライバとバッテリドライバ
WEC/WinCE の標準シェル(explorer)は、タスクバーに電源状態を示すアイコンを表示します。これは、デフォルトの動作であり、レジストリ設定で変更できます。タスクバーの電源状態アイコン表示に関するレジストリ設定は、リファレンスの次のページで説明されています。このページの、”Display Power Status” の項を見て下さい:

 Windows Embedded Compact Explorer Registry Settings (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee500839.aspx

ただし、OS の実装次第では、このアイコンは表示されません。このアイコンの表示には、電源管理ドライバとバッテリドライバが関係しており、それらの振る舞いによって、アイコンの表示動作が変わります。それぞれのソースコードは、WEC 7/WinCE 6.0 の次の場所にあります。

・タスクバーの電源アイコン表示
 %_WINCEROOT%/public/shell/oak/hpc/explorer/taskbar/power.{h,cpp}

・電源管理ドライバ
 %_WINCEROOT%/public/COMMON/oak/drivers/pm/

・バッテリドライバ
 %_WINCEROOT%/public/COMMON/oak/drivers/battdrvr/

電源管理ドライバとバッテリドライバは、どちらも二層構造の階層型ドライバ(layered driver)であり、MDD (Model Device Driver) と PDD (Platform Device Driver) で構成されています。階層型ドライバについては、WEC 7 のディベロッパーガイドにある次のページをご覧下さい:

 Layered and Monolithic Drivers (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/jj659821.aspx

PDD の実装は、プロセッサや CPU ボードの特性により、必要に応じてカスタマイズしますので、BSP (Board Support Package) にカスタマイズ部分が含まれます。カスタマイズの有無は BSP ごとに違いますが、WEC 7 付属の BSP ですと、Freescale i.MX313 のリファレンスボード用の BSP には、電源管理ドライバとバッテリドライバの両方のディレクトリが収録されています。次の場所です。

 %_WINCEROOT%/platform/IMX313DS/SRC/DRIVERS/BATTDRVR/
 %_WINCEROOT%/platform/IMX313DS/SRC/DRIVERS/PM/

この BSP の電源管理ドライバの方は、実は WEC 7 付属のものと違いません。上の PM/ ディレクトリには、ソースファイルは入っておらず、カスタマイズされていないのです。実際、sources ファイルを見ても、WEC 7 付属のデフォルト実装の .lib ファイルをリンクして pm.dll を生成する記述になっています。もしかすると、この BSP をもとにして電源管理ドライバをカスタマイズする開発者のために、テンプレートとして収録しているのかも知れません。

■電源状態の検出と表示
タスクバーに話を戻します。タスクバーは、現在の電源状態を表示に反映するために、電源管理ドライバが提供する電源状態監視機能を利用しています。電源管理 API の関数である RequestPowerNotifications() を呼び出すことにより、電源状態の変更をメッセージキューで受け取ることができます。そのメッセージキューに電源状態の変更通知が届いたことを検出すると、電源状態アイコンの表示を変更して通知内容を反映させるのです。

タスクバーのソースファイルの中で、電源管理ドライバから電源状態の変更通知を受け取る個所は、
 %_WINCEROOT%/public/shell/oak/hpc/explorer/taskbar/
ディレクトリの taskbar.cpp です。このソースファイルにある CTaskBar::MessageLoop() の中で、RequestPowerNotifications() の呼び出しと、MsgWaitForMultipleObjectsEx() を使ったメッセージループを実行します。メッセージループにおいて、MsgWaitForMultipleObjectsEx() を使ってウィンドウズメッセージのキューとメッセージキューを同時に監視して、届いたメッセージに対する応答動作を実行します。電源状態アイコン表示の変更は、冒頭で挙げた power.{h,cpp} で定義・実装されている PowerManagerUI クラスが担当します。

RequestPowerNotifications() のリファレンスは、次のページです:

 RequestPowerNotifications (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee497721.aspx

以上が、タスクバーと電源管理ドライバの連携の仕組みです。次に、電源管理ドライバとバッテリドライバの連携を見てみましょう。

電源管理ドライバは、バッテリドライバから PowerPolicyNotify() の呼び出しによって電源状態の通知を受け取ります。PowerPolicyNotify() によって、電源管理ドライバが読み出すメッセージキューに通知メッセージが投入され、その結果、タスクバーなど、電源状態監視機能のクライアントへ通知されるというわけです。

PowerPolicyNotify() のリファレンスは、次のページです:

 PowerPolicyNotify (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee497744.aspx

PowerPolicyNotify() のソースコードは、
 %_WINCEROOT%/private/winceos/COREOS/core/thunks/tpm.cpp
にあり、この関数によってメッセージが投入されるメッセージキューから読み出しを行う処理は、
 %_WINCEROOT%/public/common/oak/drivers/pm/pdd/common/pddpolicy.cpp
 %_WINCEROOT%/public/common/oak/drivers/pm/pdd/default/pwsdef.cpp
で実装されています。興味がある方は、ご覧になってみて下さい。PmPolicyReadNotificationQueue() というのが、pdbpolicy.cpp で実装されている、メッセージキューから読み出しを行う関数です。

■バッテリドライバによる電源状態監視
バッテリドライバは、電源状態を監視して、状態変化を検出した際に電源管理ドライバへ通知しますが、そのためにスレッドを起動します。このスレッドが実行する手続きは、
 %_WINCEROOT%/public/common/oak/drivers/battdrvr/mdd/battdrvr.c
で実装されている BatteryThreadProc() です。このスレッドを生成する際、CreateThread() の第5引数(fdwCreate)に CREATE_SUSPENDED を渡しており、サスペンド状態で生成されます。従って、ResumeThread() を呼び出すまでは、このスレッドは動作しません。

このスレッドに対して ResumeThread() が呼び出されるのは、バッテリドライバに対して IOCTL_BATTERY_POSTINIT という制御コードで DeviceIoControl() が呼び出された場合です。それまでの間は、バッテリドライバ内の電源状態監視スレッドはサスペンド状態で生成されたままとなり、電源状態の監視動作は行われません。この結果、タスクバーには、電源状態アイコンが表示されないのです。

今回のエントリの冒頭で、「ただし、OS の実装次第では、このアイコンは表示されません。」と書きましたが、それは、このことを指したものなのです。つまり、OS の起動時にバッテリドライバ(デバイス名は BAT1:)に対して IOCTL_BATTERY_POSTINIT の DeviceIoControl() を呼び出さないと、OS が起動してタスクバーが表示された直後に、AC 電源接続を示すアイコンが表示されたのち、そのアイコンの表示は消えてしまいます。

バッテリドライバに対して IOCTL_BATTERY_POSTINIT の DeviceIoControl() を呼び出さないと(つまり、バッテリドライバの電源状態監視スレッドを始動しないと)電源状態アイコンの表示が消えてしまうのは、電源管理ドライバが持っている電源状態のキャッシュが、無効な内容で初期化されたままになるからです。このキャッシュは、
 %_WINCEROOT%/public/common/oak/drivers/pm/pdd/default/platform.cpp
で宣言されている gSystemPowerStatus という名前の、POWER_BROADCAST_POWER_INFO 型の大域変数です。gSystemPowerStatus は、
 C:\WINCE700\public\common\oak\drivers\pm\pdd\common\pddpower.cpp
で実装されている PmInitPowerStatus() で全てのフィールドを無効値(0xFF)に初期化されます。そのため、バッテリドライバの電源状態監視スレッドがサスペンドしたままだと、キャッシュの内容は更新されず、RequestPowerNotifications() の呼び出しに対して最初に一回だけ送付する電源状態通知の内容が無効値となります。その結果、タスクバーが電源状態アイコンの表示を消すのです。

バッテリドライバに対して IOCTL_BATTERY_POSTINIT の DeviceIoControl() 呼び出しを行うと、バッテリドライバの電源状態監視スレッドが一定間隔(デフォルトは5秒)で電源状態の取得動作を実行しますので、電源管理ドライバが持つ電源状態のキャッシュが正しい内容となります。すると、タスクバーに電源状態アイコンが表示されます。

バッテリドライバの電源状態監視スレッドが、デフォルト実装では停止したままになるのは、不要にスレッドを動かして CPU リソースを消費することを避けるためなのでしょう。電源状態監視スレッドは、バッテリ駆動のハードウェアで OS が動作する場合にのみ動作させればよいわけです。デフォルト実装では AC 電源接続としていますから、電源状態監視スレッドを始動しないようになっているのではないかと思います。

■電源状態アイコン表示のレジストリ設定
最後に、レジストリ設定について補足します。バッテリ駆動のハードウェアで動かす場合に、バッテリドライバをカスタマイズして、電源状態の監視処理の実装を行ったとしましょう。そして、OS の起動時に自動実行されるアプリケーションなどを使って、バッテリドライバの電源状態監視スレッドを始動するようにした場合です。

バッテリドライバによって、電源監視状態の監視は行うが、タスクバーに電源状態アイコンを表示したくない、という場合は、レジストリ設定を変更する必要があります。デフォルトでは、バッテリドライバの電源監視スレッドが動作すると電源状態アイコンが表示されるからです。電源状態アイコンをタスクバーに表示させないためのレジストリ設定は、次の二通りです:

 ・HKEY_LOCAL_MACHINE\Software\Microsoft\Power キーの ShowIcon の値に 0 を設定する。

 ・HKEY_LOCAL_MACHINE\Software\Microsoft\Power キーのみをレジストリに登録して、ShowIcon は設定しない。

ShowIcon の値は、デフォルト値が 0 として扱われるため、HKEY_LOCAL_MACHINE\Software\Microsoft\Power キーの下に ShowIcon が存在しなければ、0 として扱われます。ただし、HKEY_LOCAL_MACHINE\Software\Microsoft\Power キーそのものが存在しない場合は、デフォルト値として 1 が使われるのです。バッテリドライバのデフォルトの設定では、HKEY_LOCAL_MACHINE\Software\Microsoft\Power キーがレジストリに登録されないため、ShowIcon の値が 1 として扱われ、電源状態アイコンが表示されます。


WEC 7 付属の gdiplus.dll

$
0
0

■WinCE/WEC と GDI+
Windows XP で導入された 2D 描画用の API である GDI+ は、WinCE では利用できません。しかし、Windows Mobile では、gdiplus.dll という DLL が組み込まれており、この DLL により、GDI+ の API を利用できたようです。

たとえば、MSDN フォーラムの “Visual Basic and C# Projects” に投稿された “How to use GDI+ on Windows Mobile?” という質問に対して、Windows Mobile において非公式 API ではあるものの、GDI+ を利用できるというコメントが寄せられています:

 How to use GDI+ on Windows Mobile?
 http://social.msdn.microsoft.com/forums/en-US/vssmartdevicesvbcs/thread/e01dfedb-9b79-468b-9e89-44f59952b2d8

そのコメントでも紹介されている次のページは、GDI+ の Flat API を .NET CF アプリケーションから使うための wrapper ライブラリを提供しています。

 Using GDI+ on Windows Mobile
 http://community.opennetcf.com/articles/cf/archive/2007/10/31/using-gdi-on-windows-mobile.aspx

御存知の方は多いと思いますが、フル版の .NET Framework では、描画 API の実装に GDI+ が用いられています。たとえば、System.Drawing.Graphics クラスの DrawArc() や DrawBezier() などです。しかし、.NET Compact Framework では、System.Drawing.Graphics クラスには DrawArc() や DrawBezier() メソッドが存在しません。上記の wrapper ライブラリは、GDI+ の Flat API を P/Invoke によりマネージドコードから呼び出すためものです。

上のページでは、gdiplus.dll が提供している GDI+ API は、デスクトップ版のサブセットであり、「未実装」エラーを返す関数が多くあると述べています。しかし、サブセットであっても、GDI の API だけでは不足する 2D 描画機能を利用したいと思うことは、少なくありません。gdiplus.dll を WinCE でも使いたいと思う人は多いようで、’gdiplus.dll WinCE’ などで検索すると、「WinCE には gdiplus.dll が付属していないのか?」という質問のページが多く見つかります。

実は、WEC 7 には、gdiplus.dll が付属しています。

■WEC 7 の gdiex/ ディレクトリ
冒頭でも述べたように、WinCE には gdiplus.dll が付属しておらず、GDI+ の API を利用できません。しかし、WEC 7 では、
 %_WINCEROOT%/public/gdiex/
ディレクトリ配下に gdiplus.dll と gdiplus.lib が収録されているのです。このディレクトリは、WinCE 6.0 にも存在しますが、配下に収録されているのは、Imaging API のヘッダファイルとライブラリファイル(.lib)だけです。

gdiplus.dll に関する説明は、WEC 7 のリファレンスには存在しません。Windows Mobile でそうだったように、非公式な API という位置づけのようです。SKU との対応も不明ですから、もし、gdiplus.dll を組み込んだ OS イメージを製品に搭載することを検討される場合には、ランタイムライセンスの販売代理店経由で Microsoft 社に確認する方が良いでしょう。

WEC 7 に gdiplus.dll が付属していることの理由は不明ですが、もしかすると、一部の開発者からの強い要望を受けて、Windows Mobile 向けに提供していたものを WEC 7 にも収録した、ということなのかも知れません。いずれにせよ、便利な機能が付属しているわけですから、もしライセンス上も支障なければ、利用できると嬉しいところです。

■ベジェ曲線描画の動作確認
というわけで、WEC 7 付属の gdiplus.dll を使った描画について、簡単なテストコードを書いて試してみました。制御点が二つだけの単純なベジェ曲線の描画ですが、Flat API を C/C++ から呼び出すコードを書いて動かしてみたところ、問題なく動作しました。ただし、パフォーマンスは評価・実測していません。

以下に、テストコードの関連部分を引用します:

static void
DrawWithGdiPlus(HDC hdc)
{
#define MAKE_ARGB(a, r, g, b) \
    (((ARGB)(b) 


上記のテストコードを動かした画面キャプチャが、次の図です。

bezier-spline

なお、上の画面キャプチャは、2012/7/4 に書いたエントリ(「デバイスエミュレータで WEC 7 を動かす」)で紹介した、デバイスエミュレータに移植した WEC 7 でテストコードを動かした様子です。興味のある方は、ご自分でテストコードを書いて試してみて下さい。

上のテストコードについて、二点補足しておきます。

  1. GdiPlus.h のインクルードが必要。さらに、上記のコードの場合、Gdiplus と Gdiplus::DllExports に対する using ディレクティブが必要。
  2. GdiPlus.h を始め、GDI+ のヘッダファイルは WEC 7 に付属しないので、別途入手が必要。
  3. アプリケーションの初期化処理と終了処理で、それぞれ、GDI+ の初期化関数と解放関数を呼び出さなければならない。

上記のテストコードのビルドと動作確認を行う際、GDI+ のヘッダファイルは、次のページで公開されているライブラリ(LibGdiplus)に収録されているものを使いました。

 GDI+ for Windows Mobile
 http://www.ernzo.com/LibGdiplus.aspx

このライブラリは、Windows Mobile に収録されている gdiplus.dll 用の wrapper です。冒頭で紹介した wrapper ライブラリとは異なり、マネージドコードではなく、C/C++ 用の wrapper です。

GDI+ の初期化関数と解放関数は、GdiplusStartup() と GdiplusShutdown() です。詳細は、GDI+ のリファレンスをご覧下さい:

 GDI+ Reference > Functions
 http://msdn.microsoft.com/en-us/library/windows/desktop/ms534055(v=vs.85).aspx

GDI+ の Flat API のリファレンスは、次のページに記載されています。

 GDI+ Flat API
 http://msdn.microsoft.com/en-us/library/windows/desktop/ms533969(v=vs.85).aspx

■GDI+ の代替ライブラリ
WEC 7 には gdiplus.dll が付属しており、それを OS イメージに組み込むことで GDI+ の API(のサブセット)を利用できることを、上で紹介しました。では、WinCE 6.0 で GDI+ の API を利用したい場合には、何か方法はないのでしょうか?

簡単な代替策は、ありません。前の節で紹介した LibGdiplus のページ("GDI+ for Windows Mobile")では、Mono プロジェクトの LibGdiplus を紹介していますが、(その紹介でも述べられているように)そのまま使うことは、できません。Mono プロジェクトの LibGdiplus は、X Window System に依存した実装だからです:

 Libgdiplus
 http://www.mono-project.com/Libgdiplus

Mono プロジェクトの Libgdiplus は、Cairo という 2D 描画ライブラリを利用しているようですが、WinCE 6.0 で使えるようにするためには、X Window System に依存した部分の実装を、WinCE へ移植する必要があるでしょう。その移植作業は、移植対象の API 関数を一部に絞ったとしても、それなりに大きな手間だと思われます。

なお、GDI+ が提供する 2D 描画 API のうち、ベジェ曲線(Bezie-spline 曲線)の描画だけであれば、自前で実装したサンプルコードが CodeProject サイトの次のページで公開されています。

 Drawing Qubic Bezier-splines on Pocket PC
 http://www.codeproject.com/Articles/9862/Drawing-Qubic-Bezier-splines-on-Pocket-PC

このサンプルコードの動作確認は行っていませんが、おそらく、WinCE/WEC でも問題なく使えるんじゃないかと思います。

■まとめ
今回は、WEC 7 に付属している GDI+ の DLL(gdiplus.dll)について紹介し、単純なベジェ曲線であれば、問題なく動作することを述べました。gdiplus.dll が、先日発表のあった WEC の次のバージョン(Windows Embedded Compact 2013)でも提供されるのかどうかは、現時点では不明です。しかし、WEC 7 に限定すれば、GDI だけでは不足する 2D 描画機能を実現するために gdiplus.dll の利用を検討することは、価値があるかも知れません。

なお、OS やミドルウェアベンダーの近年の動きを見ていると、高機能な 2D 描画は、3D 描画のグラフィクス機能に統合されるのが一般的な方向性のように思われます。Windows の場合でも、GDI/GDI+ を置き換えていくものとして Windows 7 で導入された Direct2D は、Direct3D の上に実装されているそうです:

 Introducing Direct2D
 http://msdn.microsoft.com/en-us/magazine/dd861344.aspx

今後、Windows Embedded Compact におけるグラフィクス機能が、どのように改良ないしは変革されていくのか分かりません。WEC 7 において gdiplus.dll が追加されたことは、もしかすると、Windows Embedded Compact の歴史における、一過性のものだとして捉えておく方が確実かも知れません。

とはいえ、WEC 7 は、2011年のリリースから7年後の、2018年までは、無償サポートが継続する予定です。従って、開発のターゲットを WEC 7 に絞れば、その他の API やミドルウェアと同様に、gdiplus.dll はアプリケーション開発の有力なツールとなり得るでしょう。この点は、WinCE/WEC の Long Term Suppport の利点だと思います。

insmod と ActivateDevice()

$
0
0

今回は、WEC/WinCE の、カーネルモジュールを動的にロード/アンロードする方法について述べます。Linux を御存知の方であれば、insmod や modprobe、rmmod に相当するものだといえば分かるでしょう。

■デバイスドライバの動的ロードとアンロード
Linux の insmod コマンドに相当するコマンドプログラムは、WEC/WinCE には存在しませんが、同様のことを実現可能な API が提供されています。それが、ActivateDevice[Ex]() です。

 ActivateDevice (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee484864.aspx

 ActivateDeviceEx (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee484469.aspx

これらの API を使ってデバイスドライバをロードする手順は、次の通りです:

1.) ロードするデバイスドライバを DeviceManager に登録するための、レジストリ項目を設定する。

2.) ActivateDevice[Ex]() を呼び出す。

デバイスドライバを使い終え、必要なくなったら、DeactivateDevice() を呼び出します。これで、カーネル内にロードされていたデバイスドライバの DLL がアンロードされます。

上の手順を insmod コマンドの場合と比べると、レジストリ設定が必要なぶん手順が一つ多いですが、十分シンプルだと言えるでしょう。レジストリに設定する項目は、そのドライバ用のサブキー配下の ‘Dll’ と ‘Prefix’ だけです。以下は、’MyDriver’ という名前で、デバイスファイル名に使われる3文字プレフィクスが ‘MYD’ というドライバの例です:


[HKEY_LOCAL_MACHINE\Drivers\AddOn\MyDriver]
   "Dll"="MyDriver.dll"
   "Prefix"="MYD"

上の例では、レジストリキー HKEY_LOCAL_MACHINE\Drivers の下に、動的ロード対象の意味で ‘AddOn’ というサブキーを割り当て、その下に、ドライバ用のサブキー ‘MyDriver’ を設定しています。

■LoadKernelLibrary()
ところで、Linux の insmod コマンドは、カーネルのローダブルモジュールをロードすることができ、対象はデバイスドライバに限定されていません。一方、WEC/WinCE の ActivateDevice[Ex]() は、DeviceManager が管理するデバイスドライバに対象が限定されています。

実は、WEC/WinCE にも、ローダブルモジュール(DLL)をカーネルにロードさせる API があります。LoadKernelLibrary というのが、その関数です。ただし、以下のリファレンスページで説明されているように、この API は、カーネルのログ機能を司る CeLog.dll と、カーネルデバッガの DLL をロードする用途に限定されています。実際には、それ以外の DLL もロードは可能だと思いますが、推奨はされないと考えて下さい。

 LoadKernelLibrary (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee478202.aspx

WEC/WinCE カーネルのログ機能と、ログデータの解析ツール(Kernel Tracker)については、2012/08/16 に書いたエントリ(「CeLogFlush.exe と Kernel Tracker」)で紹介しました。このエントリで、ログ機能を有効にしていないデバイスに対しても、一時的にログ機能を有効にできると書きました。CeLogFlush.exe は、LoadKernelLibrary() を呼び出すことにより、カーネルに CeLog.dll をロードさせるのです。

■動的ロードについて、もう少し
DLL をプロセスにロードする API として、LoadLibrary() がありますが、カーネル内部でも、デバイスドライバをロードする際に LoadLibrary() を呼び出す場合があります。これについては、ActivateDeviceEx() のリファレンスで説明されています。

通常は、ドライバのロードには LoadDriver() という関数が使われるのですが、ロードするドライバに対して ‘Flags’ というレジストリ項目が設定されていて、その値が 0×2 ビット(DEVFLAGS_LOADLIBRARY)を含んでいる場合は、LoadLibrary() が使われます。LoadLibrary() と LoadDriver() の違いは、ロード対象の DLL に対してデマンドページングを行うかどうかです。LoadDriver() は、ロードする DLL をデマンドページングの対象外とします。

WEC/WinCE カーネルのデマンドページングについては、リファレンスの次のページで説明されています。

 Demand Paging Considerations (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-us/library/ee482784(v=winembedded.60).aspx

時間制約の厳しいデバイスドライバの場合は、LoadDriver() によりデマンドページング無しでロードします。これが通常動作です。一方、サイズが大きく、かつ、時間制約も厳しくないドライバの場合には、LoadLibrary() を使うことにより、デマンドページング有りでロードすれば、メモリ使用量を抑えることが可能というわけです。

デバイスドライバにおいて、通常動作ではデマンドページング無しでロードするのは、リアルタイム性を確保するための仕組みです。WinCE 6.0 のリファレンスには、上のページを含む、“Real-Time Performance” という節があります。興味のある方は、ご覧になってみて下さい。

WEC 7 のリファレンスには、デマンドページングについて述べたページは見当たりませんが、割り込み応答動作のタイミングを計測するツール(ILTiming.exe)の説明などが載っています。こちらも、参考になるでしょう:

 ILTiming.exe Real-Time Measurement Tool (Windows Embedded Compact 7)
 http://msdn.microsoft.com/en-us/library/ee483144.aspx

WEC 7 の WMP サンプルアプリケーション

$
0
0

■Microsoft Silverlight for Windows Embedded の修正にまつわる問題と対処
WEC 7 で、付属のメディアプレイヤーアプリケーション(Music Player, Photo Viewer, Video Player)を組み込んだ OS イメージをビルドしていらっしゃる方は、月例アップデータを適用する場合、注意する必要があります。今年リリースされた月例アップデータの中に、適用すると、これらメディアプレイヤーアプリケーションが動作しなくなる症状を引き起こすものがあるからです。

具体的に言うと、Microsoft Silverlight for Windows Embedded に対する修正が多く投入された Monthly Update May 2014 において、その問題を確認しています。これは、不具合というよりは、月例アップデータのパッケージング上の問題だと思います。Monthly Update May 2014 には、以下の8件の修正が投入されているのですが、この中に、問題の要因があるようです:

 Windows Embedded Compact 7 Monthly Update May 2014
 http://www.microsoft.com/en-us/download/details.aspx?id=43368

  FIX: Cannot display all UI elements correctly in a SWE application for Windows Embedded Compact 7
  FIX: Storyboard doesn’t run if it references a custom DependencyProperty in Windows Embedded Compact 7
  FIX: Poor performance when you use XAMLRuntime OpenGL in Windows Embedded Compact 7
  FIX: Cannot receive the GID_END gesture message in an SWE application on a Windows Embedded Compact 7-based device
  FIX: An update is available about adding the GetTemplateChild method to the SWE IXRControl class in Windows Embedded Compact 7
  FIX: Setting DataContext to null resets two-way binding in the SWE application in Windows Embedded Compact 7
  FIX: ListBox selection issue when you use touch gestures in an SWE application on a Windows Embedded Compact 7-based device
  FIX: A RadioButton in a ListBox control stays in checked state when removed and re-added in Windows Embedded Compact 7

このアップデータを適用する前に、メディアプレイヤーアプリケーションを組み込んだ OS イメージをビルドしたことがある場合、このアップデータを適用してから OS イメージをビルドすると、その OS 上でメディアプレイヤーアプリケーションを起動しようとすると、起動時にアプリケーション内部で例外送出が起き、起動しないのです。この症状は、OS イメージをビルドする際、Platform Builder のソリューションエクスプローラで以下のフォルダ配下をリビルドすることで解決できます:

 C:/WINCE700/
  public/
   mediaapps/
    oak/
     samples/
★     cemp

‘cemp’ ディレクトリ配下に、メディアプレイヤーアプリケーションのソースコードがあります。アップデータを適用後、このディレクトリ配下をリビルドしてから OS イメージをビルドする(※OSDesign をリビルドする)ことにより、メディアアプリケーションが起動しないという問題が解消します。

この問題の原因は不明ですが、アップデータに含まれる Silverlight for Windows Embedded (SWE) の修正において、バイナリ互換性を壊してしまったものがあり、そのため、アプリケーションをリビルドしなければならない、ということのようです。

■問題の発生要因
さて、このような問題は、通常起きませんし、起きてはならないことだと思います。WEC 7 に付属しているコンポーネントが、アップデータの適用によって動作しなくなるということは、通常は考えられない事態です。実際、僕は初めて体験しました。特殊な状況だと思います。

この問題ですが、冒頭の方で、「不具合というよりは、月例アップデータのパッケージング上の問題だと思います。」と述べました。どういうことかといえば、ビルド済みの中間バイナリファイルが要因なのです。メディアプレイヤーアプリケーションと同様、WEC 7 に付属するアプリケーションである標準シェル(explorer.exe)や IE 7 は、メディアプレイヤーと同様、アプリケーション部分はソースファイルが付属するのですが、ビルド済みの中間バイナリファイル(.lib)も付属しており、手作業で明示的にソースファイルをビルドしない限りは、ビルド済みの中間バイナリファイルをリンクしてアプリケーションの .exe が生成されます。仮に、それらのアプリケーションとのバイナリ互換性を壊す修正が OS 本体に加えられた場合は、アプリケーションのビルド済み中間バイナリファイルも、修正と一緒に配布されるでしょう。従って、メディアプレイヤーアプリケーションで起きたような問題は、発生しないのです。

一方、メディアプレイヤーアプリケーションは、ソースファイルしか付属していないため、バイナリ互換性を壊す修正が OS 本体に加えられても、それに対応したビルド済み中間バイナリファイルはアップデータに含まれません。OS イメージをビルドする際、メディアプレイヤーアプリケーションのソースが未だビルドされていない場合は、ビルドされて、ビルド済み中間バイナリファイルが、ソースファイルのディレクトリ内に生成されます。OS イメージをビルドする際に、メディアプレイヤーアプリケーションのソースファイルから生成されたビルド済み中間バイナリファイルは、ソースファイルが更新されるか、または、手作業で明示的にソースファイルをリビルドしなければ更新されません。これが、上述した問題の原因、というわけなのです。

今回紹介した、Silverlight for Windows Embedded アプリケーションが月例アップデータ適用後に動作しなくなる、という問題は、僕は初めて体験しました。特殊なケースだとは思いますが、月例アップデータ、および、メディアプレイヤーアプリケーション(WMP サンプルアプリケーション)の WEC 7 における提供のされ方に要因があり、今後も起こる可能性がある問題だと思います。月例アップデータを適用する際には、適用前に、どのような修正が加えられたのかを確認し、Silverlight for Windows Embedded に関する修正の場合は、注意される方が良いと思います。

OS Design から生成した SDK インストーラの問題(日本語ロケール)

$
0
0

■はじめに
Windows Embedded Compact (WEC) では、OS のコンフィグレーション、つまり OS Design に対応した SDK を作成できることは、皆さんご存知の通りです。もし、OS Design に対応した SDK を作成する方法をご存知ないのであれば、開発者ガイドの次のページが参考になります:

 Create an SDK (Compact 7)
 http://msdn.microsoft.com/en-us/library/jj200346(v=winembedded.70).aspx

 Build an SDK (Compact 2013)
 http://msdn.microsoft.com/en-us/library/dn197930.aspx

OS Design に対応した SDK を使ってアプリケーションを作成することにより、アプリケーションと OS のコンフィグレーションの食い違いが起きるのを防ぐことができる、というわけです。たとえば、DirectShow を組み込んでいない OS で動かすアプリケーションを作成する際に、誤って DirectShow API を呼び出すコードを書いてしまうという手違いが、なくなります。そのようなコードを書いても、OS に組み込まれていない API を宣言したヘッダファイルやライブラリは、SDK には組み込まれていないので、アプリケーションをビルドする際にビルドエラーとなるからです。

ところで、WEC 7 の開発環境では、この SDK に少しだけ問題があります。作成した SDK のインストーラで、画面表示が不適切になってしまう箇所があるのです。下の図を見て下さい。

  OEM EULA Dialog

この図は、SDK のインストーラの、使用許諾契約書 (EULA; End-User License Agreement) の表示・同意確認画面ですが、「同意しない」 (Decline) のラジオボタンが途中で切れてしまい、見えていません(※「同意」までしか見えていません)。これは、ユーザに不親切で、適切ではありません。SDK をビルドする際、日本語ロケールに設定せず、英語ロケールにした場合には、”Accept” と “Decline” という二つのラジオボタンが正しく表示されるのですが、日本語ロケールだと、上の図のように、表示が途中で切れてしまうのです。

これは、どちらかといえば、WEC 7 の開発ツールの不具合ですが、少なくとも2014年8月までにリリースされたアップデータでは、修正されていません。しかし、ご安心下さい。この不具合は、自分で修正することができます。

■SDK インストーラのテンプレート
上で紹介した開発者ガイドのページで説明されているように、SDK を作成してビルドすると、SDK のインストーラ(.msi ファイル)が生成されるのですが、この .msi ファイルは、ビルドのたびに一から生成されるのではなく、テンプレートを元にして生成されます。このテンプレートは、WEC 7/Visual Studio 2008 の場合ですと、次のディレクトリに配置されています:

 C:/Program Files (x86)/Microsoft Platform Builder/7.00/cepb/ideVS/SdkTools/RollerFiles

注:上のディレクトリパスは、64bit OS の場合です。32bit OS では、’Program Files’ の後の ‘(x86)’ は、ありません。

上のディレクトリには、.msi ファイルのテンプレートの他、使用許諾契約書のテンプレートや、SDK のビルド時に実行される VB スクリプト(.vbs ファイル)も収録されています。興味のある方は、それらの内容をご覧になってみて下さい。

さて、今回重要なのは、.msi ファイルのテンプレートです。日本語ロケール用のテンプレートファイルは、拡張子の前に ‘_1041′ が付いており、
 template_1041.msi
というのが、日本語ロケール用のものです。このテンプレートには、SDK のダイアログのリソースも入っており、それを修正することで、上述した画面表示の問題を解消できます。では、.msi ファイルの内容を、どうやって修正すればよいのでしょうか?

ご安心下さい。Visual Studio には、.msi ファイルの内容を編集できる orca というツールが付属しています。このツールを使えば、.msi ファイルを開いて、インストーラのダイアログのリソースを編集できるのです。

■インストーラのテンプレートを修正する
orca を使うには、まずインストールしなければいけません。Visual Studio や WEC の開発環境(Platform Builder)をインストールしただけでは、orca はインストールされないのです。orca のインストーラが付属しているので、それを使ってインストールして下さい。orca のインストーラは、C:/Program Files (x86)/ ディレクトリ(※32bit OS の場合は、C:/Program Files/ ディレクトリ)で、’orca’ を含む名前のファイルを検索すれば見つけることができます。VS 2008 + WEC 7 をインストールしていれば、
 C:/Program Files (x86)/Windows Kits/8.0/bin/x86/
というディレクトリの中に、Orca-x86_en-us.msi というファイルが見つかるでしょう。もし、この他に、
 C:/Program Files (x86)/Orca/
というディレクトリと、その中に入っている Orca.exe というファイルが見つかる場合には、既に orca がインストールされています。orca がインストールされていない場合は、見つかったインストーラを実行して、インストールして下さい。

orca をインストールして使えるようになったら、いよいよ、日本語ロケールの SDK のインストーラのテンプレート(.msi ファイル)を開いて修正です。おっと、その前に、修正する .msi ファイルのバックアップをとっておいて下さい。万が一、修正作業で手違いが起きても、元の状態に戻せるようにするためです。

orca の使い方については、次のページが参考になるでしょう:

 Orca データベース エディタを使用して Windows インストーラ ファイルを編集する方法
 http://support.microsoft.com/kb/255905/ja

問題の、使用許諾契約書の表示・同意確認画面のラジオボタンの表示設定は、’Control’ テーブルに入っています。下に、’Control’ テーブルの該当行を編集しようとしている様子を写した画面キャプチャを示します。

 orca edit window

上の図の、選択されて青くハイライトされているのが、Control テーブルの該当行です。この行は、’OEM_EULA_Dlg’ というダイアログの、Control カラムの値が ‘Buttons’、Type カラムの値が ‘RadioButtonGroup’ という行です。この行の ‘Width’ というカラムに、二つのラジオボタンで構成されたラジオボタングループの表示幅が格納されています。日本語ロケールの SDK インストーラで表示が切れてしまうのは、この幅が、英語表示だと足りるものの、日本語表示だと足りない値だからなのです。従って、この幅の値を増やしてやれば、表示が切れなくなります。上の画面キャプチャで、黄色くハイライトされているカラムは、値が 135 ですが、これを 170 に変更すると、「同意しない」というキャプションが、正しく表示されるようになります。

.msi ファイルの編集中に、編集結果を確認したい場合には、orca の ‘Tools’ メニューから ‘Dialog Preview…’ を選択すれば、ダイアログ表示をプレビューできます。試してみて下さい。

IE 7 での日本語表示と AC3 フォント圧縮

$
0
0

2012/07/13 に書いたエントリ(「WEC 7 の Meiryo フォント」)で、「Meiryo フォントを OS イメージに組み込む場合は、カタログ項目の “Monotype Imaging AC3 Font Compression” を選択しては、いけません。」と書きました。この Monotype Imaging AC3 Font Compression は、Meiryo フォントを組み込まない場合にも注意が必要なケースのあることが分かりました。それは、IE 7 を組み込む場合です。

Monotype Imaging AC3 Font Compression を組み込んだ OS イメージで IE 7 を動かすと、日本語ページを表示する際に、IE 7 内部で例外送出が繰り返し発生し、表示までに長い時間を要したり、あるいは、日本語テキストが表示されない場合もある、という問題があるのです。この問題は、少なくとも ARMv5 と ARMv7 のプロセッサでは発生することを確認しています。僕自身は確認していませんが、x86 では発生しないようです。

IE 7 で日本語ページを表示する際、Monotype Imaging AC3 Font Compression を組み込んだ OS イメージでは、次のようなログが繰り返し出力されます:


  48706 PID:5d80026 TID:5de002e Exception 'Raised Exception' (0xe06d7363): Thread-Id=05de002e(pth=c04a20c0), Proc-Id=05d80026(pprc=c049c8b8) 'iesample.exe', VM-active=05d80026(pprc=c049c8b8) 'iesample.exe'
  48706 PID:5d80026 TID:5de002e PC=400512c8(coredll.dll+0x000412c8) RA=800956f0(kernel.dll+0x0000e6f0) SP=00148ad0, BVA=00148b0c

IE 7 で日本語ページを表示する際に、繰り返し例外送出が起きて表示に時間を要する、という問題は、以前にも経験していたのですが、その時は、原因が分からず、対策をとっていませんでした。先日、この問題に取り組む必要が生じ、あらためて追ってみたところ、ようやく、AC3 フォント圧縮(Monotype Imaging AC3 Font Compression)との因果関係が分かったのです。この問題に以前遭遇した際に、カーネルデバッガで追ってみた時の記憶では、上記の例外送出は、IE 7 内部で、フォントの表示幅を算出する処理で起きているようです。

以前に調べた時の記憶が正しければ、フォントの表示幅を算出する処理で例外送出が起きていますので、フォントデータへのアクセスで例外送出が起きている可能性があります。このことと、ARM プロセッサでは症状が発生し、x86 プロセッサでは症状が発生しないようだ、ということを考え合わせると、フォントデータへのアクセスで word alignment のとれていないデータ読み出しを行っている箇所があり、そこで例外送出が起きる、ということなのかも知れません。全くの憶測にすぎませんが、AC3 フォント圧縮されたフォントファイル(非圧縮の .ttc ではなく、圧縮版の .ac3)内のデータをアクセスする際に、圧縮によって word alignment のとれていないフィールドがあり、そこに対して整数値の読み出しを行おうとして例外送出が起きている、ということなのかも知れません。

なお、このような症状は、WinCE 6.0 では発生していませんでした。従って、WinCE 6.0 から WEC 7 への変更点の中に、要因があるのではないかと思われます。WinCE 6.0 から WEC 7 への変更点の中に、ARM コンパイラの強化があります。WinCE 6.0 までは、ARMv4 アーキテクチャの命令しか出力できなかったのが、WEC 7 では、ARMv5, ARMv6, ARMv7 をサポートしています(※最新メジャー版の WEC 2013 では、ARM コンパイラが再び変更され、ARMv7 のみのサポートとなったのは、皆さんご存知の通りです)。WEC 7 での ARM コンパイラの強化には、この他に、memcpy() や memset() が Intrinsic Function となった、というものがあります。これは、ARM コンパイラだけではなく、x86, ARM, MIPS 共通です。

memcpy() や memset() が Intrisic Function となった結果、これらの関数に渡す実引数の型次第では、byte 単位ではなく、word 単位でのアクセスが行われるようです。これは、一般的には高速化に役立ちますが、[unsigned ]short や [unsigned ]long、[unsigned ]int のポインタが実引数として渡され、かつ、実際には、そのポインタ値が、word alignment がとれていない場合(つまり、short のポインタ値が 2Byte 単位のアドレス境界に揃っていなかったり、long のポインタ値が 4Byte 単位のアドレス境界に揃っていない場合)、ARM プロセッサでは、例外送出が起きてしまいます。x86 では、例外送出は起きません。このような状況は、たとえば、可変長のヘッダを持つ通信パケットがあり、そのペイロードを構造体にキャストしてアクセスする場合に起こり得ます。もしかすると、IE 7 が AC3 フォント圧縮されたフォントファイル内のデータをアクセスする際に、そのようなことが起きているの *かも* 知れません。

WinCE 6.0 から WEC 7 への変更点には、コンパイラの強化の他に、IE の変更もあり、レンダリングエンジンの強化も行われていますから、コンパイラの違いが要因ではなく、レンダリングエンジンの変更が要因である可能性もあります。IE 7 のレンダリングエンジンのソースコードは開示されていませんので、真相は、Microsoft で調べてもらわなければ分かりません。

ともあれ、少なくとも現時点では、Meiryo フォントに加え、IE 7 とも、Monotype Imaging AC3 Font Compression を共存させてはいけない、ということが言えます。IE 7 と日本語フォントを OS イメージに組み込まれる方は、ご留意下さい。

■おまけ
WEC 7 のコンパイラの Intrinsic Function のうち、CPU アーキテクチャ共通のものについては、リファレンスの次のセクションに記載されています:

 Compiler Intrinsic Functions (Compact 7)
 http://msdn.microsoft.com/en-us/library/ee480143(v=winembedded.70).aspx

memcpy() や memset() は、次のページに載っています:

 Intrinsic Forms of CRT Functions (Compact 7)
 http://msdn.microsoft.com/en-us/library/ee479418(v=winembedded.70).aspx

WEC のネットワークフィルタドライバ(NDIS フィルタ)

$
0
0

今回は、ネットワークドライバに対するフィルタドライバについて述べます。既存のドライバに対してフィルタドライバを attach することにより、ドライバの動作診断に役立てることができます。あるいは、どのように呼び出されるのかという視点からドライバの振る舞いを解析し、既存のドライバを改修する際に役立てたり、また、サンプルドライバの動作を解析して新規にドライバを実装する際の参考にする、といった利用もできるでしょう。

■はじめに~WEC 7 での NDIS 6.0 の導入
NDIS フィルタドライバは、WEC/WinCE で NDIS 6.0 に対応した版、つまり WEC 7 で導入されました。リファレンスにもサンプルコードにも、NDIS フィルタドライバが登場するのは WEC 7 からで、WinCE 6.0 にはありません。WEC 7 と WEC 2013 のリファレンスの、NDIS フィルタドライバの説明は、それぞれ次のページです:

 NDIS Functions for Filter Drivers (Compact 7)
 http://msdn.microsoft.com/en-us/library/gg158504(v=winembedded.70).aspx

 NDIS Filter Driver Reference (Compact 2013)
 http://msdn.microsoft.com/en-us/library/gg159366.aspx

NDIS 5.x だった WinCE 6.0 では、NDIS フィルタドライバに相当する機能は、NDIS 中間ドライバ(NDIS intermediate driver)として提供されていました。興味のある方は、WinCE 6.0 のリファレンスの次のページをご覧ください。

 Intermediate Drivers (Windows Embedded CE 6.0)
 http://msdn.microsoft.com/en-us/library/ee483408(v=winembedded.60).aspx

NDIS の 5.x と 6.0 の違いについては、次のページが参考になるでしょう。

 Port Miniport Drivers from NDIS 5.x to 6.0 (Compact 7)
 http://msdn.microsoft.com/en-us/library/jj838857(v=winembedded.70).aspx

 Port Miniport Drivers from NDIS 5.x to 6.0 (Compact 2013)
 http://msdn.microsoft.com/en-us/library/jj838857.aspx

 Introduction to NDIS 6.0
 http://msdn.microsoft.com/en-us/library/windows/hardware/ff556026%28v=vs.85%29.aspx

■NDIS フィルタドライバのサンプルコード
NDIS フィルタドライバのサンプルコードは、WEC 7 も WEC 2013 も、次のディレクトリに収録されています:

 %_WINCEROOT%/public/common/oak/drivers/netsamp/lwfilter/

このサンプルコード(lwfilter)は、WEC 2013 のサンプルコードページにも WEC 7 のサンプルコードページにも、説明が載っていません。そのため、見落としていた方もいらっしゃるかも知れません。もし興味がわいたら、この機会に、ご覧になってみて下さい。lwfilter は、Windows Vista/7 用の NDIS 6.0 フィルタドライバのサンプルコードがベースになっているようで、同じ名前の Win7 用のサンプルコードが、次のページで提供されています:

 NDIS 6.0 Filter Driver
 https://code.msdn.microsoft.com/windowshardware/NDISLWFSYS-Sample-NDIS-60-42b76875

上述した、NDIS 5.x の NDIS 中間ドライバのサンプルコードは、WEC 7 以降でも提供されており、次のディレクトリに収録されています:

 %_WINCEROOT%/public/common/oak/drivers/netsamp/passthru/

NDIS 中間ドライバが WEC 7 以降も使えるのは、NDIS 5.x のサポートが含まれているからです。NDIS 5.x 関連のドライバインタフェースは、リファレンスの次のページで説明されています:

 NDIS 5.x Legacy Reference (Compact 7)
 http://msdn.microsoft.com/en-us/library/gg158312(v=winembedded.70).aspx

 NDIS 5.x Legacy Reference (Compact 2013)
 http://msdn.microsoft.com/en-us/library/gg158312.aspx

ちなみに、WEC 7 と WEC 2013 のネットワーク関連のサンプルコードは、次のページで紹介されています。興味のある方は、こちらもご覧になってみて下さい。

 Networking Code Samples (Compact 7)
 http://msdn.microsoft.com/en-us/library/hh802406(v=winembedded.70).aspx

 Networking Code Samples (Compact 2013)
 http://msdn.microsoft.com/en-us/library/hh802406.aspx

■フィルタドライバの効用
最後に、フィルタドライバの効用について述べます。冒頭で、既存のドライバの動作診断や、振る舞いの解析に役立てることができると書きましたが、その他に、既存のドライバに対する機能追加、という効用があります。NDIS は、フィルタドライバが attach されたドライバを直接呼び出さず、フィルタドライバを経由して間接的に呼び出します。従って、フィルタドライバは、既存のドライバに対する NDIS からの呼び出しをフックして追加の処理を実行できるのです。つまり、既存のドライバの実装を変更せずに、フィルタドライバによって機能追加を行うことができる、というわけです。

フィルタドライバにより機能追加を行うという方策は、機能追加したい対象のドライバが複数存在する場合に、より効果的です。たとえば、NDIS フィルタドライバによってドライバに機能拡張したいデバイスが、複数のネットワークインタフェースを持つ場合のことを考えてみて下さい。有線 LAN のインタフェースと無線 LAN のインタフェースを両方持つデバイスは、近年珍しくありません。それら複数のネットワークインタフェースのドライバに対して、同じ機能追加を行う場合、個々のドライバの実装を変更して機能追加するよりも、NDIS フィルタドライバを使って機能追加する方が、実装変更箇所が一つで済みますから、より低コストで実現できるでしょう。既存のドライバの実装を変更しなくて済むというのは、既存のドライバのソースコードを入手できず、自分で改変できない場合にも役立つ点です。

NDIS は、ネットワークインタフェースのハードウェアを抽象化したレイヤですから、そのレイヤのインタフェースに対するフィルタドライバは、異なるネットワークインタフェースのドライバに対して共通に適用できます。機能追加の例として、「ネットワーク通信が行われている間は、WEC の Power Manager の activity timer のイベントを発火させ、自動サスペンドしないようにする」という機能があります。この機能は、個々のネットワークインタフェースのドライバの実装を改変して実装するよりは、NDIS フィルタドライバで実装し、フィルタドライバを各ネットワークインタフェースのドライバに attach する方がシンプルで良いでしょう。これは、あくまでも一つの例に過ぎませんが、フィルタドライバの役立て方として参考になれば幸いです。

Viewing all 14 articles
Browse latest View live




Latest Images