Windows desktop coordinate system is off for certain windows - c#

I've run into an issue when developing some software for windows, an issue related around moving windows on the screen.
Basically, I've found that specific windows will consitantly not follow the coordinate system. I have a function that takes a window and a ratio, then scales up the window to the max size it can be (in that ratio) and still be within the working area of the monitor (not going over the edges or the taskbar).
Example 1: The function works as intended, sizes the window (VSCode) to be the max size it can be in 4:3, and puts it in the corner of the screen (using SetWindowPos and passing in 0,0 for the coords).
Example 2: The exact same function is run on a different window (Firefox) and it is again resized to 4:3 and set to 0,0. However, this time you can see the window isn't quite in the corner, off by 8 pixels to be exact. If I fetch the window position with the api call for that, it returns 0,0, even though it clearly is not. If I manually snap it into the corner myself, then it returns -8,0.
I have no idea what's wrong or how to fix it. It always happens on the same windows, not exactly sure but I think it has something to do with the type of titlebar the window has.
The only other person I've ever seen with this problem is here: https://answers.microsoft.com/en-us/insider/forum/insider_wintp-insider_desktop/desktop-coordinate-system-is-broken/9e6fd9ab-6d27-45e0-bb55-4c868cd6ac45
Unfortunately, he never got a real answer, so I'm back to square one.
So, any ideas of some way to consistently set windows to actually be in the corner? I've come up with some janky solutions by like trying to dynamically find how much a window offsets from the corner but it's not really something I want to be relying on. Is this just a bug with windows and I'm stuck?
Thanks, let me know if you have any questions!

This is the design of windows system.
I saw similar questions long ago.
Windows 10 has thin invisible borders on left, right, and bottom, it is used to grip the mouse for resizing. The borders might look like this: 7,0,7,7 (left, top, right, bottom).
The borders are invisible in Windows 10, so it appears that the window is in the wrong place. Visual Studio IDE has its own tool-windows, when tool-window is docked, it uses no borders or custom NC_PAINT; and when its tool-window is floating, it uses default borders.
A workaroud:
RECT rect, frame;
GetWindowRect(hwnd, &rect);
DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &frame, sizeof(RECT));
//rect should be `0, 0, 1280, 1024`
//frame should be `7, 0, 1273, 1017`
RECT border;
border.left = frame.left - rect.left;
border.top = frame.top - rect.top;
border.right = rect.right - frame.right;
border.bottom = rect.bottom - frame.bottom;
//border should be `7, 0, 7, 7`
Then offset the rectangle like so:
rect.left -= border.left;
rect.top -= border.top;
rect.right += border.left + border.right;
rect.bottom += border.top + border.bottom;
//new rect should be `-7, 0, 1287, 1031`
For more information, please refer #Barmak Shemirani's answer.
Similar case:
Retrieve Window Size without Windows Shadows
GetWindowRect returns a size including “invisible” borders
Note: DwmGetWindowAttribute() returns physical coordinates, but GetWindowRect() returns logical coordinates. So the border width will be wrong for a non-DPI aware application on a screen scaled to anything other than 100%.

Related

Draw inline at mobile screen border [With example pictures]

Is it possible to draw a line at the border of the screen, like an "inline" with a consistent width of lets say 10 pixels, so that it aligns to the edges of the screen, even at the rounded corners?
Like this:
normal screen
with the wanted inline (Orange line)
Is there a unity solution? (Otherwise any other solution would be great too! Android studio maybe?)
What I want to achieve is a line that's always the same shape as the screen borders, on every screen, no matter the radius of the corners
I don't think this is possible in normal ways, since Unity considers the screen as a rectangle, so it will give you no information about the shape of the corners of your screen.
However, it is not impossible. You can use SystemInfo.deviceModel to get the model of a device and then you can retrieve information of its screen shape from a server or something like that.
The only necessary information the server needs to store is the radius of the corner. If its 0, means the screen is a rectangle, otherwise the screen is rounded with the given radius r:
Having this information, you can pass it to a post processing shader that will evaluate the minimum distance from each pixel to the corner of the screen, and if this distance is less than some value you defined, you can paint it differently.

True size of my MDI Client area - height - 14?

