GDI+の初期化と終了

使う前には初期化、使い終わったら最後に終了処理を行います。
行わなかった場合はどうなるのでしょうか・・・。きっとgdiplus.dllが困るのでしょう。
初期化と終了の関数のプロトタイプです。

Status GdiplusStartup( ULONG_PTR token *token,
	const GdiplusStartupInput *input,
	GdiplusStartupOutput *output);

void GdiplusShutdown( ULONG_PTR token);

GdiplusStartup関数で設定を渡して、トークンを受け取り、終了時にはそのトークンを渡す事になっているらしいです。
各パラメータについて説明。

  • tokenは終了時にだけ必要なデータを受け取る変数のポインタ
  • inputはGDI+に対する設定の構造体へのポインタ
    • inputの型GdiplusStartupInputは構造体だけど、デフォルトコンストラクタが普通の設定をしてくれる
  • outputはinputで特別な設定をした場合にだけ必要で、普通はNULL*1

流れとしてはWinMain関数の最初にGdiplusStartup関数を呼び出し、returnの直前でGdiplusShutdown関数を呼び出します。

初期化/終了処理に関する注意

GdiplusShutdownを呼び出す前に、全てのGDI+オブジェクト(*2)を解放しておく事です。
先ほど落とし穴にはまったのですが、C++の仕様なのか、staticな、あるいはグローバルなGDI+オブジェクトは、
WinMain関数が終わった後にデストラクタが呼ばれるようです。
これではエラーが出てしまうので(*3)、このようなオブジェクトを作りたいなら、
それへのポインタを作り、終了処理前にdeleteするといいです(*4)。

また、DllMain関数や、それが呼び出す関数などから初期化/終了をしてはいけない。
代わりにDLLのユーザーに初期化/終了をしてもらうか、各関数ごとに初期化/終了するなど。

この処理をもうちょっと楽にしたい

  1. 以下のコードを"GDIPlusInit.h"で保存する
  2. それをインクルードする
  3. WinMainの先頭にCGdiplusInit hoge;と書くだけ。*5
// GDI+の初期化クラス
#pragma once
#include <windows.h>
#include <gdiplus.h>
using namespace Gdiplus;

class CGdiplusInit {
private:
	ULONG_PTR           gdiplusToken;

public:
	// Initialize
	CGdiplusInit()
	{
		GdiplusStartupInput gdiplusStartupInput;
		GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
	}
	// O WA RI
	~CGdiplusInit()
	{
		GdiplusShutdown(gdiplusToken);
	}
};

ただしこれでは特殊な設定はできません。

追記(09/02/12)

上記のソースコードMacro to initialize GDI+ in VC6.0 MFC projectsのコメント欄に、6年とひと月ほどの昔に出てました。いわゆるがい出ですね。
CGdiplusInitでググるといっぱい出てくる・・・。はずかしや。

*1:どうやらhook/unhook関数とかデバッグ用関数とかの話らしいけどよくわからない。

*2:GDI+のクラスのインスタンス。ImageやBitmapクラス。

*3:例外を投げてきた気がする。

*4:WM_DESTROYで処理するとか

*5:終了処理はデストラクタが代行