I have a point in screen coordinates and I need to find which window it "falls" onto. I.e. find the window (hWND) that is foremost of all windows containing the point. Pinvoke and WinApi is fine...
PS. I actually need to detect, which window is my mouse cursor currently "over", to put it another way.
Use WindowFromPoint.
Related
I have a C# application that is attempting to create a customizable version of Windows's Snap functionality. I primarily use the native functions MoveWindow and ShowWindowAsync. I also use GetWindowPlacement to determine maximized/normal/minimized state.
I can seamlessly snap a "normal" window around to my user definable frames. The window instantly snaps to new desired position and size.
The problem is when I transition from maximized to normal. If I only call MoveWindow then the window snaps to my desired position and size. However the window still thinks it's "maximized" which causes attempts to re-maximize to fail.
However if I call ShowWindowAsync(wnd, SW_SHOWNORMAL) followed by MoveWindow(wnd, x, y, width, height, true) it causes the maximized window to animate to it's old position then snap to its new position. This is very jarring and unpleasant. Attempting to flip the call order or use ShowWindow instead of ShowWindowAsync does not help.
The answer to this question might be to disable the animation. I have not found a clean way to do that.
Solution found!
The fix is to call SetWindowPlacement instead of MoveWindow. SetWindowPlacement takes a WINDOWPLACEMENT structure which allows setting both position/size and showCmd state at the same time.
In a C# winform app, I'm trying to implement some of Linux window manager features.
I already did a lot of stuff, but right now, I'm trying to do the re-sizing part, where you press a certain combo at a window, then move your mouse to the right/left, the width of the window increases to the right/left, move it diagonally, the window will increase in both directions.
Now I already know how to register the hotkeys, get/set mouse cursor pos, move a window, etc. All in winapi.
The thing that I can't seem to get that much, is how can I increase the window's, say width, in one direction? if I normally increase it, it will span in both directions. I gave this a thought, and I think that: the window will increase in both directions, but if we want to just increase it's width to the right, we keep re-positioning/moving it at it's start point, so that the left side of it will remain fixed, will the right one will span.
What is the right and easy way to do this? Am I right about my guess?
And please note that I don't just want this to work only in my form, but on any window.
Any C++/C#/Winapi code would help.
Any ideas/thoughts of some sort would also be great.
Thanks a lot.
Any Windows window:
Alt+Space - brings up the standard Windows menu
S - selects Size
Arrow keys (Or Mouse) - Resizes the window
Enter - commits the operation
I have a list of all open windows, the ones in the windows taskbar. What I want to do is to remove the ones that are not visible from the list.
What I mean is, if a window is hidden by another one, it should not be in my list.
I've been searching google for the past two days without success...
Any ideas?
PS: I can get the location and size of each process, so getting the last time a process was used/idle time would work too...
You need to use regions, what's still visible of the window can be a complex set of rectangles. Start with the window you want to check, GetWindowRect and CreateRectRegion to create a region for the window rectangle.
Call GetWindow() in a loop, passing GW_HWNDPREV. Which returns the previous window in the Z-order so it could overlap. GetWindowRect() to get its rectangle, CreateRectRegion() and combine that with the original window region using CombineRgn() with RGN_DIFF.
When GetWindow returns NULL you've found all possible overlapping windows. Use GetRgnBox to check if there's anything left of the region. If there is, at least one part of the window wasn't overlapped.
I was wondering if anybody could give insight on how to implement the window selector in Winspector Spy. Basically, I would want to provide a panel that I could mouse down on, drag over to another processes window (or sub window) and get something like the HWND out of it. Ideally, I would do this in C#, but if it's only possible by wrapping the C APIs, then I can just do it in C++.
I messed around with the DragDrop event and calling DoDragDrop on mouse down in C#, but wasn't really sure if that could give me what I want. Will it be easier to just get the global X/Y pos of the mouse and find the topmost window at that location? Is there an API which does that automagically for me given x, y parameters?
EDIT: Just discovered WindowFromPoint for the latter question
You don't normally get mouse messages when the mouse isn't over your window. But you need to in order to do drag and drop operations. So, Windows provides a mechanism called mouse capture. To prevent mouse capture from being abused, you can only capture the mouse on a button down message. Once you have capture, you get mouse move messages no matter where the mouse is on screen until you release capture or when Windows sees the corresponding button up message.
The C++ code for this looks something like this
case WM_LBUTTONDOWN:
{
SetCapture(hwnd);
}
break;
case WM_MOUSEMOVE:
if (GetCapture() == hwnd)
{
POINT pt = {GET_MOUSE_X(lParam), GET_MOUSE_Y(lParam));
ClientToScreen(hwnd, &pt);
HWND hwndAtPoint = WindowFromPoint(pt);
// Show info for hwndAtPoint....
}
break;
case WM_LBUTTONUP:
if (GetCapture() == hwnd)
{
ReleaseCapture();
}
break;
case WM_CANCELMODE:
// this is a request from Windows that leave my modal state
if (GetCapture() == hwnd)
ReleaseCapture(hwnd);
break;
case WM_CAPTURECHANGED:
// notification that I lost capture (I released it or it was taken from me)
break;
The GetAncestor function can be helpful to go from the window at the point, to the top level window that own it. GetWindow can be used to walk around the window tree.
In .NET, the Control class has a Capture property that does the same thing see
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.capture.aspx
You'll need to consider how you are going to draw the rectangle around the window first, that affects the rest of your code. The easiest way to do this is by using a Form that has its TransparencyKey set to its BackColor and FormBorderStyle set to None. Draw a rectangle in the Paint event, the same size as the form's ClientRectangle, that gets you a visible rectangle with everything else transparent. Set the form's Location and Size property to match the window you found.
Now finding the window from the mouse position. You can't use WindowFromPoint(), it doesn't consider disabled windows. You'll need to use EnumWindows(). In the callback, call GetWindowRect() and check if the mouse is located inside the rectangle. Be sure to ignore your rectangle drawing window.
When you get a match, now call GetWindow() repeatedly with the GW_HWNDPREV to find windows that overlap the window you found. Keep checking the rectangle and keep ignoring your rectangle window.
This eventually gets you the top-level window that the mouse cursor is on. Now use ChildWindowFromPoint() to check if the mouse is on a child window, if any. Create your rectangle drawing form, if necessary, and give it the same size and location as the found window.
Call this code from the MouseMove event of, say, a PictureBox that displays a bulls-eye graphic. Set its Capture property to true in its MouseDown event.
Close the Close() method of your rectangle drawing form in the MouseUp event.
Since you have tagged this with C#, I can put in a link or two for this job that you are trying to accomplish and hopefully will give you the necessary insight into how to achieve this:
'A Simple Windows Forms properties Spy'
'Spying Windows Messages from the Inside'
'.Net Object Spy and InvokeRemote'
'Runtime Object Spy' <- This is my favourite tool!
All of the above articles are on CodeProject.
Hope this helps,
Best regards,
Tom.
Simple. You just set the mouse capture on mouse down, so you get all mouse messages even if they are outside your own window. Then on mouse up, use WindowFromPoint.
I'm not familiar with .NET, but with the Win32 API, you use SetCapture to set the mouse capture.
Imports:
using System.Runtime.InteropServices;
My suggestion, when the mouse is on your form, handle the mouse move/mouse up events (To capture the mouse outside of your form using a windows hook, look here: http://support.microsoft.com/kb/318804 ), and when the mouse button is released, get the mouse position on the screen, and get the window behind the cursor, using the link you provided like this:
[DllImport("user32.dll")]
public static extern IntPtr WindowFromPoint(Point lpPoint);
[DllImport("user32.dll")]
public static extern bool GetCursorPos(out Point lpPoint);
public static IntPtr GetWindowUnderCursor()
{
Point ptCursor = new Point();
if (!(PInvoke.GetCursorPos(out ptCursor)))
return IntPtr.Zero;
return WindowFromPoint(ptCursor);
}
Now you have your window handle, from there the possibilities are endless.
NOTE: The link above, (the windows hook) will only work if the mouse down occurs on your form, and the hook ends when the mouse is lifted
You could look at the C++ source for Winspy++, another window inspector program similar to Winspector Spy. I don't know of any open-source C# program like this, though.
I'm looking for a nice way to render overlays over a native Windows form not owned by myself preferably using a library available for .NET (WinForms, GTK#, ...). Precisely, I'd like to display a few labels or text boxes at a given location on the window.
Device Context & System.Drawing: What I'm currently doing is drawing directly onto the other windows' device context, which causes flickering, as parts of the other application are redrawn in unpredictable intervals. I therefore would have to catch its WM_PAINT event using hook magic, but that's actually not as far down as I'd like to go unless there's no simpler way.
Transparent window overlay with visible child labels: another technique I tried was creating a Windows.Forms.Form with the other windows' size, using TransparencyKey to make only the children visible. This seems pretty hard to get correct, as I don't want the window to be the upper-most one but only exactly one Z-level above the foreign window. The upside would be, that I could add more behaviour to it, as I could actually handle click events, etc.
How would you implement it / deal with the problems in the two techniques described above?
Definitely go with the transparent window approach as that should be simpler to implement. Creating a transparent form is very easy. You already know how to use the TransparenyKey to get the background to not drawn. Also remove the border from the window and remove the min/max/close buttons so you do not have any chrome showing.
Create your window as owned by the window of interest and it will always be on top of the target and act like a modeless dialog. I.e. it is visible only when the owning window is visible.
Thanks for your answer, but I'm still a little confused. How exactly would you set the owner of a window to anything not owned by your own application? I guess that's not even possible when the other application is unmanaged, is it?
Edit:
I now got a little step closer. The example code is in Boo.
[DllImport("user32.dll", SetLastError: true, CharSet: CharSet.Auto)]
public def SetParent(child as IntPtr, parent as IntPtr):
pass
def createAttachedForm(parentHandle as IntPtr):
f = Form()
f.Text = "My overlay"
f.Show()
SetParent(f.Handle, parentHandle)
Application.Run(f)
Now only the TransparencyKey thing doesn't seem to work. Instead the form is completely invisible when the value is set.
Setting the owner of a form can be done with
Form.Show(IWin32Window w)
where w exposes the Handle to the parent window.