WinForms の描画処理

id:NyaRuRu:20060203#p2 より

個人的に気にしているパフォーマンスに関しても,トップレベルウィンドウとメニューやツールチップなどの一部の特殊ウィンドウのみをWin32ウィンドウとし,後はクライアント領域に完全自前描画になったことで,
(中略)
要はこれまで WinForms が重かったのはアルゴリズム的問題があったということなわけですが

このあたりはかなり自前でやってしまっていた、またはやろうとしていた人が多いところではないでしょうか。*1
標準コントロールのどこが重たいのでしょうか。主に、

  1. Win32 から HDC(S) を指定されて WM_PAINT が発生
  2. HDC(S) から GDI+ の Canvas-A を作成
  3. 描画用の GDI+ の Canvas-B(Bitmap) を作成
  4. Canvas-B から write-only-pseudo HDC(C) を作成
  5. Win32 API で HDC(C) の上に標準の描画を行う*2
  6. HDC(C) を commit して Canvas-B を更新
  7. Canvas-B の Bitmap を Canvas-A に描画
  8. Canvas-A を commit して HDC(S) へ描画

という手順が重たいのではないかと思っています。少なくとも GDI - GDI+ 間の変換はそれなりのコストがありますし、.NET から GDI および GDI+ の API セットに対してアクセスする際にも、相当のコストがかかっていると考えられます。*3
カスタムコントロールでは、OnPaint() メソッドと System.Drawing namespace を利用して Canvas-A に対して GDI+ の描画機能を呼び出すことができるため、手順の多くを省略することができます。

*1:そういえば、どこかでボタンを大量に並べるだけで重たいと書いていたのに id:NyaRuRu さんが時間がとれたら調べてみたいようなことを書いてたので、それを期待して自分ではほっとこうと思った記憶も...id:yaneurao さんところだと思ったけど、はてなダイアリーでは日記検索もアーカイブ検索もコメント文は対象外なので探せなかった

*2:Appearance プロパティなどによって変化

*3:それなりに Blittable types で構成されている反面、パレット関連や変換関連の GDI+ API はメモリブロックを要求する場合が多いところや、CAS 関連など