2010-06-18 139 views
28

我想要一个相对无破解的方式来做到这一点,任何想法?例如,下面以截图不包括半透明窗口:捕获屏幕截图包括.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 

无论是我的谷歌福真的很烂或者这并不像听起来那么容易。我很确定为什么会发生这种情况,因为视频驱动程序必须将内存分开才能完成这项工作,但我不在乎它为什么不起作用,我只是想不这样做......
*打印屏幕键黑客
*第三方软件
* SDK功能是确定的,但我会给予好评的,可以告诉我,它在纯框架用户所拥有的所有对象(开个玩笑,但是这将是很好)。

如果This是唯一的方法来做到这一点,如何在VB中做到这一点?
1M谢谢。

+0

“如果这是做到这一点的唯一方法......”一个小小的研究似乎表明,这也行不通。 – FastAl 2010-06-18 18:54:01

回答

65

具有TransparencyKey或Opacity属性集的窗体是所谓的分层窗口。它们使用视频适配器的“覆盖”功能显示。这使他们能够获得其透明度效果。

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

不幸的是,这种超载有一个严重的错误,阻止了它的工作。它不适当地验证值。在.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版本,因此您不能真正依赖它。

+7

该解决方案是Hot Hot Hot !!!!说实话,汉斯,如果我不是基督徒,我会跪下来拜拜你!这就像一个魅力! – FastAl 2010-06-18 20:08:13

+6

您可以通过使用'Screen.AllScreens'创建一个新的'Size sz'来捕获多个屏幕;' – Jon 2011-12-07 10:13:54

+0

这是否也与'SystemInformation.VirtualScreen'一起作为输入? – Kobor42 2014-01-06 15:58:11