Pocket PCの部屋 by I.N.
 2005/9/26

はじめに
HP iPAQ hx4700 (初PDA!)を買ったので,早速プログラミングに挑戦してみた.
Microsoftや他の先人方のページから得られた知識および
自分で試行錯誤して分かったことなどをメモしておく.

対象機種
HP iPAQ hx4700 (日本語版)
 スペック:
  搭載OS Windwos Mobile 2003 SE (Windows CE .NET 4.2)
  CPU: Intel PXA270 (624MHz)
  RAM:64MB
  Flash ROM:128MB
 CPUについて:
  IntelのXscale PXA270 は ARM系 らしく,コア部分のアーキテクチャはARMv5TE であり,
  ARM 1020E というプロセッサ資料が役に立ちそうだ.

使用するソフト
 ・eMbedded Visual C++ 4.0 (日本語版)
 ・eMbedded Visual C++ 4.0 SP3 (日本語版)
 ・Windows Mobile 2003 software for Pocket PC 日本語版 ソフトウェア開発キット (SDK) (日本語版)
 ・Windows Mobile 2003 Second Edition 開発リソースキット (英語)
 ・Windows Mobile 2003 Second Edition-based Pocket PC 用エミュレータ (日本語版)
 ・ActiveSync 3.7.1 (日本語版)

 「動作検証は実機で行えばいい」という人はエミュレータはなくてもよい.
 ActiveSyncは実機へ実行ファイルを転送するために使われる.

プログラム開発の流れ
 上記の開発用ソフトのインストールが済んでいるとして,
 1.eMbedded Visual C++を起動する.
 2.新規作成 → プロジェクトの種類は'WCE Pocket PC 2003 Application'
   プロジェクト名は適当に → OK → 'A simple Windows CE application' → 終了 → OK
   ここでいくつかのファイルが勝手に自動作成される.
   [プロジェクト名].cppのソースファイルを開いて,WinMain関数の中身を書く.
 3a.実機で動作させる場合は上のツールバーで
   アクティブな構成の選択=Win32(WCE ARMV4),規定のデバイスの選択=POCKET PC 2003 Device
   を選択しておく.
 3b.エミュレータで動作させる場合は
   アクティブな構成の選択=Win32(WCE Emulator),規定のデバイスの選択=POCKET PC 2003 Emulator
   を選択しておく.
 4.ビルド[F7]で実行ファイルが作成され,エラーがなければ自動的に実機またはエミュレータに
   実行ファイルが転送される.
   ビルドと転送の後,自動で実行させたければ[Ctrl+F5]を使う.
 5.動作確認が済んだら,Pocket PC上のプログラムは終了させておく.
   ※再実行する場合,Pocket PC上のプログラムが実行中のままだと
    exeファイルの転送が失敗する.

エミュレータでシリアルポート(COMポート)を使うには [2005/9/26]
 eVC++をインストールしただけでは,エミュレータのプログラム上でCOMポートを使う通信プログラムが
 期待の動作をしないようです.下記のようにシリアルポートを使うためには設定が必要のようです.
 eVC++において,ツール→Platform Managerを構成→POCKET PC 2003 Emulator(など)→
 プロパティ→起動サーバー 構成→通信 シリアルポート1(など)→NoneをCOM1(など)へ変更

VGA対応アプリを開発するには
 実行ファイル(.exeファイル)にHI_RES_AWAREという情報を埋め込んでおかないと,
 そのアプリはVGA解像度(480x640)を利用できないようだ.
 Windows Mobile 2003 SE では実行ファイルのリソースに上記情報が見つからなければ,
 そのアプリを QVGA互換モード(240x320) で実行する.
 (この辺りのことは Microsoft の White Paper の1文書である DPI_Awareness.doc に書いてある)
 HI_RES_AWARE情報をリソースへ追加する例
 挿入→リソース→カスタム→タイプは CEUX →OK→01 00と入力→表示メニュー→プロパティ
 IDは"HI_RES_AWARE"(←ダブルクォーテーションで必ず囲むこと)→ファイル名の欄を削除する→
 外部ファイルのチェックを外す→閉じる.リソースウィンドウを閉じる.
 これで再ビルドすれば,実行ファイルのリソースに HI_RES_AWARE=0x0001が埋め込まれる.
 なお,従来のQVGA互換モードで起動させるには,
 HI_RES_AWARE=0x0001 を HI_RES_AWARE=0x0000 に変更するか,このリソース自体を削除すればよい.

