Win32 exception is being thrown while taking a screenshot [c#] - c#

My application is recording the screen (taking screenshots) using Graphics.CopyFromScreen(...) function. The problem is that sometimes an ,,Invalid handle win32" exception is being thrown for some unknown reason. The program is running in the background (it's a console app project with hidden console). I was looking for a solution with google, but I haven't found anything helpful in my case.
The function I wrote:
static Bitmap takeScreenshot()
{
Bitmap bmpScreenCapture = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height);
using (Graphics g = Graphics.FromImage(bmpScreenCapture))
{
g.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y,
0, 0,
bmpScreenCapture.Size,
CopyPixelOperation.SourceCopy);
}
return bmpScreenCapture;
}

I've just found out that the app was trying to create files that already existed. Somehow that caused an exception, but I don't know why. I deleted old files and now program seems to work properly...

Related

C# Memory issue using bitmaps for creating a screenrecorder

Im developing a screen recorder but having problems with the bitmaps and disposing them. The problem is that ram is being eaten fast. Then i started wondering if it was bad practice creating a screen recorder using bitmaps?
I tried Bitmap.Dispose() but then i get a System.ArgumentException: 'Parameter is not valid.' error.
So the 2 questions i have:
Is it bad practice creating a screen recorder using Bitmap?
Any idea how to solve the memory issue?
Below is some code, after using the videoFileWriter i tried disposing the image since it would not have been usefull but still it crashes.
Thank you for your time.
using (Bitmap bmpImage = new Bitmap(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height))
{
graphics = Graphics.FromImage(bmpImage);
graphics.CopyFromScreen(0, 0, 0, 0, bmpImage.Size);
pictureBox1.Image = bmpImage;
lblTime.Text = stopwatch.Elapsed.ToString();
videoFileWriter.WriteVideoFrame(bmpImage);
}

How do screenshot in c# (low level may be) when desktop blocked?

