Toolbar elements cutting due to 150% DPI - MFC C++ - c++

The MFC application looks weird with 150% DPI settings on Windows 7.
When display settings on Windows 7 are changed to 150% following things happen:
Toolbar gets expanded a lot making menu items almost invisible.
In addition, a black gap get's introduced between the toolbar and application frame (as shown in new)
The app used to work fine a while ago (as shown in old). Many changes have been introduced to the app including integration of DevExpress.
But nothing particularly changed in DPI settings.
Need help in understanding why this change might have occurred. And how to get rid of this unwanted zoom effect / DPI effect.

Related

DPI Scaling with windows-generated dialogues in C++?

I'm trying to properly DPI scale an application in C++ and I'm having trouble getting this to work with the File Picker window created from calling OPENFILENAMEW from commdlg.h.
I'm using three monitors: two with 1.0 dpi and one with 2.5 dpi. For me, the file picker only opens with 1.0 DPI regardless of what window my application is in. So when I drag the file picker to the 2.5 dpi monitor, the window is so small is hard to read. I can only get it to scale with 2.5 dpi when I disconnect the other monitors. I looked at the documentation for OPENFILENAMEW and there is a flag to allow the dialogue to resize manually but that's about it.
It has to register the dpi at some point to scale but I just can't find it.
Does anyone know how to do this?
Enabling per monitor DPI awareness in Manifest settings didn't solve this completely but it did lead me to the answer I was looking for! So the issue that persisted was that once the file-picker window was created, it kept it's DPI scale from its original window even after moving it to a window with different DPI.
Apparently the options in Manifest don't support this and neither does the SetProcessDpiAwareness function in the shellscaling api, which can be used to set that Manifest setting programmatically.
However, the SetProcessDpiAwarenessContext from winuser.h has one more option that the others don't: DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2. This can only be used on windows machines with the Creators update (named Redstone 2) and you can check that to do DPI scaling right when you can, and wrong but as good as possible when you can't:
if (IsWindowsVersionOrGreater(HIBYTE(NTDDI_WIN10_RS2), LOBYTE(NTDDI_WIN10_RS2), 0)) {
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
else {
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
}
And this works!

Visual studio creating wrong sized windows and wrong system metrics

Never mind, this question is a duplicate. I might be able to figure this out from other sources.
I'm so so confused. I was working on my project and realised that the window created with CreateWindowEx() was bigger than I was specifying. I noticed the windows are bigger in release mode than in debug mode. Then I took the values of GetSystemMetrics(SM_CXSCREEN) and SM_CXFULLSCREEN and noticed that in debug mode it gives me 1920 x 1080, which is correct, but in release mode it gives me 1536 x 864.
Furthermore, if I just start a new Win32 project, which is up and ready to run just by pushing ctrl + F5, I get the wrong value in both debug AND release mode, same values as before, and the windows are bigger.
I don't see how providing any code might help, I could make a video of it, but... this just doesn't make sense. Could anyone maybe see if it happens to them by starting a new Win32 project, and seeing 1600 x 900 actually takes up that much space? Because 1600 x 900 takes up my entire screen when it shouldn't.
Thanks.
On further inspection, the 1536 x 864 resolution it gives me is 80% the size that it should be, or in other words it should be 1.25 times bigger, the reciprocal. Also if I change my desktop resolution to 1600 x 900 the metrics gives me 1280 x 720, which is again 80%, or the resolution is 1.25 bigger than what's given.
Well, this is a duplicate, but if this helps anyone I'll explain the problem of DPI scaling. Basically the default Windows setting is 96 DPI. There are options in Control Panel to "make stuff bigger", which is easier on the eyes. My slider is set to the middle one, which is equivalent to 125% bigger, or 120 dpi, which is why System Metrics was returning the wrong values, and my windows were bigger. The dpi gets bigger, so the system assumes it has to draw everything larger in proportion to the upscaling. If you consider someone programs a window to be 200 pixels across, when someone with a super duper double resolution display runs it, it's still going to be 200 pixels across, but half the physical size, say inch-wise. So by doubling the dpi "setting", not the dpi, but dpi "setting" from 96 to 194, or scaling it up 200% makes the window occupy 400 pixels across, but is the same size with respect to the original display.
Anyway, the easiest fix for this, if on Visual Studio, is simply through the project properties, go down to the "manifest" menu, then select "input/output", the last option should be DPI Awareness. Mine was on "None". It's only necessary in most cases to put it on "High DPI Aware", and that will fix the problem. The other option, which is "per monitor DPI awareness" means that it will adjust accordingly in a dynamic way, say for example the dpi scaling is changed while the app is running, or moving the window onto another monitor while it's running. The High DPI Aware setting will do a check at startup.
Interestingly, if you go to the properties of any exe, and under the compatibility tab, you can check "Disable display scaling on high DPI settings", and that will work also. Finally, there is a free program, now owned by Microsoft, called process explorer, which is basically like task manager with extra features, and you can select the DPI Awareness column and see which programs are DPI aware. Yes, DPI Awareness is a thing, I feel so dumb. There are also many other ways to do it, like with function calls and merging manifests, but I have no idea about that, and am too tired to even breathe now.

How do you scale the title bar on a DPI aware win application?

I am making my app dpi-aware per monitor by setting <dpiAware>True/PM</dpiAware> in the manifest file. I can verify with process explorer that this is indeed working or by calling GetProcessDpiAwareness.
This is all working fine and I can scale anything in the client area fine in my code. However, my only problem is that if I drag my app from a system-dpi monitor to a non-system dpi monitor, the title bar and any system menu would either become too big or too small. This isn't the case for most built-in apps (e.g. calc, edge browser, etc..) so there must be away to scale it properly. Does anyone how the devs at MS did this?
The screenshot below should explain my problem better. Also notice, that the padding between the close, min, and max button is different when it's scaled (96dpi).
Sample app I'm attaching a very simple app that is per-monitor dpi aware.
The Windows 10 Anniversary Update (v1607) has added a new API you must call to enable DPI scaling of the non-client areas: EnableNonClientDpiScaling. This function should be called, when WM_NCCREATE is received. The message is sent to the window's procedure callback during window creation.
Example:
case WM_NCCREATE:
{
if (!EnableNonClientDpiScaling(hWnd))
{
// Error handling
return FALSE;
}
return DefWindowProcW(...);
}
If the application's DPI-awareness context is DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, then calling EnableNonClientDpiScaling should be omitted, as it won't have any effect, although the function will still return successfully.
From the documentation:
Non-client scaling for top-level windows is not enabled by default. You must call this API to enable it for each individual top-level window for which you wish to have the non-client area scale automatically. Once you do, there is no way to disable it. Enabling non-client scaling means that all the areas drawn by the system for the window will automatically scale in response to DPI changes on the window. That includes areas like the caption bar, the scrollbars, and the menu bar. You want to call EnableNonClientDpiScaling when you want the operating system to be responsible for rendering these areas automatically at the correct size based on the API of the monitor.
See this blog post for additional information about DPI scaling changes in Windows 10 AU.
Does anyone how the devs at MS did this?
This has a pretty disappointing answer. Using Alin Constantin's WinCheat and inspecting the top-level window of Calculator, I see a window size of 320x576, and a client size that is also 320x576.
In other words, Microsoft entirely avoids the problem by suppressing the non-client area of the window, putting everything in the client area instead. Making this work well for you may involve custom drawing of the title bar.
Something worth noting is that Calculator and e.g. Windows Explorer don't use the same colour for the title bars. Calculator doing custom drawing of the title bar would explain that perfectly.
UPDATE:
It is enough to add new <dpiAwarness> declaration to manifest to solve all this mess. Example is here.
Remnants of former investigations (obsolete):
More investigations on the subject.
System setup: two monitors, one is 96 dpi another one is 267 dpi (Microsoft Surface 4).
Testing window is moved to secondary 96 dpi monitor:
Here is rendering (wrong, IMO) with <dpiAware>true/pm</dpiAware> in manifest:
Note huge size of caption bar and wrong sizes of window icons.
And here is correct rendering using <dpiAware>true</dpiAware>
And I suspect that MSDN documentation is plainly misleading about values of PROCESS_DPI_AWARENESS. I do not see any differences in messages and styles between <dpiAware>true</dpiAware> and <dpiAware>true/pm</dpiAware>. The later one just makes caption larger. In both case application receives WM_DPICHANGED message while moving between monitors with different DPI.
Sigh.
The documentation says:
Note that the non-client area of a per monitor–DPI aware application is not scaled by Windows, and will appear proportionately smaller on a high DPI display.
The Microsoft apps that you link to deal with this by removing the non-client area and making the client area cover the entire window.

Disabling the 'Aero Blur' from the Windows 7 taskbar (using C++?)

I found a small program a while back that let me disable the Aero Blur while keeping the transparency that came with the theme. The program worked on literally everything, except for the taskbar which still appears to blur everything that happens to be underneath it.
This curious behavior led me to experimenting with the DWM api, in C++. Sadly, this didn't really help me at all, since no matter what functions I'd use - like DwmEnableBlurBehindWindow() -, none of them would actually affect the taskbar in a way that I wanted them to. I even tried turning the alpha levels of the taskbar's owner "window" down, but sadly that didn't work either - It made the taskbar icons transparent too which is a no-no for me, and it didn't actually remove the blur it just made the effect weaker.
As it seems that my skills are not enough to accomplish this task, I'm asking you - how can I remove the Aero blur from the Windows 7 taskbar? (Possibly using C++)
Remove Transparency that will do, else go to
Personalize by right clicking on desktop.
There go to theme, personalize the theme,
and find transparency/opacity. if you want with no blur and enabled transparency make it 100%
else disable transparency.
this you can do using c++ by doing twiks with Registry.
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM]
"Composition"=dword:00000000
"CompositionPolicy"=dword:00000000
"ColorizationColor"=dword:6b74b8fc
"ColorizationColorBalance"=dword:00000008
"ColorizationAfterglow"=dword:6b74b8fc
"ColorizationAfterglowBalance"=dword:0000002b
"ColorizationBlurBalance"=dword:00000031
"ColorizationGlassReflectionIntensity"=dword:00000032
"ColorizationOpaqueBlend"=dword:00000000
"EnableAeroPeek"=dword:00000001
"AlwaysHibernateThumbnails"=dword:00000000
this are the values for Windows 7,
if you will change here, you will get the result. it contains all things you need to change.
you may change values for this three
ColorizationBlurBalance, ColorizationGlassReflectionIntensity, ColorizationOpaqueBlend
I think that will do :)
I found a small program that will remove the blur.
Link to DeviantArt

