web-dev-qa-db-ja.com

System.ComponentModel.Win32Exception:操作は正常に完了しました

Windowsフォームアプリを長時間実行しているときに、この例外が発生することがあります。

System.ComponentModel.Win32Exception: The operation completed successfully
   at System.Drawing.BufferedGraphicsContext.CreateCompatibleDIB(IntPtr hdc, IntPtr hpal, Int32 ulWidth, Int32 ulHeight, IntPtr& ppvBits)
   at System.Drawing.BufferedGraphicsContext.CreateBuffer(IntPtr src, Int32 offsetX, Int32 offsetY, Int32 width, Int32 height)
   at System.Drawing.BufferedGraphicsContext.AllocBuffer(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle)
   at System.Drawing.BufferedGraphicsContext.AllocBufferInTempManager(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle)
   at System.Drawing.BufferedGraphicsContext.Allocate(IntPtr targetDC, Rectangle targetRectangle)
   at System.Windows.Forms.Control.WmPaint(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.DataGridView.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

これの原因は何でしょうか?

25
Jakub Kaleta

要約すると、私が作成した.NetのDataGridViewに基づくカスタムグリッドは、カスタムコードを使用してセルを描画します。グリッドの行は、複数のビジュアルページにまたがることができます。 (それはビジネス要件でした)

問題は、.NetがDoubleBufferingが有効になっているコントロールにメモリのバッファを事前に割り当てることでした。 DataGridViewsグリッドの場合、グリッド内の可能な大きな行に対応するために、バッファーをかなり大きくする必要があります。極端な場合、行は最大32000ピクセルに及ぶ可能性があります(.netの制限のため)。プロジェクトのグリッド幅は通常500〜800ピクセルです。したがって、結果のバッファは(32bpp * 800 * 32000 = 〜100MB)になります。

つまり、システムは互換性のあるグラフィックスオブジェクトを作成できませんでした。これは、必要なデータを収めるのに十分な大きさのバッファを予約できない場合があるためです。

それを修正するには、一連の最適化を導入する必要がありました。

  • カスタムグリッドで許可される最大行の高さを1500ピクセルに制限
  • 新しいバッファサイズが既存のバッファサイズよりも大きい場合にのみ実行されるように、バッファ再割り当てコードを更新しました
  • バッファがすべてのデータバインディングで再割り当てされるのではなく、適切なサイズに事前に割り当てられるようにしました。
  • ここで推奨されているように、すべてのコードを確認し、管理されていないリソースが使用されていないときに適切に破棄されることを確認しました: http://nomagichere.blogspot.com/2008/03/systemcomponentmodelwin32exception-is.html
21
Jakub Kaleta

Windowsには、プロセスごとに10000ハンドルのハード制限があります。やや役に立たない例外「操作が正常に完了しました」は、この制限に達したことを示している可能性があります。

コードのリソースリークが原因でこれが発生した場合は、少なくともコードを修正する機会があるため、幸運です。

残念ながら、WinFormsによって内部的に作成されたハンドルについてできることはほとんどありません。たとえば、TreeViewコントロールによるフォントハンドルの作成が多すぎると、非常に大きなツリーをUIで表現する必要があるシナリオでは使用が困難になります。

いくつかの便利なリンク:

http://support.Microsoft.com/kb/327699http://nomagichere.blogspot.com/2008/03/systemcomponentmodelwin32exception-is.html

13

巨大なPictureBoxを作成するときに、私はかつて同様の例外がありました。グラフィックを十分に割り当てることができなかったようです。実際、私がやっていたのは、単純なゲーム用のある種のマップを描くことでした。ズームイン機能があり、基本的に大きなバッファーを作成してから、すべてのグラフィックを大きなスケールで再描画しました。このズームイン機能を長時間または十分に深く操作すると、この例外が発生しました。おそらく、あなたはたくさんのグラフィックを作成していて、それらを処分していないか、または割り当てできないほど大きなグラフィックだけを作成しているのでしょう。

3
Alejandro Piad

VB.NETでも同じ問題が発生しました。これの理由は奇妙でした:

オーストリアでは、Windowsシステムには通常、コンマと。があります。千の区切りとして。これがねじれている場合(これは米国では標準だと思います)、Windowsはこのエラーをスローします。オーストリアのように変更すると、すべてが解決しました...

幸運を!

3
HI_

極端な場合、画像を破棄しないことが原因です。これを克服するには、ビットマップをロードするときにIDisposableを利用する必要があります。

using(Bitmap b = Bitmap.FromFile("myfile.jpg"))
{
   //Do whatever
}
2
user448374

見つかりました this これは役立つかもしれません-グラフィックスまたはコントロールの廃棄の問題のようです

2
zebrabox

また、メモリの断片化と関係がある可能性があります。アウトアプリでもアンマネージドコンポーネントを使用しており、アンマネージドコンポーネントが隣接する大きなブロックをすべて使い果たした場合、ダブルバッファーグラフィックスに十分な大きさのバッファーを割り当てることができないという問題が発生する可能性があります。

1
Marc

また、メモリリークにより、例外がスローされる可能性があります。たとえば、2〜3個のWebブラウザを備えたアプリケーションは、 this のようなInternet Explorerのバグの1つが原因で、数分で1GBを超える可能性があります。

0
iCantSeeSharp