Archive for 2011/08

Device2Cloud コンテスト 2012

東京エレクトロンデバイス社主催の「Device2Cloud コンテスト」が、昨年に続き、今年も開催されます:
 http://www.atmark-techno.com/news/press-releases/20110830_D2C2012

弊社もお手伝いしており、Armadillo-440 用の WEC 7 BSP (Lilas-am440-7) 無償版の、コンテスト向け特別バージョンを提供します。多くの学生の方に、参加して頂けると嬉しいです。

1 comment 2011/08/31 koga

WEC 7 の月例アップデート(2011/07)

今日になって気づいたのですが、これまでリリースされていなかった、WEC 7 (Windows Embedded Compact 7) の月例アップデートの7月分が、8/11 に公開されていました:
 http://www.microsoft.com/download/en/details.aspx?id=27111

リリースノート(Windows Embedded Compact 7_M07_2011.htm)の内容を見ると、今回の修正では、HTTP コンポーネントに対する改善のみのようです。今後、WinCE 6.0 や 5.0 など、サポート継続中のバージョンと同様、毎月少しずつアップデートが重ねられていくことを期待します。

なお、上のアップデートは、WEC 7 のダウンロードページには、記載されていません:
 http://www.microsoft.com/windowsembedded/en-us/downloads/download-windows-embedded-compact-ce.aspx (Download Windows Embedded Compact 7)

WinCE 6.0 では、上記 “Home >> Downloads >> Compact & CE” の対応ページに、7月分の月例アップデートへのリンクが載っているのですが、WEC 7 については、載っていません。また、WinCE 5.0 についても、6月分までの月例アップデートは載っているものの、7月分の月例アップデートは、載っていません:
 http://www.microsoft.com/windowsembedded/en-us/downloads/download-windows-embedded-ce6.aspx (Download Windows Embedded CE 6.0)
 http://www.microsoft.com/windowsembedded/en-us/downloads/download-windows-embedded-ce-5.aspx (Download Windows Embedded CE 5.0)

これら、従来のダウンロードページには記載されていない、最新(2001年7月版)の月例アップデートは、Microsoft Download Center ページで検索すると、ヒットすることに気づきました。たとえば、WEC 7 であれば、URL は
 http://www.microsoft.com/download/en/search.aspx?q=Windows%20CE%207.0
となります。

WinCE/WEC のアップデータは、http://www.microsoft.com/download/en/search.aspx に対して、’q=Windows%20CE%20<バージョン番号>‘ というクエリを与えることで検索できるようです。または、Microsoft Download Center のデフォルトページ(http://www.microsoft.com/download)の検索入力ボックスに、’Windows CE <バージョン番号>‘ という形式で、対象の WinCE/WEC を指定すれば、検索できます。

従来のダウンロードページにおいても、これら最新アップデータ情報を反映してもらえると助かりますが、その運用が落ち着くまでは、Microsoft Download Center ページで検索するのが良いでしょう。

1 comment 2011/08/24 koga

タスクバーの非表示~Taskman Shell の組込み

前回 は、OS をカスタマイズせずに、レジストリ設定や API 呼び出しだけでタスクバーの非表示対応(アプリケーションのフルスクリーン表示対応)を行う方法について、説明しました。今回は、タスクバーを表示しないシェルを組み込む方法について説明します。

■Taskman Shell
WinCE 6.0(および WEC 7)には、タスクバーを表示しないカスタムシェルのソースコードが付属しており、WinCE 6.0 のリファレンスでも説明されています:
 http://msdn.microsoft.com/en-US/library/ee502244(v=WinEmbedded.60).aspx (Including the Taskman Shell)

標準シェルを使用する必要がなく、専用のフルスクリーン表示アプリケーションを搭載するデバイスを開発する場合には、標準シェルの代わりに、この Taskman Shell を OS イメージに組み込むのが、簡単で良いのではないかと思います。

ただし、上のページに書かれている、Taskman Shell を組み込む方法は、実際には使えません。説明が間違っているように思われます。そこで、Taskman Shell を組み込むやり方について、以下に一例を述べます。

■Taskman Shell の組み込み
上記の、WinCE 6.0 のリファレンスページでは、Taskman Shell を OS イメージに組み込む場合、’__SYSGEN_TASKMAN’ という環境変数の値を 1 に設定すればよいと書かれています。しかし、その設定を行っても、Taskman Shell は OS イメージに組み込まれず、それどころか、Tasklman Shell のビルドすら行われません。WinCE のソースツリー配下のファイルを ‘__SYSGEN_TASKMAN’ で検索しても、この環境変数を参照している個所は見当たりませんし、さらに、Taskman Shell のソースコードの親ディレクトリ(%_WINCEROOT%/Public/Wceshellfe/Oak/)にある dir ファイルを見ると、Taskman Shell のディレクトリ(taskman)が記載されておらず、ビルド対象から外れていることが分かります。

では、どうすれば、OS Design をビルドした時に、Taskman Shell が OS イメージへ組み込まれるようになるのでしょうか?以下に、Taskman Shell を OS イメージへ組み込む手順の一例を述べます。

1.) taskman/ ディレクトリを、ビルド対象に含める。
 VS 2005/Platform Builder の「ソリューションエクスプローラー」で、TASKMAN のアイコンを右クリックしてポップアップメニューを開き、[ビルドに含める] を選択します。TASKMAN は、ソリューションエクスプローラーで、次の階層にあります:

 
  C:/WINCE600
   PUBLIC
    wceshellfe
     OAK
      TASKMAN ★

