initial oogynize check in _ this actually used to work!
This commit is contained in:
207
GUILib/ScreenCapture.cs
Normal file
207
GUILib/ScreenCapture.cs
Normal file
@@ -0,0 +1,207 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using System.Reflection;
|
||||
|
||||
using Foo.Platform;
|
||||
using Foo.Platform.Win32;
|
||||
|
||||
namespace Foo.GUILib
|
||||
{
|
||||
|
||||
public class ScreenCapture
|
||||
{
|
||||
// Declare the Log4net Variable
|
||||
private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a Window using a DC of the Full Screen, then crops the window out of the
|
||||
/// full screen capture. We have to do this because SaveWindowUsingDCNBitBlt() doesn't
|
||||
/// work for all programs that overwrite the glass area on Aero (like MS Office)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// IMP! - This function will work on some multiple monitor configurations but currently NOT all!
|
||||
/// If for example, the primary display is on the left and sec on the right, and the window is on the
|
||||
/// right monitor, then all x and y values will be positive, (We currently only handle multiple monitors,
|
||||
/// where one x or y value is negative!),
|
||||
/// ~more calculations must be done for multiple x, multiple y positive configurations
|
||||
/// </remarks>
|
||||
/// <param name="hWnd">handle to a Window</param>
|
||||
public Image SaveWindowUsingFullScreenShotCrop(IntPtr hWnd)
|
||||
{
|
||||
try
|
||||
{
|
||||
// First get the Window Rect
|
||||
RECT rectWnd;
|
||||
Win32Functions.GetWindowRect(hWnd, out rectWnd);
|
||||
|
||||
// Now figure out which monitor the window is in
|
||||
IntPtr hMonitor = Win32Functions.MonitorFromRect(ref rectWnd, (int)Win32_Constants.MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
// Get the szDevice Name for the Monitor
|
||||
MONITORINFOEX monitorinfoex = new MONITORINFOEX();
|
||||
monitorinfoex.cbSize = Marshal.SizeOf(monitorinfoex);
|
||||
if (!Win32Functions.GetMonitorInfo(hMonitor, ref monitorinfoex))
|
||||
return null;
|
||||
|
||||
// Use szDevice to create a DC
|
||||
IntPtr hDC = Win32Functions.CreateDC(monitorinfoex.szDeviceName, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
||||
|
||||
//Here we make a compatible device context in memory for screen device context.
|
||||
IntPtr hMemDC = Win32Functions.CreateCompatibleDC(hDC);
|
||||
|
||||
// Let's get all the monitor dimensions we need
|
||||
Rectangle rectDim = monitorinfoex.rcMonitor.AsRectangle;
|
||||
int DisplayHeight = rectDim.Height;
|
||||
int DisplayWidth = rectDim.Width;
|
||||
|
||||
//The .net way to retrieve dimensions
|
||||
Screen screen = Screen.FromHandle(hWnd);
|
||||
|
||||
//We create a compatible bitmap of screen size using screen device context.
|
||||
IntPtr hBitmap = Win32Functions.CreateCompatibleBitmap(hDC, DisplayWidth, DisplayHeight);
|
||||
|
||||
if (hBitmap != IntPtr.Zero)
|
||||
{
|
||||
//Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
|
||||
IntPtr hOld = (IntPtr)Win32Functions.SelectObject(hMemDC, hBitmap);
|
||||
|
||||
//We copy the Bitmap to the memory device context.
|
||||
Win32Functions.BitBlt(hMemDC, 0, 0, DisplayWidth, DisplayHeight, hDC, 0, 0, Win32_Constants.SRCCOPY);
|
||||
|
||||
//We select the old bitmap back to the memory device context.
|
||||
Win32Functions.SelectObject(hMemDC, hOld);
|
||||
|
||||
//We delete the memory device context.
|
||||
Win32Functions.DeleteDC(hMemDC);
|
||||
|
||||
//Delete the screen device context.
|
||||
Win32Functions.DeleteDC(hDC);
|
||||
|
||||
//Image is created by Image bitmap handle and stored in local variable.
|
||||
Image image = (Image)System.Drawing.Image.FromHbitmap(hBitmap);
|
||||
|
||||
// * For Debugging *
|
||||
//string strFileNameNPathWExtPNG = (Env.GetSnapshotDirectory() + @"\" + hWnd.ToString() + ".png");
|
||||
//image.Save(strFileNameNPathWExtPNG, System.Drawing.Imaging.ImageFormat.Png);
|
||||
|
||||
//Release the memory for compatible bitmap.
|
||||
Win32Functions.DeleteObject(hBitmap);
|
||||
|
||||
////
|
||||
// Imp! - Now we want to crop the Window out of the Screen Image
|
||||
// NOTE! - Here we convert the screen positions into the corresponding
|
||||
// image position on that screen
|
||||
////
|
||||
int height = rectWnd.AsRectangle.Height;
|
||||
int width = rectWnd.AsRectangle.Width;
|
||||
|
||||
rectWnd.left = Math.Abs(rectWnd.left - screen.Bounds.Left);
|
||||
rectWnd.right = rectWnd.left + width;
|
||||
|
||||
rectWnd.top = Math.Abs(rectWnd.top - screen.Bounds.Top);
|
||||
rectWnd.bottom = rectWnd.top + height;
|
||||
|
||||
// Convert the Rectangle for .Net Use
|
||||
Rectangle rectangleWnd = rectWnd.AsRectangle;
|
||||
|
||||
Bitmap bmpImage = new Bitmap(image);
|
||||
Bitmap bmpCrop = bmpImage.Clone(rectangleWnd, bmpImage.PixelFormat);
|
||||
|
||||
//Bitmap bmpCrop = (Bitmap)image;
|
||||
//bmpCrop = bmpCrop.Clone(rectangleWnd, bmpCrop.PixelFormat);
|
||||
|
||||
return (Image)bmpCrop;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(string.Format("{0}() - Error thrown", MethodBase.GetCurrentMethod().Name), e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the Window using a DC, this works well for bUseClientDC = true, but doesn't
|
||||
/// work when using the Window's DC because of Aero drawing via directx, the window frame
|
||||
/// won't be in the image
|
||||
/// </summary>
|
||||
/// <param name="hWnd">handle to a Window</param>
|
||||
/// <param name="bUseClientDC">true to use ClientDC, false to use WindowDC</param>
|
||||
public Image SaveWindowUsingDCNBitBlt(IntPtr hWnd, bool bUseClientDC)
|
||||
{
|
||||
try
|
||||
{
|
||||
SIZE size;
|
||||
IntPtr hDC;
|
||||
IntPtr hBitmap;
|
||||
Image image;
|
||||
RECT Rect = new RECT();
|
||||
|
||||
if (bUseClientDC)
|
||||
Win32Functions.GetClientRect(hWnd, out Rect);
|
||||
else
|
||||
Win32Functions.GetWindowRect(hWnd, out Rect);
|
||||
|
||||
size.cx = (Rect.right - Rect.left);
|
||||
size.cy = (Rect.bottom - Rect.top);
|
||||
|
||||
// TRY USING GetDCEx() - May actually do better
|
||||
//hDC = Win32Functions.GetDCEx(hWnd);
|
||||
if (bUseClientDC)
|
||||
hDC = Win32Functions.GetDC(hWnd);
|
||||
else
|
||||
hDC = Win32Functions.GetWindowDC(hWnd);
|
||||
|
||||
//Here we make a compatible device context in memory for screen device context.
|
||||
IntPtr hMemDC = Win32Functions.CreateCompatibleDC(hDC);
|
||||
|
||||
//We create a compatible bitmap of screen size using screen device context.
|
||||
hBitmap = Win32Functions.CreateCompatibleBitmap(hDC, size.cx, size.cy);
|
||||
|
||||
if (hBitmap != IntPtr.Zero)
|
||||
{
|
||||
//Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
|
||||
IntPtr hOld = (IntPtr)Win32Functions.SelectObject(hMemDC, hBitmap);
|
||||
|
||||
//We copy the Bitmap to the memory device context.
|
||||
Win32Functions.BitBlt(hMemDC, 0, 0, size.cx, size.cy, hDC, 0, 0, Win32_Constants.SRCCOPY);
|
||||
|
||||
//We select the old bitmap back to the memory device context.
|
||||
Win32Functions.SelectObject(hMemDC, hOld);
|
||||
|
||||
//We delete the memory device context.
|
||||
Win32Functions.DeleteDC(hMemDC);
|
||||
|
||||
//We release the screen device context.
|
||||
Win32Functions.ReleaseDC(hWnd, hDC);
|
||||
|
||||
//Image is created by Image bitmap handle and stored in local variable.
|
||||
image = (Image)System.Drawing.Image.FromHbitmap(hBitmap);
|
||||
|
||||
// * For Debugging *
|
||||
//string strFileNameNPathWExtPNG = (Env.GetSnapshotDirectory() + @"\" + hWnd.ToString() + ".png");
|
||||
//image.Save(strFileNameNPathWExtPNG, System.Drawing.Imaging.ImageFormat.Png);
|
||||
|
||||
//Release the memory for compatible bitmap.
|
||||
Win32Functions.DeleteObject(hBitmap);
|
||||
return image;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error(string.Format("{0}() - hBitmap is Null, something is wrong", MethodBase.GetCurrentMethod().Name));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(string.Format("{0}() - Error thrown", MethodBase.GetCurrentMethod().Name), e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user