Захват экрана с учетом DPI

Раньше я использовал _ScreenCapture_Capture() AutoIt без каких-либо проблем. Но в Windows 10 с экраном с разрешением 4k я использую масштабирование DPI на уровне 200%. _ScreenCapture_capture() теперь получает 2-кратное увеличение и половину местоположения, которое я просил.

Например :

 _ScreenCapture_Capture("c:\a.bmp", 100, 100, 200, 200)
;                             Path,  X1,  Y1,  X2,  Y2

Не возвращает квадрат экрана размером 100x100 пикселей (от 100,100 до 200,200). Вместо этого он возвращает квадрат размером 100x100 пикселей (от 50,50 до 100,100).

Я нашел решение:

DllCall("User32.dll", "bool", "SetProcessDPIAware")

Однако это портит внешний вид графического интерфейса. Затем я нашел этот код:

GUISetFont(8.5 * _GDIPlus_GraphicsGetDPIRatio()[0])
Func _GDIPlus_GraphicsGetDPIRatio($iDPIDef = 96)
  Local $aResults[2] = [1, 1]
  _GDIPlus_Startup()
  Local $hGfx = _GDIPlus_GraphicsCreateFromHWND(0)
  If @error Then Return SetError(1, @extended, $aResults)
  #forcedef $__g_hGDIPDll, $ghGDIPDll
  $aResult = DllCall($__g_hGDIPDll, "int", "GdipGetDpiX", "handle", $hGfx, "float*", 0)
  If @error Then Return SetError(2, @extended, $aResults)
  Local $iDPI = $aResult[2]
  Local $aresults[2] = [$iDPIDef / $iDPI, $iDPI / $iDPIDef]
  _GDIPlus_GraphicsDispose($hGfx)
  _GDIPlus_Shutdown()
  Return $aresults
EndFunc   ;==>_GDIPlus_GraphicsGetDPIRatio

Что отлично работает для графического интерфейса, но не помогает для _ScreenCapture_Capture() вызовов. Кажется, у меня может быть либо красивая, либо работающая программа, но не то и другое одновременно.

Как я могу объединить эти два решения, чтобы получить как хороший графический интерфейс, так и работающую программу? Если бы я знал, как сделать противоположное:

DllCall("User32.dll", "bool", "SetProcessDPIAware")

Затем, когда мне нужно захватить часть экрана, я могу включить совместимость, а затем сразу же отключить ее после завершения захвата. Но я не знаю, как «UNsetprocessdpiaware».


person Legit Stack    schedule 13.10.2016    source источник


Ответы (1)


Если вы используете обновление Windows 10 A (10.0.14393), вы можете развернуть отдельный поток и настроить поток отдельно для каждого монитора DPI, а основной графический интерфейс оставить без учета dpi.

Видеть

функция SetThreadDpiAwarenessContext

Если вы создаете версию Visual Studio до 2015 года, вы можете объявить указатель на прототип функции.

DPI_AWARENESS_CONTEXT WINAPI SetThreadDpiAwarenessContext(
  _In_  DPI_AWARENESS_CONTEXT  dpiContext
);

и используйте GetProcAddress для проверки наличия функции перед ее вызовом. Все в этом потоке даст вам необработанную физическую информацию, если вы использовали

DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE

Обратите внимание, что эта функция недоступна в Windows 10 10.0.10586. Вы должны проверить его доступность.

person birdwes    schedule 18.10.2016
comment
Это лучшее решение, чем обходной путь, к которому я в итоге пришел: autoitscript.com/forum/topic/ Большое спасибо! - person Legit Stack; 18.10.2016
comment
Обязательно вызовите SetThreadDpiAwareness еще раз после вызова интересующего вас API и верните осведомленность DPI вашего потока на осведомленность процесса по умолчанию, иначе режим осведомленности может позже испортить что-то еще... если вы не получил выделенный поток, который вызывает этот API. - person peterfelts; 16.03.2017