Getting Pixel Values "Under" Current Window - c#

I'm trying to make, essentially, a screen capture program, that captures the pixel values under the current window. (I'm working in C#, in Visual Studio 2015.) However, for various reasons, the window itself needs to be opaque (for filters and such). How can I best achieve this?

It is possible to find the window below yours and get a screenshot of it even if it is hidden with the method: PrintWindow (see PInvoke.net as well)
See Copying content from a hidden or clipped window in XP?

It is very simple to do in Winforms. Just set the form's Opacity value to 99%. Now Graphics.CopyFromScreen() will not see your window anymore.
Except when the window underneath yours is also a layered window, then it also won't be visible to CopyFromScreen() for the same reason. Then you have to set Opacity to 0, copy and set it back to 0.99. Very quick, probably good enough for what you want to do.

Related

Take a screenshot behind window in C# WinForm

I'm working on an app in c# windows forms, I have a form called Form1 with a button, and after click this button the idea is to take a screenshoot of everything behind it except the Form1 itself (without minimizing Form1).
Any idea or suggestion?
Thank you!
If you want a solution without hiding, moving, minimizing etc., you need the following approach:
EnumWindows() to iterate all windows. This will give you the windows top to bottom.
Don't forget to exclude your own window
Exclude windows that are invisible. Check out GetWindowLongPtr with GWL_STYLE and compare against WS_VISIBLE
GetWindowRect() to get their size
PrintWindow() to get a bitmap of the window, no matter whether it's in the background
Create a bitmap with the size of the VirtualScreen
Paint the windows in reverse order (bottom to top) using DrawImage()
I found that this is quite fast (514 ms on a 2560x1440 screen with 20 visible windows to draw).
Limitations:
since it sends a WM_PRINT message to the application, you can not capture applications that are "not responding"
For me, Firefox does not render well. It's missing page contents.
For me, control panel content appears black, although it's there when getting a screenshot of the whole screen.
you can use hard code. Actually light shot and other tools working such as. When you click to screenshot button you may close the form window after the event and reopen it. it is the basic way of solution...
Please check this way: How can i capture the screen without the Form?

How to have different opacity for multiple controls?

I have a problem with the opacity of some controls.
So I set the form opacity to 0.3, when the form is loaded, and the problem is that it makes the other controls as tranparent as the form. Here is the code.
private void Form1_Load(object sender, EventArgs e)
{
this.Opacity = 0.3;
}
By doing this, all my controls are as transparent as the form. Is there any way to have different opacity for the controls inside the form ? I don't want the other to be transparent at all.
My first recommandation would be to avoid that. Having a semi-transparent background with opaque controls will look somewhat weird. Instead, consider changing the opacity when the form is active say from 0.3 to 0.7 so that it is easier to read.
Also another problem if some controls are opaque and the background is almost transparent, then your UI might not work well on some background. For example, if the background is really dark, then dark text (control) will be hard to see. If the background is white, then white controls like edit box would be the same color as the background.
You can get a few idea from other people comments. Even though some comment are for WPF, you might be able to take some idea for WinForms. And if you don't get the expected result, you might also consider using WPF for that part of the UI.
Having said that, a possible workaround to get what you want is to create two top-level windows at the same position (and move/resize them as appropriate). That way, you can have one window with a transparency key and the desired background for opaque area that will be used to have opaque and semi-transparent area. The other window will use the opacity so that it would be semi-transparent. This is the window that will contain your UI controls (and the one that would be on the top).
I have used that technic in the past to have a semi-transparent client area with a fully opaque frame in one application where I want to be able to see through client area (adjustable opacity) so that I could "draw" in my window using the image in another application as a reference.
Another comment is that you might need actual control with windows handle and direct Win32 API access for some customization that are not available in WinForms and/or WPF. In my application, I was handling activation in a way that if I click on the bottom level windows, the top-level window still appears as the active one (caption bar color). If one has no standard caption bar (either the frame is custom or no frame at all), then you would not have that problem.
As suggested by some links in the comment section, it might also be possible to get what you want using a single top-level windows. I have not tried that. In fact, when I try the above solution, I think that my application was still supported on Windows XP and as such you are more limited in options and the behavior is somewhat different essentially because XP more or less write directly to screen while Vista and later use bitmaps (buffers) for each windows.
I have also used combined transparency key and opacity for splash screen (on a single window) and it works on most system but sometime I got black background instead of desired background on some system (probably some XP machine with specific configuration).

