Crystal Reports では動的に読み込んだフォントを使用できないようだ。

バーコードのフォントをシステムにインストールせずに使いたかったので、動的に生成したラベルにこのバーコードフォントを設定し、ラベルの画像を取り出して、Crystal Reports にその画像を渡すようにした。

ただ、一度に何千ページも印刷しようすると、ある程度のページ数まで処理が進んだときに、ラベルの DrawToBitmap 呼び出しで ArgumentException が発生する。

たとえば以下のコードを実行すると、自分のマシンではループカウンタが1300 あたりでArgumentException が発生する。以下では label と image は Dispose を行っていないため、それが原因のようにも思うが、たとえ Dispose を呼ぶようにしても、ループカウンタ 4600 あたりでやはり同様のエラーが起こる。
private void button1_Click(object sender, EventArgs e)
{
	for (int i = 0; i < 5000; i++)
	{
		counter.Text = i.ToString();
		counter.Refresh();

		var label = new Label();
		label.Font = new Font("Arial", 20);
		label.Text = "test";

		try
		{
			Bitmap image = new Bitmap(300, 500);
			label.DrawToBitmap(image, label.ClientRectangle);
		}
		catch (Exception ex)
		{
			MessageBox.Show(ex.ToString());
			return;
		}
	}

	MessageBox.Show("complete");
}

今回は GC.Collect を呼んで、回避した。ただし、GC.Collect は以下のような使いかたをしなければ効果がなかった。
private void button1_Click(object sender, EventArgs e)
{
	for (int i = 0; i < 5000; i++)
	{
		counter.Text = i.ToString();
		counter.Refresh();

		var label = new Label();
		label.Font = new Font("Arial", 20);
		label.Text = "test";

		try
		{
			Bitmap image = new Bitmap(300, 500);
			label.DrawToBitmap(image, label.ClientRectangle);
		}
		catch (ArgumentException ex)
		{
			GC.Collect();
			GC.WaitForPendingFinalizers();
			GC.Collect();
			i--;
		}
		catch (Exception ex)
		{
			MessageBox.Show(ex.ToString());
			return;
		}
	}

	MessageBox.Show("complete");
}

.NET アプリケーションのパフォーマンスとスケーラビリティの向上 - 第 5 章 「マネージ コード パフォーマンスの向上 によれば、GC.Collect の呼び出しは避けたほうがいいが、もし GC.Collect を呼び出さなければならない特別な事情がある場合は、以下の3行をセットで書くようにしたほうがいいようだ。
System.GC.Collect(); // アクセス不可能なオブジェクトを除去
System.GC.WaitForPendingFinalizers(); // ファイナライゼーションが終わるまでスレッド待機
System.GC.Collect(); // ファイナライズされたばかりのオブジェクトに関連するメモリを開放

以上。