捕获截图包括.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真的很糟糕,或者这并不像听起来那么容易。 我很清楚为什么会发生这种情况,因为video驱动程序必须将内存分开以使其工作,但我不在乎为什么它不起作用,我只想在没有…的情况下这样做
*打印屏幕键黑客
*第三方软件
* SDKfunction还可以,但我会提升用户拥有的每个对象,这些对象可以在纯框架中显示它(只是开个玩笑,但这会很好)。

如果这是唯一的方法,我怎么在VB中这样做?
1M谢谢。

具有TransparencyKey或Opacity属性集的表单是所谓的分层窗口。 它们使用video适配器的“叠加”function显示。 这使他们能够具有透明效果。

捕获它们需要打开接受CopyPixelOperation参数的CopyFromScreen重载中的CopyPixelOperation.CaptureBlt选项。

不幸的是,这个重载有一个严重的错误,阻止它工作。 它不能正确validation该值。 仍然没有在.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版本为这个bug提供了一个解决方法。 不完全确定哪个,我认为是Win7 SP1。 如果传递CopyPixelOperation.CaptureBlt选项,BitBlt()函数现在可以执行您想要的操作。 但是当然,这种解决方法并没有对早期的Windows版本进行逆向应用,因此您无法真正依赖它。