DPI 感知屏幕捕获
DPI aware screen capture
我以前使用 AutoIt 的 _ScreenCapture_Capture()
没有任何问题。但是在具有 4k 分辨率屏幕的 Windows 10 上,我使用 200% 的 DPI 缩放比例。 _ScreenCapture_capture()
现在可以将某些内容放大 2 倍并缩小到我要求的位置的一半。
例如:
_ScreenCapture_Capture("c:\a.bmp", 100, 100, 200, 200)
; Path, X1, Y1, X2, Y2
不是 return 100x100 像素的正方形屏幕(在 100,100
到 200,200
处)。它 return 是一个 100x100 像素的正方形(在 50,50
到 100,100
之间)。
我确实找到了解决方案:
DllCall("User32.dll", "bool", "SetProcessDPIAware")
然而,这搞砸了 GUI 的外观。所以我然后发现 this code:
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
这对 GUI 非常有用,但对 _ScreenCapture_Capture()
调用没有帮助。看来我要么有一个好看的程序,要么有一个功能正常的程序,但不能两者兼而有之。
我如何结合这两种解决方案来获得良好的 GUI 和功能正常的程序?如果我知道如何做相反的事情:
DllCall("User32.dll", "bool", "SetProcessDPIAware")
然后当我需要捕获屏幕部分时,我可以打开兼容性,然后在完成捕获后立即将其关闭。但我不知道如何 'UNsetprocessdpiaware'.
如果您正在使用 Windows10 A 更新 (10.0.14393),您可以启动一个单独的线程并使该线程单独感知每个监视器 DPI,而让您的主 GUI 不感知 dpi。
见
SetThreadDpiAwarenessContext function
如果您使用的是 2015 年之前的 visual studio 版本,您可以声明一个指向函数原型的指针
DPI_AWARENESS_CONTEXT WINAPI SetThreadDpiAwarenessContext(
_In_ DPI_AWARENESS_CONTEXT dpiContext
);
并在调用函数之前使用 GetProcAddress 测试该函数是否存在。如果您使用
,该线程中的任何内容都会为您提供原始物理信息
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
请注意,此功能在 Windows10 10.0.10586 上不可用。您必须测试其可用性。
我以前使用 AutoIt 的 _ScreenCapture_Capture()
没有任何问题。但是在具有 4k 分辨率屏幕的 Windows 10 上,我使用 200% 的 DPI 缩放比例。 _ScreenCapture_capture()
现在可以将某些内容放大 2 倍并缩小到我要求的位置的一半。
例如:
_ScreenCapture_Capture("c:\a.bmp", 100, 100, 200, 200)
; Path, X1, Y1, X2, Y2
不是 return 100x100 像素的正方形屏幕(在 100,100
到 200,200
处)。它 return 是一个 100x100 像素的正方形(在 50,50
到 100,100
之间)。
我确实找到了解决方案:
DllCall("User32.dll", "bool", "SetProcessDPIAware")
然而,这搞砸了 GUI 的外观。所以我然后发现 this code:
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
这对 GUI 非常有用,但对 _ScreenCapture_Capture()
调用没有帮助。看来我要么有一个好看的程序,要么有一个功能正常的程序,但不能两者兼而有之。
我如何结合这两种解决方案来获得良好的 GUI 和功能正常的程序?如果我知道如何做相反的事情:
DllCall("User32.dll", "bool", "SetProcessDPIAware")
然后当我需要捕获屏幕部分时,我可以打开兼容性,然后在完成捕获后立即将其关闭。但我不知道如何 'UNsetprocessdpiaware'.
如果您正在使用 Windows10 A 更新 (10.0.14393),您可以启动一个单独的线程并使该线程单独感知每个监视器 DPI,而让您的主 GUI 不感知 dpi。
见
SetThreadDpiAwarenessContext function
如果您使用的是 2015 年之前的 visual studio 版本,您可以声明一个指向函数原型的指针
DPI_AWARENESS_CONTEXT WINAPI SetThreadDpiAwarenessContext(
_In_ DPI_AWARENESS_CONTEXT dpiContext
);
并在调用函数之前使用 GetProcAddress 测试该函数是否存在。如果您使用
,该线程中的任何内容都会为您提供原始物理信息DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
请注意,此功能在 Windows10 10.0.10586 上不可用。您必须测试其可用性。