Archive for 2013/02

insmod と ActivateDevice()

今回は、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

Add comment 2013/02/10 koga

WEC 7 付属の gdiplus.dll

■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) << 0) \
    |((ARGB)(g) << 8 ) \
    |((ARGB)(r) << 16) \
    |((ARGB)(a) << 24)) \

    GpGraphics*    graphics = NULL;
    GpPath*    path = NULL;
    GpPen*    pen  = NULL;
    PointF    points[] = {
        PointF(0.0f + 50, 0.0f + 50),
        PointF(40.0f + 50, 20.0f + 50),
        PointF(80.0f + 50, 150.0f + 50),
        PointF(100.0f + 50, 10.0f + 50),
    };

    if (0 != ::GdipCreateFromHDC(hdc, &graphics)) {
        return;
    }
    if (0 != ::GdipCreatePath(FillModeAlternate, &path)) {
        goto finish;
    }
    if (0 != ::GdipAddPathBeziers(path, points, 4)) {
        goto finish;
    }
    if (0 != ::GdipCreatePen1(MAKE_ARGB(255, 255, 0, 0), 1.0, UnitPixel, &pen)) {
        goto finish;
    }
    if (0 != ::GdipDrawPath(graphics, pen, path)) {
        goto finish;
    }

finish:
    if (NULL != pen) {
        (void)::GdipDeletePen(pen);
    }
    if (NULL != path) {
        (void)::GdipDeletePath(path);
    }
    (void)::GdipDeleteGraphics(graphics);
}


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

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 の利点だと思います。

Add comment 2013/02/05 koga


Categories

Links

Posts by Authors

Recent Posts

Calendar

2013年2月
« 1月   8月 »
 12
3456789
10111213141516
17181920212223
2425262728  

Posts by Month

Posts by Category

Meta