2017-07-27 6 views
6

CopyFromScreenメソッドを使用して画面をキャプチャするアプリケーションを作成していて、キャプチャした画像を保存してローカルネットワーク経由で送信します。 キャプチャされた画面を1つのビットマップに保存し、もう1つのビットマップ(以前にキャプチャした画面)を2つのスレッドに保存しようとしています。ビットマップを保存してgraphics.copyFromScreen parallel-yを使用しているときにInvalidOperationExceptionが発生しました

しかし、これはInvalidOperationExceptionを投げています。オブジェクトは現在、他の場所で使用されています。例外はSystem.Drawing.dllによってスローされます。
私はロックを試みて、画面を保存してキャプチャするために別々のビットマップを使用しています。これをどうやって止めるのですか?関連コード:私はのC#のコードので、私はここで間違っているかもしれませんが、私はWindowsを使用していると仮定

Bitmap ScreenCapture(Rectangle rctBounds) 
{ 
    Bitmap resultImage = new Bitmap(rctBounds.Width, rctBounds.Height); 

    using (Graphics grImage = Graphics.FromImage(resultImage)) 
    { 
     try 
     { 
      grImage.CopyFromScreen(rctBounds.Location, Point.Empty, rctBounds.Size); 
     } 
     catch (System.InvalidOperationException) 
     { 
      return null; 
     } 
    } 
    return resultImage; 
} 

void ImageEncode(Bitmap bmpSharedImage) 
{ 
    // other encoding tasks 
    pictureBox1.Image = bmpSharedImage; 
    try 
    { 
     Bitmap temp = (Bitmap)bmpSharedImage.Clone(); 
     temp.Save("peace.jpeg"); 
    } 
    catch (System.InvalidOperationException) 
    { 
     return; 
    } 
} 

private void button1_Click(object sender, EventArgs e) 
{ 
    timer1.Interval = 30; 
    timer1.Start(); 
} 

Bitmap newImage = null; 

private async void timer1_Tick(object sender, EventArgs e) 
{ 
    //take new screenshot while encoding the old screenshot 

    Task tskCaptureTask = Task.Run(() => 
     { 
      newImage = ScreenCapture(_rctDisplayBounds); 
     }); 
    Task tskEncodeTask = Task.Run(() => 
      { 
       try 
       { 
        ImageEncode((Bitmap)_bmpThreadSharedImage.Clone()); 
       } 
       catch (InvalidOperationException err) 
       { 
        System.Diagnostics.Debug.Write(err.Source); 
       } 
      }); 

    await Task.WhenAll(tskCaptureTask, tskEncodeTask); 

    _bmpThreadSharedImage = newImage; 
} 

img1img2

+1

どこで使用されているのか正確に判断しますか? – BugFinder

+0

問題の原因となっている上記のコードに含まれていない '_bmpThreadSharedImage'を想定していますか? – DavidG

+0

@BugFinder例外処理されていないメッセージがProgram.csの 'Application.Run(new Form1())'行に現れ、 'CopyFromScreen'と' Bitmap.Save'メソッドがハイライト表示されます – Priyank

答えて

4

単純なwinformsプロジェクトを作成してボタンを1つ押して問題を再現しました。

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     Task.Run(() => SomeTask()); 
    } 

    public void SomeTask() //this will result in 'Invalid operation exception.' 
    { 
     var myhandle = System.Drawing.Graphics.FromHwnd(Handle); 
     myhandle.DrawLine(new Pen(Color.Red), 0, 0, 100, 100); 
    } 
} 

あなたが次のことを行う必要があり、この固定するために:非UIスレッドからUIのメソッドを呼び出そうとした結果を(Spektreが暗示として)

public partial class Form1 : Form 
{ 
    private Thread myUIthred; 

    public Form1() 
    { 
     myUIthred = Thread.CurrentThread; 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     Task.Run(() => SomeTask()); 
    } 

    public void SomeTask() // Works Great. 
    { 
     if (Thread.CurrentThread != myUIthred) //Tell the UI thread to invoke me if its not him who is running me. 
     { 
      BeginInvoke(new Action(SomeTask)); 
      return; 
     } 
     var myhandle = System.Drawing.Graphics.FromHwnd(Handle); 
     myhandle.DrawLine(new Pen(Color.Red), 0, 0, 100, 100); 
    } 

} 

を問題があります。 'BeginInvoke'は実際には `this.BeginInvoke 'で、' this 'はUIスレッドによって作成されたフォームなので、すべて動作します。

1

...

任意のビジュアルコンポーネント(などへのアクセスGDIビットマップまたはウィンドウ...)は、WndProcの外では安全ではありません。したがって、GDIビットマップ(ビットマップとデバイスコンテキスト)を使用している場合、または任意のスレッド内のウィンドウからのビジュアルコンポーネントのレンダリング/アクセスに問題があります。その後、あなたのアプリにWinAPIを呼び出すと例外が発生する可能性があります(グラフィックとは関係なく)

WndProc機能にそのようなコードを移動しようとします。アクセスできない場合は、ウィンドウのイベント(OnTimerまたはOnIdleなど)を使用してください。

関連する問題