Подтвердить что ты не робот

Захват скриншота Включая полупрозрачные окна в .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 действительно сосет, либо это не так просто, как кажется. Я уверен, почему это происходит из-за того, как видеодрайверу придется разделить память, чтобы сделать эту работу, но мне все равно, почему она не работает, я просто хочу сделать это без...
* Ключи для экранных ключей
* Стороннее программное обеспечение
* Функции SDK в порядке, но я буду продвигать каждый объект, принадлежащий пользователю, который может показать мне его в чистом виде (просто шучу, но было бы неплохо).

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

4b9b3361

Ответ 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, поэтому вы не можете действительно зависеть от него.