Получите снимок экрана окна Including Semitransparent в.NET

Я хотел бы способ относительно без взломов сделать это, какие-либо идеи? Например, следующее делает снимок экрана, который не включает полупрозрачное окно:

Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown
        Text = "Opaque Window"
        Dim win2 As New Form
        win2.Opacity = 0.5
        win2.Text = "Tranparent Window"
        win2.Show()
        win2.Top = Top + 50
        win2.Left = Left() + 50
        Dim bounds As Rectangle = System.Windows.Forms.Screen.GetBounds(Point.Empty)
        Using bmp As Bitmap = New Bitmap(bounds.Width, bounds.Height)
            Using g As Graphics = Graphics.FromImage(bmp)
                g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size)
            End Using
            bmp.Save("c:\temp\scn.gif")
        End Using
        Process.Start(New Diagnostics.ProcessStartInfo("c:\temp\scn.gif") With {.UseShellExecute = True})
    End Sub
End Class

Или мой google-fu действительно сосет, или это не столь легко, как это звучит. Я вполне уверен, почему это происходит из-за способа, которым видеодрайвер должен был бы разделить память для создания этой работы, но я не забочусь, почему это не работает, я просто хочу сделать это без...
* взломы клавиши Print Screen
* стороннее программное обеспечение
* функции SDK в порядке, но я буду upvote каждый объект, принадлежавший пользователю, который может показать мне его в чистой платформе (Просто ребячество, но это было бы хорошо).

Если Это - единственный способ сделать это, как я делаю это в VB?
1M спасибо.

29
задан FastAl 18 June 2010 в 18:53
поделиться

1 ответ

Формы, для которых задано свойство TransparencyKey или Opacity, представляют собой так называемые многоуровневые окна. Они отображаются с помощью функции «наложения» видеоадаптера. Что дает им возможность иметь свои эффекты прозрачности.

Для их захвата требуется включить параметр CopyPixelOperation.CaptureBlt в перегрузке CopyFromScreen, которая принимает аргумент CopyPixelOperation.

К сожалению, эта перегрузка содержит критическую ошибку, которая не позволяет ей работать. Он не проверяет значение должным образом. По-прежнему не исправлено в .NET 4.0. Нет другого хорошего решения, кроме как вернуться к использованию P / Invoke для создания снимка экрана. Вот пример:

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication1 {
  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
    }
    private void button1_Click(object sender, EventArgs e) {
      Size sz = Screen.PrimaryScreen.Bounds.Size;
      IntPtr hDesk = GetDesktopWindow();
      IntPtr hSrce = GetWindowDC(hDesk);
      IntPtr hDest = CreateCompatibleDC(hSrce);
      IntPtr hBmp = CreateCompatibleBitmap(hSrce, sz.Width, sz.Height);
      IntPtr hOldBmp = SelectObject(hDest, hBmp);
      bool b = BitBlt(hDest, 0, 0, sz.Width, sz.Height, hSrce, 0, 0, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
      Bitmap bmp = Bitmap.FromHbitmap(hBmp);
      SelectObject(hDest, hOldBmp);
      DeleteObject(hBmp);
      DeleteDC(hDest);
      ReleaseDC(hDesk, hSrce);
      bmp.Save(@"c:\temp\test.png");
      bmp.Dispose();
    }

    // P/Invoke declarations
    [DllImport("gdi32.dll")]
    static extern bool BitBlt(IntPtr hdcDest, int xDest, int yDest, int
    wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, CopyPixelOperation rop);
    [DllImport("user32.dll")]
    static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDc);
    [DllImport("gdi32.dll")]
    static extern IntPtr DeleteDC(IntPtr hDc);
    [DllImport("gdi32.dll")]
    static extern IntPtr DeleteObject(IntPtr hDc);
    [DllImport("gdi32.dll")]
    static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
    [DllImport("gdi32.dll")]
    static extern IntPtr CreateCompatibleDC(IntPtr hdc);
    [DllImport("gdi32.dll")]
    static extern IntPtr SelectObject(IntPtr hdc, IntPtr bmp);
    [DllImport("user32.dll")]
    public static extern IntPtr GetDesktopWindow();
    [DllImport("user32.dll")]
    public static extern IntPtr GetWindowDC(IntPtr ptr);
  }
}

Fwiw, более поздняя версия Windows предоставила обходной путь для этой ошибки. Не совсем уверен, что это была за Win7 SP1. Функция BitBlt () теперь будет делать то, что вы хотите, если вы передадите только параметр CopyPixelOperation.CaptureBlt. Но, конечно, этот обходной путь не применялся ретроактивно к более ранним версиям Windows, поэтому вы не можете на него полагаться.

66
ответ дан 28 November 2019 в 01:13
поделиться