29

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)

これの原因は何ですか?

4

8 に答える 8

24

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

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

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

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

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

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

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

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

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

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

于 2011-06-21T16:22:37.953 に答える
3

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

于 2011-12-07T15:26:03.657 に答える
3

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

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

幸運を!

于 2012-06-13T11:36:51.760 に答える
3

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

using(Bitmap b = Bitmap.FromFile("myfile.jpg"))
{
   //Do whatever
}
于 2010-12-08T18:41:20.913 に答える
2

役立つかもしれないこれを見つけました - グラフィックスまたはコントロールの処分の問題のようです

于 2009-07-30T22:42:15.377 に答える
1

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

于 2009-08-06T12:05:59.853 に答える
0

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

于 2012-12-21T15:16:44.740 に答える