一尘不染

捕获屏幕截图,包括.NET中的半透明窗口

c#

我想要相对自由的方式来做到这一点,有什么想法吗?例如,以下内容截取了不包含半透明窗口的屏幕截图:

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谢谢。


阅读 319

收藏
2020-05-19

共1个答案

一尘不染

设置了TransparencyKey或Opacity属性的表单是所谓的分层窗口。使用视频适配器的“覆盖”功能显示它们。这使他们能够具有透明效果。

捕获它们需要在CopyFromScreen重载中打开CopyPixelOperation.CaptureBlt选项,该重载接受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。如果
传递CopyPixelOperation.CaptureBlt选项,则BitBlt()函数现在将执行所需的操作。但是,当然,该解决方法并未追溯应用到早期Windows版本,因此您不能真正依赖它。

2020-05-19