Taking Screen shot continuously without slow down the PC - C# - c#

I have to capture a screen shot continuously after every 250 milliseconds for my program (Similar to Netmeeting). I used the following code:
Image CaptureScreenShot()
{
bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
return bmpScreenshot;
}
To capture the screenshot but it slow the performance of the PC. Where, Netmeeting do not.
Is there any way to get screen shot without slowing the PC?
Code sample will be appreciated

You won't find a basic answer here. They use much more involved mechanisms for detecting changes on the screen and sending them.
Check out how terminal svcs work -
http://technet.microsoft.com/en-us/library/cc755399%28WS.10%29.aspx
ideally you are hooking into the GUI and monitoring events, etc. much more advanced than simply screen scraping. If you want to look at less advanced code check out http://www.tightvnc.com

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

Take screenshot of external OpenGL game C# with BitBlt (CopyFromScreen)

I am trying to create some kind of antycheat for counter strike (hl) game. Of course funcionality of making a screenshot in-game is built-in, but exploited (detected) by antyss applications, so every time screenshot is taken from the game, antyss is disabling the cheats (so that no cheats are visible on the screenshots)
For the last few days, I've read dozens of threads regarding this topic. Most of them are outdated and are using libraries, that are obsolete right now.
I've read about the approach with mirage driver (which is not working on windows 10), about injecting to the application (of course application/game is not part of my code) and using/incjeting some code with OPEN GL/D3D library (to read backbuffer). Probably this could be in the end the only solution.
But right now I have almost a working solution. I write "almost" because it is working but giving me only some kind of "cached" data. It is giving me a correct screenshot, but if I take another screenshot - still the same screenshot is taken as last time. If while being in-game I minimize the application (full-screen mode) and then get back to the game, the new screenshot taken will have up to date screenshot, but then again, the next screenshot would be exactly the same.
I don't know if it is "by design" or is it "some sort of bug" Nevertheless my question is: Can I force somehow this "reloading" without having to programmatically call some kind of "alt+tab" and then focusing on the application once again?
In this topic:
How to take screenshots of a game with OpenGL
#Andon M. Coleman wrote:
Are you on Windows? In fullscreen mode starting with Windows Vista, there is trouble with anything that tries to capture the front-buffer (including the built-in Alt + PrintScreen). The easiest solution is to change your buffer swap behavior to Copy Swap (PFD_SWAP_COPY, slower but guaranteed to work). Often if you Alt+TAB out and back in after making the fullscreen mode switch that will fix it too; though I have never been able to explain that ;) If you did not write the game in the question, then the second solution may be your only choice if you want to use that code.
This is exactly the problem I am facing. As he wrote: "Alt+Tab" is fixing the problem (although he did not know whether it is a feature or a bug) He proposed to change the buffer swap behavior to Copy Swap(PFD_SWAP_COPY) Any tips on how to change my code with that will also be most welcome (I can try this one) But if I understood correctly, this approach is the viable solution only if you can change this in the game (and this is not my case)
Here is my working code (which in topics about such scenarios was claiming that in this approach the screenshot is BLACK. But it is working for me)
private const int SW_RESTORE = 9;
public void TakeScreenShot()
{
var guid = Guid.NewGuid();
string procName = "hl";
Process proc;
try
{
proc = Process.GetProcessesByName(procName)[0];
}
catch (IndexOutOfRangeException e)
{
return;
}
// Focus on the application
SetForegroundWindow(proc.MainWindowHandle);
ShowWindow(proc.MainWindowHandle, SW_RESTORE);
Thread.Sleep(1000);
Rect rect = new Rect();
IntPtr error = GetWindowRect(proc.MainWindowHandle, ref rect);
while (error == (IntPtr)0)
{
error = GetWindowRect(proc.MainWindowHandle, ref rect);
}
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
using (Bitmap printscreen = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
using (var graphics = Graphics.FromImage(printscreen))
{
graphics.CopyFromScreen(rect.left,
rect.top,
0,
0,
new Size(width, height),
CopyPixelOperation.SourceCopy);
printscreen.Save($#"{Path.GetTempPath()}\{guid.ToString()}.jpg", ImageFormat.Jpeg);
}
}
}
I want this application to work on Windows7, Windows8, Windows 10. The best would be to cover full screen and windowed mode (but fullscreen is probably more important)
Any advice how to proceed (or why I am getting the "cached" data) would be nice :)
Of course if someone will say (with full authority), that what i want to achieve is impossible with CopyFromScreen (and there is no hack to fix that, apart from minimizing and maximazing the screen) i will consider option with injecting the code. But normally i would want to stay away from this one, as this could be treated as cheat and can lead to VAC ban.
====== UPDATE ======
You can try reproduce the process of taking screenshot by downloading the game (is small one, 260 MB):
https://cssetti.pl/Api/GameDownload.php?GameDownloadId=v43
Then you can copy-paste my code to Linqpad (or any other editor) and run the code. The application after launching will launch the HL process which is then use to try to grab the screenshot.
====== UPDATE 2 ======
In windows mode everything works correctly (the printscreens are ok)

Reduce time to take a screenshot to 40ms

I'm taking a screenshot, shrinking it down to 50% of resolution,to take less space and then I put bytes in the buffer, however unfortunately this process takes too much time.
Currently it takes from 60 to 100ms for 1920x1080 source resolution, this causes that the output video at 30fps is speeded up as I'm not producing screenshots fast enough. I need to achieve about 40ms to make video that I make out of it fluent.
Question: How can I apply a faster interpolation algorithm or limit the required operation to speed it up?
public void Screenshot(byte[] buffer)
{
using (var bmp = new Bitmap(Params.SourceWidth, Params.SourceHeight))
{
using (var g = Graphics.FromImage(bmp))
{
g.CopyFromScreen(Point.Empty, Point.Empty, new Size(Params.SourceWidth, Params.SourceHeight), CopyPixelOperation.SourceCopy);
g.Flush();
using (Bitmap resized = new Bitmap(bmp, new Size(Params.TargetWidth, Params.TargetHeight)))
{
var bits = resized.LockBits(new Rectangle(0, 0, Params.TargetWidth, Params.TargetHeight), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
Marshal.Copy(bits.Scan0, buffer, 0, buffer.Length);
resized.UnlockBits(bits);
}
}
}
}
This approach is slow because you're using GDI, which is no longer the main graphics API in Windows (and hasn't been since Windows Vista). One of the reasons it's slow is because it copies image data from your GPU's memory (VRAM) into your computer's main memory (RAM) for it to be manipulated with through GDI.
If you want fast operations on your computer's framebuffer, use the DWM APIs and only copy memory between buffers in your GPU. You can probably also do the image resizing and other operations really fast by doing them as shaders or CUDA programs.

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.

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

Categories

Resources