フォーカスって大事だよね - 長めのループをする際の「応答無し」回避方法 -

 今回は気をつけていないと意外とやってしまいがちなミスに関して。



 大きめのデータを一つずつ加工したりして、

ファイルに書き出したりしないといけないときとかがあると思うんですが、

(例えば、自前の音源で鳴らした音をwaveファイルにそのまま落とし込んだりするときとか(←オマエだけだよ))

こういう場合は、大抵


...
int i; // カウンタ用変数
int data_len; // データ長
char *buf; // データ一時格納用バッファ

FILE *fp; // 書き出し用ファイルポインタ
int read_size; // ブロックx1のサイズ
...
for( i=0 ; i// データをカウンタに応じて何らかの加工
// ここでは仮に加工後のバッファのサイズを返すものとする
read_size = TransformData( buf, i );
...
// ファイルに書き出す
fwrite( buf, read_size, 1, fp );
...
}
...

こんな感じになると思うんですが、

data_lenが1000や2000ならまだいいんですが、何Mとかになってくると、結構このループには時間がかかると思います。

 しかし、この処理時間がクセモノ(?)で、

この処理中に別のアプリにフォーカスが奪われるようなことがあると、

再度フォーカスを渡しても、「応答無し」になってしまうことがあります。



 これを回避するにはどうすればいいかというと、

応えは単純で、

・定期的にWindowsのメッセージを拾う。

これを実行してやるだけで大丈夫です。

さっきの例の場合なら、


...
int i; // カウンタ用変数
int data_len; // データ長
char *buf; // データ一時格納用バッファ

FILE *fp; // 書き出し用ファイルポインタ
int read_size; // ブロックx1のサイズ

MSG msg; // メッセージループ用
...
// メッセージキューを確実に生成しておく
PeekMessage( &msg, hwnd, 0, 0, PM_NOREMOVE );

...
for( i=0 ; i// メッセージ管理(簡易版)
PeekMessage( &msg, hwnd, 0, 0, PM_REMOVE );
TranslateMessage( &msg );
DispatchMessage( &msg );
...
// データをカウンタに応じて何らかの加工
// ここでは仮に加工後のバッファのサイズを返すものとする

read_size = TransformData( buf, i );
...
// ファイルに書き出す
fwrite( buf, read_size, 1, fp );
...
}
...

こんな感じでループの頭にメッセージ処理を入れてやるだけで、

きちんとスコープを拾ってくれるようになるはずです。

(本当は、

「PeekMessage()の戻り値による分岐」

とか

「ヤバめなメッセージのときは強制終了」

とかもやらないといけないんですが、とりあえず簡易版ということで…。)



 --- 修正(08/05/17 23:00)

「スコープ」を「フォーカス」に修正。
(しっかりしろ、自分…)