Taking a screenshot without screen freeze. C# and WindowsXP - c#

I am using C# .NET to take a screenshot of the contents of a second monitor and display it in a windows on the primary screen.
The code I have is:
screenShotGraphics.CopyFromScreen(
Screen.AllScreens[screen].Bounds.X,
Screen.AllScreens[screen].Bounds.Y,
0,
0,
Screen.AllScreens[screen].Bounds.Size,
CopyPixelOperation.SourceCopy);
This works quite well when it is triggered by a button click, because the slight delay is not noticeable, however when it is run automatically (say every few seconds) the user can easily notice their mouse 'lock up' for a few seconds.
Obviously that's not ideal. So is there a faster way to perform this operation? (Or a way to perform it without interrupting mouse movements or interactivity?

You could try performing the screen shot with a BackgroundWorker Control, which is an easy way of running the function on a separate thread. Just call your screen shot function within the DoWork event of the BackgroundWorker and whenever you want to run your function just call:
yourBackgroundWorker.RunWorkerAsync()
Edit:
It's probably doing this so anything moving on the screen (like the mouse) won't blur the screenshot. You could try to break the screen down into smaller sections and take screenshots, then stitch them together. This would free the mouse for movements between each partial screenshot since you're on a separate thread, but it runs the risk of something changing on the screen (depending on how long it actually takes)

Try to make the call on the principal thread and if you need to save the image to file, do it in another thread...
I think that there isn't other way, cuz the CopyFromScreen, calls the BitBlt api function, witch is the one you must call if you want to do this by api calls... So that is the only thing that Windows provides.

Related

Run code repeatedly when a certain form is visible

I want to run a certain method every x milliseconds when a form is visible (so as to change the contents of a picturebox within that form, so that an animation is displayed, to be precise) without obviously blocking events. I cannot load a .gif since I will be using spritesheets and atlas files. I believe this approach steps outside of the event-driven programming language paradigm that comes with .net/c#. I am not sure of the correct way to face this problem - maybe using a thread, but that sounds a bit overkill - any suggestions?
You can use a timer which will fire an event at regular intervals. As to only doing that while the form is visible, you can disable the timer when the form is minimized or hidden, and re-enable it when it's shown again.

How to write AVI from a Callback, keep UI responsive and wait for completion

I have to use a camera SDK for a microscope that comes with a sample C# Windows Forms application.
The SDK functions are imported to the app via DLLImport.
In this sample application the single frames from the camera are read from RAM via a callback function.
This callback function then updates a PictureBox to show the live image.
For my useage however I want to not only show the frames, but also record them.
I think the easiest way to do this is by using SharpAvi.
However I don't know how to initialize the AviWriter (I obviously can't initialize it everytime the callback fires) and then add the single frames to the stream from the callback function.
At the moment I solved my problem by using another function that waits in a seperate thread for a public counter to go up - the counter itself is updated in the callback function.
Everytime the counter is updated this function then also reads the frame from RAM and adds it to the AviWriterStream.
To top it of I had to make the thread block my UI by using
var resetEvent = new ManualResetEvent(false);
System.Threading.ThreadPool.QueueUserWorkItem(delegate
{
WriteAVI()
resetEvent.Set();
}, null);
resetEvent.WaitOne();
This is due to the fact that I need to record several videos at different XY positions - so everytime my for loop arrives at a new XY position the recording is triggered and I have to make sure to only move to the next position once the recording is actually finished.
My way of doing this is obviously hackish and very bad practice (I already feel bad but just don't know better) and I am wondering what the correct solution would be.
So far it works - just the UI freeze is really annoying.
Edit: These are probably two questions:
1) How to correctly write frames to the AVI and
2) How to wait for the recording to be completed without making it freeze my UI

Showing a please wait animation while UI is populated