注:確認していませんが、この(1)(「ビルドに含める」)は、必要ないかも知れません。

2.) %_WINCEROOT%/PUBLIC/CEBASE/OAK/MISC/ にある wceshellfe.bat を編集して、次の行を追加する:


    REM for Taskamn shell
    if "%__NO_SYSGEN_TASKMAN%"=="1" goto noTaskmanShell
        rem Turn off StandardShell
        set __SYSGEN_EXPLORER=
        rem add TaskmanShell to WCESHELL module
        set WCESHELLFE_MODULES=%WCESHELLFE_MODULES% taskman
    :noTaskmanShell


 上の行を追加する位置は、wceshellfe.bat の440行付近にある、以下の行の直前にして下さい。


    goto :EOF
:Not_Pass1


3.) OS Design をリビルドする。

上記の手順により、OS イメージ(nk.bin)に taskman.exe が追加され、さらに、レジストリの [HKEY_LOCAL_MACHINE\init] キーの Launch50 の値が "taskman.exe" になります。標準シェル(explorer.exe)は OS イメージには収録されず、標準シェルを Taskman Shell が置き換えられます。ここで、標準シェルが OS イメージに収録されないのは、上の (2) で wceshellfe.bat に追加した行の中の


        set __SYSGEN_EXPLORER=


という行の働きによるものです。一方、Taskman Shell が OS イメージに収録されるのは、


        set WCESHELLFE_MODULES=%WCESHELLFE_MODULES% taskman


という行の働きによるものです。この行の意味については、2011/08/14 に書いた「CESYSGEN 条件文での ‘Component’ 名」を併せ読んでみて下さい。この行の働きにより、taskman がビルドターゲットの依存ファイル/ターゲットの一部となり、ビルドされるようになるというわけです。さらに、 %_WINCEROOT%/Public/Wceshellfe/Oak/FILES/ にある wceshellfe.bib と wceshellfe.reg の中の taskman.exe に関する記述が、上の行の設定により有効になる、というわけです。以下に、wceshellfe.bib と wceshellfe.reg の当該個所を引用します:

wceshellfe.bib


; @CESYSGEN IF WCESHELLFE_MODULES_TASKMAN
	taskman.exe     $(_FLATRELEASEDIR)\taskman.exe             		NK  SH
; @CESYSGEN ENDIF


wceshellfe.reg


; Choose only *one* of the taskman or explorer components in your cesysgen.bat
; @CESYSGEN IF WCESHELLFE_MODULES_TASKMAN
[HKEY_LOCAL_MACHINE\init]
	"Launch50"="taskman.exe"
	"Depend50"=hex:14,00, 1e,00
; @CESYSGEN ENDIF

Taskman Shell を OS イメージに収録せず、標準シェルに戻す場合は、%_WINCEROOT%/PUBLIC/CEBASE/OAK/MISC/wceshellfe.bat に追加した行を削って元に戻すか、または、'__NO_SYSGEN_TASKMAN' という環境変数の値を 1 に設定して OS Design をビルドして下さい(*)。

* 上述した例では、'__NO_SYSGEN_TASKMAN' という環境変数を設定しない場合、Taskman Shell が組み込まれます。つまり、デフォルトで Taskman Shell が組み込まれる設定になってしまいます。どちらかといえば、デフォルトでは標準シェルが組み込まれるように設定できるのが良いと思います。つまり、冒頭で述べた WinCE 6.0 のリファレンスページに書かれているように、'__SYSGEN_TASKMAN' という環境変数を 1 に設定した時にだけ、Taskman Shell が組み込まれるようにできる方が良いでしょう。しかし、試してみたところ、wceshellfe.bat に追加する行の中で '__SYSGEN_TASKMAN' という環境変数を参照して条件分岐するようにしても、期待通りに動作しませんでした。簡単に動きを追ってみたところ、Platform Builder の環境変数設定で __SYSGEN_TASKMAN の値を設定しても、wceshellfe.bat の当該個所が実行される時点で、__SYSGEN_TASKMAN の値が空になってしまっていることが原因でした。詳細は不明ですが、WinCE のビルドシステムにおいて、'__SYSGEN' という接頭辞の環境変数に対しては、ビルド処理を開始する前に、その値を空にする内部処理を実行しているのかも知れません。
 おそらく、今回述べた手順例よりも、もっと良いやり方があるのではないかと思います。WinCE のビルドシステムに対し、ビルド内容をカスタマイズする「フック」の仕組みが提供されていますから、その仕組みを使うことで、もっとエレガントな対応ができるのかも知れません。興味のある方は、ご自分で調べて、追ってみて下さい。

1 comment 2011/08/18 koga

タスクバーの非表示(フルスクリーン表示)

アプリケーションをフルスクリーン表示したい場合、つまり、タスクバーを表示しないで、アプリケーションのウィンドウを全画面に表示したい場合、WinCE 6.0 では、いくつかの方法があります。標準シェル(explorer.exe)を使わずに、カスタムのシェルを組み込んだ OS イメージを作る、というのは、その方法の一つです。しかし、今回は、OS をカスタマイズせず、レジストリ設定や、アプリケーションからの API 呼び出しだけで対応する方法を述べます。

以下では、OS をカスタマイズせずにタスクバーを非表示にする方法を、三通り紹介します。一つは、レジストリ設定を変更することにより、全てのアプリケーションをフルスクリーン表示可能にする方法で、残り二つは、アプリケーションが API 呼び出しを行ってフルスクリーン表示する方法です。では、順に見ていきましょう。

