Ответ 1
Высокий DPI - это триггер, и это приводит к решению.
Приложения, которые демонстрируют эту проблему, не осведомлены о высоком значении DPI. Решение проблемы зависания состоит в том, чтобы информировать их или включить соответствующий режим совместимости, используя одно из решений под 1, 2 или 3.
Примечание. Будет ли остальная часть приложения вести себя корректно при включении высокой осведомленности о DPI, является другой проблемой и будет отличаться от приложения к приложению.
-
В режиме совместимости установите флажок "Отключить масштабирование дисплея при высоких настройках DPI"
-
Вызвать
SetProcessDPIAware
как первый вызов в файле.dpr
- как отметил Ян Бойд, вызов этой функции может привести к состоянию гонки, а предпочтительный способ - использовать манифест. SetProcessDPIAware -
Использовать пользовательский манифест с настройками
true
илиtrue/PM
(дефолт Delphi, включенный в "Включить темы времени выполнения", не отличается высоким уровнем DPI)
В текущих версиях фреймворков Delphi VCL и FMX отсутствует поддержка для каждого монитора DPI, поэтому используйте true/PM
манифест, только если вы обрабатываете каждый монитор DPI самостоятельно. Сообщается QP как VCL и FireMonkey не поддерживают поддержку DPI для Windows 8.1 (и Windows 10)
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
или
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true/PM</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
Update:
Delphi VCL является источником ошибочного поведения, в частности, вопрос находится где-то в классе TForm
или его предках. Когда используется прямой интерфейс Windows API, в результате окна ведут себя нормально.
Код API Windows, который ведет себя правильно:
MessageBox(0, 'Correct', 'Caption', MB_OK);
ShowMessage('Correct'); // if themes are enabled -> Windows Task dialog is used
Полное приложение примера Delphi, которое создает главное окно без использования VCL - ведет себя правильно
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.
Неверные формы VCL:
var
f: TForm;
f := CreateMessageDialog('Broken', mtWarning, mbOKCancel, mbOk);
f.ShowModal;
f.Free;
f := TForm.Create(nil);
f.ShowModal;
f.Free;