Change the icon on windows 7 taskbar for a pinned application

My software Pomodoro Timer is going to display a dynamic icon on Windows 7 taskbar. You may wonder why the application icon need to be dynamic. It's actually a counting down timer for me to help me focus on current task, so called the pomodoro technique:
My way to change the icon is to simply change the Window icon. It works fine when I start the application, but after I pinned it to taskbar, it will display the default icon for the application. The dynamic counter down number will disappear. More worse, after I unpinned it from taskbar, the default behavior will never be recovered, that is, the dynamic icon will not able to be updated correctly. When I start the application again, it will display the default icon, unless I pinned it and unpinned it again, the counting down icon displays again.
I've searched this forum, and Change pinned taskbar icon (windows 7), and tried to change the overlay icon. It works, but not fulfill my requirement, the overlay icon can only display 16x16, and no enough room to display 4 digits.
I also read the MSDN article Application User Model IDs, but i am still not clear whether it can make it or not.
Anyone can help on this? Thanks a lot!
Windows 7 supports having a green progress bar be shown over an icon, and pinning doesnt effect the progress bar. So, instead of changing the icon every second, why not change it every few seconds, but have the progress bar count down from 100% of the original set counter value?
The pinned items in the Taskbar are stored as a shortcut at:
%appdata%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar
You can try changing the icon of the Shortcut of your program.
My final solution is:
on Windows: use icon overlay. You can get more screen shots here.
on Mac: use different icon. You can get more screen shots here.
I use different solution for Windows and Mac.
Generally an application would make use of the System Tray to show interactive state such as this to the user. There is a whole API set for interacting with it, setting icons, menus, providing text feedback (balloons), and so on.
The following is a good article on how such functionality can be achieved:
http://www.codeproject.com/Articles/74/Adding-Icons-to-the-System-Tray