■レジストリ設定による方法
まず最初は、レジストリ設定による方法です。この方法では、タスクバーが最前面(TOPMOST)に表示されないように設定することで、スクリーンと同サイズのウィンドウを表示した際、ウィンドウの下端がタスクバーで隠されてしまうのを防ぎます。具体的には、
 [HKEY_LOCAL_MACHINE\Software\Microsoft\Shell\OnTop]
キーのデフォルト値を dword:0 に設定します。この設定を行うと、CreateWindow() でウィンドウの幅と高さに 0 を指定して、幅と高さにデフォルト値を使う場合や、それから、SystemParametersInfo() に SPI_GETWORKAREA を指定して work area を取得して、work area と同サイズでウィンドウを表示するアプリケーションは、全てフルスクリーン表示となります。たとえば、シェルのエクスプローラーウィンドウ(フォルダウィンドウ)でも、タスクバーが表示されず、フルスクリーン表示されます。シェルのエクスプローラーウィンドウもフルスクリーン表示されると都合がよくない場合は、以下で述べる、API 呼び出しによる方法を使ってみて下さい。

なお、シェルの OnTop というキーに対する説明は、WinCE のリファレンスには記載されておらず、MSDN フォーラムの投稿などでしか見当たりません。たとえば、次のページです:

 http://social.msdn.microsoft.com/Forums/en-US/netfxcompact/thread/a5293f70-0587-4812-b50f-cbfdee9e6d0e

WinCE のリファレンスには、[HKEY_LOCAL_MACHINE\Software\Microsoft\Shell\AutoHide] というキーに関する説明が載っていますが、このキーを設定しても、タスクバーは完全に隠れず、隠れた状態では6ピクセルの高さだけ、画面下端にタスクバーが表示されます:

 http://msdn.microsoft.com/en-US/library/ee501693(v=WinEmbedded.60).aspx (Enabling Slide Animation for the Taskbar)

■AYGShell API による方法
二番目は、AYGShell の API を使う方法です。この方法では、フルスクリーン表示用の API を呼び出したうえで、アプリケーションのウィンドウのサイズを、スクリーンと同サイズにします。ただし、WinCE 6.0 付属の標準シェルでは、フルスクリーン表示用の AYGShell API に対する応答動作の実装に不足があると思われ、追加の API 呼び出しが必要です。

フルスクリーン表示用の AYGShell API は、SHFullScreen() という関数です:

 http://msdn.microsoft.com/en-US/library/ee499392(v=WinEmbedded.60).aspx (SHFullScreen)

上のリファレンスページには、タスクバーを非表示にしてフルスクリーン表示する処理、および、タスクバーを表示してフルスクリーン表示を解除する処理のサンプルコードも記載されています。しかし、WinCE 6.0 付属の標準シェルでは、SHFullScreen() に対する応答動作の実装が、リファレンス記載の仕様とは合っておらず、そのため、上のページ記載のサンプルコードは、期待通りに動作しません(タスクバーが非表示となりません)。SHFullScreen() のリファレンスには、この関数の第二引数に SHFS_HIDETASKBAR を渡した場合、「タスクバーが、z オーダーの底」に移動する、つまり、ウィンドウの重なり位置の最背面に移動すると書かれていますが、WinCE 6.0 付属の標準シェルの実装は、そうなっていないのです。

標準シェルのソースファイルは、%_WINCEROOT%/PUBLIC/shell/oak/hpc/explorer/ 配下にあり、タスクバーのソースファイルは、taskbar/ サブディレクトリに配置されています。そして、SHFullScreen() に対する応答動作は、taskbar,cpp の CTaskBar::TaskBarWndProc() で実装されています。CTaskBar::TaskBarWndProc() の中の switch 文で、SPECIAL_HIDE_MESSAGE と SPECIAL_SHOW_MESSAGE に対する case 節が、当該個所です。ソースを追ってもらえば分かると思いますが、SHFullScreen() の呼び出しによって SPECIAL_HIDE_MESSAGE が送られても、標準シェルのタスクバーの実装(CTaskBar クラス)では、タスクバーがウィンドウメッセージに応答しないようにするだけで(※受け取ったメッセージを、SHFullScreen() の第1引数に渡されたウィンドウに全て転送します)、タスクバーの表示変更は、何も行いません。つまり、リファレンスに書かれている「タスクバーを z オーダーの底」に移動する処理は、行わないのです。

SHFullScreen() の呼び出しに対するタスクバーの動作が、リファレンスに記載された通りではないことへの対応策の一つは、標準シェルの実装を修正することです。しかし、その対応では、OS のカスタマイズが必要であり、アプリケーションだけでは対応できません。アプリケーションだけで対応する場合は、SHFullScreen() の呼び出しの後、SetWindowPos() を使って、アプリケーションのウィンドウを最前面に移動することで解決できます。

SHFullScreen() のリファレンスページに記載されているサンプルコードの場合で言うと、次の対応を追加することにより、タスクバーの非表示/表示切り替えによる、アプリケーションのウィンドウのフルスクリーン表示/解除ができるようになります:

・タスクバーを非表示/アプリケーションのウィンドウをフルスクリーン表示する時
 SHFullScreen() の呼び出しの後に、次の行を追加する:

 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

