MouseWheelで画面をスクロールするとC++ Exceptionが発生する

解決


HS  2005-02-02 15:05:46  No: 56250  IP: 192.*.*.*

WindowsMEでMouseWheelを使い画面の一部をスクロールさせているのですが、スクロールを数回続けていると、画面の指定部分が全面白くなってしまいます。
アウトプットウインドウには、
「Warning: Uncaught exception in WindowProc (returning 0).
例外処理 (初回) は 01keisen.exe (MSVCRTD.DLL) にあります: 0xE06D7363: Microsoft C++ Exception。
と出ます。
なお、WindowsXP、Windows2000、WindowsNTでも実行してみたのですが、その現象は、発生しませんでした。どなたか心当たりのある方、教えてください。

編集 削除
HS  2005-02-02 15:54:37  No: 56251  IP: 192.*.*.*

情報の追加です。
環境はVC++6.0 SP5 MFC
OnMouseWheel関数は以下の通りです。

BOOL CMy01keisenView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{
  m_topno -= zDelta / 120;  // 行の先頭番号を増減させる
  if(m_topno < 1)           // 行の下限を0とする
    m_topno = 0;
  if(m_topno >36)           // 行の上限を37とする
    m_topno = 37;

  CRect lpRect(p12, p43);   // スクロールの範囲を 
  InvalidateRect(lpRect,TRUE); // 再描画させる

  return CView::OnMouseWheel(nFlags, zDelta, pt);
}

編集 削除
たく  2005-02-03 10:58:12  No: 56252  IP: 192.*.*.*

解決策ではありませんが同様の問題に遭遇したことがあります。

そのときは、
マウスドライバがスクロールしないはずのWindowを
強制的にスクロールさせようとしていたために
現象が発生していました。

MOUSEWHEELではないメッセージや、
直接ScrollWindowなどがcallされていないか確認されてはいかがでしょうか?

編集 削除
HS  2005-02-03 20:53:21  No: 56253  IP: 192.*.*.*

たく  さん  早速のアドバイスありがとうございます。
>MOUSEWHEELではないメッセージ
ですでに実行しましたが結果は同じでした。つまり
メニュからページ単位で次のようにいました。
void CMy01keisenView::OnMENUNextPage() 
{
  if((m_topno + 10) > 37)
    m_topno = 37;
  else
    m_topno += 10;
  CRect lpRect(p12, p43);
  InvalidateRect(lpRect,TRUE);
  
}
が同じ結果でした。

>直接ScrollWindowなどがcallされていないか
ScrollWindowは使っていません。

編集 削除
n  2005-02-04 10:35:34  No: 56254  IP: 192.*.*.*

描画部分でリソースリークさせてないですか?
ブラシを作りっぱなしとか。

編集 削除
HS  2005-02-04 23:30:44  No: 56255  IP: 192.*.*.*

n さん、アドバイスありがとうございます。
>描画部分でリソースリークさせてないですか?
スクロールさせながらリソースメータを見ておりますと、おっしゃるとおり
GDIとシステムのリソースが0になったところで画面が乱れます。
描画部分(OnDraw(CDC* pDC)内)では、確かにFontとPenを使っておりまして、
作りっぱなしでした。
が、DeleteObjectにてその関数内でFontやPenのオブジェクトを削除したのですが、結果が同じでした。
もう少し詳しく調べて見るつもりです。
ありがとうございました。

編集 削除
HS  2005-02-07 21:27:25  No: 56256  IP: 192.*.*.*

再描画させたときに、リソースを消費するようです。
たとえば、罫線のみの画面でさえも、プログラムロード時64%あったGDIリソースが、100回再描画(invalidateで)させると51%に減じました。罫線間に文字を表示した場合、再描画10回でGDIリソースは数%になりました。

Windows2000はじめ他のWindowsでさえもGDIリソースが増えていくとの報告があります。
http://forums.belution.com/ja/vc/000/281/57.shtml


リソースの余裕がないWindows9x系では、このような再描画の多いプログラムの適用はよろしくないようです。

たくさん、nさんありがとうございました。

編集 削除
n  2005-02-08 08:38:11  No: 56257  IP: 192.*.*.*

OnDraw以外で、例えばOnCtlColorとかでリークしてたりしないでしょうか。
いくらMeでも10回や100回の再描画でリソースが不足してしまうとは
速すぎると思います。

また、全てのGDIオブジェクトを、描画の都度、作成・破棄するのでなく
メンバ変数として保持しておいて使いまわすようにすると軽減されるかも
しれないです(検証してないですが)。

編集 削除
HS  2005-02-08 23:20:59  No: 56258  IP: 192.*.*.*

nさん  ありがとうございます。

実は、本日WinMEにてダメもとで、SelectObjectを使ってみたらば、なーんと解決したのではありませんか。

つまり、
FontとPenを使っていたのですが、それらについて元のオブジェクトに戻すだけでリソースの消費が累積されなくなったのです!。

詳細:
CFont* oldFont1 = pDC->SelectObject(&FontSS);
pDC->TextOut(q121.x,q121.y,GetznName(m_topno+i));
pDC->SelectObject(oldFont1);

この1行目の=以前と3行目を追加することにより
リソースの増大を防ぐことができました。
SelectObjectはMSDNによると「デバイス コンテキストに対してオブジェクトを選択します。」とありますのでリソースの増大とは関係ないものとおもっておりました。

ちなみに、DeleteObjectをはずして実行しても同じ結果でした。
DeleteObjectはMSDNによると「オブジェクトに関連付けられていたすべてのシステム領域を解放することによって、CGdiObject オブジェクトに結び付けられていた Windows の GDI オブジェクトをメモリから削除します。」
とあり、こちらのほうがリソースの消費と密接な関係があると思っていたのですが・・・。

いずれにしろ、WinMEでも快適に動くようになりました。

ありがとうございました。

編集 削除
説明  2005-02-09 00:27:39  No: 56259  IP: 192.*.*.*

FAQですが Select されたままだと Delete が実は失敗してます。

編集 削除
NS  2005-02-09 17:47:46  No: 56260  IP: 192.*.*.*

説明さん  御発言有難うございます。

私もそのように考え、
BOOL ret = FontSS.DeleteObject();
if(!ret) TRACE("Fail Delete");
と関数の最後にオブジェクトごとに入れたのですが、すべて成功でした。つまりretは0でなく1でした。
したがって、オブジェクトはSelectされたままでも削除されたと解釈しておりました。

編集 削除