リード開発メモ

大阪のソフトウェア会社です。 技術的な事柄についてのメモとしてブログを始めます。

2013年11月

C# コントロールの DrawToBitmap で ArgumentException が発生する

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(); // ファイナライズされたばかりのオブジェクトに関連するメモリを開放

以上。

PHP タイムゾーンが8時間ずれている

XAMPP に含まれる PHP のタイムゾーンの初期設定は Europe/Berlin となっているようだ。そのため date 関数などで時刻を取得すると8時間ずれている。

日本時間に合わせるには php.ini を編集し、date.timezone を Asia/Tokyo に変更する。
[Date]
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
;date.timezone = Europe/Berlin
date.timezone = Asia/Tokyo

以上。

Windows リモートデスクトップで大きなファイルを転送する

リモートデスクトップでは、コピー&ペーストで接続先のマシンとの間でファイルをコピーすることができるが、その間リモートデスクトップは操作不能になってしまう。

ある程度大きなファイルを転送する場合は、で接続先のマシンとの間でドライブを共有して、ファイルをコピーするといい。

手順は以下のとおり。

接続する前に、リモートデスクトップ接続ダイアログで[オプション]を開く。
remote-desktop-localdrive1

[ローカル リソース]タブを選び、[ローカル デバイスとリソース]の[詳細]を選ぶ。
remote-desktop-localdrive2

[ドライブ]にチェックを入れ、[OK]を押す。
remote-desktop-localdrive3

以上の設定を行ったあと、リモートデスクトップ接続を行うと、接続先のマシンのドライブとして、接続元のマシンのドライブが現れる。これで接続先のマシンとの間で、ファイルの操作がエクスプローラー上で行えるようになる。

以上。

C# 継承したフォーム上のコントロールのサイズが変更できない

Visual Studio 2012 の C# で開発をしているが、継承したフォーム上のコントロールのサイズ変更ができないという現象が起こった。

もうすこし詳しく言うと
・マウスでドラッグしてのサイズ変更ができない。そもそもコントロールの淵にマウスポインタを持って行ってもサイズ変更用のマウスポインタにならない。
・プロパティウィンドウでの変更は可能。
・いったんコントロールをウィンドウの外に移動すると、ウィンドウからはみ出た部分だけサイズ変更用のマウスポインタになる。
といった具合。

調べてみると、継承元のフォームの WindowState プロパティが Normal 以外のとき(つまり Maximized か Minimized にしているとき)に起こるようだ。この設定が必要なら実行時に設定するのがよさそうだ。

以上。

C# DataGridView の IME 制御

DataGridView で IME 制御するは、CellEnter で行うのが一般的なようだ。デザインでできないが、CellEnter なら列ごとやセルごと、値によって動的に切り替えることができる。
private void DataGridView1_CellEnter(object sender, DataGridViewCellEventArgs e)
{
	var columnName = DataGridView1.Columns[e.ColumnIndex].Name;
	if (columnName == "Name")
	{
		DataGridView1.ImeMode = System.Windows.Forms.ImeMode.Hiragana;
	}
	else
	{
		DataGridView1.ImeMode = System.Windows.Forms.ImeMode.Disable;
	}
}

以上。

アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

livedoor 天気