・タスクバーを表示/アプリケーションのウィンドウのフルスクリーン表示を解除する時
 SHFullScreen() の呼び出しの後に、次の行を追加する:

 SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

■レジストリ設定の動的変更による方法
最後の三番目は、一番目に述べた OnTop キーの値を動的に変更することにより、フルスクリーン表示するアプリケーションの動作中にだけ、タスクバーの最前面表示を行わないようにする、という方法です。この方法は、AYGShell API が OS イメージに組み込まれていない場合に有効です。AYGShell API は、WinCE 6.0 の SKU のうち、最もライセンス価格が安価な “Core”、および “Core Plus” には含まれません。そのため、AYGShell を組込まないコンフィグレーションの OS イメージがデバイスに搭載されている場合があります。

さて、レジストリの [HKEY_LOCAL_MACHINE\Software\Microsoft\Shell\OnTop] キーの値を動的に変更する場合は、単にキー値を変更するだけでは、タスクバーの非表示・表示の切り替え(最前面表示の無効化・有効化の切り替え)を行うことは、できません。レジストリのキー値を変更した際に、タスクバーに通知して、レジストリ設定をロードし直させる必要があるのです。標準シェルのソースを読むと分かりますが、この通知は、WM_WININICHANGE メッセージを使って行うことができます。メッセージのパラメータは、wParam が 0、lParam が 5000 です。

SHFullScreen() のリファレンスページ記載のサンプルコードを真似て書くと、次のようになります。


LRESULT CALLBACK SHFullScreenWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static fFullScreen = FALSE;
    switch (message)
    {
        case WM_KEYDOWN:
        {
            // Toggle between full screen and normal mode when the user presses the space bar.
            if (VK_SPACE == wParam)
            {
                HWND   tbWndH;
                HKEY   keyH;
                DWORD  onTop = (!fFullscreen ? 0 : 1);
                DWORD  dwState;
                RECT   rc;

                if (0 != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                    L"Software\\Microsoft\\Shell\\OnTop",
                    0, KEY_ALL_ACCESS, &keyH))
                {
                    DWORD	disp;

                    if (0 != ::RegCreateKeyEx(HKEY_LOCAL_MACHINE,
                        L"Software\\Microsoft\\Shell\\OnTop",
                        0, NULL, 0, KEY_ALL_ACCESS, NULL, &keyH, &disp))
                    {
                            break;  // error
                    }
                }
                (void)RegSetValueEx(keyH, L"", 0, REG_DWORD, (LPBYTE)&onTop, sizeof(DWORD));
                (void)RegCloseKey(keyH);

                tbWndH = FindWindow(L"HHTaskBar", NULL);
                if (NULL == windowH)
                {
                    break;  // error
                }
                SendMessage(windowH, WM_WININICHANGE, 0, 5000);

                if (fFullScreen)
                {
                    // resize the main window to the size of the work area.
                    SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
                    MoveWindow(hwnd, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, TRUE);
                    fFullScreen = !fFullScreen;
                }
                else
                {
                     // resize the main window to the size of the screen.
                    SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
                    MoveWindow(hwnd, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, TRUE);
                    fFullScreen = !fFullScreen;
                }
            }
        }
        break;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

Add comment 2011/08/15 koga

CESYSGEN 条件文での ‘Component’ 名

WinCE のビルドシステムでは、.bib ファイルや .reg ファイルなどで、@CESYSGEN IF … @CESYSGEN ENDIF という構文を使って、条件指定を記述できます。たとえば、WinCE のカタログ項目で「SD バス ドライバー」が選択されたら、BSP 固有の SD ホストコントローラのドライバが OS Design へ組み込まれるようにするには、BSP の platform.bib において、次のように記述します:

; @CESYSGEN IF CE_MODULES_SDBUS2
    <SD ホストドライバ名>.dll       $(_FLATRELEASEDIR)\<SD ホストドライバ名>.dll            NK  SHK
; @CESYSGEN ENDIF CE_MODULES_SDBUS2


ここで、条件指定に使っている ‘CE_MODULES_SDBUS2′ という変数名は、どうやって決まるのでしょうか?カタログ項目「SD バス ドライバー」の Sysgen 変数(システム生成変数)は ‘SYSGEN_SDBUS’ ですから、Sysgen 変数の名前を使っているわけでは、ありません。今回は、この条件指定に使う変数名について調べてみて分かったことを記します。

まず、WinCE のリファレンスの CESYSG 条件文に対する説明は、次のページです:

 http://msdn.microsoft.com/en-US/library/ee478869(v=WinEmbedded.60).aspx (Preprocessing Using Cesysgen Conditionals)

このページでは、CESYSGEN 条件文で指定する変数名(’Component’ 名)について、次のように説明しています。

・対応するものが module の場合は、<OS tree name>_MODULES_<module_name>。

・対応するものが component の場合は、<module_name>_<component_name>。

ただし、この説明では、’module’ と ‘component’ について具体的な説明がなく、また、<OS tree name>, <module_name>, <component_name> について、説明されていません。これらについては、%_WINCEROOT%/PUBLIC/ 配下の .bat ファイルに記述された、ビルド用の変数設定を見るのが確実だと思います。

たとえば、カタログ項目「SD バス ドライバー」の例でいえば、プロパティの「モジュール」が sdbus2.dll ですが、’sdbus2′ をキーにして %_WINCEROOT%/PUBLIC/ 配下の .bat ファイルを検索すると、%_WINCEROOT%/PUBLIC/CEBASE/OAK/MISC/winceos.bat がヒットします。ヒットするのは、以下の行です:

        set CE_MODULES=%CE_MODULES% sdbus2


