Page 1 sur 1

DPI Awareness par moniteur.

Publié : jeu. 13/avr./2023 13:22
par ❤x1

Code : Tout sélectionner

#WM_DPICHANGED = $2E0 ;https://learn.microsoft.com/en-us/windows/win32/hidpi/wm-dpichanged

Procedure EnableDPIAwarness()
	Protected ver.OSVERSIONINFOEX, hDLL.i, Result
	
	ver\dwOSVersionInfoSize = SizeOf(ver)
	
	hDLL = OpenLibrary(#PB_Any, "ntdll.dll")     
	If hDLL   
		CallFunction(hDLL, "RtlGetVersion", @ver)
		CloseLibrary(hDLL)       
	EndIf
	
	If ver\dwMajorVersion > 6 Or (ver\dwMajorVersion = 6 And ver\dwMinorVersion = 3)
		hDLL = OpenLibrary(#PB_Any, "SHCore.dll")
		If hDLL
			; SetProcessDpiAwareness(Value) : https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setthreaddpiawarenesscontext
			; 2 = DPI_AWARENESS_PER_MONITOR_AWARE as defined here : https://learn.microsoft.com/en-us/windows/win32/api/shellscalingapi/ne-shellscalingapi-process_dpi_awareness
			Result = CallFunction(hDLL, "SetProcessDpiAwareness", 2)
			CloseLibrary(hDLL)
			
			If Result = #S_OK
				Result = #True
			Else
				Result = #False
				CompilerIf #PB_Compiler_Debugger
					MessageRequester("EnableDPIAwareness", "Couldn't set DPI awareness. Please make sure that `DPI awereness executable` is DISABLED in the compiler options.")
				CompilerEndIf
			EndIf
		EndIf
	EndIf
	
	ProcedureReturn Result
EndProcedure

; Example :
ImportC "user32.lib"
	GetDpiForWindow(WindowID.i)
EndImport

EnableDPIAwarness()

OpenWindow(0, 200, 200, 400, 400, "DPI Test", #PB_Window_SystemMenu)

Procedure Callback(WindowID, Message, WParam, LParam)
	If Message = #WM_DPICHANGED
		Debug GetDpiForWindow(WindowID(0))
	EndIf
	ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

SetWindowCallback(@Callback(), 0)

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Un peu d'explication : l'implémentation dans PureBasic de la DPI Awareness est limitée au niveau PROCESS_SYSTEM_DPI_AWARE et renverra toujours la valeur de l'écran principal. Cependant, cette valeur peut changer si les préférences de l'OS sont modifiées ou si la fenêtre est passée sur un moniteur différent. C'est ce deuxième cas qui est problématique : ça arrive quotidiennement à tous les gens qui branchent et débranchent leur laptop à un écran.
Voilà la solution pour passer la DPI Awareness à PROCESS_PER_MONITOR_DPI_AWARE, qui prend en compte ces cas de figure.

J'ai mis quelques liens en commentaire dans le code pour en apprendre plus si ça vous intéresse. Ça fonctionne avec Windows 8.1 et au-delà (donc toutes les versions encore maintenues) et il y a des failsafes pour éviter les problèmes que j'ai pu envisager.
J'ai testé ça sous Windows 11 Entreprise à jour, j'aimerais beaucoup une confirmation sous 10.