Programming/PocketPC
PocketPCってのは、Microsoftが作ったPDA用OS(あるいはそのハードウェアも含めた規格のこと)ですな。内容はPocketPC2002が出たばかりの頃に仕事で開発していた知識を元にしているので、結構古いかも。
Pocket PC Programming TIPS(?)
Pocket PCとHandheld PC
Windows CEは主にPocket PCとHandheld PCがあり(Palm-size PCもあったが、今はPocket PCに移行。最近ではCASIOのラジェンダのように、Windows CE機でありながらPocket PCでもHandheld PCでもないものもある)、その機体の形状で異なる。
大雑把にいえば、Pocket PCはキーボードを装備せず、ペンによる入力を主体とした片手で使用できる小型携帯機で、少し特殊なUIを持つ。Palm OS機(Palmのm505やSONYのCLIE、HandspringのVisorなど)やSHARPのZAURUSなどの対抗機種。
一方Handheld PCは、ペンだけでなくキーボードを装備した、サブノートPCをさらに小型化したような携帯機で、Pocket PCより広い画面を使用でき、UIはほぼ通常のWindowsと同じ。
ちなみに、Windows CEはPocket PCやHandheld PCのOSの部分を指しており、Windows CEにハードウェア仕様と各添付アプリケーションをパッケージングすることで、Pocket PCやHandheld PCといった規格になる。
メモリ(RAM)構成
Windows CEは特殊なメモリ(RAM)管理構造を持っている。メモリは大まかにファイルやデータベースを記憶するための領域(ObjectStore:オブジェクトストア)と、アプリケーションが自由に利用できるヒープ領域の2つに分けられる。
前者はいわばRAMディスクである。たいていの機種ではバッテリバックアップされていないため、電源を完全に切ると内容が消えてしまう(通常Windows CEデバイスは電源を切るのではなく、PCでいうところのサスペンド状態に移行する。サスペンド/リジュームが日常的に行われるデバイスと言える)。Windows CEのOS関連のファイルを保持しているROMディスクとマージして、デバイスのファイルシステムを構成する。
後者は、アプリケーションのワーク領域としてだけでなく、アプリケーションの実行コード自体を読み込んで配置する用途にも使われる。つまりPCのメインメモリに相当する。
このような構成になっていることから、メモリを仮に64MB実装している機種の場合、ヒープ領域として使えるのはおよそ半分程度の32MBと考えたほうがよい…のだが、厳密に半分といえない特殊な事情がある。
実はこの2つの領域はメモリマネージャによって動的に管理されており、運用状況およびユーザ操作に応じてその大きさを随時変えることができるようになっている。例えばオブジェクトストアがほとんど使用されていない状態であれば、オブジェクトストア領域をヒープ領域に分け与えることによって、より多くのアプリケーションを同時に動かしたり、大きなメモリをアプリケーションが確保できるようになる。
逆に、ファイルを大量にオブジェクトストアに格納してしまった場合、ヒープ領域の中の空き領域をオブジェクトストアに分け与えることで、より多くのファイルをオブジェクトストア内に格納することもできる。これらの調整作業はほとんどメモリマネージャが自動的に行うが、ある程度はユーザ操作によって変えることもできる。
Pocket PCのダイアログ
Pocket PCでは原則としてダイアログはフルスクリーンにする(Handheld PCはその限りではない)。また、デフォルトボタンとして利用する[OK]ボタンは、ボタンコントロールをダイアログ上に置くのではなく、ナビゲーションバー(画面トップのキャプションバー)上に配置するフラグを指定し、OS側に任せることが多い。
モーダルダイアログはSHInitDialog関数で作成し、パラメータのSHINITDLGINFO構造体のうちdwFlagsメンバに設定する必要がある。
- SHIDIF_SIZEDLGFULLSCREENは、フルスクリーンにするフラグ
- SHIDIF_DONEBUTTONは、[OK]ボタンをナビゲーションバーに配置させるフラグ
- SHIDIF_FULLSCREENNOMENUBARは、画面下のメニューバーを消してフルスクリーンにするフラグ
- SHIDIF_SIPDOWNは、入力パネル(ソフトウェアキーボード)を強制的に閉じるフラグ
時計カーソル
マウスではなくペンによる入力を主体としているので、マウスカーソルは表示しない。ただし、何らかの処理中に使用するWaitカーソル、いわゆる砂時計カーソルは表示できる(Pocket PCでは砂時計ではないが…)。
砂時計カーソルの表示は以下のようなコードを使用する。使用方法自体は、普通のWindowsと変わらない。
HCURSOR hCur = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
ちなみに砂時計カーソル表示から元に戻すには、以下のようなコードを使用する。これも普通のWindowsと変わらない。
::SetCursor(hCur);
サスペンド(自動電源切断)を止める方法
サスペンドへの移行(何も操作をせずにあらかじめ設定した時間が来ると自動的に電源を切る)を止めるには、SystemIdleTimerReset関数を呼ぶ。これを呼ぶと、サスペンド移行タイマが初期化され、しばらくの間サスペンドに移行しなくなる。ただし、これはあくまでサスペンドへ移行するまでの時間を計測するタイマをリセットしているだけで、完全にサスペンドさせないようにするためには、タイマのカウントが終了してサスペンドする前に毎回呼ぶ必要がある。
SystemIdleTimerReset関数を呼ぶ間隔はどうすればいいかというと、レジストリの
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power
内にある
BattPowerOff ExtPowerOff
に設定されている値(秒単位)を参考にすること。前者はバッテリ駆動時、後者はAC接続時に参照する値で、何の操作もなくこの時間が経過するとサスペンドに移行することを示している。ということは、これよりも少ない時間間隔でなくてはならない。
また、この設定値が0の場合は、サスペンドに移行しないことを意味している。
例外
C++例外のtry〜catch文やthrow文は使用できない。使用するためには何かライブラリを必要としているみたい(コンパイル時はwanning、リンク時にはリンクエラーが発生する)だが、詳細は不明。その代わりに構造化例外であるtry〜finally〜__exceptを使用する。
メモリカードのフォルダ名
日本語版では半角カタカナで"メモリ カード"となり、Windows CEデバイスのルートフォルダ(マイデバイス)直下に出現する。
機種によって異なるが、2スロット以上カードスロットを持つ機種の場合、メモリカードとして認識した順番によって、"メモリ カード"(実際には1バイトカタカナ文字使用)をprefixにして2以降の数字が付加されるが、1番めのカードに1や0が付加されることはない。この数値の上限値は不明。
スロットにメモリカードが挿入されていない場合には、メモリカードのフォルダは存在しない。つまり、カードが挿入されている間しかメモリカードのフォルダは存在しない。
英語版ではフォルダ名は"Storage Card"となる模様。その他の国は不明。
メモリカードフォルダ名の異常
カードスロットが1つか2つしかないにも関わらず、「メモリ カード3」といった変なものができることがたまにある。これは電源を切った状態(サスペンド状態)でメモリカードを抜き差しするとわかりやすいが、電源が入る(サスペンドから復帰する)タイミングでおかしくなるらしい。とくに発生しやすいのは東芝のGENIOで(この機種固有かもしれないが)起動時のカードのドライバの挙動によるものと思われる。
メモリカードのフォルダの属性
メモリカードのフォルダには、通常のフォルダの属性であるFILE_ATTRIBUTE_DIRECTORYに加え、FILE_ATTRIBUTE_TEMPORARYが立つ。前に記したように、メモリカードが刺さっている間しかフォルダが存在しないため、このような扱いになっている模様。
ファイルやフォルダなどのパスから、そのパスがメモリカード内にあるか、それとも本体メモリ上にあるかを判定するには、第1階層のフォルダ名の属性を調べ、FILE_ATTRIBUTE_TEMPORARYが立っていればメモリカード内、立ってなければ本体メモリとわかる。
Pocket PCのメニュー
通常のWin32アプリケーションのメニューとは異なり、画面下にタスクバーのように配置されるメニューバーがトップメニューとして使用する。ただし解像度の都合上横の幅の制限がきついため、トップメニューに大量のメニューアイテムを並べるのは難しい。サブメニューにまわすか、なるべくメニューを使わないようにするなどの対策が必要。
メニューバーはSHCreateMenuBar関数で作成する。また、メニューバーを作成した場合にはその縦幅の分だけウィンドウの幅を狭くすること。
Pocket PCアプリケーションの終了処理
Win32アプリケーションとは異なり、メニューやボタンなどでアプリケーションの終了を明示的に指定させるのは推奨されない。アプリケーションの終了はOSが自動的にメモリが不足した場合になどに行われる。
終了時には、WM_CLOSEメッセージが来る。ここで必要であればその時点のデータをストレージなどに保存しておくこと。再度起動するときに、終了した時点の状態を復元し、作業の続きが行えるのが望ましい。
文字列リソースの直接参照
リソースは普通にWin32と同じ様に使えるが、文字列についてはWindows CEのみ少し特殊な使い方が可能になっている。
通常は文字配列にコピーを読み込んで使用するが、リソース領域をそのまま直接参照することで、多少なりともメモリの節約とメモリ確保時エラーなど例外処理の手間を減らすことができる。
そのためには、
(LPCTSTR)LoadString(hInst, IDS_STRING, NULL, 0);
のように、読み込む文字配列へのポインタを渡す第3パラメータにNULLを入れることで、この関数の戻り値が文字列リソースの実体へのポインタを返すようになる。これをLPCTSTRでキャストすることで、そのままReadOnlyの文字列として利用できる。
ただし、この方法を使うためには文字列リソースの格納方法を変更し、文字列の最後に終端を書き込むようにリソースコンパイラに指示を出さなくてはならない(通常はBASICやPascalなどの文字列と同じく、文字列長+文字列本体の連続になっている)。それには-nオプションをリソースコンパイラに付ければ良い。
リテラル文字列
Windows CEでは全ての文字列がUnicodeで扱われ、それに関連してMBCS系の文字列処理関数が用意されていないため、簡単にはMBCSを使用できないことになる。また、普通にリテラル文字列を
"foo"
のように記述すると、MBCSとみなされコンパイル時にエラーになるので、必ず
_T("foo")
のようにマクロで挟むか、
L"foo"
のようにUnicodeリテラル文字列の指定を付加しなくてはならない。
ヘルプ
ヘルプはHTMLファイルで記述する。拡張子は.htm限定。ヘルプの表示はPegHelp.exeが行う。ヘルプ呼び出し時には、PegHelpに対してヘルプのHTMLファイルを引数にして起動する。
トピックごとに
<!-- PegHelp -->
を使用して区切りを入れ、トピックをこの記述で囲む。さらにトピックへのジャンプのためにラベルとして
<A NAME="foo">
も入れること。そのトピックを呼び出すためには、ラベルを指定して呼び出す。
PegHelp \\Windows\foo_help.htm#foo
のようにすると、"foo"のラベルを持つトピック(<!-- PegHelp -->で囲まれた範囲)をヘルプとして表示します。トピックの範囲外はPegHelpを使うと表示しない(ブラウザを使うか、リンクにラベルを付けないとHTMLファイル全部が見える)。
なお、ヘルプ内のジャンプも、トピック範囲内だけを表示するのであれば、ラベル付きでハイパーリンクを設定するのと、<!-- PegHelp -->でトピックを囲むのを忘れないこと。
メモリカードの抜き差し検出
メモリカードの抜き差しを検出するには、Plug&Play関係のメッセージであるWM_DEVICECHANGEメッセージを受け取る方法と、随時メモリカードのフォルダの存在を監視(タイマやスレッドなど)する方法がある。
WM_DEVICECHANGEメッセージは、カードを挿入した場合と抜いた場合に送信される。そのため比較的正確に知ることができる反面、東芝のGENIOeにおいてSDカードで挿入のタイミングでメッセージが来ないなど、ドライバの実装次第では検出できなくなる場合がある(SDカードについてはMicrosoft側でも特にルールを設けていないらしい。CompactFlashなら規定されているので問題ないそうな)。
フォルダを監視する方法をとると、ドライバなどの実装の影響を受けずに検出できる反面、適当な間隔でポーリングしなくてはならなくなり、それによって性能面で若干の影響が出る。
限界時の挙動
もともとWindowsシリーズはメモリやディスクの使用料が容量の限界付近までくるとOS自体の動きが不安定になって、アプリケーションでどうにかできなくなることが多いが、Pocket PC(Windows CE)でも同じことが起こる。特にメモリの制限がWin32に比べるとキツイため、比較的起こしやすいので厄介である。
何より問題なのは、例えばメモリが不足して限界までいくと、OS側が勝手にメモリ不足である旨のメッセージボックスを表示してしまい、さらにアプリケーションへ処理を戻してくれない場合がたまに起こるのだ。そのため、仮にメモリ不足などの後始末の処理を記述しても、その処理を飛ばしてしまうので、「どーすりゃいいんじゃ(#゚Д゚)ゴルァ!」と叫びたくなる。
初期のWindowsCEから見受けられた現象であるが、WindowsCE3.0になった今に至っても変わっていない。なるべく動作には余裕をもたせるように気をつけるしかない。それでも問題が起きてしまうのだが、そうなるともはや手のつけようがない。
メモリの確保
Pocket PCにおけるメモリの確保はWin32の手法に従えばよいが、資源が限られているため、一度に多くのメモリをとるような真似ができない。仮想記憶を持っているわけではないので、実装されているメモリ以上は確保できないし、ましてやメモリはファイル格納用のメモリと共用しているため、全てを利用できるわけではない。
多少強引な方法をとるならば、SHCloseApp関数を使う手がある。確保したいメモリサイズを指定してこの関数を呼び出すと、未使用のアプリケーションを終了させて可能な限りメモリを確保できる用意をしてくれる。といってもあくまで確保するための準備をするだけで、実際にこの関数が成功してメモリが解放されてから、自分でメモリを確保しなくてはならない。
また、実装メモリを超えた範囲のメモリはどうやっても確保できないので、少ないメモリでも動作するための工夫があれこれ必要になる。
関連リンク集
ちなみに、結構古い…。
| サイトタイトル | URL |
|---|---|
| Mobile Devices | http://www.microsoft.com/mobile/default.asp |
| Windows CE for Programmers | http://www.microsoft.com/japan/developer/winds/Ce/ce.htm |
| WindowsCE開発者向け情報(WindowsCE FAN内) | http://www.wince.ne.jp/Dev/ |
| Pocket PC 2002 Bugs- Software -(CEWindows.NET内) | http://www.cewindows.net/bugs/pocketpc2002.htm |
| HOW TO: Use a Windows CE Database in VC++ | http://support.microsoft.com/default.aspx?scid=kb;JA;q300928 |
| Creating Shortcuts to Feature Settings | http://www.microsoft.com/MOBILE/developer/technicalarticles/shortcuts2.asp |
最終更新時間:2006年07月05日 00時57分20秒