ここで、CE_MODULES というビルド変数は、%_WINCEROOT%/PUBLIC/common/CESYSGEN/makefile で参照されており、ターゲット ‘preproc’ の依存ファイルリストの一部として記述されています。つまり、ビルドの preproc ステージで、CE_MODULES にセットされたターゲット群が、依存ファイルとしてビルドされるというわけです。

さて、上で述べた、CESYSGEN 条件文で指定する Component 名の ‘module’/'component’ は、このビルド変数の名前の末尾が ‘_MODULES’ と ‘_COMPONENTS’ のどちらなのか、に対応するようです。sdbus2 の場合は、CE_MODULES というビルド変数の値の一部としてセットされますので、’module’ です。そして、Component 名は、ビルド変数の名前に ‘_’ と、.dll/.exe の名前(つまり、当該 module/component のビルドターゲット名)を大文字にしたものを連結した形式となるようです。sdbus2 の場合は、CE_MODULES_SDBUS2 ですね。

Component 名が ‘component’ の場合の例は、pmif です。pmif は、%_WINCEROOT%/PUBLIC/CEBASE/OAK/MISC/winceos.bat の中で、次のように DEVICE_COMPONENTS というビルド変数の値の一部としてセットされます。

          set DEVICE_COMPONENTS=%DEVICE_COMPONENTS% pmif


pmif は、対応するカタログ項目が選択された場合に、DeviceManager (devmgr.dll) にリンクされるライブラリ(pmif.lib)に対するビルドターゲットです。CESYSGEN 条件文の変数名は、Component 名が ‘component’ の場合、ビルド変数の名前から末尾の ‘_COMPONENTS’ を削って、’_’ とビルドターゲット名を大文字にしたものを連結した形式となるようです。つまり、pmif に対しては、DEVICE_PMIF となります。DEVICE_PMIF は、たとえば %_WINCEROOT%/PUBLIC/common/OAK/FILES/common.bib で参照されており、common.bib には次の行があります:

; @CESYSGEN IF DEVICE_PMIF
   pm.dll       $(_FLATRELEASEDIR)\pm.dll                      NK  SHMK
; @CESYSGEN ENDIF


ちなみに、pmif に対応するカタログ項目は、「電源管理 (完全)」(Sysgen 変数:SYSGEN_PM)と「電源管理 (最小)」(Sysgen 変数:SYSGEN_PMSTUBS)です。これらのカタログ項目が、どちらも選択されていない場合は、pmif.lib が devmgr.dll にリンクされません。pmif が DEVICE_COMPONENTS の値の一部にセットされることにより、devmgr.dll のリンクライブラリに pmif.lib が追加される様子は、%_WINCEROOT%/PUBLIC/common/CESYSGEN/makefile をご覧ください。

さらに補足すると、pmif.lib のソースは、WinCE のカーネルソースの一部となっており、%_WINCEROOT%/PRIVATE/winceos/COREOS/device/pmif/ に配置されています。

さて、CESYSGEN 条件文で指定する Component 名の命名規約の説明における、’module’ と ‘component’ の違いは、上で述べた実例を振り返ると、おそらく、次のような使い分けなのだと思います:

・module
 ビルドターゲットが、.dll または .exe、つまり、executable であるもの。

・component
 ビルドターゲットが、.lib などの、ビルドの中間生成ファイルであるもの。

また、module については、Platform Builder のカタログ項目ビューで対応する項目のプロパティを見ると、「モジュール」という項目があり、component については、そうではない、ということも言えそうです。

module と component の概念については、WinCE のリファレンスの、次のページにも記述があります:

 http://msdn.microsoft.com/en-US/library/ee482113(v=WinEmbedded.60).aspx (Windows Embedded CE Modules and Components)

このページの説明には、component は、module の構成要素であり、module によっては、(コンフィグレーションにより組込むかどうかを切り替えできる)オプションの component を含む、と書かれています。上で述べた解釈は、この説明にも合っていると思います。

蛇足ですが、.bat ファイルにおける、OS Design に module を含める記述の例(ビルド変数 XXX_MODULES の設定例)が、WinCE のリファレンスの次のページに載っています:

 http://msdn.microsoft.com/en-US/library/ee478860(v=WinEmbedded.60).aspx (Cesysgen Batch File)

Add comment 2011/08/14 koga

RAM-Based レジストリの永続化に関する補足

先日書いた「レジストリの永続化~RAM-Based の場合」では、RAM-Based のレジストリを永続化した場合の注意点として、次のことを書きました:

 レジストリの変更内容を永続記憶域に保存するためには、RegFlushKey() の呼び出しが必要です。Hive-Based のレジストリとは異なり、RAM-Based のレジストリでは、RegFlushKey() を呼び出さない限り、レジストリの変更内容は保存されません。

これに加えて、もう一つ注意すべきことがあります。それは、OS イメージを更新する場合です。

OS イメージを更新して、NOR Flash などに新しいイメージを書き込む際、新しいイメージに収録されたレジストリの内容が、置き換え前のイメージに収録されたものと異なっていた場合は、Hive-Based のレジストリと RAM-Based のレジストリで振る舞いが異なります。Hive-Based のレジストリでは、新しいイメージに収録されたレジストリ内容が優先されるのに対し、RAM-Based のレジストリでは、永続記憶域に保存されているレジストリ内容が優先されるのです。

