Windows 10, DPI scaling and fullscreen - winapi

I have an application which is PROCESS_PER_MONITOR_DPI_AWARE from Windows 8.1 and DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 from Windows 10 v1703. My windows have the WS_OVERLAPPEDWINDOW style when in windowed mode, and I switch them to a monitor-sized WS_POPUP when fullscreening.
When I change DPI on the same monitor, a windowed-mode window get a correctly-scaled window size in the WM_DPICHANGED message on both Windows 8.1 and Windows 10 v1703. When fullscreened however, Windows 8.1 doesn't resize a fullscreen window (it keeps the same dimensions) but Windows 10 v1703 does. This means that a 2560x1440 fullscreen window at 96 dpi stays 2560x1440 on Windows 8.1 when going to, say, 144 dpi, but gets resized to 3840x2160 on Windows 10 v1703.
Is this normal i.e. is keeping a fullscreen window the same size something I should now be manually doing when receiving the WM_GETDPISCALEDSIZE message, which just used to be done automatically on Windows 8.1?
EDIT: After further testing, the WM_GETDPISCALEDSIZE message doesn't even seem to be sent if the window is fullscreen, only if it's windowed (WS_POPUP works but only if the size isn't the same as the monitor). Therefore I can't even override this behaviour, and Windows 8.1 works different to Windows 10 v1703 for fullscreened windows.

Try this:
void ShowFullScreen(HWND hwnd)
{
LONG exStyle = ::GetWindowLong(hwnd, GWL_EXSTYLE);
LONG style = ::GetWindowLong(hwnd, GWL_STYLE);
::SetWindowLong(hwnd, GWL_STYLE,
(style & ~WS_OVERLAPPEDWINDOW) | WS_POPUPWINDOW);
::SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST);
::ShowWindow(hwnd, SW_SHOWMAXIMIZED);
}
Will it help to solve the problem on W8.1?

Related

DPI scaling a complete dialog box from resource

I setup per-monitor DPI scaling in a Win32 app, and my part works fine, however opening up a dialog box created in the resource editor doesn't scale itself (I would think using dialog units, it would).
Is there a way to scale everything from a dialog resource and be compatible with, say, Win8.1, as well as Win10, and even Win7?
Per-Monitor and Per-Monitor (V2) DPI Awareness:
It is recommended that desktop applications be updated to use
per-monitor DPI awareness mode, allowing them to immediately render
correctly whenever the DPI changes. When an application reports to
Windows that it wants to run in this mode, Windows will not bitmap
stretch the application when the DPI changes, instead sending
WM_DPICHANGED to the application window. It is then the complete
responsibility of the application to handle resizing itself for the
new DPI. Most UI frameworks used by desktop applications (Windows
common controls (comctl32), Windows Forms, Windows Presentation
Framework, etc.) do not support automatic DPI scaling, requiring
developers to resize and reposition the contents of their windows
themselves.
You can resize the dialog box in the WM_DPICHANGED message.
case WM_DPICHANGED:
{
LPRECT lpRect = (LPRECT)lParam;
SetWindowPos(hWnd, nullptr, lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, SWP_NOZORDER | SWP_NOACTIVATE);
return 0;
}
Updated:
For per-monitor DPI, v2 is the only one that can handle the dialog DPI scale., v1 does not so on WIndows 8.1 and older versions of Window 10, it has to be done manually. Windows 8.1 and older Windows 10, we don't scale controls. So the solution should be just resize the dialog. It has to enumerate all controls and resize them during WM_DPICHANGED if the dialog is not resizable.

MFC dialog window on top of tablet mode view windows 10

We are creating a dialog window to display information, this dialog is invoked by application which is running in background on local (Host) machine when it receives instructions from remote machine. This is working fine in Windows 10 OS when running in desktop mode. But we are NOT seeing the dialog when the Windows 10 OS is switched to tablet mode, rather it is in background.
So far we have tried the following,
building the application with "UIAccess=true"
SetWindowLong(m_hWnd, GWL_STYLE,
GetWindowLong(m_hWnd, GWL_STYLE) | WS_MINIMIZEBOX);
SetWindowLong(m_hWnd, GWL_STYLE,
GetWindowLong(m_hWnd, GWL_STYLE) & ~WS_MAXIMIZEBOX);
SetWindowPos(m_hWnd, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE );
Any suggestions.

