Gallo_Teo

Hi to all
i have a problem capturing screen with Graphic.copyFromScreen function.
My problem is that if a form has no full opacity the function can't capture it

i used this code

Code Snippet

Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y);
Graphics g = Graphics.FromImage(bmp);
g.CopyFromScreen(0, 0, 0, 0, Screen.PrimaryScreen.Bounds, CopyPixelOperation.SourceCopy);
bmp.Save("c:\\captured.jpg");


how can i fix it
Teo



Re: Windows Forms General copyFromScreen - no alpha window captured

nobugz

You get a nice screenshot of the background of the form, don't you The problem here is that Windows uses a special hardware "overlay" feature of the video adapter to achieve the layered window effect. The bits that make up the form image live inside the video card where they are combined with the desktop bits. You can't get to them, afaik.

Here's a way to capture the image of the form itself:

Bitmap bmp = new Bitmap(this.Width, this.Height);
this.DrawToBitmap(bmp, new Rectangle(0, 0, this.Width, this.Height));
bmp.Save(@"c:\temp\test.png");






Re: Windows Forms General copyFromScreen - no alpha window captured

Gallo_Teo

thanks, it's a first step!
It works but i need to capture all the form on the desktop like print sreen how can do it

thanks a lot
Teo





Re: Windows Forms General copyFromScreen - no alpha window captured

nobugz

You could use Print Screen. SendKeys won't work, this does:

public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
keybd_event(0x2c, 0, 0, IntPtr.Zero);
Application.DoEvents();
Image img = Clipboard.GetImage();
img.Save(@"c:\temp\test.png");
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr keybd_event(int key, int dummy, int flags, IntPtr info);
}






Re: Windows Forms General copyFromScreen - no alpha window captured

Gallo_Teo

I have already triedthat way but it is a capturing software and if a user is copying a portion of image in a sowtare like photoshop, using the clipboard could create problems.

Now i tried to enum all the opened windows with windows api, and create a form from that handle for using the DrawToBitmap function that you posted before... but it don't seems to work

look

Code Snippet

//------------------- this class is for enum windows
public class VisibleWindow
{
static ArrayList list;
static Semaphore sem;
String text;
Rectangle bounds;
int handler;

public VisibleWindow(String text, Rectangle bounds, int handler)
{
this.text = text;
this.bounds = bounds;
this.handler = handler;
}

public static VisibleWindow[] GetAllOpenWindows()
{
list = new ArrayList();
sem = new Semaphore(1, 1);
Win32.CallBackPtr del = new Win32.CallBackPtr(EnumCB);
Win32.EnumWindows(del, 0);
/*sem.WaitOne();
sem.WaitOne(1500,true);*/
VisibleWindow[] array = new VisibleWindow[list.Count];
int i = 0;
foreach (VisibleWindow data in list)
{
array[i] = data;
i++;
}
list.CopyTo(array);
return array;
}


private static bool EnumCB(int hWnd, int lParam)
{
Rectangle rec = new Rectangle(0, 0, 0, 0);
StringBuilder buf = new StringBuilder(256);

Win32.GetWindowRect(hWnd, ref rec);
Win32.GetWindowText(hWnd, buf, buf.Capacity);
rec.X += 4;
rec.Y += 4;
rec.Width -= rec.X + 4;
rec.Height -= rec.Y + 4;

if ((rec.Left < -1000) || (rec.Top < -1000) )
return true;

if (Win32.IsWindowVisible(hWnd) && ((buf.ToString() != ""))
&& (rec.Left < System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width) && ((buf.ToString() != "Program Manager")))
// if (Win32.IsWindowVisible(hWnd) && ((buf.ToString() != "")))
{
if (rec.X - 4 >= 0)
{
rec.X -= 4;
if (rec.Width + 8 <= System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width)
{
rec.Width += 8;
}
}
if (rec.Y - 4 >= 0)
{
rec.Y -= 4;
if (rec.Height + 8 <= System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width)
{
rec.Height += 8;
}
}
VisibleWindow vw = new VisibleWindow(buf.ToString(), rec, hWnd);
list.Add(vw);
}
// debug
/*VisibleWindow vw = new VisibleWindow(buf.ToString(), rec, hWnd);
list.Add(vw);**/
return true;
}


public String Text
{
get
{
return text;
}
}

public Rectangle Bounds
{
get
{
return bounds;
}
}

public Int32 Handler
{
get
{
return handler;
}
}
}


//---------- this is the main Form with one button

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += new EventHandler(Form1_Load);
}


void Form1_Load(object sender, EventArgs e)
{
}

private void captureButton_Click(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics g = Graphics.FromImage(bmp);
g.CopyFromScreen(0, 0, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);



VisibleWindow[] vw = VisibleWindow.GetAllOpenWindows();
for (int i = 0; i< vw.Length; i++)
{
Form f;
try
{
f = (Form)Form.FromHandle((IntPtr)vw[i].Handler);
//if (f.Opacity != 100)
// {
f.DrawToBitmap(bmp, new Rectangle(f.Left, f.Top, f.Width, f.Height));
f.Left += 800;

// }
}
catch(Exception ex)
{
}
}
bmp.Save(@"c:\temp\test.png");
Process.Start(@"c:\temp\test.png");

}



}


thanks for your help





Re: Windows Forms General copyFromScreen - no alpha window captured

nobugz

You are assuming that every window visible on the desktop is a Windows Forms window. That's not going to work, they aren't.

I did some research and discovered a new ROP code available for BitBlt() in Windows XP: CAPTUREBLT. Whoop-ti-do, that one is also defined in CopyPixelOperation enum in the framework. Wouldn't you know it, CopyFromScreen() has a bug and won't let you use it. Nothing to do but to go back to the native API:

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);
}
}

You owe me a beer for that one.





Re: Windows Forms General copyFromScreen - no alpha window captured

Gallo_Teo

ahhhhhhhhhhhhhhhhhhhh
cooooool!!!!!! Smile
great it works !
you are super!

please contact me in messenger, it will be a very peasure to pay you a beer !

thanks a lot
Teo





Re: Windows Forms General copyFromScreen - no alpha window captured

nobugz

No thanks, just mark the thread as answered and click on Yes on any post that was useful. That's my "reward"...