10

私は、出力ごとに 1280x1024 ピクセルなど、4 つの出力 (モニター) を持つシステムを使用しています。デスクトップ全体とその上で開いているすべてのアプリケーションのスクリーンショットが必要です。

GetDesktopWindow()(MSDN)を試しましたが、正しく動作しません。一部のフォームは、キャプチャされた画像に表示されません。

4

2 に答える 2

36

GetDesktopWindow() 関数を試しましたが、正しく動作しません。

もちろん違います。

このGetDesktopWindow関数は、デスクトップ ウィンドウへのハンドルを返します。そのウィンドウの画像をキャプチャすることとは何の関係もありません。

また、デスクトップウィンドウは「画面全体」と同じものではありません。特にデスクトップウィンドウを指します。詳細と、この関数によって返されるハンドルを悪用した場合に起こりうる問題については、この記事を参照してください。

私は、出力ごとに 1280x1024(eg) の 4 つの出力 (モニター) を持つシステムを使用しています。デスクトップ全体とその上で開いているすべてのアプリケーションのスクリーンショットが必要です。

Graphics.CopyFromScreenこれは、メソッドを使用して .NET Framework で行うのは比較的簡単です。P/Invoke を実行する必要さえありません。

この場合の唯一の秘訣は、適切な寸法を確実に渡すことです。4 台のモニターがあるため、プライマリ スクリーンのサイズだけを渡しても機能しません。すべてのモニターを含む仮想画面全体の寸法を渡す必要があります。SystemInformation.VirtualScreen仮想スクリーンの境界を返すプロパティをクエリして、これを取得します。ドキュメントが示すように、これはマルチ モニター システム上のデスクトップ全体の境界です。

サンプルコード:

// Determine the size of the "virtual screen", which includes all monitors.
int screenLeft   = SystemInformation.VirtualScreen.Left;
int screenTop    = SystemInformation.VirtualScreen.Top;
int screenWidth  = SystemInformation.VirtualScreen.Width;
int screenHeight = SystemInformation.VirtualScreen.Height;

// Create a bitmap of the appropriate size to receive the screenshot.
using (Bitmap bmp = new Bitmap(screenWidth, screenHeight))
{
    // Draw the screenshot into our bitmap.
    using (Graphics g = Graphics.FromImage(bmp))
    {
        g.CopyFromScreen(screenLeft, screenTop, 0, 0, bmp.Size);
    }

    // Do something with the Bitmap here, like save it to a file:
    bmp.Save(savePath, ImageFormat.Jpeg);
}

編集:

メインスレッドではないスレッドで wpf アプリケーションを使用してソリューションを確認してください。私はそれを試してみました。うまくいきません!

うーん、質問に WPF タグが表示されなかったり、本文のどこにも言及されていませんでした。

しかし、関係ありません。私が投稿したコードは、適切な参照を追加し、宣言を使用する限り、WPF アプリケーションで問題なく動作します。と が必要System.Windows.FormsになりSystem.Drawingます。これらの WinForms アセンブリへの依存を必要としない、より WPF 風の方法があるかもしれませんが、それが何であるかはわかりません。

別のスレッドでも機能します。ここには、UI スレッドを必要とするものは何もありません。

はい、テストしました。ここに私の完全なテストコードがあります:

using System.Windows;
using System.Windows.Forms;   // also requires a reference to this assembly
using System.Drawing;         // also requires a reference to this assembly
using System.Drawing.Imaging;
using System.Threading;

public partial class MainWindow : Window
{
   public MainWindow()
   {
      InitializeComponent();
   }

   private void button1_Click(object sender, RoutedEventArgs e)
   {
      // Create a new thread for demonstration purposes.
      Thread thread = new Thread(() =>
      {
         // Determine the size of the "virtual screen", which includes all monitors.
         int screenLeft   = SystemInformation.VirtualScreen.Left;
    int screenTop    = SystemInformation.VirtualScreen.Top;
    int screenWidth  = SystemInformation.VirtualScreen.Width;
    int screenHeight = SystemInformation.VirtualScreen.Height;

         // Create a bitmap of the appropriate size to receive the screenshot.
         using (Bitmap bmp = new Bitmap(screenWidth, screenHeight))
         {
            // Draw the screenshot into our bitmap.
            using (Graphics g = Graphics.FromImage(bmp))
            {
               g.CopyFromScreen(screenLeft, screenTop, 0, 0, bmp.Size);
            }

            // Do something with the Bitmap here, like save it to a file:
            bmp.Save("G:\\TestImage.jpg", ImageFormat.Jpeg);
         }
      });
      thread.SetApartmentState(ApartmentState.STA);
      thread.Start();
   }
}
于 2013-04-07T11:52:38.987 に答える