2010-06-18 102 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