I'm coding in c++ on windows 10 - straight win32 API.
I wanted to make a window show up in the top right of the screen.
As I was doing this, I noticed that screen coordinates for a maximized window are left=-8, top=-8, right=1936, bottom=1088.
Also, when I position a window so right=1920 and top=0, there's about an 8 pixel gap on the right. I tried moving the window around to see what screen coordinates I got.
rect.left for a nonmaximized window can go from -7 to 1912.
so things are slid by 7 pixels ? WTF microsoft ??
How am I supposed to come up with the rec.right=1913 value to position my window aligned to right side of screen without that dang gap ?
But rect.right of 1920 leaves a gap. So rect.right of 1912 would leave MORE of a gap...
And I need a solution that'll work back to Vista.
Pre win10, that rect.right should be 1920 like ya expect.
Whaaaaat is going on here? I'm about to start throwing knives around !!
Code wise, this is just what GetWindowRect is reporting...
(excuse my weird debugging function)
::GetWindowRect (_wndo, r);
DBG("ExtRc l=`d r=`d t=`d b=`d w=`d h=`d",
r->left, r->right, r->top, r->bottom, r->right-r->left, r->bottom-r->top);
Well thanks to #ChristopherOicles
This is really his answer. Duplicate this as your own (or tweak it, whatever) and I'll accept your's.
What's going on is microsoft wrecking border widths in windows 10.
GetWindowRect returns the outside window coordinates as screen coordinates.
GetClientRect returns the inside the window coordinates.
Up until Windows 10 (F U Win10 !!),
The difference in width and height between them was the width and height of the borders.
Upon win10, the border width reports 16 pixels, so 8 pixels a side.
However, only 1 of those pixels are visible. 7 of them are transparent.
So your window has a transparent 7 pixels to the left, right, and bottom.
So you need to take those transparent 7 pixels into account if you're going to line up the window on the screen programmatically. The user doesn't want that 7 pixel gap next to the screen border !
DwmGetWindowAttribute with the attribute DWMWA_EXTENDED_FRAME_BOUNDS will get you the width and height of the ACTUALLY SHOWING part of the border in screen coordinates. So similar to GetWindowRect, but the rect does not include the invisible-ness.
You're still going to need GetWindowRect most of the time to set the width and height of your window and those 7 pixels per side of invisible-ness are needed to size the window properly programmatically.
So use the difference between the .left of the rect GetWindowRect returns and .left of what DwmTerribleName returns to get that 7 pixels of offset.
In my opinion, whoever did this at Microsoft should be immediately shot.
This is a hoop I didn't need to jump through.
This breaks compatibility with the past.
This is because of the width of the window border and other factors, which vary depending on OS version, user preference, and DPI settings. See the GetSystemMetrics function.
Related
I'm trying to make a C++ code that prints the rgb value of pixel where mouse cursor is every second.
I used
GetDC(NULL) for HDC of desktop,
GetCursorPos(&pos) for the position of mouse cursor,
getPixel(hDC, pos.x, pos.y) for the RGB value of the pixel that the mouse cursor points.
Here is my full C++ code.
#include <iostream>
#include <Windows.h>
using namespace std;
int main(){
POINT pos;
int R;
int G;
int B;
while (1) {
GetCursorPos(&pos);
HDC hDC = GetDC(NULL);
COLORREF color=GetPixel(hDC, pos.x, pos.y);
R = GetRValue(color);
G = GetGValue(color);
B = GetBValue(color);
std::cout <<"x : "<<pos.x<<", y : "<<pos.y<<", R : "<< R <<", G : " <<G << ", B : "<<B << endl;
ReleaseDC(NULL, hDC);
Sleep(1000);
}
return 0;
}
When I compiled this,
it prints the rgb value of some pixel every second, however, the pixel doesn't match the pixel where mouse is on.
At first, I just thought that the client of some window may have different point, or the total number of pixels in my laptop is less than 1920x1080 (it's actually 1536x864), so there may be a bug, and it could be solved by just translating the point.
But although for some points, it did work, but most points, it didn't work.
And I tried some test. (The code is compiled using visual studio 2017.)
While the code running, I dragged the console window by mouse. (Note that the console window's Non-client window is almost white. i.e. the RGB value is (255, 255, 255). ) So, the relative position of mouse cursor on the console window doesn't change.
However, the printed rgb value changed!
I suggest that it may be related to the ppi, but I don't know why exactly.
What should I do and know to get the rgb value of pixel that the mouse cursor points?
UPDATED ANSWER: The solution appears to be related to the system's DPI setting and the level of DPI awareness of the application as reported by #정재우 and #Remy Lebeau in the comments. In Windows 10, the relevant setting can be found in:
Settings -> Display -> Scale and Layout
The OP's code works fine if this setting is 100%. Otherwise the coordinates returned by GetCursorPos() are scaled. More information can be found in the following articles:
Windows scaling issues for high-DPI devices
High DPI Desktop Application Development on Windows
Setting the default DPI awareness for a process
ORIGINAL ANSWER (WITH SPECULATION):
Your code appears to display the correct pixel values on my machine, however you may get different results from different screen configurations such as when using multiple monitors as coordinates left of your primary monitor can be given in negative values. However on my Windows 7 machine using multiple monitors, negative mouse coordinates still properly translate.
Additionally, the "client" area of the screen excludes areas like the taskbar, at least this is how I remember older versions of Windows working. To address this possibility, try replacing your GetDC() call with GetWindowDC() or GetDCEx(NULL,NULL,DCX_WINDOW) and see if you get different results.
To help with debugging, add the following call directly after your GetPixel() call to create subtle red pixel artifacts:
SetPixel(hdc,pos.x,pos.y,RGB(255,0,0));
This places a red pixel on the screen from the same spot you just read the pixel value. Observe how near your red pixels are to the actual mouse cursor as you move the mouse around.
I use OpenGl. I would like to create a menu-control, but for this I need a constant resolution-control. I mean that I can set the position of a button by giving a coordinate, in 1024x768. But what if my window doesn't in it. And in full screen mode I hasn't found a method to change the resolution, nevertheless I can get it. So I got the screen width/height, the window width/height and 4 coordinates in 1024x768 for a rectangle. What should I do?
I'm currently developing an application with OpenCV to do visual recognition of elements on the screen.
While a visual representation of the process is not needed, it would be very useful for debugging purposes if I could find a way to draw circles, lines and possibly text directly on the screen, without having an app window.
There are certain applications that, for instance, draw HUDs over the screen. How do they go about doing that?
I need a way for my drawing to always be at the front. In general, all the ways I managed to find involve painting on a window (WinAPI, Direct2D, OpenGL). Is there a workaround to make it appear like it's simply a layover on the desktop (including all open windows)?
for the purpose of debugging, just literally draw on the screen. IIRC GetDC(0) will get you a device context for the screen, but check out that whole family of functions. in Windows 7 it doesn't even foul up other applications' displays, and reportedly it's likewise "safe" on the mac.
for example, this draws an ellipse in the upper left of the screen:
#include <windows.h>
int main()
{
HDC const dc = GetDC( 0 );
Ellipse( dc, 10, 10, 200, 200 );
}
the graphic disappears if it's on top of a window and that window is moved.
You can achieve the device context (DC) of the screen, and draw in that DC as usual. The output will be directed to the screen. To achieve that, call WinApi GetDC("DISPLAY"), if i'm not mistaken.
I'm drawing a custom border in my application by handling the WM_NCPAINT message in my message handler. The problem is that even after setting the window region, the corners of my app aren't "smooth".
I thought that maybe i could just get the HDC for the screen and interpolate the pixels around the corners to get a translucency effect, but seeing as i would have to re-draw the border constantly when the user moves the window, i don't think it's a valid option.
Does anyone know of a way to simulate translucency or at least smooth out the border near the corners?
Here's what the corners look like:
Thanks in advance.
Use a Layered Window. This works from Windows 2000 onwards.
If you want Aero Glass effects (Vista onwards) then this article has a nice overview of historical painting techniques and details on using The Desktop Window Manager.
Using wxwidgets. I want a window without a border. I pass the follwoing flags to the frame wxFRAME_NO_TASKBAR | wxSTAY_ON_TOP but it still draws a black outline 1 px wide around the window. Is this a bug or something?
You must also set wxBORDER_NONE.