VGA対応のエミュレータを使用するには
 標準で設定されているエミュレータは POCKET PC 2003 Emulator であり,これはQVGA仕様である.
 VGA対応のエミュレータはプラットフォームを追加しないと利用できない.
 追加の仕方(eMbedded Visual C++ 4.0)
 ツール→Platform Managerを構成→デバイスを追加→適当な名前(例:VGA Tate)→プロパティ
 トランスポート=Windows CE用 TCP/IPトランスポート
 起動サーバー=エミュレータ起動サーバー
 起動サーバの構成 → イメージ=JPN PPC 2003 SE VGA,スキン=PPC_2003_SE_VGA →OK→OK→はい→OK
 上のツールバー「規定のデバイスの選択」の箇所をVGA Tateに選択する.
 「アクティブな構成の選択」はWin32(Wce Emulator)を選択する.
 これでVGA対応のエミュレータが利用できるようになる.
 なお,エミュレータには横画面(Landscape)タイプも用意されている.

  VGAエミュレータ用オリジナルスキン
  標準VGAエミュレータのスキンでは私のPCのXGA画面に収まりきらないので,
  XGA画面でも収まるスキン(Pocket_PC_Emulator_VGA_skin.zip)を自作した.
  使い方:
  eVC++を終了させておく.上のファイルを解凍し,出てきた4つのファイルを
  C:\Program Files\Pocket PC 2003 Second Edition Emulators\JPN\Pocket_PC_VGA フォルダの中へ
  上書きする.あとは,上に書いた方法でJPN PPC 2003 SE VGAエミュレータを登録する.
  動作風景はこんな感じ.

GAPIを使うには
 まず,GAPI は Game API の略で,WindowsのDirect Drawのようなもの.
 これを使うと直接 VRAM にアクセスできるため,頑張ればグラフィックスの高速描画が可能となる.
 VRAM の先頭アドレスや解像度を得る以外の機能はほとんど用意されていない.
 また,操作ボタンの情報を直接得ることもできる.
 使用するヘッダファイルは 'gx.h'
 使用するライブラリは 'gx.lib'
 なお,エミュレータは GAPI に対応していないらしく,GAPI関数を使ったプログラムは実行エラーが出る.

 QVGA との互換性が理由で,VGAモードで使うときは注意点がある.
 VGAのときはGXBeginDraw()やGXEndDraw()が使えない.
 VRAM先頭アドレス等の情報を得るには次のようにする.
 (これは Microsoft の White Paper の1文書である DPI_Awareness.doc に書いてある)
#define GETRAWFRAMEBUFFER   0x00020001

#define FORMAT_565 1
#define FORMAT_555 2
#define FORMAT_OTHER 3

typedef struct _RawFrameBufferInfo
{
        WORD wFormat;           // =1   (iPAQ hx4700)
        WORD wBPP;              // =16  (iPAQ hx4700)
        VOID *pFramePointer;    // =0x4A800000 (iPAQ hx4700)
        int cxStride;           // =2   (iPAQ hx4700)
        int cyStride;           // =960 (iPAQ hx4700)
        int cxPixels;           // =480 (iPAQ hx4700)
        int cyPixels;           // =640 (iPAQ hx4700)
} RawFrameBufferInfo;

RawFrameBufferInfo rfbi;

HDC hdc = GetDC(NULL);
ExtEscape(hdc, GETRAWFRAMEBUFFER, 0, NULL, sizeof(RawFrameBufferInfo), (char *) &rfbi);
ReleaseDC(NULL, hdc);

unsigned short *vram_address;
vram_address=(unsigned short *)rfbi.pFramePointer;
 なお,上の構造体 RawFrameBufferInfoの定義の中に書いてあるコメントは
 hx4700で実行したときに得られた実際の値である.
 Pocket PCを横画面モード(Landscape)に設定しても,得られる値に変化はなかった.

画面右上の×ボタン
 これはクローズボタンではなく,Windowsの最小化ボタンに相当するようだ.
 送られるメッセージはWindowsプログラミングの場合と同じ.

 CreateWindow()でスタイルを WS_VISIBLE|WS_NONAVDONEBUTTON と書けば
 ×ボタンなしのウィンドウになる.

 ここを×ボタンではなく,[OK]ボタンにしたければ,
	SHDoneButton(hWnd,SHDB_SHOW);		//OKボタンを出す
 という関数を使用する.
 あとはWM_COMMANDおよびIDOKのメッセージを捕まえて処理すればよい.