Title bar buttons lose highlighted state when hovered in D7 on Win10 [duplicate]

In a Delphi application, when you hover over a border icon, e.g.:
Minimize
Maximize
Restore
it doesn't behave correctly:
Compare to an application that does behave correctly:
Step to Reproduce
Click File, New, VCL Forms Application - Delphi
Click Run (F9)
Hover over the Minimize, Maximize, or Close buttons.
How to fix?
Windows 10, 64-bit (running natively on desktop PC)
Delphi XE6
Edit - It also fails with Delphi 7:
and in Delphi 5:
and in Delphi 4:
I assumed (i.e. was afraid) that it was caused by the ThemeServices engine; where they might have thought it was cool to not honor the user's preferences. But looks like it's something more fundamental.
Compatibility Modes
none: fails
Windows 8: fails
Windows 7: fails
Windows Vista (Service Pack 2): fails
Windows Vista (Service Pack 2): fails
Windows Vista: fails
Windows XP (Service Pack 3) (non-client area theming disabled): works
Windows XP (Service Pack 2) (non-client area theming disabled): works
Windows 98 / Windows Me (non-client area theming disabled): works
Windows 95 (non-client area theming disabled): works
Skype
Also fails in Skype; also written in Delphi:
High DPI is the trigger
I finally figured out why it fails on every Windows 10 machine i've used; but not for everyone. High dpi.
Set your dpi to 97 (101%) or higher.
Close Enough
Dalija's solutions works:
We'll ignore the problem with the tooltip and live to fight another day.
It should also be noted that Windows 10 will suggest that you might have to sign off and sign back on for some applications to work correctly after changing the DPI. This is definitely true of Delphi.
It should also be noted that Delphi doesn't tolerate the DPI changing behind its back like this. This includes adjusting the zoom slider. This would also include placing the app on any monitor besides the primary monitor.
And we never did figure out what the problem is; only kicked it down the road for users running multiple monitors.
QC Bug Report
Because Bor...Impr...CodeG...Embarca... Idera's QC site is behind a pay-wall, here's a copy of the bug report:
http://archive.is/v77rz
As you can see: nobody cares.
High DPI is the trigger and it leads to the solution.
Applications that exhibit the issue are not High DPI aware. Solution to hovering problem is to make them aware or turn on associated compatibility mode by using one of solutions under 1, 2 or 3.
Note: whether will rest of the application behave properly when High DPI awareness is turned on is another issue and will differ from application to application.
Under compatibility mode check "Disable display scaling on high DPI settings"
Call SetProcessDPIAware as first call in .dpr file - as noted by Ian Boyd, calling this function can leat to race condition and preferred way is using manifest. SetProcessDPIAware
Use custom manifest with true or true/PM setting (default Delphi manifest included with "Enable runtime themes" is not high DPI aware)
Current versions of Delphi VCL and FMX frameworks lack support for per monitor DPI awareness, so use true/PM manifest only if you are handling per monitor DPI yourself. Reported to QP as VCL and FireMonkey lack Per-Monitor DPI support for Windows 8.1 (and Windows 10)
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
or
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true/PM</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
Update:
Delphi VCL is source of buggy behavior, specifically issue is somewhere in TForm class or its ancestors. When direct Windows API is used resulting windows behave normally.
Windows API code that behaves properly:
MessageBox(0, 'Correct', 'Caption', MB_OK);
ShowMessage('Correct'); // if themes are enabled -> Windows Task dialog is used
Full Delphi sample app that creates main window without using VCL - behaves properly
program win;
{$R *.res}
uses
Windows,
Messages,
SysUtils;
var
Msg: TMSG;
LWndClass: TWndClass;
hMainHandle: HWND;
function WindowProc(HWND, Msg: Longint; wParam: wParam; lParam: lParam): Longint; stdcall;
begin
if Msg = WM_DESTROY then PostQuitMessage(0);
Result := DefWindowProc(HWND, Msg, wParam, lParam);
end;
begin
LWndClass.hInstance := hInstance;
with LWndClass do
begin
lpszClassName := 'WinApiWnd';
Style := CS_PARENTDC or CS_BYTEALIGNCLIENT;
hIcon := LoadIcon(hInstance, 'MAINICON');
lpfnWndProc := #WindowProc;
hbrBackground := COLOR_BTNFACE + 1;
hCursor := LoadCursor(0, IDC_ARROW);
end;
RegisterClass(LWndClass);
hMainHandle := CreateWindow(LWndClass.lpszClassName, 'Window Title', WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU or WS_VISIBLE, 0, 0, 360, 200, 0, 0, hInstance, nil);
while GetMessage(Msg, 0, 0, 0) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end.
Misbehaved VCL forms:
var
f: TForm;
f := CreateMessageDialog('Broken', mtWarning, mbOKCancel, mbOk);
f.ShowModal;
f.Free;
f := TForm.Create(nil);
f.ShowModal;
f.Free;

