====== Todayプラグインの作成 ====== ====== Todayプラグインとして実装すべきもの ====== Todayプラグインは、Today本体が適切にイベントを送り、また、画面を破綻させないように、定められた作法で作る必要がある。 WindowsCEの初期のものから、PocketPCを経るうちに拡張されたものもあり、これらの情報が散在していて探すのが面倒である。 ここに、USB Select Todayを実装するにあたって、調べた事項をまとめておく。 ===== エントリポイント ===== Todayプラグインは、DLLとして実装しなければならない。 このため、基本的には、C++/Win32アプリとして実装しなければならない。((C#.NETで作る方法もあるが、どの程度実用的なのか不明。性能的には疑問符が付く。)) Visual Studio 2005の場合、C++でスマートデバイスアプリを選んで、Win32のDLLを作成するプロジェクトを作る。 リソースは、普通に作成することが出来るが、resource.hの内容は自動的には includeされないので、stdafx.hの最後に、 #include "resource.h" を追記しておく。.cppファイルの中で #include "resource.h"を指定しても、何故か、全く読み込まれないので、注意が必要である。((この問題で半日悩んだのは秘密。)) さらに、Todayプラグインのお約束としては、次の内容の、defファイルを作る必要がある。 EXPORTS InitializeCustomItem @ 240 NONAME CustomItemOptionsDlgProc @ 241 NONAME InitializeCustomItemとCustomItemOptionsDlgProcは、Today本体がプラグインを呼び出すためのエントリである。.cppの中にエントリだけ作っても、.defファイルを作成して、この内容を記述していないと、プラグインの一覧にさえ現れないので、忘れないようにする。 ==== DllMain ==== BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ); [in] hModule これはインスタンスへのハンドル。必要に応じて大域変数にでも保存しておく。 [in] ul_reason_for_call 呼び出された理由。DLL_PROCESS_ATTACHとDLL_PROCESS_DETACHが想定される。 [in/out?] lpReserved 予約。使われていないはず。 DllMainは、全てのDLLが備えていなければならないエントリポイントである。 ここでは、モジュールのインスタンスハンドルを取得したり、アイコンなどのリソースを用意したり、WNDCLASSを登録したりするのがDLL_PROCESS_ATTACH時に、またこれらの解放を行なうのがDLL_PROCESS_DETACH時に求められる動作である。 ここで、WndProc()を登録しないと、イベントがやってこないので、確実に行なう。 // IDS_TODAY_XXX_APPNAME は適当な文字列リソースを作っておくこと。 // 別に直接、L"SAMPLE" などとして、文字列を埋め込んでもいいだろうが // あまり美しくないと思う。 // WndProcは、LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM) で // 別途作成しておくこと。 WNDCLASS wc; memset(&wc, 0, sizeof(wc)); wc.style = 0; wc.lpfnwndProc = (WNDPROC)WndProc; wc.hInstance = hModule; wc.hIcon = 0; wc.hCursor = 0; wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszClassName = (LPCTSTR)LoadString(hModule, IDS_TODAY_XXX_APPNAME, 0, 0); if (!RegsterClass(&wc)) { // 登録失敗 } DLL_PROCESS_DETACHが来たら、確保したリソースなどを解放するとともに、クラスの登録を削除する。 // g_hInst は ATACHした際に、hModuleをコピーしておいた大域変数 // IDS_TODAY_XXX_APPNAMEは、上を参照。 UnregisterClass((LPCTSTR)LoadString(g_hInst, IDS_TODAY_XXX_APPNAME, 0, 0), g_hInst); ==== InitializeCustomItem ==== HWND APIENTRY InitializeCustomItem( TODAYLISTITEM *ptlistItem, HWND hwndParent ); [in] ptlistItem szName, tlit, dwOrder, fEnabled, fOptions,およびgrfFlagsが設定されている。 fEnabledがFALSEなら、即座にNULLを返して終了すること。 [out] hwndParent 目に見えない初期化は、DllMainがDLL_PROCESS_ATTACHを受け取ったときに、行なわれている。ここでは、目に見える部分の初期化を行なう。即ち、ウィンドウを作成し、ウィジェットを適切に配置して、パネルの表示を行なう。 このとき、ptlistItem->grfFlagsに、オプション設定が渡ってきている。オプション設定画面を持つパネルの場合には、この情報に基づいて、表示や動作のカスタマイズを行なう。 ウィンドウは**高さを0で作成**しておく。WndProc()で、WM_TODAYCUSTOM_QUERYREFRESHCACHEを受け取ったときに、ptlistItem->cypを検査し、これが0ならば、適切な高さを設定し、描画イベントが発生する用に TRUEを返す。これが、初期化動作ということになる。 // g_hInst は、インスタンスハンドル // g_hWnd は、作成したウィンドウハンドルを格納する大域変数 // IDS_TODAY_XXX_APPNAME は、文字列リソースのID値 HWND APIENTRY InitializeCustomItem(TODAYLISTITEM *ptlistItem, HWND hwndParent) { LPCTSTR appName = (LPCTSTR)LoadString(g_hInst, IDS_TODAY_XXX_APPNAME, 0, 0); // Windowの高さは '0'で作る。 g_hWnd = CreateWindow(appName, appName, WS_VISIBLE | WS_CHILD, CW_USEDEFAULT, CW_USEDEFAULT, 240, 0, hwndParent, NULL, g_hInst, NULL); // 他に必要なリソースがあればここで作成しておく // ウィンドウハンドラを登録する SetWindowLong(g_hWnd, GWL_WNDPROC, (LONG)WndProc); // ウィンドウを表示する ShowWindow(g_hWnd, SW_SHOWNORMAL); UpdateWindow(g_hWnd); return g_hWnd; } ==== CustomItemOptionsDlgProc ==== BOOL APIENTRY CustomItemOptionsDlgProc( HWND hDlg, UINT message, UINT wParam, LONG lParam ); [in] hDlg ダイアログのハンドル [in] message メッセージID [in] wParam 16bitパラメータ(メッセージに依存) [in] lParam 32bitパラメータ(メッセージに依存) レジストリに、Options == 1をセットした場合には、このエントリに中身を書いてやらなければならない。0なら、ただリターンするだけの関数でもいいだろう。 このハンドラに対応するダイアログは、IDD_TODAY_CUSTOM (500)をIDとして作成されていなければならない...あんまりちゃんと書いてないけれど。((最初適当なIDで作ったらやっぱり表示されなかった。どこにも、ダイアログを表示するコードフラグメントがないのだから、どっかでシステムが決めウチで面倒を見てくれているのだろう。)) オプションは、DWORD TODAYLISTITEM::grfFlagsを介して、パネル本体とやり取りされる。32bitのデータ幅なので、大抵の場合は、単純なON/OFFや、機能番号などを渡すのに用いるのだろう。他の用い方があるかどうかは調べていない。USB Select Todayは、5bitを受け渡しに使っている。 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +-----------------------------------------------------+-+-+-+-+-+ |あき |I|3|2|1|0| +-----------------------------------------------------+-+-+-+-+-+ I: 初期化フラグ 0なら初期状態 0〜3は不定と見なし、全て1に初期化される 0〜3: ActiveSync(NDIS), Modem, Mass Storage, Serialの各アイコンを表示するか否か。 WM_INITDIALOG中で、**ptlistItem == NULLのケースが初期状態ではない**ことに注意する。初回からちゃんと、ptlistItemは割り当てられている。ので、上のような初期化フラグを1bit設けた。別のやり方も勿論あるだろう。 BOOL APIENTRY CustomItemOptionsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) { static TODAYLISTITEM *s_ptlistItem = NULL; switch (message) { case WM_INITDIALOG: { SHINITDLGINFO shidi; // ダイアログを初期化 shidi.dwMask = SHIDIM_FLAGS; shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN; shidi.hDlg = hDlg; SHInitDialog(&shidi); // ptlistItemを取得 s_ptlistItem = (TODAYLISTITEM*)lParam; if (s_ptlistItem) { // 例えばこれはUSB Select Todayの初期化シーケンス if ((s_ptlistItem->grfFlags & 0x10) == 0) { s_ptlistItem->grfFlags |= 0x1f; } } else { // これは異常系、どうするかは決めてください。 } // チェックボタンなどのウィジェットの状態を初期化 } return TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK) { // ウィジェットの値を読み取って、grfFlagsに設定する。 // ダイアログを閉じる EndDialog(hDlg, LOWORD(wParam)); return TRUE; } break; case WM_DESTROY: s_ptlistItem = NULL; break; } return FALSE; } ===== メッセージハンドリング ===== ==== WM_CUSTOMTODAY_QUERYREFRESHCACHE ==== ==== WM_CUSTOMTODAY_CLEARCACHE ==== ==== WM_CUSTOMTODAY_RECEIVEDSELECTION ==== ==== WM_CUSTOMTODAY_LOSTSELECTION ==== ==== WM_CUSTOMTODAY_USERNAVIGATION ==== ==== WM_CUSTOMTODAY_ACTION ==== ==== WM_LBUTTONUP ==== ==== WM_PAINT ==== ==== WM_ERASEBKGND ==== ===== API ===== ==== TODAYM_GETCOLOR ==== ==== TODAYM_DRAWWATERMARK ==== ==== TODAYM_TOOKSELECTION ==== ===== レジストリ ===== ==== DLL ==== ==== Type ==== ==== Options ==== ==== Selectability ==== ===== オプションダイアログ ===== ====== リンク ====== * [[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mobilesdk5/html/mob5conWritingCustomTodayScreenItem.asp|Today Screen]] * [[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnppcgen/html/today_screen_selection_api.asp|Today Screen Plug-in Selection API in Windows Mobile 2003 Second Edition Software for PocketPCs]] * [[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnppcgen/html/TodayScrn.asp|Creating a Pocket PC Today Screen Plug-in with .NET Compact Framework]] [[W-ZERO3:W-SIM端末:Windows Mobileに関して]]