I'm writing a WinForms window in C# which displays about 12 ListBox and 6 ComboBox controls each with a few hundred to a few thousand items.
It takes a little while to populate these. Not a long while - just a few seconds, but it's nice for the user to have something to look at so they know the program is working away in the background while they wait.
I have a generic "Please Wait" animated borderless top-most window which appears while this happens, however I'm having trouble with the animation.
For most tasks which take a little while, I solve this in the following way:
Program.ShowPleaseWait(); // Show top-most animation
Thread t = new Thread(stuffToDo); // Run stuffToDo() in separate thread
t.Start();
While (t.IsAlive)
Application.DoEvents(); // Run message queue, necessary for animation
Program.HidePleaseWait(); // Hide top-most animation
and it works quite well. Occasionally the stuff in the thread will need to Invoke something and that sometimes causes a small hiccup in the animation, but it's generally not a big deal.
With this form, however, the entire code in the thread is UI code: populating ListBoxes and ComboBoxes. That means everything would have to be enclosed with Invoke blocks, which doesn't make any sense because then there's no point in having it run in a separate thread in the first place.
Aside from scrapping the whole worker thread for this particular case and throwing in an Application.DoEvents() every hundred or so insertions in each loop, is there anything I can do to allow the working animation to continue while the controls are populated?
Just run your animation in a second thread. You're allowed to have multiple UI threads, what's not allowed is accessing any UI object from a thread other than the one that initialized it. The new thread should accept an instance of LoadingAnimationForm (or whatever you call your animated dialog) and call Application.Run(animForm); When the main thread gets done populating everything, call animForm.Invoke(animForm.Close). Do not call any other methods on animForm from the main thread.
One possible approach is to use idle time processing for performing your populating code. So you create a dialog box class that is used to show yours waiting animation. You hook into the idle time processing event at the same time you show the waiting dialog box. Once the idle time processing has fully completed you send a message to your dialog telling it to quit.
The only complication is you need to organize your idle time event so it only performs a little work each time it is called, rather than performing all of it in one go. If you perform it all in one go then the dialog never has chance to process and show an updated wait animation.
Taken from this post:
May I add this CodeProject link?
All you need is to build, drag from toolbar and use. The LoadingCircle component works without any trouble at all. Works like a charm, you can even customize it!

Why is this WinMobile (Compact Framework) app hanging after photo taken?

I am having a very difficult time trying to debug/fix an application.
Briefly:
- I created a "wizard" type app that starts with the user taking a photograph (using the common dialog for photos)
If the user tries to use the text input window (SIP) (the little keyboard input window) after a photo is taken the event loop seems to hang - the event is not processed or is delayed for a while.
If the user does not take a picture the SIP keyboard works great.
This only happens on some of my devices. Specifically it is not a problem on an MC65 but is a problem on an ES400.
It appears that the app's event loop gets screwed up with the way I am displaying forms and taking photos.
If created a simple test app with single form containing a button (Event handler takes a photo) and a text box that accepts input. That works fine. But it is only a single form app that does nothing else.
When I combine the photo taking with my form displaying (making a "wizard" ) things go badly.
I wonder what kind of event loop should I be running?
Essentially the user takes a photo then goes through some forms (I hide one form and show another when they click the "next" button.)
The Form.Show is called from the main form after a picture is taken and then I have something like:
while(UserNotFinished)
{
Application.DoEvents()
}
Where UserNotFinished is a flag set from my wizard/forms after the "submit" button is pressed.
I will be happy to provide more code but not sure what would be useful.
I am new to C# and CF development (lots of years of C++/Win32)
The real confusing part is that this works on one device but not on another. In fact, the device hangs completely. It ends the activesync connection and sometimes I have to hard reset by removing the battery.
I think your problem stems from the while(true) { DoEvents(); } and perhaps how you are trying to go between forms. The only time I've used the DoEvents() method is when I'm already in the scope of a windows event and I need to be sure something in the message queue is processed so screen updates are correct. I'd suggest making a controller class to manage the screen flow for your wizard. You can control the screen flow by either using ShowDialog() and execute the flow control directly in the scope of a single call, or you'll have to use Show() and an asynchronous mechanism such as subscribing to and handling specific form and control events in the controller class. Also saw the comment about introducing another thread, beware that Forms belong to the thread they were created in and you must Invoke(...) all Form members in the context of the creating thread.
Hmm. Very strange
I started a new thread and basically call Application.DoEvents() in in as well and it seems to fix the problem...
I don't know why the
while(true)
{
DoEvents()
}
in the main thread doesn't work.

Automatically show loader on long operation

I'm trying to show a loader animation when my application it's blocked for more than 500ms.
I want that to be automatic, I don't want to add any piece of code before every long operation.
I know that in WinForms it was possible (I used this: https://snipplr.com/view/24851/), but It does not work in WPF.
I've found that I can do that with the mouse cursor(display Hourglass when application is busy)
I've tried to launch a window with a spinner.
I've found this answer (https://stackoverflow.com/a/21411656/10820863), that works detecting long operation.
Problem is that if I launch a window from a thread that is not the main one, I got a ThreadException because it's not the main thread. If I use Application.Current.Dispatcher.BeginInvoke
method, the window appears only when UI is not blocked anymore.
So, how can I automatically detect long operation and show a loading window/page/image/whatever if it lasts for more than 500ms?
[EDIT]
I don't want to add code to every long function, evaluating case for case which function can be long.
I'd prefer to have an automatic method that do that for me.

Categories