How to save Bitmap from ActiveX component - c#

Try to save screen of AxMsTscAxNotSafeForScripting (Microsoft Terminal Services Client Control), but cant find any information about it...
I try one code, but it screen only field of element...
https://i.imgur.com/fo6jKDT.png
[Flags]
private enum DrawingOptions
{
PRF_CHECKVISIBLE = 0x00000001,
PRF_NONCLIENT = 0x00000002,
PRF_CLIENT = 0x00000004,
PRF_ERASEBKGND = 0x00000008,
PRF_CHILDREN = 0x00000010,
PRF_OWNED = 0x00000020
}
private const uint WM_PAINT = 0xF;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr dc, DrawingOptions opts);
var bm = new Bitmap(rdp.Width, rdp.Height, rdp.CreateGraphics());
using (Graphics g = Graphics.FromImage(bm))
{
IntPtr dc = g.GetHdc();
try
{
SendMessage(rdp.Handle, WM_PAINT, dc,
DrawingOptions.PRF_CLIENT |
DrawingOptions.PRF_NONCLIENT |
DrawingOptions.PRF_CHILDREN);
}
finally
{
g.ReleaseHdc();
}
}
pictureBox1.Image = bm;

This code helped to save the form image and displays ActiveX perfectly. Since the item is static, I'll just crop the image and get the screenshot I want.
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, int nFlags);
public static Bitmap PrintWindow(IntPtr hwnd)
{
RECT rc;
GetWindowRect(hwnd, out rc);
Bitmap bmp = new Bitmap(rc.Width, rc.Height, PixelFormat.Format32bppArgb);
Graphics gfxBmp = Graphics.FromImage(bmp);
IntPtr hdcBitmap = gfxBmp.GetHdc();
PrintWindow(hwnd, hdcBitmap, 0);
gfxBmp.ReleaseHdc(hdcBitmap);
gfxBmp.Dispose();
return bmp;
}

Related

c# capture window content without borders

I have to capture content and only content of one window. Like that:
(captured by ScreenCaptor)
But my program captures that:
I use this code:
IntPtr ParenthWnd = GetForegroundWindow();
if (!ParenthWnd.Equals(IntPtr.Zero))
{
IntPtr prevChild = IntPtr.Zero;
IntPtr currChild = IntPtr.Zero;
while (true)
{
currChild = FindWindowEx(ParenthWnd, prevChild, null, null);
if (currChild == IntPtr.Zero) break;
result.Add(currChild);
label3.Text += currChild.ToString() + " _ ";
prevChild = currChild;
}
}
then I choose my child window, e.g:
handle = result[0];
and finally capture screenshot:
RECT rect = new RECT();
GetWindowRect(handle, ref rect);
Bitmap image = new Bitmap(rect.Right - rect.Left, rect.Bottom - rect.Top);
using (Graphics graphics = Graphics.FromImage(image))
{
IntPtr hDC = graphics.GetHdc();
PrintWindow(new HandleRef(graphics, handle), hDC, 0);
graphics.ReleaseHdc(hDC);
}
of course I cannot crop captured image, because don't know size of each 'border'
thanks in advance
a little bit late but maby it does someone help:
private const int GWL_STYLE = -16; //hex constant for style changing
private const int WS_BORDER = 0x00800000; //window with border
private const int WS_CAPTION = 0x00C00000; //window with a title bar
private const int WS_SYSMENU = 0x00080000; //window with no borders etc.
private const int WS_MINIMIZEBOX = 0x00020000; //window with minimizebox
public static Bitmap printWindow(IntPtr hwnd)
{
RECT rc;
GetWindowRect(hwnd, out rc);
Bitmap bmp;
//make window borderless
SetWindowLong(hwnd, GWL_STYLE, WS_SYSMENU);
SetWindowPos(hwnd, -2, rc.X, rc.Y, rc.Width, rc.Height, 0x0040);
DrawMenuBar(hwnd);
bmp = new Bitmap(800, 800, PixelFormat.Format32bppArgb);
Graphics gfxBmp = Graphics.FromImage(bmp);
IntPtr hdcBitmap = gfxBmp.GetHdc();
PrintWindow(hwnd, hdcBitmap, 0);
gfxBmp.ReleaseHdc(hdcBitmap);
gfxBmp.Dispose();
//restore window
SetWindowLong(hwnd, GWL_STYLE, WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX);
DrawMenuBar(hwnd);
ShowWindowAsync(hwnd, 1); //1 = Normal
return bmp;
}
Another solution is to print the window and remove the borders from the bmp:
[DllImport("user32.dll")]
static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, int nFlags);
public Bitmap printWindow()
{
RECT clientRect;
GetClientRect(WindowHandle, out clientRect);
RECT windowRect;
GetWindowRect(WindowHandle, out windowRect);
int borderSize = (windowRect.Width - clientRect.Width) / 2;
int titleBarSize = (windowRect.Height - clientRect.Height) - borderSize;
PrintWindow(MainWindowHandle, hdcBitmap, 0);
gfxBmp.ReleaseHdc(hdcBitmap);
gfxBmp.Dispose();
Bitmap bmp = bmp.Clone(new Rectangle(borderSize, titleBarSize, bmp.Width - 2*borderSize, bmp.Height - titleBarSize-borderSize), PixelFormat.Format32bppRgb);
return bmp;
}

