2010-06-18 11 views
28

Me gustaría una forma relativamente libre de pirateo para hacer esto, ¿alguna idea? Por ejemplo, la siguiente toma una captura de pantalla que no incluye la ventana semitransparente:Captura de pantalla Incluyendo ventanas semitransparentes en .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 

O mi google-fu es una mierda o esto no es tan fácil como parece. Estoy bastante seguro de por qué sucede esto debido a la forma en que el controlador de video tendría que separar la memoria para hacer que esto funcione, pero no me importa por qué no funciona, solo quiero hacerlo sin ...
* impresión de pantalla hacks clave
de software * 3 ª parte
funciones * SDK están bien, pero voy a upvote todos los objetos propiedad del usuario que me pueda declarar en el marco puro (es broma, pero sería agradable).

Si This es la única manera de hacerlo, ¿cómo hacerlo en VB?
1M gracias.

+0

"Si esta es la única manera de hacerlo ..." una pequeña investigación parece indicar que eso tampoco funcionaría. – FastAl

Respuesta

65

Los formularios que tienen la propiedad TransparencyKey u Opacity configurada son las denominadas ventanas en capas. Se muestran usando la función "superposición" del adaptador de video. Lo que los hace capaces de tener sus efectos de transparencia.

Capturarlos requiere activar la opción CopyPixelOperation.CaptureBlt en la sobrecarga CopyFromScreen que acepta el argumento CopyPixelOperation.

Desafortunadamente, esta sobrecarga tiene un error crítico que impide que esto funcione. No valida el valor correctamente. Todavía no está arreglado en .NET 4.0. No hay otra solución buena, pero recurra al uso de P/Invoke para hacer la captura de pantalla. Aquí hay un ejemplo:

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, una versión posterior de Windows proporcionó una solución para este error. No estoy exactamente seguro de cuál, creo que fue Win7 SP1. La función BitBlt() ahora hará lo que usted desee si pasa solo la opción CopyPixelOperation.CaptureBlt. Pero, por supuesto, esa solución no se aplicó de forma retroactiva a las versiones anteriores de Windows, por lo que no se puede depender realmente de ella.

+7

Esa solución es Hot Hot Hot !!!! Honestamente, Hans, si no fuera cristiano, me inclinaría y te adoraría. Esto funciona como un encanto! – FastAl

+6

Puede capturar varias pantallas creando un nuevo 'Tamaño sz' con el ancho total y la altura máxima usando' Screen.AllScreens; ' – Jon

+0

¿Esto también funciona con' SystemInformation.VirtualScreen' como entrada? – Kobor42