■永続化されたレジストリ内容の扱い方の違い
以下に、OS イメージが置き換えられた際に、永続記憶域に保存されているレジストリ内容がどう扱われるのか、Hive-Based の場合と RAM-Based の場合のそれぞれについて、順に述べます。

(1)Hive-Based の場合
Hive-Based レジストリの場合に、OS イメージが置き換えられた直後のブートにおいて、OS イメージに収録されたレジストリの内容が優先される様子は、リファレンスの次のページの説明を見て下さい:

 http://msdn.microsoft.com/en-US/library/ee489764(v=WinEmbedded.60).aspx (Hive-based Registry Initialization)

このページの、Filesys.dll による Hive-Based レジストリの初期化手順の 15 には、次の記述があります:

 15. If a clean registry is not required, the system registry hive file (System.hv) is loaded from the file system that contains it. A signature in the system hive file is checked against a signature in the ROM portion of the system registry. If the signatures do not match, a clean registry is required, even if this is not indicated by IOCTL_HAL_GET_HIVE_CLEAN_FLAG.

つまり、永続記憶域に保存されているレジストリファイル(System.hv)の signature と、OS イメージに収録されている System.hv の signature を照合し、signature が等しくない場合は、永続記憶域に保存されているレジストリファイルを捨てて初期化する、というわけです。

(2)RAM-Based の場合
RAM-Based レジストリを永続化した場合に、OS イメージが置き換えられても、永続記憶域に保存されているレジストリ内容が優先される様子は、リファレンスの次のページの説明を見て下さい:

 http://msdn.microsoft.com/en-US/library/ee490800(v=WinEmbedded.60).aspx (OAL Initialization of RAM-based Registry)

このページの、OAL での対応により RAM-Based のレジストリを永続化した場合の、Filesys.dll によるレジストリの初期化手順の 2 には、次の記述があります:

 2. If the boot process is a cold boot, Filesys.dll performs the following steps:
  a. Filesys.dll loads the registry data stored in the Default.fdf file from ROM.
  b. If pReadRegistryFromOEM is implemented in the OAL and registry data is available, Filesys.dll deletes the registry data that was restored from Default.fdf. Filesys.dll calls pReadRegistryFromOEM until all of the data is returned. If the data retrieval fails, Filesys.dll cleans the registry and restores Default.fdf.

つまり、OAL が ReadRegistryFromOEM() を実装しており、それを呼び出してレジストリ内容を永続記憶域からロードできた場合は、OS イメージから取り出したレジストリ内容を捨てて、ReadRegistryFromOEM() でロードした内容を使う、ということです。

■RAM-Based レジストリの場合の注意
上で述べたように、RAM-Based のレジストリを永続化した場合は、OS イメージを置き換えても、永続記憶域に保存されたレジストリ内容が優先され、新しい OS イメージに収録されたレジストリ内容は、参照されません。このことは、あるレジストリ設定を変更したくて OS イメージを作りなおした場合に、OS イメージを置き換えても、意図したレジストリ設定の変更が行われない、ということを意味します。作り直した OS イメージに収録したレジストリ内容を有効にするには、永続記憶域に保存されたレジストリを消去して、OS イメージに収録されたレジストリ内容が永続記憶域に保存されるようにしなければいけません。

このことは、OS のバージョンアップを行う際、つまり、WinCE 本体に対する QFE の適用や、あるいは、OS イメージに含める独自デバイスドライバの修正などを行う際に、レジストリ内容の更新が必要な場合に問題となります。そのような場合を考慮して、RAM-Basded レジストリを永続化する対応を行う時は、永続記憶域に保存されたレジストリを消去する機能も実装しておく必要があります。

たとえば、OS イメージの置き換えを行う際にレジストリを消去できるように、イメージ置き換え機能を実装する、という方策が考えられます。あるいは、ブートローダにレジストリ初期化機能を追加し、WinCE カーネルを起動する前にレジストリを消去できるようにする、という方策も考えられます。

Add comment 2011/08/13 koga

WinCE 6.0 用 UVC ドライバとアップデータ

WinCE 6.0 用の UVC (USB Video Class) ドライバを、Microsoft Download Center から入手できます。次のページです:

 Windows Embedded CE 6.0 USB Camera Driver
 http://www.microsoft.com/download/en/details.aspx?id=19512

このドライバは、WinCE 6.0 の Camera Driver Interface に対応した UVC ドライバであり、このドライバを OS イメージへ組み込むことにより、DirectShow の Video Capture Filter を使って UVC カメラから映像や静止画をキャプチャできるようになります。Camera Driver Interface と Video Capture Filter については、リファレンスの次のページをご覧ください。

 http://msdn.microsoft.com/en-US/library/ee486313(v=WinEmbedded.60).aspx (Camera Driver Interface)
 http://msdn.microsoft.com/en-US/library/ee494400(v=WinEmbedded.60).aspx (Video Capture Filter)

さて、上記の UVC ドライバをインストールしてビルドした際、もしかすると、次のようなコンパイルエラーが起きて、ビルドに失敗するかも知れません。

 error C3892: ‘g_wszPinDeviceNames’ : you cannot assign to a variable that is const

もし、このようなコンパイルエラーが起きた場合には、WinCE 6.0 のアップデータを適用して下さい。WinCE 6.0 R3 までをインストールしていらっしゃる場合、2010/12/31 までのアップデータを集積した Cumulative Product Update Rollup Package を適用して下さい:

 Windows Embedded CE 6.0 Cumulative Product Update Rollup Package (through 12/31/2010)
 http://www.microsoft.com/download/en/details.aspx?id=1127

