I need to draw an overlay using WPF on top of a number of Win32 windows. In order to draw the overlay in the correct place, I will need to hook into the window move, but have no idea how to do this. Which Win32 calls should I be looking at?
SetWinEventHook
var hook = SetWinEventHook(EVENT_SYSTEM_MOVESIZESTART,
EVENT_SYSTEM_MOVESIZEEND, NULL, WinEventProc,
0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
Related
My application is a Winforms transparent overlay attached to another application.
Since there can be multiple overlays running at one time for different apps, I need my overlay to be always on top, but only over its target application.
What I tried was to bring the form to the foreground with
[DllImport("User32.dll")]
public static extern Int32 SetForegroundWindow(int hWnd);
When target app gains focus through my WindowHook eventType == NativeMethods.SWEH_Events.EVENT_OBJECT_FOCUS.
The problem is that the overlay gains focus after going on top, not allowing me to interact with the app underneath. Like if I try to drag the target app it will block me at first, and if I try to click anywhere nothing happens despite being clickthrough (works when I set Winforms TopMost = true;).
I would consider setting the form topmost when target app gains focus, but there is no event to check for loss of focus to undo the topmost, and even then it would be less than an elegant solution, to say the least.
There must be a simpler way to keep my overlay on top of its target app process. Or the very least, a way to bring the form on top without gaining focus / disrupting my mouse events.
So EVENT_SYSTEM_CAPTUREEND = 0x0009 gets called after any interaction with the target process window. This means I can set my form topmost
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
and undo it with
SetWindowPos(Handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); on EVENT_SYSTEM_CAPTUREEND.
I'm not a fan of this solution but works and it's seamless.
I want to maximize a random window on the left side of my screen. Can I use Windows Aero functions from my code ? This window can be maximized like that with the mouse. I just want to do that programmatically.
I use C# and I can get the IntPtr of the window.
If possible without faking mouse or keyboard input.
This can be done without p/invoke.
Try this:
Rectangle rect = Screen.PrimaryScreen.WorkingArea;
rect.Width = rect.Width / 2;
Bounds = rect;
This will put the current window on the left of the primary screen.
Then just add this to put it on the right of the screen.
Location = new Point(rect.Width, 0);
It's not exactly the same but fakes it well:
ShowWindow(handle, SW_MAXIMIZE);
// for a split second you might see a maximized window here
MoveWindow(handle, 0, 0, Screen.PrimaryScreen.WorkingArea.Width / 2, Screen.PrimaryScreen.WorkingArea.Height, true);
Will require heavy lifting for real-time placements, especially for non-child processes. Example - www.ishadow.com/vdm. For manual "fixing" of maximized windows position MoveWindow(hWnd, startPos, 0, winWidth, winHeight, true) after ShowWindow(hWnd, SW_MAXIMIZE) usually (try Task Manager on Windows 10) works as pointed above.
I created a small app in C# that removes border and caption from window, then it sets size to the user's resolution and centers it. It's a utility for me to use when I want to play games in windowed mode without being annoyed by the borders. Everything works fine with most games, but I tried to use it on a recently released game Alpha Protocol and it doesn't work. I could almost say that the game reverts my changes, but I'm not sure how to tell if that's true or not. I'm using imported API functions MoveWindow, SetWindowLong and SetWindowPos.
Snippet:
Win32.MoveWindow(hWnd, 0, 0, Convert.ToInt32(sizeXText.Text), Convert.ToInt32(sizeYText.Text), true);
Win32.SetWindowLong(hWnd, GWL_STYLE, Win32.GetWindowLong(hWnd, GWL_STYLE) & ~WS_CAPTION & ~WS_BORDER);
Win32.SetWindowPos(hWnd, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_DRAWFRAME);
Every time SetWindowPos is called it sends a message: WM_WINDOWPOSCHANGING to the window with a writable copy of the SetWindowPos parameters. This gives the window the chance to validate and change the parameters. Many window's automatically react to repositioning and sizing to "smartly" manage their non-client decorations - which I guess is what is happening here. The OnWindowPosChanging code is re-setting the non client decorations just before the DRAWFRAME is handled.
You should use Spy++ to investigate the game's window structure.
I have a form, which sets these styles in constructor:
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
And I draw some rectangles in Paint event. There are no controls on the form. Hovewer, when I resize the form, there are black strips at right and bottom of the form. Is there any way to get rid of them? I've tried everything, listening for WM_ERASEBKGND in WndProc, manually drawing the form on WM_PAINT, implementing custom double buffer, etc. Is there anything else I could try?
I've found this:
https://connect.microsoft.com/VisualStudio/feedback/details/522441/custom-resizing-of-system-windows-window-flickers
and it looks like it is a bug in DWM, but I just hope I can do some workaround.
Please note that I must use double buffering, since I want to draw pretty intense graphic presentation in the Paint event. I develop in C# .NET 2.0, Win7.
Status Update 1
I've managed to get rid of most of the black stripes by implementing the resize functionality by myself. Hovewer there are still some minor glitches. Is there any way to do resize and paint operation at once? Here is a pseudo-code of what I need to do:
IntPtr hDC;
var size = new Size(250, 200);
IntPtr handle = API.PaintAndResizeBegin(this.Handle /* Form.Handle */,
size.Width, size.Height, out hDC);
using (var g = Graphics.FromHdc(hDC)) {
this.backBuffer.Render(g, size);
}
API.PaintAndResizeCommit(handle);
Is there any way to implement the above code?
The second solution could be to back-buffer whole form, including non-client area. But how to do that? I don't want to paint the non-client area by myself, as I want to keep the nice aero effect on Vista/7. Any help will be deeply appreciated.
Status Update 2
It looks like this problem is unsolvable, since it is omnipresent on Windows, in every application. We can just hope that MS will take some inspiration in Mac OS X and will provide appropriate APIs in new Windows.
I've found the function which can paint and resize window at the same time - UpdateLayeredWindow.
So now it should be possible to create resizable windows, which do not have any strips while being resized. However, you need to paint the window content yourself, so it is a little inconvenient. But I think that using WPF and UpdateLayeredWindow, there shouldn't be any problem.
Update
Found problems. :-) When using UpdateLayeredWindow, you must paint the window's border yourself. So, if you want standard window painted using UpdateLayeredWindow with nice glass effect in win7, you are screwed.
On Microsft Connect is even a thread about this problem, where Microsoft says it is a bug by design, and if it ever gets fixed, then probably in Win8 or some newer system. So there isn't much we could do about this.
I found that it is best not to do any custom rendering directly on the Form surface. Instead, put a docked PictureBox on the form, create Bitmap object that will be displayed in the PictureBox, draw everything onto that using the System.Drawing.Graphics.FromImage(Image) method.
I used that method with a game loop to make a simple shooter game (Crimsonland-style) and got pretty good performance (with anti-aliased lines), above 100 FPS.
Is there an api to bring the vista side bar to the front (Win+Space) programatically and to do the reverse (send it to the back ground).
Probably using SetWindowPos you can change it to be placed the top / bottom of the z-order or even as the top-most window. You would need to find the handle to the sidebar using FindWindow or an application like WinSpy.
But after that something like.
Sets the window on top, but not top most.
SetWindowPos(sidebarHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NORESIZE);
Sets the window at the bottom.
SetWindowPos(sidebarHandle, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NORESIZE);
This is my best guess on achieving what you asked, hopefully it helps.
You probably shouldn't do it at all, since such action may annoy the user when executed at the wrong time (95% of cases*), just like stealing focus with a "Yes/No" prompt.
Unless your product's task is to toggle the sidebar of course. ;)
There's no official API for that anyway.
*Purely hypothetical figure