0

バックグラウンドワーカーを含む単一のフォームを含むWinFormsアプリがあります。フォームには、RunWorkerAsync()を介してバックグラウンドワーカーを開始するボタンと、アプリケーションを終了する別のボタンが含まれています。約1/3の時間、バックグラウンドワーカーが作業を完了した後、次のような例外を除いて、[終了]ボタンをクリックするとアプリケーションがクラッシュします。

System.NullReferenceException was unhandled
  Message=Object reference not set to an instance of an object.
  Source=System.Drawing
  StackTrace:
       at System.Drawing.Graphics.Dispose(Boolean disposing)
       at System.Drawing.Graphics.Finalize()

アプリケーションを終了するボタンのイベントハンドラーは次のとおりです。

    private void buttonExit_Click(object sender, EventArgs e)
    {
        if (!buttonStartWorker.Enabled)
        {
            DialogResult dr = MessageBox.Show("Background worker is still running!  Exit anyway?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

            if (dr == DialogResult.OK)
            {
                backgroundWorker.CancelAsync();
                Close();
            }
        }
        else
        {
            Close();
        }
    }

前に述べたように、バックグラウンドワーカーがまだ実行されている間はアプリケーションを終了しないので、ここで見ているコードパスはClose()呼び出しだけです。USB関連のハンドルでcloseメソッドとdisposeメソッドを呼び出すFormClosingイベントハンドラーもあります。そのコードは次のとおりです。

    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        try
        {
            // close and dispose all open handles to the USB device
            if (hidHandle != null)
            {
                if (!(hidHandle.IsInvalid))
                {
                    hidHandle.Close();
                    hidHandle.Dispose();
                }
            }

            if (readHandle != null)
            {
                if (!(readHandle.IsInvalid))
                {
                    readHandle.Close();
                    readHandle.Dispose();
                }
            }

            if (writeHandle != null)
            {
                if (!(writeHandle.IsInvalid))
                {
                    writeHandle.Close();
                    writeHandle.Dispose();  // unhandled exception seems to occur after this
                }
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.ToString());
        }
    }

writeHandle.Dispose()とアプリケーションが実際に終了する時間の間のある時点で、この例外が発生しています。私を最も混乱させているのは、私のコードがSystem.Drawingを明示的に使用していないため、これを追跡するのに問題があるという事実です。

その価値について、私のバックグラウンドワーカーは次のことを行います。

  1. USBデバイスとの間でデータの読み取りと書き込みを行います
  2. いくつかのデータをダウンロードするためのWebクライアントを作成します
  3. それはいくつかのSOAP呼び出しを行います

アプリケーション(System.Drawingを明示的に使用していない)が終了したときに、System.Drawingで未処理のNullReferenceExceptionが発生する原因について誰かが考えていますか?

4

2 に答える 2

1

KeithSの答えは原則として正しいですが、コードには目に見える問題があるようです。CancelAsync()を呼び出しthis.Close();た直後に呼び出しています。バックグラウンドワーカーがビジネスを終了するのを待つか、キャンセルされたイベントが存在する場合はそれをサブスクライブしようとします。

バックグラウンドワーカーが終了していない可能性があります。また、バックグラウンドワーカーは、フォームのイベント階層に関連するコンポーネントであることに注意してください。

新しいタスクを作成してみてください。

this.BeginInvoke(new Action(() => (Thread.Sleep(1000); this.Close();)));

構文が間違っていることをお詫びしますが、私は開発マシンを使用していません。

于 2012-04-27T03:16:54.143 に答える
0

プログラムで System.Drawing を明示的に使用しない場合がありますが、その名前空間はほとんどの WinForms オブジェクト コード全体にあります。フォームのどこかで、ある GUI オブジェクトに別のオブジェクトの Graphics ハンドルへの参照が与えられているように見えます。ただし、そのハンドルを所有するコントロールが既に破棄されているか、Graphics オブジェクト自体の Dispose メソッドが明示的に呼び出されているため、2 回目の実行時に Dispose() コードが失敗します。私は、.NET 開発者が double-Dispose が問題にならないことを確認するためにチェックを入れることを期待していましたが、この場合、彼らはそれを見落としていたようです。

Windowsフォームに何があるのか​​ 、System.Drawing.Graphicsのどのインスタンスがスローされているのかを正確に知らなければ、これ以上助けることはできません. それが私がさらに調査する場所です。破棄されている正確なインスタンス、それを所有している他のオブジェクト、および既に破棄された後にファイナライズされている理由を見つけようとします (通常、明示的に破棄された場合は、GC.SuppressFinalize() を呼び出す必要があります)。

「反映された」コードベース参照の 1 つが役立つ場合があります。System.Drawing.Graphics.Dispose(bool disposing) を探し、2 回続けて実行すると失敗するコード行を探します。それはあなたにヒントを与えるかもしれません。

于 2012-04-26T15:44:28.393 に答える