この集積アップデートのうち、上に示したコンパイルエラーに関係するのは、090930_KBSOURCE のソースコード修正に含まれる
 public\common\oak\drivers\capture\camera\layered\inc\camerapddprops.h
です。修正前の camerapddprops.h では、変数 g_wszPinDeviceNames の宣言が const 修飾されており、そのために、コンパイルエラーが発生します。

WinCE 6.0 R3 のインストールが未だであれば、このアップデータを適用する前に、R3 までをインストールして下さい。このページの “System requirements” に記載されていますが、WinCE 6.0 R3 までのインストール順序は、次の通りです:

 1. Visual Studio 2005
 2. Visual Studio 2005 Service Pack 1
 3. Visual Studio 2005 Service Pack 1 Update for Windows Vista (※Windows Vista および、それ以降の OS をお使いの場合)
 4. Windows Embedded CE 6.0 Platform Builder
 5. Windows Embedded CE 6.0 SP1
 6. Windows Embedded CE 6.0 R2
 7. Windows Embedded CE 6.0 R3

なお、僕は2009年2月に、この UVC ドライバを一度評価したことがあるのですが、その時の環境では(WinCE 6.0 R2 だったはずです)、上記のコンパイルエラーは、起きていませんでした。なぜ、WinCE 6.0 R3 でコンパイルエラーが起きるようになったのか、原因は不明です。ここでは、その解決策(アップデータの適用)だけを記しておきます。

ところで、Video Capture Filter を使ったキャプチャ処理のやり方については、
 %_WINCEROOT%/PRIVATE/TEST/MULTIMEDIA/DIRECTX/DSHOW/CAMERA/
配下のソースコードが参考になるでしょう。ただし、このソースコードは、PRIVATE/ ディレクトリ配下の Shared Source code です。使用例として読み、参考にするにとどまらず、もしソースコードの再利用をお考えの場合には、ライセンス条件をご確認下さい。

1 comment 2011/08/03 koga

レジストリの永続化~RAM-Based の場合