BHO, SW_HIDE and Windows 8.1

This BHO I have works just fine in Win XP IE 8 and Win 7 IE 11 both 32 bit, but not on Win 8.1 64 bit, no EPM.
It retrieves the HWND of an IE 11 window and calls ShowWindow(hwnd, SW_HIDE); on it. The window does not get hidden. Verified with WinSpy that the grabbed window handle is the correct one and the call to the function above returns FALSE with last error = 0.
Help! Thanks
Seems that the BHO dll is loaded into child iexplore processes running at AppContainer or Low Integirty Levels whereas the HWNDs of Internet Explorer all reside in the parent, main iexplore process running at Medium Integrity Level, thus rendering what I was trying to achieve impossible the way I was attempting.

MFC Application font issues - dialogs look wrongon Win2k8

My legacy application that runs on win2k3 citrix is about to be migrated to win2k8 citrix.
While testing on win2k8 I noticed UI issues that are not apparent on 2k3 - buttons are not wide enough for their labels, text fields are truncated, etc.
I noticed Win2k3 default font is Tahoma and 2k8 uses Segoe UI, not sure if this is the cause
It's a controlled environment that hosts only my application so changing the windows UI settings is preferable to redesigning all my windows and dialogs.
How can i make my application look the same on win2k8 as it does on win2k3?
Here is an example of my login dialog from the rc file. On win2k8 the text "please enter your user id" wraps over 2 lines and is hidden under the edit box.
IDD_LOGON DIALOG DISCARDABLE 0, 0, 545, 361
STYLE WS_POPUP | WS_VISIBLE
FONT 8, "Arial"
BEGIN
LTEXT "Welcome",IDC_USER_LOGON_HEAD1,368,192,140,19
LTEXT "Please enter your User ID",IDC_USER_LOGON_HEAD2,368,220,
118,14
EDITTEXT IDC_USER_LOGON_USER,368,236,81,12,ES_AUTOHSCROLL
LTEXT "and your password",IDC_USER_LOGON_HEAD3,368,260,118,14
EDITTEXT IDC_USER_LOGON_PASSWORD,368,276,81,12,ES_PASSWORD |
ES_AUTOHSCROLL
PUSHBUTTON "OK",IDOK,368,316,50,14,WS_DISABLED
PUSHBUTTON "E&xit",IDCANCEL,424,316,50,14
END
edit:
I did some further investigation by taking some screen shots of the above dialog. it appears the problem is not that the text is the wrong size - the problem in the controls on the dialog are too small!
eg:
for the control IDC_USER_LOGON_PASSWORD which is 81 dialog units x 12 dialog units.
it should be rendered as 142 px by 24 px
instead it is rendered too small as 122 px by 21 px
Does this give anyone any clues?
Looks like you have "Desktop Experience" installed. You can uninstall it, and the server will run in "Classic" mode.
Additionally, you can play with "Personalisation Settings". Open Control panel\Appearance and Personalisation\Display and select "Make text and other items larger or smaller". There you can set the size of each elements. I recommend you set everything at 100%.
Also, if this does not help, you can change Compatibility for the application in Win2k8 to run as Win2k3.
As suggested by Hans, the problem was a DPI setting. The Win2k8 system has a DPI of 96 and the win2k3 system has a DPI of 120.
Setting the DPI on win2k8 to 120 resolves the issue when logged on via remote desktop, however there are still some issues getting citrix settings to respect this DPI settings, but I'm on the right track now.
thanks everyone

Resources