I found out the Yahoo Messenger window that notifies you when someone signs in or out is the only window that actually appears on top of a full screen movie or game and won't force you to exit full screen.
So my question is how can I find out what makes this window behave like this? I tried Spy++ but nothing interesting came up.
There are different ways to do this. Some video card drivers on older versions of windows will behave differently.
1) Grab the desktop hwnd and paint to it.
HWND hwnd = GetDesktopWindow();
HDC hdc = GetDC(hwnd);
RECT rect = {};
GetClientRect(hwnd, &rect); // dimensions of the primary monitor are rect.right,rect.bottom
// Use hdc to paint whatever you want to the screen
2) Just create a top-most window without a titlebar and use the WS_EX_TOPMOST style. Then draw whatever you want on it
CreateWindowEx(WS_EX_TOPMOST, ...);
Could be using the windows notification API (I don't have Yahoo messenger, so I'm not sure). Here's some more information about the notification area:
http://msdn.microsoft.com/en-us/library/aa511448.aspx
Related
I tried capturing live thumbnail of running applications using these codes:
http://community.bartdesmet.net/blogs/bart/archive/2006/10/05/4495.aspx
I have successfully captured some applications except those borderless fullscreen windows.
I am actually trying to capture a UWP application that plays a video in a fullscreen mode and integrate the thumbnail into my application. I don't need to get a bitmap image of it, I just need to display in real-time.
I tried changing the values of
GWL_STYLE
WS_VISIBLE
WS_BORDER
but none of it works.
When trying to Alt+Tab windows, the Windows 10 DWM can handle it and displays the live thumbnail, so I believe this could work with some little modifications on the code.
Thanks!
I checked the window styles for the example uwp application in full screen with Spy++.
Styles were normal so then i hardcoded window handle and it worked. After a moment of debugging, it turned out that the EnumWindows method did not return this window, so it did not matter what styles were checked.
So I looked for a problem with this method and there are many topics, for example:
EnumWindows function in Win10 enumerates only desktop apps
Instead of using EnumWindows, get all windows using this method and insert your filter logic for your desired window handler
IntPtr thisWindow = IntPtr.Zero ;
IntPtr desktopWindow = GetDesktopWindow();
while (true)
{
if (desktopWindow == IntPtr.Zero)
break;
IntPtr nextWindow = FindWindowEx(desktopWindow, thisWindow, null, null);
if (nextWindow == IntPtr.Zero)
break;
/** your code here **/
thisWindow = nextWindow;
}
I currently have implemented a DirectShow live source screen capture filter in C#. The DShow filter is being consumed by a separate process (ffmpeg) that is live encoding the stream.
I would like to render some UI/Controls on the screen for starting/stopping the capture of ffmpeg, (UI provided by a separate process) but I don't want the UI to be captured by the DShow filter and end up in the screen capture video.
Here is an excerpt, which contains the DirectShow FillBuffer method where I capture the screen frames.
public int FillBuffer(ref IMediaSampleImpl _sample)
{
IntPtr _ptr;
_sample.GetPointer(out _ptr);
IntPtr srcContext = User32.GetWindowDC(IntPtr.Zero);
IntPtr destContext = GDI32.CreateCompatibleDC(srcContext);
IntPtr destBitmap = GDI32.CreateCompatibleBitmap(srcContext, _captureWidth, _captureHeight);
IntPtr hOld = GDI32.SelectObject(destContext, destBitmap);
GDI32.BitBlt(destContext, 0, 0, _captureWidth, _captureHeight, srcContext, _captureX, _captureY, GDI32.SRCCOPY);
//Draw cursor, ommitted for brevity
GDI32.SelectObject(destContext, hOld);
GDI32.GetDIBits(destContext, destBitmap, 0, (uint)Math.Abs(_captureHeight), _ptr, ref m_bmi, 0);
GDI32.DeleteDC(destContext);
User32.ReleaseDC(IntPtr.Zero, srcContext);
GDI32.DeleteObject(destBitmap);
_sample.SetActualDataLength(_sample.GetSize());
_sample.SetSyncPoint(true);
return NOERROR;
}
I'm not exactly 100% sure how this would be possible, but here are the only things that remotely make sense to me (not saying they are possible, just brainstorming):
Render the UI controls via a passed window pointer from another process to srcContext each frame but only after its copied to destContext
how would you even render the passed pointer?
how do you refresh the screen so that it wont just get captured next frame (now that its rendered to the screen)?
could this really be viable performance wise (refreshing the screen each frame)?
Is it really going to look nice? - i can't imagine that rendering to the WindowDC is reccomended
is there a way to trigger a re-draw of just the UI control region before the next frame and not refresh the entire screen?
Some how capture the window with GDI but omit the UI window handle via some native API interface i'm unaware of
Capture the entire screen with current method, then re-draw the area that contains the UI controls with the contents of whatever window(s) were underneath (is this even possible?)
Capture individual windows, and then render each visible window separately in z-order but skip the UI window (i have a sneaking suspicion that this may be the only way to actually do this, but i doubt that it would meet reasonable performance requirements)
EDIT, i just thought of using PrintWindow of all of the windows behind the UI control, but PrintWindow is slow and unreliable, and this is performance critical code.. So i would really like a different solution.
I understand that Fraps and similar, use DirectX hooks to intercept paint messages further up the pipeline, and are able to draw overlays on the screen that way - but this is not an option, and neither is a display mirror driver.
I am playing a video using IVMRWindowlessControl9 i.e. WindowlessControl w/ VMR-9. When I initially had difficulty setting the video up, I noticed many examples found online had this piece of code in the Window's Paint handler:
IntPtr hdc = e.Graphics.GetHdc();
int hr = 0;
hr = windowlessCtrl.RepaintVideo(this.Handle, hdc);
e.Graphics.ReleaseHdc(hdc);
My video is playing correctly yet I do not have the above code. What does the above code do and is there a point in using it?
In most cases you don't need to repaint the video explicitly because the video renderer does it automatically. Yes, if the hosting window needs - for any reason - to request forced replaint, such as as part of WM_PAINT window message handler, then RepaintVideo method is here at your service.
See more on MSDN, VMR Windowless Mode:
During playback, the application should notify the VMR of the
following Windows messages:
WM_PAINT: Call IVMRWindowlessControl::RepaintVideo to repaint the
image.
As to what it does:
if the video is being drawn using a destination colour key, then it paints the key colour into the destination window.
if the image is letterboxed, or part of it falls on another monitor, it will paint the parts that are not covered by the image.
So it may be that you won't see any difference if it is not done at all, if none of these things apply.
I'm writing a simple Windows Forms utility to screenshot either the entire screen or an active window and save the file. The winform has a button called 'Capture' that, when clicked, takes the screenshot.
I have the code entirely working for the entire screen but can't figure it out for the active window.
By my current code, if I select 'Active Window', it ends up Print Screening the application itself which isn't what I want.
Here's my code (under the Capture_Click method):
try
{
this.Hide();
bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
//bmpScreenshot = new Bitmap(this.Bounds.Width, this.Bounds.Height, PixelFormat.Format32bppArgb);
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
if (AltPrint.Checked)
{
gfxScreenshot.CopyFromScreen(this.Bounds.X, this.Bounds.Y, 0, 0, this.Bounds.Size, CopyPixelOperation.SourceCopy);
}
else
{
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
}
bmpScreenshot.Save(SaveLocation, ImageFormat.Png);
number++;
}
In your button_Click method, to capture a window other than the one which is doing the capturing, the only possible way I can see is to make use of the user32 Windows API.
You will first need to platform invoke some methods like this:
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, GetWindowLongNIndex nIndex);
I recommend www.pinvoke.net/ for more info about this.
Here is my own Window class (work in progress, but useable) which you are welcome to use as an example: http://pastebin.com/fj2tEaPY
Some useful properties in there for you are:
get AllWindows
get TaskbarWindows
set ForegroundWindow
You'll need to get the handle of your current window (use get ForegroundWindow, then the Handle property), then find the window which you want to capture the image of, perhaps using code similar to that in TaskbarWindows. Once you have the window, you will need to send the keypresses Alt + PrtScn (again maybe using user32 API, but I won't go into it.) Then use the static ForegroundWindow property to set the orignal window as the forground using the handle which you saved at the start.
Good luck!
As far as I can see your code uses the bounds of its own form to capture the "active" window. That is probably not what you intend.
If you want to use the mouse to "print" a window (and not hotkey which probably is easier to implement) you need to be able to from your own form let the user point to another window to capture. Here is an idea describing how to do that:
When the user presses the "Capture" button capture the mouse and initiate a drag operation.
Let the user drag the mouse (perhaps now having a "bullseye" or a "camera" cursor) to the window to capture.
When the user releases the mouse determine the window it was on top and use the location and size of this window to capture the correct pixels.
You will probably need to use P/Invoke to get information about all top-level windows on the desktop.
Note that "mouse capture" is very different from "screen capture". When an application "captures the mouse" it takes ownership of the mouse cursor and doesn't the ability to track the mouse even when it is moved outside the bounds of the window of the application.
Your comments seem to understand that once your app gets the focus (when you click on it) the other app has lost it and is no longer 'active'.
A possible alternative: your application gets a WM_SETFOCUS message when it gets focus. The wParam of that message is a handle to whichever window has just given up the focus -- and that window belongs to the app you want to capture.
Of course, that window will only be a subwindow or control, but you can figure out which app owns that button.
I ended up taking a different route.
I allow the user to resize my form window to cover exactly the area they need to screenshot, and then when they click the button, the form hides itself, takes a screenshot of the area it was covering and appears again. Contrary to my initial plan, I believe this will be more beneficial, as my targeted users (friends at an overclocking forum I'm part of) seldom take screenshots of just one window. They mostly need a couple of windows covered (temp monitoring, clockspeed monitoring, stability test etc.).
Thanks for all the answers guys. They definitely got me thinking, and made me realize what my options were.
Should anyone else need it, this is the code I use for the button that captures only part of the screen:
try
{
this.Hide();
Thread.Sleep(250);
bmpScreenshot = new Bitmap(this.Bounds.Width, this.Bounds.Height, PixelFormat.Format32bppArgb);
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen(this.Bounds.X, this.Bounds.Y, 0, 0, this.Bounds.Size, CopyPixelOperation.SourceCopy);
bmpScreenshot.Save(SaveLocation, ImageFormat.Png);
tbxStatus.AppendText(Environment.NewLine);
tbxStatus.AppendText(Environment.NewLine);
tbxStatus.AppendText("Screenshot saved at " + SaveLocation);
numSuffix++;
}
catch (Exception ex)
{
tbxStatus.AppendText(Environment.NewLine);
tbxStatus.AppendText(Environment.NewLine);
tbxStatus.AppendText("Unable to take screenshot. Exception: " + ex.ToString());
}
finally
{
this.Show();
}
You need to borrow the design of commercially available screen capturing apps, such as Psp. I think you need to use a 'hot' key to trigger the capturing of the active window. Instead of doing it on Capture_Click event. This way, you can hide your application's window so that it does not become the active window. Then when the user pushes the 'hot' key, you can capture it.
What about SendKeys?
Windows.Forms.SendKeys.Send("%{PRTSC}");
It will copy currently selected window in to Clipboard object.
Than calling
BitmapSource image = Clipboard.GetImage();
you can get your image back
I want to draw directly on the desktop in C#. From searching a bit, I ended up using a Graphics object from the Desktop HDC (null). Then, I painted normally using this Graphics object.
The problem is that my shapes get lost when any part of the screen is redrawn. I tried a While loop, but it actually ends up drawing as fast as the application can, which is not the update rate of the desktop.
Normally, I would need to put my drawing code in a "OnPaint" event, but such thing does not exist for the desktop.
How would I do it?
Example code: https://stackoverflow.com/questions/1536141/how-to-draw-directly-on-the-windows-desktop-c
I posted two solutions for a similar requirement here
Basically you have two options.
1- Get a graphics object for the desktop and start drawing to it. The problem is if you need to start clearing what you have previously drawn etc.
Point pt = Cursor.Position; // Get the mouse cursor in screen coordinates
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
{
g.DrawEllipse(Pens.Black, pt.X - 10, pt.Y - 10, 20, 20);
}
2- The second option that I provide in the link above is to create a transparent top-most window and do all your drawing in that window. This basically provides a transparent overlay for the desktop which you can draw on. One possible downside to this, as I mention in the original answer, is that other windows which are also top-most and are created after your app starts will obscure your top most window. This can be solved if it is a problem though.
For option 2, making the form transparent is as simple as using a transparency key, this allows mouse clicks etc. to fall through to the underlying desktop.
BackColor = Color.LightGreen;
TransparencyKey = Color.LightGreen;
When you draw to HDC(NULL) you draw to the screen, in an unmanaged way. As you've discovered, as soon as windows refreshes that part of the screen, your changes are overwritten.
There are a couple of options, depending upon what you want to achieve:
create a borderless, possibly
non-rectangular window. (Use
SetWindowRgn to make a window
non-rectangular.) You can make this a child of the desktop window.
subclass the desktop window. This is not straightforward, and involves
injecting a DLL into the
Explorer.exe process.
To get an OnPaint for the desktop you would need to subclass the desktop window and use your drawing logic when it receives a WM_PAINT/WM_ERASEBKGND message.
As the thread you linked to says, you can only intercept messages sent to a window of an external process using a hook (SetWindowsHookEx from a DLL).
As mentioned a transparent window is another way to do it, or (depending on the update frequency) copying, drawing and setting a temporary wallpaper (as bginfo does).
This is difficult to do correctly.
It will be far easier, and more reliable, to make your own borderless form instead.