How could I make the bitmap image by using fromHdc method?

I'd like to get the specific region by using way to get DesktopWindow handle like below code.
[DllImport("user32.dll")]
static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
static extern IntPtr GetDCEx(IntPtr hwnd, IntPtr hrgn, uint flags);
[DllImport("user32.dll")]
static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc);
public void ScreenShot()
{
try
{
IntPtr hwnd = GetDesktopWindow();
IntPtr hdc = GetDCEx(hwnd, IntPtr.Zero, 1027);
Point temp = new Point(40, 40);
Graphics g = Graphics.FromHdc(hdc);
Bitmap bitmap = new Bitmap(mPanel.Width, mPanel.Height, g);
g.CopyFromScreen(PointToScreen(temp) , PointToScreen(PictureBox.Location) , PictureBox.Size);
}
This code actually works, but I'd like to get a copied image which is made from the process of CopyFromScreen. I have tried using code like Graphics.FromImage(bitmap), however I could not get the image that I wanted... I mean,, copied Image.
I could not find the way to get a Bitmap image when I use Graphics object fromHdc.
I have to use DC.... Is there any proper way??
You are going the wrong way here, you don't need to get the desktop handle, CopyFromScreen will copy whatever is on screen now to the target graphics so you need to create graphics object from the image.
The following code create an 500x500 image of the top left of the screen.
public static void ScreenShot()
{
var destBitmap = new Bitmap(500, 500);
using (var destGraph = Graphics.FromImage(destBitmap))
{
destGraph.CopyFromScreen(new Point(), new Point(), destBitmap.Size);
}
destBitmap.Save(#"c:\bla.png");
}
and if you really have HDC you need to use BitBlt from gdi32:
[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);

Easiest way to select screen region

I'm writing a simple program in C# + WPF that records/serializes user mouse and keyboard activities and then he can playback it.
Some of its features require user to specify coordinates of a small area in the screen. Typing coordinates of top left and bottom right corners to textboxes is not very comfortable so I want to select it in similar way like Windows Snipping Tool, ZScreen/ShareX etc. do that.
Something like that, maybe simplified
What is the easiest way to implement that?
I've googled a lot but didn't find anything simple and clear. http://cropper.codeplex.com/ source code looks like too complicated and I don't need image, only coordinates relative to screen.
You can try with this static class CaptureScreen and Capture method
static public class CaptureScreen
{
public static BitmapSource Capture(Rect area)
{
IntPtr screenDC = GetDC(IntPtr.Zero);
IntPtr memDC = CreateCompatibleDC(screenDC);
IntPtr hBitmap = CreateCompatibleBitmap(screenDC, (int)SystemParameters.VirtualScreenWidth, (int)SystemParameters.VirtualScreenHeight);
SelectObject(memDC, hBitmap); // Select bitmap from compatible bitmap to memDC
// TODO: BitBlt may fail horribly
BitBlt(memDC, 0, 0, (int)area.Width, (int)area.Height, screenDC, (int)area.X, (int)area.Y, TernaryRasterOperations.SRCCOPY);
BitmapSource bsource = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
DeleteObject(hBitmap);
ReleaseDC(IntPtr.Zero, screenDC);
ReleaseDC(IntPtr.Zero, memDC);
return bsource;
}
#region WINAPI DLL Imports
[DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
[DllImport("gdi32.dll", SetLastError = true)]
private static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateBitmap(int nWidth, int nHeight, uint cPlanes, uint cBitsPerPel, IntPtr lpvBits);
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
private enum TernaryRasterOperations : uint
{
/// <summary>dest = source</summary>
SRCCOPY = 0x00CC0020,
/// <summary>dest = source OR dest</summary>
SRCPAINT = 0x00EE0086,
/// <summary>dest = source AND dest</summary>
SRCAND = 0x008800C6,
/// <summary>dest = source XOR dest</summary>
SRCINVERT = 0x00660046,
/// <summary>dest = source AND (NOT dest)</summary>
SRCERASE = 0x00440328,
/// <summary>dest = (NOT source)</summary>
NOTSRCCOPY = 0x00330008,
/// <summary>dest = (NOT src) AND (NOT dest)</summary>
NOTSRCERASE = 0x001100A6,
/// <summary>dest = (source AND pattern)</summary>
MERGECOPY = 0x00C000CA,
/// <summary>dest = (NOT source) OR dest</summary>
MERGEPAINT = 0x00BB0226,
/// <summary>dest = pattern</summary>
PATCOPY = 0x00F00021,
/// <summary>dest = DPSnoo</summary>
PATPAINT = 0x00FB0A09,
/// <summary>dest = pattern XOR dest</summary>
PATINVERT = 0x005A0049,
/// <summary>dest = (NOT dest)</summary>
DSTINVERT = 0x00550009,
/// <summary>dest = BLACK</summary>
BLACKNESS = 0x00000042,
/// <summary>dest = WHITE</summary>
WHITENESS = 0x00FF0062
}
[DllImport("gdi32.dll")]
private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
#endregion
}

Drawing Window to Image file

Anyone know why this keeps returning a blank image? I found this function here.
I pass in a handle to a notepad process/window.
public static Image DrawToBitmap(IntPtr handle)
{
Bitmap image = new Bitmap(500, 500, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(image))
{
IntPtr hDC = graphics.GetHdc();
SendMessage(new HandleRef(graphics, handle), WM_PRINT, hDC, PRF_CHILDREN);
graphics.ReleaseHdc(hDC);
}
return image;
}
I make use of the above like so:
Image myimage = DrawToBitmap(handle);
myimage.Save("C:\\here.png", ImageFormat.Png);
Thanks all for any help
Update
I think I have managed to get the error code from SendMessage using the below:
if (SendMessage(handle, WM_PRINT, hDC, PRF_CLIENT))
{
Console.WriteLine("Success!");
}
else
{
Console.WriteLine("Error: " + Marshal.GetLastWin32Error());
}
I get an error of 8 and I found it means not enough memory? I have over 500MB free! Maybe I am understanding this wrong?
Instead of SendMessage you could just use PrintWindow
Here is a sample
public static Image DrawToBitmap(IntPtr handle)
{
RECT rect = new RECT();
GetWindowRect(handle, ref rect);
Bitmap image = new Bitmap(rect.Right - rect.Left, rect.Bottom - rect.Top);
using (Graphics graphics = Graphics.FromImage(image))
{
IntPtr hDC = graphics.GetHdc();
PrintWindow(new HandleRef(graphics, handle), hDC, 0);
graphics.ReleaseHdc(hDC);
}
return image;
}
#region Interop
[DllImport("USER32.DLL")]
private static extern bool PrintWindow(HandleRef hwnd, IntPtr hdcBlt, int nFlags);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
#endregion
Try passing PRF_CLIENT or PRF_NONCLIENT to SendMessage in addition to PRF_CHILDREN.
Also, how are you deriving the handle that you are passing to the function?

How to get the screenshot of the form

Any method to output the screenshot of an active form?
Even simpler answer supported by .NET:
Control.DrawToBitmap.
Use the Control.DrawToBitmap() method. For example:
private void timer1_Tick(object sender, EventArgs e) {
var frm = Form.ActiveForm;
using (var bmp = new Bitmap(frm.Width, frm.Height)) {
frm.DrawToBitmap(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height));
bmp.Save(#"c:\temp\screenshot.png");
}
}
Try this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
namespace ScreenshotCapturer
{
public partial class Form1 : Form
{
private static Bitmap bmpScreenshot;
private static Graphics gfxScreenshot;
public Form1()
{
InitializeComponent();
}
private void btnCapture_Click(object sender, EventArgs e)
{
// If the user has choosed a path where to save the screenshot
if (saveScreenshot.ShowDialog() == DialogResult.OK)
{
// Hide the form so that it does not appear in the screenshot
this.Hide();
// Set the bitmap object to the size of the screen
bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
// Create a graphics object from the bitmap
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
// Take the screenshot from the upper left corner to the right bottom corner
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
// Save the screenshot to the specified path that the user has chosen
bmpScreenshot.Save(saveScreenshot.FileName, ImageFormat.Png);
// Show the form again
this.Show();
}
}
}
}
Here's an extension method you can use:
#region Interop
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr hdc, PRF_FLAGS drawingOptions);
const uint WM_PRINT = 0x317;
[Flags]
enum PRF_FLAGS : uint
{
CHECKVISIBLE = 0x01,
CHILDREN = 0x02,
CLIENT = 0x04,
ERASEBKGND = 0x08,
NONCLIENT = 0x10,
OWNED = 0x20
}
#endregion
public static Image CaptureImage(this Control control)
{
Image img = new Bitmap(control.Width, control.Height);
using (Graphics g = Graphics.FromImage(img))
{
SendMessage(
control.Handle,
WM_PRINT,
g.GetHdc(),
PRF_FLAGS.CLIENT | PRF_FLAGS.NONCLIENT | PRF_FLAGS.ERASEBKGND);
}
return img;
}
Form inherits from Control, so you can use it on a form too.
Because Control.DrawToBitmap has some limitations (most notably drawing child controls in reverse order) I have made this alternative. The variable _control is the WinForms Control/Form that you want to copy.
using (Bitmap bitmap = new Bitmap(width, height)) {
using (Graphics gb = Graphics.FromImage(bitmap))
using (Graphics gc = Graphics.FromHwnd(_control.Handle)) {
IntPtr hdcDest = IntPtr.Zero;
IntPtr hdcSrc = IntPtr.Zero;
try {
hdcDest = gb.GetHdc();
hdcSrc = gc.GetHdc();
BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, SRC_COPY);
} finally {
if (hdcDest != IntPtr.Zero) gb.ReleaseHdc(hdcDest);
if (hdcSrc != IntPtr.Zero) gc.ReleaseHdc(hdcSrc);
}
}
bitmap.Save(...);
}
[DllImport("gdi32.dll", EntryPoint = "BitBlt")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool BitBlt(
[In()] System.IntPtr hdc, int x, int y, int cx, int cy,
[In()] System.IntPtr hdcSrc, int x1, int y1, uint rop);
private const int SRC_COPY = 0xCC0020;
this.Opacity = 0;
Rectangle bounds = Screen.GetBounds(Point.Empty);
// create the bitmap to copy the screen shot to
Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
// now copy the screen image to the graphics device from the bitmap
using (Graphics gr = Graphics.FromImage(bitmap))
{
gr.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
}
this.Opacity = 100;
Now just
gr.Save(#"c\pic.jpg",ImageFormat.jpg);
This will save a screenshot of your active window to your C: drive.
The SendKeys.Send("") is used to send keypresses to the computer. In this case % is used to press Alt and {PRTSC} obviously to press the Print Screen button on your keyboard.
Hope this helps someone!
private void printScreenButton_Click(object sender, EventArgs e)
{
SendKeys.Send("%{PRTSC}");
Image img = Clipboard.GetImage();
img.Save(#"C:\\testprintscreen.jpg");
}
here is:
public const int SRCCOPY = 0x00CC0020; // BitBlt dwRop parameter
[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest,
int nWidth, int nHeight, IntPtr hObjectSource,
int nXSrc, int nYSrc, int dwRop);
[DllImport("gdi32.dll")]
public static extern bool StretchBlt(
IntPtr hdcDest, // handle to destination DC
int nXOriginDest, // x-coord of destination upper-left corner
int nYOriginDest, // y-coord of destination upper-left corner
int nWidthDest, // width of destination rectangle
int nHeightDest, // height of destination rectangle
IntPtr hdcSrc, // handle to source DC
int nXOriginSrc, // x-coord of source upper-left corner
int nYOriginSrc, // y-coord of source upper-left corner
int nWidthSrc, // width of source rectangle
int nHeightSrc, // height of source rectangle
int dwRop // raster operation code
);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth,
int nHeight);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
private void run_test()
{
Rectangle rc = new Rectangle();
Image img = ScreenToImage(ref rc, false);
img.Save(#"C:\Users\ssaamm\Desktop\Capt44ure.JPG", System.Drawing.Imaging.ImageFormat.Jpeg);
img.Dispose();
}
private Image ScreenToImage(ref Rectangle rcDest, bool IsPapaer)
{
IntPtr handle = this.Handle;
//this.Handle
// get te hDC of the target window
IntPtr hdcSrc = GetWindowDC(handle);
// get the size
RECT windowRect = new RECT();
GetWindowRect(handle, ref windowRect);
int nWidth = windowRect.right - windowRect.left;
int nHeight = windowRect.bottom - windowRect.top;
if (IsPapaer)
{
float fRate = (float)rcDest.Width / nWidth;
//float fHeight = nHeight * fRate;
//rcDest.Height = (int)(nHeight * fRate);
//rcDest.Width = (int)(rcDest.Width);// * fRate);
rcDest.X = 0;
rcDest.Y = 0;
rcDest.Height = (int)(nHeight * fRate);
//rcDest.Width = (int)(nWidth * fRate);
}
else
{
rcDest.X = 0;
rcDest.Y = 0;
rcDest.Height = nHeight;
rcDest.Width = nWidth;
}
// create a device context we can copy to
IntPtr hdcDest = CreateCompatibleDC(hdcSrc);
// create a bitmap we can copy it to,
// using GetDeviceCaps to get the width/height
IntPtr hBitmap = CreateCompatibleBitmap(hdcSrc, rcDest.Width, rcDest.Height);
// select the bitmap object
IntPtr hOld = SelectObject(hdcDest, hBitmap);
// bitblt over
StretchBlt(hdcDest, rcDest.X, rcDest.Y, rcDest.Width, rcDest.Height, hdcSrc, 0, 0, nWidth, nHeight, SRCCOPY);
// restore selection
SelectObject(hdcDest, hOld);
// clean up
DeleteDC(hdcDest);
ReleaseDC(handle, hdcSrc);
// get a .NET image object for it
Image img = Image.FromHbitmap(hBitmap);
// free up the Bitmap object
DeleteObject(hBitmap);
return img;
}

Categories