2011/02/21 に書いたエントリ(「レジストリ変更内容の永続化(2/2)」では、Hive-Based と RAM-Based の二種類があるレジストリのうち、Hive-Based のレジストリを永続化する仕組みについて説明しました。今回は、RAM-Based のレジストリの永続化について、Hive-Based のレジストリとの比較を交えて書きます。

まず、RAM-Based のレジストリを永続化する方法については、リファレンスの次のページに記載されています:

 http://msdn.microsoft.com/en-us/library/ee489958(v=WinEmbedded.60).aspx (Persisting Data with the RAM-Based Registry)
 http://msdn.microsoft.com/en-US/library/ee490769(v=WinEmbedded.60).aspx (Data Persistence with the RAM-based Registry Using the OAL)

実は、RAM-Based のレジストリを永続化する方法は二つあり、上の二つのページで、その各々について説明されています。それぞれの概要は、次の通りです。

(1) Oemregistry.dll という DLL を組み込む。この DLL で、ReadRegData(), WriteRegData(), RegistryOperation() を実装する。

(2) OAL (OEM Adaptation Layer) に、WriteRegistryToOEM() と ReadRegistryFromOEM() の実装を追加する。

これら二つの方法のうち、(1) は、永続記憶域としてファイルシステムを使う場合に適しています。一方、(2) は、NOR Flash の特定領域を割り当てるなどして、ファイルシステムを介さず、生の(raw)ストレージメディアにレジストリ内容を保存する場合に適しています。

どちらの場合も、レジストリの変更内容を永続記憶域に保存するためには、RegFlushKey() の呼び出しが必要です。Hive-Based のレジストリとは異なり、RAM-Based のレジストリでは、RegFlushKey() を呼び出さない限り、レジストリの変更内容は保存されません。

さて、上記 (1) と (2) のどちらも、WinCE 6.0 ではサンプル実装が提供されています。(1) は、リファレンスのページでも紹介されているように、%_WINCEROOT%/Public/Common/Oak/Drivers/FSD/Oemfs/ がサンプル実装です。このサンプル(Oemfs)では、永続記憶域として、リリースディレクトリファイルシステムを使用します。つまり、開発ホスト機の Flat Release Directory に、RAM-Based レジストリの内容がファイルとして保存されます。当然ですが、使用する場合は、OS Design のカタログ項目で、「リリースディレクトリファイルシステム」を選択して OS イメージをビルドしなければいけません。また、サンプルのままでは、ビルドの target name が Oemfs になっており、’Oemregistry’ とは違います。さらに、他の Public/ ディレクトリ配下のコンポーネントと同様、target type が LIBRARY になっていて、一旦 static library (.lib) としてビルドされた後、sysgen 変数でビルド対象に設定された場合にのみ、DLL (.dll) が生成されるように sources ファイルが記述されています。従って、sources ファイルを作り直し、target name を Oemregistry、target type を DYNLINK にする必要があります。

(2) のサンプル実装は、%_WINCEROOT%/Platform/Common/Src/Common/PerReg/ です。このソースから、oal_perreg.lib という static lilbrary がビルドされます。NOR Flash を搭載したボードの BSP で、NOR Flash に対する OALFlashErase() と OALFlashWrite() が実装されている場合には、oal_perreg.lib を oal.exe のリンクライブラリに追加して、PerReg の初期化関数を OAL の初期化時に呼び出せば(※OEMInit() の末尾がよいでしょう)、そのまま使用することができます。そのようにして oal_perreg.lib を組み込むだけで、NOR Flash の特定領域を使った永続化が、RAM-Based レジストリに対して可能になります。PerReg の初期化関数は、%_WINCEROOT%/Platform/Common/Src/INC/oal_perreg.h で宣言されている OALPerRegInit() です。

ところで、ここまで見てきて、レジストリを永続化する方法には、次の三つがあることが分かりました:

(a) Hive-Based のレジストリを組込み、永続化の設定を行う。

(b) RAM-Based のレジストリと Oemregistry.dll を組み込む(※配置先ファイルシステムは、適切に変更する必要あり)。

(c) RAM-Based のレジストリを組込み、OAL に WriteRegistryToOEM() と ReadRegistryFromOEM() の実装を追加する。

どれが最も良いのでしょうか?結論としては、WinCE 6.0 を動かすハードウェア次第であり、ケースバイケースだと言えます。ただし、NOR Flash を搭載したハードウェアであり、かつ、レジストリの書き換えが頻繁には起こらず、あらかじめ意図した変更内容だけを永続記憶域に保存したい場合には、(c) の方法が最も良いのではないかと思います。

なお、WinCE 6.0 のリファレンスを見ると、次のように書かれています:

 ”The preferred method for persisting registry data is to use the hive-based registry.”
 (Persisting Data with the RAM-Based Registry

 ”The preferred method for persisting data with the RAM-based registry is to include the OEMRegistry.dll sample file in your OS image.”
 (Data Persistence with the RAM-based Registry Using the OAL

これを見ると、最も preferred なのが (a)、その次が (b) で、最後が (c) という順番です。しかし、ここで言う “preferred” の順番は、堅牢性の観点から推奨されるものではなく、より一般的に使える方策の順、および、OS のカスタマイズが必要な度合いが小さい順であると思います。以下に、(a)~(b) の各々について、長所・短所を述べます。

 (a) Hive-Based のレジストリ
  長所:OS のカスタマイズは最小限。「レジストリ変更内容の永続化(2/2)」 で説明したように、OS イメージに組み込むレジストリの設定だけで対応できる。

  短所:レジストリの Hive を配置するファイルシステムを Bootable に設定しなければならないため、そのファイルシステムが破損するなどしてマウントできなくなった場合、ブートの第2フェーズへ遷移できず、第1フェーズの完了待ちで WinCE カーネルの起動が停止してしまう。

  その他:レジストリの Hive ファイルが、WinCE によってオープンされたままとなる。このため、WinCE の起動後にバックアップファイルで上書きするといったことができない。また、RegFlushKey() を呼び出さなくても、暗黙裡に Hive ファイルが更新されるため(※試してみたところでは、起動のたびに、ファイルが更新されます)、レジストリ内容の永続記憶域への書き出しを、意図したタイミングでしか行いたくない場合には、不向き。

 (b) RAM-Based のレジストリ + Oemregistry.dll
  長所:Oemregistry.dll を組み込むだけで対応でき、OAL の改変が不要。レジストリ内容を、ファイルシステム上にファイルとして保存するが、そのファイルシステムは Bootable に設定する必要がない。そのため、保存先のファイルシステムが破損しても、WinCE は起動する。

  短所:レジストリ内容をファイルとして保存するため、レジストリ内容を隠したい場合には不向き。

 (c) RAM-Based のレジストリ + OAL に WriteRegistryToOEM() と ReadRegistryFromOEM() を追加
  長所:レジストリ内容は、ファイルシステムを介さずに保存できるため、ユーザから隠して保護するのが容易。また、NOR Flash を搭載したハードウェアであれば、NOR Flash 用のサンプル実装(PerReg)をそのまま使える。

  短所:OAL の改変が必要。NOR Flash を搭載していないハードウェアの場合には、WriteRegistryToOEM() と ReadRegistryFromOEM() の実装は、それなりに手間がかかる。

どうでしょうか?それぞれの長所と短所は、相対的なものですから、どれかが絶対的に優れているとはいえず、ケースバイケースだと思います。

たとえば、ハードディスク(や SSD)を搭載し、そこに OS イメージも配置する設計のデバイス(ハードウェア)であれば、(a) が最も適しているでしょう。あるいは、上述したように、NOR Flash を搭載していて、レジストリの更新内容を特定の場合にしか保存しなくてよい仕様のデバイスであれば、最も適しているのは (c) だと思います。また、CF カードなどのストレージメディアに Bootable なファイルシステムを置くデバイスで、Bootable なファイルシステムへの書き込みを極力抑えたい、という場合には、(b) が適しているのではないかと思います。

※2011/08/13 追記
RAM-Based のレジストリを永続化した場合、OS イメージを書き換える際に問題となることがあります。新しい OS イメージで、レジストリ項目の追加や削除など、レジストリ内容の変更を行っていても、OS イメージを書き換えた際に、その変更が反映されない、という問題です。これについて、「RAM-Based レジストリの永続化に関する補足」に書きました。

2 comments 2011/08/02 koga


Categories

Links

Posts by Authors

Recent Posts

Calendar

2011年8月
« 2月   9月 »
 123456
78910111213
14151617181920
21222324252627
28293031  

Posts by Month

Posts by Category

Meta