I am trying to center an MDI Child window in the center of my parent window's client area. By trial and error, I had found the following to work:
((parent.ClientSize.Width - 4)-centerchild.Width)/2, ((parent.ClientSize.Height - 14)-centerchild.Height)/2
I figured the 4 that I subtract from the width is the size of the border on either side, and I am able to get that number by either getting the MDIClient control within the parent (thanks to stack overflow for my finding that), or by subtracting SystemInformation.Border3DSize.Width * 2. This makes sense to me.
I am having a much harder time figuring out why I need to subtract 14 from the height. Assuming the bottom border is 2, that still leaves a number of 12 which I cannot reconcile with anything. (If there's also a top border of 2, then t hat still leaves 10 unexplained.) I have looked into the following:
Getting the MDIClient control within the parent does not get me that exact height as it does the width. Rather, it gets me parent.ClientSize.Height - 28, which is double the difference I worked out by trial and error. 28 might represent a bottom border (2) + a top border (2) + the height of the menu strip (24), but that does not explain the 14 that I have found to be perfect.
The Menu Strip height - as I said above, that's 24.
Various other window-element measures in SystemInformation. Perhaps I overlooked one, but nothing seems to explain it to me.
I could certainly use the code with my trial and error numbers, but I hate to not understand. Does anyone have any ideas that would explain the (total) height difference of 14?
It seems none of the framework functions will give the correct dimensions for the MDIClient, nor will API functions like GetWindowRect or GetWindowInfo. Derive from NativeWindow to subclass the MDIClient window and peek at WM_NCCALCSIZE when it comes across with wparam==true in which case lparam points to a NCCALCSIZE_PARAM struct that will have the right values.
struct NCCALCSIZE_PARAMS
{
public RECT rcNewWindow;
public RECT rcOldWindow;
public RECT rcClient;
IntPtr lppos;
}

C# Setting cursor position - different results with WinForms and WPF

I have a strange problem. I am trying to set the cursor position with WPF. So far so good. The problem is the following:
On my computer screen (1920x1080, 100% windows scaling) everything works fine, but on my surface laptop (3000x2000, 200% windows scaling) I have run into some problems. Because of the scaling factor the "new resolution" is 1500x1000 (because of the 200% every pixel is "twice as big").
When I set the cursor to 750, 500 with WinForms the cursor appears in the exact middle of the screen but when I set the cursor position to the same point with WPF the cursor appears in the upper left section.
So apparently WinForms uses the resolution 1500x1000 and WPF uses the resolution 3000x2000 when setting the cursor position...
Why are they using different resolutions here? This doesn't make sense to me. Because when I am reading the ScreenWidth and Height with
System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width // and Height, WinForms
and
System.Windows.SystemParameters.PrimaryScreenWidth // and Heigth, WPF
both are showing 1500x1000.
Can anyone help me? Maybe it is just a WPF/WinForms difference?
Code to set cursor:
Cursor.Position = p; // with imported System.Windows.Forms;
// or (tryed both)
[DllImport("User32.dll")]
private static extern bool SetCursorPos(int X, int Y);
SetCursorPos(p.X, p.Y);
First post so please don't kill me!
I am not an expert in this topic, but maybe:
WPF uses vector graphics to render things, and has a native support for scaling. If you change font size in Windows to 200%, every WPF application will be 2x bigger.
But in WinForms, if you didn't write your application correctly, scaling can ruin your UI.
To avoid this, if you run WinForms app (in Windows 10) it will just use 100% font size and it will stretch rendered image to 200% size. So you can see for example blurry text. If image is stretched - screen coordinates must be stretched too.
But that's just my guess, I'm not an expert at this.

Cropping the borders of image based on color in windows phone

Above is the image i am using. What i am trying to achieve is removing the red portion of the border from the image. How can I achieve this programmatically in windows phone? I found WriteableBitmapExtensions.Crop() method, but I am confused with the arguments (how i can find the x,y position of the image, as well as the size and the width?)
Also another issue I am facing is: I will get the images with differently sized borders, so I can't hardcode the x or y values.
Can anyone suggest a solution, or guide me to solve the issue?
This is not such a trivial thing and you haven't shared any code with us, so I can give you a few suggestions. Every WriteableBitmap has width and height defined. You should be able to access it via
wb.PixelWidth;
wb.PixelHeight;
where wb is your WriteableBitmap (the picture)
Having said that, it's trivial to crop a WriteableBitmap using WriteableBitmapEx library
var croppedBmp = wb.Crop(10, 10, 300, 220);
If your wb was 320x240 and the border was of width 10, then the above Crop call will do the trick - you will take the inner rectangle starting from point (10,10) and ending at (310, 230)
Now to your second issue - not knowing the width of the border. It would help if you know that
Border is of the same thickness on every side of the picture
Border is always in one color only
Assuming that's true, you could think of a simple algorithm (that may not be correct every time, but you can test it and adjust) which would take a few random points, for example
(0,randNumber < wb.PixelHeight), (randNumber < wb.PixelWidth, 0), (wb.PixelWidth, randNumber < wb.PixelHeight), (randNumber < wb.PixelWidth, wb.PixelHeight)
and then move towards the inner part of the picture as long as the neighbour pixel is the same color as the starting pixel. The more points you take randomly, the better chances you have of getting it right. The obvious problem with this is that it may happen that something on the picture is the same color as the border (exactly the same) which will make it seem like the border is wider than it really is. That's why you should take more points.
If you showed some code, I'd be happy to expand the answer.

Get drop shadow dimensions of window

I need to know the drop shadow dimensions of a window. I tried receiving values via the GetSystemMetrics WinAPI function, but I could not find the parameter to pass over.
Any idea on how I can get this value globally (or for a single window handle)? I know that the width of a drop shadow depends on the window type (dialog/normal/and so on).
Ibwould implement this functionality using C#, but C++ would also be fine.
There is a way using the DWM API to figure out the size of the drop shadow, however, it does not work until the window is visible.
In previous versions of Windows, there was the Client Rect, and the Window Rect. But ever since Vista came out, there has been a third Rect for a window called the Extended Frame Bounds. The third rect is larger than the Client Rect and smaller than the Window Rect, and excludes the area taken up by the drop shadow.
Call DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &rect, sizeof(RECT)) to read the Extended Frame Bounds rect. This function is from <dwmapi.h>, and is
not available in Windows XP or earlier.
Note that if you call this before the window has been shown, you will get incorrect results.
EDIT:
Note that Extended Frame Bounds are in physical pixel coordinates, and are not affected by the Scaling features of Windows. You may need to convert back to virtual coordinates, or convert the virtual coordinates to physical coordinates to make them match.
As far as I know there is no way of obtaining that information. Programs such as WindowClippings solve it by taking a screenshot and cropping to the shadow dimensions afterwards.

Categories

Resources