EternalWindows
GDI / GDIという視点

Windowsにおける描画処理で最初の関門となるのは、再描画にまつわる問題です。 クライアント領域に対して行った描画は、ウインドウを最小化した場合などに無効化されるため、 このタイミングを適切に捕らえ、再び描画する必要がありました。 ここで得た1つの教訓は、WM_PAINTでBeginPaintを呼び出して デバイスコンテキストのハンドルを取得し、それを使用して描画を行うというものです。 こうすることで、クライアント領域の内容は有効となり、 常に同じグラフィックスが描画され続けているように見えることになります。 さて、それではデバイスコンテキストというものは、そもそも何者なのでしょうか。 これを理解するためにはこれまでより一歩進んで、 GDIについての知識が必要となります。

GDI(Graphics Device Interface)とは、gdi32.dllに実装されている関数群のことです。 Microsoftから提供されるDLLは、Windows APIと呼ばれる関数のコードが含まれており、 gdi32.dllにはGetDCやRectangleのようなデバイスコンテキストのハンドルを 必要とする関数のコードが含まれています。 このため、GDIという言葉を目にした場合は、 デバイスコンテキストのハンドルを必要とする関数の事であると考えて問題ありません。 たとえば、GDIによる描画という言葉が使われていた場合、 それが意味しているのは、GetDCやBeginPaintでデバイスコンテキストのハンドルを取得し、 そのハンドルと共にRectangleなどの描画関数を呼び出すということです。

GDIが掲げる目標の1つとして、描画デバイスの抽象化があります。 描画デバイスというのはいわば描画対象であり、大抵の場合それはウインドウとなりますが、 時にはプリンタであることや、メモリ内のビットマップである場合もあります。 描画デバイスを抽象化するとは、どのようなデバイスに描画する場合でも、 その違いをアプリケーションに意識させないということです。 次に、1つの例を示します。

hdc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
Rectangle(hdc, 0, 0, 50, 50);

CreateDCという関数の第1引数に"DISPLAY"という文字列を指定した場合、 ディスプレイのデバイスコンテキストが返ることになり、 いわばデスクトップに対して描画を行えるようになります。 一方、CreateDCにはプリンタの名前も指定することが可能であり、 その場合はプリンタのデバイスコンテキストが返ります。 ここで重要なのは、いずれのデバイスコンテキストを取得した場合でも、 描画デバイス毎に呼び出すべき関数を変更する必要がないという点です。 つまり、プリンタの場合ならRectanglePrinterという専用関数を呼び出すということではなく、 あくまでRectangleという共通の関数で描画を行うことができるのです。 このような事が可能になるのは、デバイスコンテキストをハンドルという形で アプリケーションから抽象化していることに他なりません。 デバイスコンテキストは、描画デバイスや描画属性についての情報を含む構造体であると考えられますが、 仮にこれがハンドルではなく構造体として返された場合、 アプリケーションが描画デバイス毎にメンバを調整することになってしまいます。 このため、アプリケーションにはハンドルを返すようにし、 描画デバイス毎の調整は描画関数の内部で行うようにするのです。

GDIを使用して描画を行っているという視点を持つことが重要です。 これは言い換えれば、GDIとはまた別の描画APIを使用して描画を行えるということになります。 たとえば、GDI+はGDIにないアルファ値を指定した描画や、 JPEGやPNGといったファイル形式もサポートしています。 よって、このような機能を必要とする場合は、GDI+の利用を検討するのも候補といえます。 また、3D機能を利用した描画を行いたい場合は、Direct3Dを利用することになるでしょう。 グラフィックスの描画が重要となるアプリケーションの開発時には、 描画に使用するAPIを十分に検討しておく必要があるといえます。


戻る