Adding components to a transparent form

I used this code from the code project in order to display a .png image (with transparency). At line 87 I tried to add a label in which I succeeded but somehow It won't appear on the form. I tried Refresh, Invalidate but none of them worked. Maybe someone can point me into the right direction.
I think, since you're using UpdateLayeredWindow the "normal" painting mechanism is disabled, i.e. no WM_PAINT messages are sent to the window, and the WinForms library has no chance to render the Label Controls.
I found this article about using layered windows on MSDN stating:
Note that when using UpdateLayeredWindow the application doesn't need to respond to WM_PAINT or other painting messages, because it has already provided the visual representation for the window and the system will take care of storing that image, composing it, and rendering it on the screen. UpdateLayeredWindow is quite powerful, but it often requires modifying the way an existing Win32 application draws.
So I'm afraid that WinForms isn't able to work together with your approach. Even if it would, you would likely get unpleasant results since "real" transparency is not easily done with winforms (i.e. the labels wouldn't show up transparently but would be drawn the parent forms background color)

Taking screenshot of a partially hidden window in a programmatic way

Is it possible to get a screenshot of a window that is not on the top, i.e. if it is partially hidden by another window, without bringing it to the top?
Unfortunately, it's not trivial to take a screen-shot in C# at all, you can create a graphics object based on the current window or viewport and capture that, but its not what you're asking for.
This
Screenshot of Hidden Window
might help, but you'd have to do this with Interop code anyway.
I dare say that it's not a common thing that is supported as really, one program has no business knowing what's being displayed in another program; it's potentially a nasty exploit.
You dont need to take screenshot, if it is your application you can use Control.DrawToBitmap(Bitmap bitmap, Rectangle targetBounds); of the form object.
If it is other application window, you can try un-managed way to get the UI of window. I dont remember all the methods but I have tried and it was working. Probably GetWindow and SendMesage with WM_PRINT / WM_PRINTCLIENT

Display Form non-maximized with borders on Windows Mobile

I need to create a status dialog for a Windows Mobile application (C# 2.0) that needs to be updated, so MessageBox is out. I tried to just create a new Form class, change the size and call ShowDialog, but it always comes up full screen (minus the title bar of course). The only way I could figure out how to display it small is to set FormBorderStyle to None, but then it really does have no border or title bar at all!
I want it to still look like a message box (with title bar and borders) but, I need to actually use a Form so I can update it.
Any ideas of how to do this?
The challenge here is the WinMo shell itself. What's not apparent is that the caption on the form (at the top of the screen) is actually not the caption of the Form you see - it's a completely different application. So to get your Form to "float" requires subverting the way the shell handles Form display. A quick and dirty way is to set the Form BorderStyle to none, but then you lose your caption bar. An option then is to manually draw it in with a FillRect and DrawString in OnPaint. Not too difficult and doesn't require any P/Invoke shenanigans, but it does require that you take the new header into consideration when you layout your controls.
Another option is to use P/Invoke and manipulate the Form's style bits yourself. This works well, but take care that you do it in the right location in code, as some bits have to be set on Window creation. Also beware the shell, as it might want to change the bits back on you - so this mechanism requires more testing and attention to detail. IMO this is a better route, and I've blogged about it in more detail here. That blog entry isn't specifically about floating forms, but it covers style manipulation well. For more specifically on non-fullscreen Forms, see my other blog entry here.

Categories