I try get screenshot (windows 8) with code and get black screen when desktop blocked:
public static Bitmap ImageFromScreen()
{
Graphics gr;
Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height,PixelFormat.Format32bppRgb);
gr = Graphics.FromImage(bmp);
gr.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y,
0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
return bmp;
}
You don't.
Apart from window cache (which isn't accessible, and doesn't really have to be there), the data simply isn't there. You'd have to fake WM_PAINT messages and force the application to draw to your surface (most controls will take the HDC from wParam; that still excludes a ton of badly written (or not Windows-native) applications - and even then, this will not work most of the time, like when the windows are minimized or the desktop is locked.
What is it that you're actually trying to do?
EDIT:
Okay, it's obvious that you're explicitly talking about the "locked screen" case - there's no way to get a screenshot of the desktop in that case - it doesn't really exist. The lock screen exists in a different session, so you no longer have any connection to the "hidden" user session. This is similar to trying to take screenshots on a server application after you've disconnected Remote Desktop - there's nothing to take shots of. It may be possible to force some applications to draw to your context, but nothing that would simply work.

GDI throws OutOfMemoryException on loading or cloning bitmap while in an Thread Pool

I have a problem where loading or cloning an png file to an .Net (3.5) Bitmap class causes an OutOfMemoryException within the GDI framework.
This code on run inside an ThreadPool.QueueUserWorkItem, at any time the code creates up to 20 calls to the image loading method that has this code.
// The GDI may throw an OutOfMemoryException on either load or clone of an bitmap
using (var bmp = new Bitmap(filename))
{
var clone = bmp.Clone(new Rectangle(new Point(0, 0), bmp.Size), PixelFormat.Format32bppPArgb);
//post clone bitmap to main thread
}
The solution is to put and try catch around the using statement
try {
using (var bmp = new Bitmap(filename))
{ ... }
}
catch (OutOfMemoryException) { // Swallow the exception}
I have tested and shown this defect on Win7 32&64bit machines and Win8 in Normal and safe modes. This defect only shows on 5 out of 8 machines where the tests where carried out.
Machines are high end Dell and Asus workstations and laptops with different video cards.
Due to the exception coming from the GDI software stack, I don't believe this defect is related to hardware.
The exception may be thrown less than 0.1% of the time, so rare and random. The files are in good order and are not the cause of the problem.
I am looking for an explanation as to why the GDI throws this exception, so I can explain it to my software team and our customer.

Screenshot of the main WPF window under second monitor/TV

I use my application on the second monitor and sometimes at the primary monitor of the computer.
How I can get screenshot of the second monitor?
The following code doesn't work for the second monitor...
Graphics gfx;
Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
gfx = Graphics.FromImage(bmp);
gfx.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
MemoryStream ms = new MemoryStream();
bmp.Save(ms, ImageFormat.Jpeg);
byte[] bitmapData = ms.ToArray();
Use Screen.AllScreens[1].Bounds isntead of Screen.PrimaryScreen.Bounds.
Or more reliable to get the first non Primary Screen.
var secondScreen = Screen.AllScreens.Where(screen => !screen.Primary).FirstOrDefault();
check for secondScreen == null to know if you have a secondScreen.
Edit:
You might also be interested in Screen.FromControl that gives the screen that the application is currently running on.
That code does not work for your second screen because it is explicitly using Screen.PrimaryScreen.
If you want to pull from the second display explicitly (ignoring the case where you have 3…n displays), you can replace PrimaryScreen with AllScreens[1].
Keep in mind that this will break if you ever disconnect that second display.
It sounds like maybe you want to be capturing your application window instead of the screen, in case the application isn't taking up the whole screen or straddles two screens. WPF has this capability natively: Get System.Drawing.Bitmap of a WPF Area using VisualBrush

Is passing System.Drawing.Bitmap across class libraries unreliable?

I have a 3rd party dll which generates a Bitmap and send back its reference. If I generate a System.Windows.Media.Imaging.BitmapSource out of it immediately then all goes well. But if I save the reference and later on (after a few seconds and many function calls) I try to generate the Bitmapsource, I get
System.AccessViolationException was
unhandled by user code
Message=Attempted to read or write
protected memory. This is often an
indication that other memory is
corrupt. Source="System.Drawing"
when doing :
System.Windows.Media.Imaging.BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
bmp.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
Any clues on whats going wrong here ? Any pointers will be useful. Thanks.
I think this indicates that the handle (reference to a resource managed by the operating system, rather than .Net) returned by bmp.GetHBitmap is no longer valid - possibly a Dispose has been called somewhere or something like that (not necessarily by your code though).
I'd recommend using another way of persisting the bitmap data that does not rely on handles - possibly stream out the binary data of the bitmap itself immediately, and then throw a reference to that around.
I had a big problem with Bitmaps and access violations as well. What I believe to be happening is that certain bitmap constructors leave file handles open when they should not. Thus, the program you are running detects that the files are in use, when they shouldn't be.
I eventually figured out a solution in that I make a copy of the original bitmap and then dispose the original. Here is my code, which preserves the resolution of the original Bitmap:
Bitmap Temp = new Bitmap(inFullPathName);
Bitmap Copy = new Bitmap(Temp.Width, Temp.Height);
Copy.SetResolution(Temp.HorizontalResolution, Temp.VerticalResolution);
using (Graphics g = Graphics.FromImage(Copy))
{
g.DrawImageUnscaled(Temp, 0, 0);
}
Temp.Dispose();
return Copy;
Obviously, for the first line, yours would be Bitmap Temp = MyThirdPartyDLL.GetBitmap(); or something. If you don't care about the resolution it can be simplified to:
Bitmap Temp = MyThirdPartyDLL.GetBitmap();
Bitmap Copy = new Bitmap(Temp, Temp.Width, Temp.Height);
Temp.Dispose();
return Copy;
After making this change, I was able to do all kinds of File I/O, etc, perfectly fine, hope you can do the same.

Categories

Resources