画面下のメニューバー
 これはWindowsのメニューではなく,別のメニューバー専用の関数 SHCreateMenuBar() を使ってプログラミングする.
 プログラム例:
        SHMENUBARINFO mbi;

        memset(&mbi, 0, sizeof(SHMENUBARINFO));
        mbi.cbSize = sizeof(SHMENUBARINFO);
        mbi.hwndParent = hWnd;
        mbi.nToolBarId = IDM_MENU;
        mbi.hInstRes = hInst;
        mbi.nBmpId = 0;
        mbi.cBmpImages = 0;

        if (SHCreateMenuBar(&mbi)==FALSE) {
                MessageBox(hWnd,TEXT ("Couldn't create menu bar"),szAppName,MB_OK);
        }
        hwndMenuBar = mbi.hwndMB;
 作成したメニューバーを消すには
	DestroyWindow(hwndMenuBar);	//メニューバーを消す
 とすればよい.

フルスクリーンを使用する
 メニューバー,SIPボタン,タスクバーを消せば,ウィンドウを全画面サイズへ変更できる.
 これによってクライアント領域は画面全体(480x640)となり,フルスクリーンが使える.
 ただし,×ボタンもOKボタンも表示されなくなるため,
 プログラムの終了or切替or最小化のための手段を自分で用意しておかないと
 リセットする羽目になるかも.
	DestroyWindow(hwndMenuBar);	//メニューバーを消す
	SHFullScreen(hWnd,SHFS_HIDESIPBUTTON|SHFS_HIDETASKBAR);	//SIPボタンとタスクバーを消す
	SetWindowPos(hWnd,HWND_TOP,0,0,480,640,NULL);	//ウィンドウサイズを全画面に設定する

SHLoadImageFile()は優れもの [2005/01/26]
 SHLoadImageFile()関数を使えば画像ファイル(.bmp/.gif/.jpg/.png)が簡単に表示できる.
 この関数はファイル名を指定するとビットマップのハンドルが返ってくる.
 たとえファイルの拡張子が変えて(偽装して)あったとしても,
 ファイルの中身が上記4形式のいずれかであれば読み込むようだ.

 簡単なプログラム例
 (hwnd,hdc:表示させたいウィンドウのハンドルとデバイスコンテキスト)
        HBITMAP hbm,hbmold;
        BITMAP bm;
        HDC hdc1;
        hbm=SHLoadImageFile(_T("\\Windows\\Banner.gif"));
        if(!hbm)return;
        GetObject(hbm,sizeof(bm),&bm);
        hdc1=CreateCompatibleDC(NULL);
        hbmold=(HBITMAP)SelectObject(hdc1,hbm);
        BitBlt(hdc,0,0,bm.bmWidth,bm.bmHeight,hdc1,0,0,SRCCOPY);
        SelectObject(hdc1,hbmold);
        DeleteObject(hbm);
        DeleteDC(hdc1);
        InvalidateRect(hwnd,NULL,FALSE);

hx4700を分解!
 中の基板が見てみたかったので恐る恐る開けてみた.
 ◇写真 1:基板(裏) 2:基板(表) 3:表ケースの内側
  グラフィックアクセラレータ ATI Imageon 3220 (215W3220AFA12F)が見える.
  SDRAMは256Mbit(Infineon HYB25L256160AC-7.5)×2 のようだ.
  あとよく分からないが,4400L0ZDQ0 x2, MAXIM MAX1587A ETL, TI 48A8LKJ WAH4245 x2 があった.
  バッテリーを外し,特殊な形のビス4本を外すと裏ケースは外れる.
  メイン基板は2本のビスで固定されていた.そのうち1つはワイヤレスモジュール基板の
  下に隠れている.
  LCDにつながっているケーブル&コネクタの抜き差しには最も神経を使った.

Internet Explorerのキャッシュフォルダのパスを変更する方法 [2005/5/18]
 レジストリエディタ(TRE等)で
 \HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\
 の中を見ると
 Cache
 History
 Cookies
 の3項目がある.各項目に設定されているパス名を変更すれば,キャッシュデータや履歴等の保存場所が変更される.
 メインメモリ以外の場所を指定すれば,メインメモリの消費を抑制することができる.

 追加[2005/06/20]
 キャッシュのサイズを変更するには
 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\Cache\Content\
 CacheLimit=サイズ(bytes)

その他
 Windows CE 5.0が予定されているらしい.
 Direct3D Mobileなどが搭載されるようだ.


1つ上へ戻る