get a process's GDI handles (e.g. get/set title bar font and apply WM_SETFONT to a control) Topic is solved

Get help with using AutoHotkey and its commands and hotkeys
User avatar
jeeswg
Posts: 6649
Joined: 19 Dec 2016, 01:58
Location: UK

get a process's GDI handles (e.g. get/set title bar font and apply WM_SETFONT to a control)

30 Apr 2017, 20:46

NirSoft GDIView can retrieve GDI handles for all open processes. I used it to get the hFont for the title bar, and then used WM_SETFONT to set the Edit control in Notepad to have the same font as the title bar.

This could be useful if you want to easily apply a font of your choice to a control. You just need to set the title bar font for all programs, and a large number of control types support WM_SETFONT.

[Note: NirSoft GDIView does not need to be run in Admin mode.]
GDIView - View GDI handles/resources list and detect GDI leaks
http://www.nirsoft.net/utils/gdi_handles.html

Basically, I've started trying to convert the code below into AutoHotkey, and will continue when I have the chance.

The following code appears to be able to enumerate GDI handles:
c++ - How to get list of GDI handles - Stack Overflow
http://stackoverflow.com/questions/1390 ... di-handles

Thanks for reading.
Last edited by jeeswg on 25 May 2017, 01:32, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6649
Joined: 19 Dec 2016, 01:58
Location: UK

Re: get a process's GDI handles (e.g. get/set title bar font and apply WM_SETFONT to a control)

30 Apr 2017, 21:46

Things that are required: set title bar font, get GDI handles, get hFont information.
Here is code to set the title bar font and get hFont information:

Code: Select all

q:: ;get font information
SendMessage, 0x31, 0, 0, Edit1, ahk_class Notepad ;WM_GETFONT
hFont := ErrorLevel
oFontInfo := JEE_FontGetInfo(hFont)
MsgBox, % oFontInfo.Summary
oFontInfo := ""
return

;==================================================

JEE_FontGetInfo(hFont)
{
	vSize := DllCall("gdi32\GetObject", Ptr,hFont, Int,0, Ptr,0)
	VarSetCapacity(LOGFONT, vSize) ;LOGFONT Unicode
	DllCall("Gdi32\GetObject", Ptr,hFont, Int,vSize, Ptr,&LOGFONT)

	oFontInfo := {}
	oFontInfo.Height := NumGet(LOGFONT, 0, "Int") ;lfHeight
	oFontInfo.Width := NumGet(LOGFONT, 4, "Int") ;lfWidth
	oFontInfo.Escapement := NumGet(LOGFONT, 8, "Int") ;lfEscapement
	oFontInfo.Orientation := NumGet(LOGFONT, 12, "Int") ;lfOrientation
	oFontInfo.Weight := NumGet(LOGFONT, 16, "Int") ;lfWeight
	oFontInfo.Italic := NumGet(LOGFONT, 20, "UChar") ;lfItalic
	oFontInfo.Underline := NumGet(LOGFONT, 21, "UChar") ;lfUnderline
	oFontInfo.StrikeOut := NumGet(LOGFONT, 22, "UChar") ;lfStrikeOut
	oFontInfo.CharSet := NumGet(LOGFONT, 23, "UChar") ;lfCharSet
	oFontInfo.OutPrecision := NumGet(LOGFONT, 24, "UChar") ;lfOutPrecision ;(CreateFont: fdwOutputPrecision)
	oFontInfo.ClipPrecision := NumGet(LOGFONT, 25, "UChar") ;lfClipPrecision
	oFontInfo.Quality := NumGet(LOGFONT, 26, "UChar") ;lfQuality
	oFontInfo.PitchAndFamily := NumGet(LOGFONT, 27, "UChar") ;lfPitchAndFamily
	oFontInfo.FaceName := StrGet(&LOGFONT + 28, 32) ;lfFaceName[LOGFONT_FACESIZE] ;(CreateFont: lpszFace)

	vScreenDPI := A_ScreenDPI
	if (vScreenDPI = "")
		RegRead, vScreenDPI, HKEY_LOCAL_MACHINE, SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontDPI, LogPixels
	oFontInfo.Size := DllCall("kernel32\MulDiv", Int,-oFontInfo.Height, Int,72, Int,vScreenDPI)
	vList := "Height,Width,Escapement,Orientation,Weight,Italic,Underline,StrikeOut,CharSet,OutPrecision,ClipPrecision,Quality,PitchAndFamily,FaceName"
	Loop, Parse, vList, % ","
		oFontInfo.Summary .= oFontInfo[A_LoopField] " "
	oFontInfo.Summary .= "[" oFontInfo.Size "]"
	return oFontInfo
}

;==================================================

Code: Select all

q:: ;set title bar font
JEE_SystemSetFont("Caption", "Arial", 18, 700)
return

;==================================================

;e.g.
;JEE_SystemSetFont("Message", "Arial", 18, 700)

;JEE_SetSystemFont
;JEE_SystemFontSet
JEE_SystemSetFont(vType:="", vName:="", vSize:=0, vWeight:=0, vIsItalic:=-1)
{
	;SPI_GETICONTITLELOGFONT := 0x1F
	;SPI_SETICONTITLELOGFONT := 0x22
	;SPI_GETNONCLIENTMETRICS := 0x29
	;SPI_SETNONCLIENTMETRICS := 0x2A
	;SPIF_UPDATEINIFILE := 0x1
	;SPIF_SENDCHANGE := 0x2

	static vSizeLF := A_IsUnicode ? 92 : 60
	static vSizeNCM := 40 + 5*vSizeLF

	if (vType = "Icon")
	{
		VarSetCapacity(LOGFONT, vSizeLF, 0)
		if !DllCall("SystemParametersInfo", UInt,0x1F, UInt,vSizeLF, Ptr,&LOGFONT, UInt,0)
			return 0
		vAddress := &LOGFONT
		vMode := "Icon"
	}
		else
		{
			vOffset := ""
			(vType = "Caption") ? (vOffset := 24) : ""
			(vType = "SmCaption") ? (vOffset := 32 + vSizeLF) : ""
			(vType = "Menu") ? (vOffset := 40 + 2*vSizeLF) : ""
			(vType = "Status") ? (vOffset := 40 + 3*vSizeLF) : ""
			(vType = "Message") ? (vOffset := 40 + 4*vSizeLF) : ""
			if (vOffset = "")
				return

			VarSetCapacity(NONCLIENTMETRICS, vSizeNCM, 0)
			NumPut(vSizeNCM, &NONCLIENTMETRICS, 0, "UInt")
			if !DllCall("SystemParametersInfo", UInt,0x29, UInt,vSizeNCM, Ptr,&NONCLIENTMETRICS, UInt,0)
				return 0
			vAddress := &NONCLIENTMETRICS + vOffset
		}

	if vName
		StrPut(vName, vAddress+28, 32)
	if vSize
	{
		vHeight := -DllCall("MulDiv", Int,vSize, Int,A_ScreenDPI, Int,72)
		NumPut(vHeight, vAddress+0, "Int")
	}
	if Weight
		NumPut(vWeight, vAddress+16, "Int")
	if (vIsItalic = 1) || (vIsItalic = 0)
		NumPut(vIsItalic, &vAddress+20, "UChar")

	if (vMode = "Icon")
		vRet := DllCall("SystemParametersInfo", UInt,0x22, UInt,vSizeLF, Ptr,&LOGFONT, UInt,0x3)
	else
		vRet := DllCall("SystemParametersInfo", UInt,0x2A, UInt,vSizeNCM, Ptr,&NONCLIENTMETRICS, UInt,0x3)

	return !!vRet
}

;==================================================
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6649
Joined: 19 Dec 2016, 01:58
Location: UK

Re: get a process's GDI handles (e.g. get/set title bar font and apply WM_SETFONT to a control)  Topic is solved

24 Aug 2017, 00:27

OK, I managed to get everything to work now. It uses the JEE_FontGetInfo function from above. I basically had to learn C++ from scratch to get it all working.

Code: Select all

q:: ;process - get gdi handles
DetectHiddenWindows, On
WinGet, hWnd, ID, A
WinGet, vPID, PID, % "ahk_id " hWnd
WinGetTitle, vWinTitle, % "ahk_id " hWnd
WinGetClass, vWinClass, % "ahk_id " hWnd
vListAll := JEE_ProcessGetGDIHandles(vPID)
;Clipboard := vListAll
MsgBox, % vListAll

vListFont := JEE_ProcessGetGDIHandles(vPID, "`n", 10, 0)
;Clipboard := vListFont
MsgBox, % vListFont
vOutput := vPID "`t" vWinTitle "`t" vWinClass "`r`n"
Loop, Parse, vListFont, `n, `r
{
	hFont := A_LoopField
	vOutput .= hFont "`t" JEE_FontGetInfo(hFont).Summary "`r`n"
}
MsgBox, % SubStr(vOutput, 1, -2)
return

;==================================================

;DetectHiddenWindows, On
;WinGet, hWnd, ID, A
;WinGet, vPID, PID, % "ahk_id " hWnd
;MsgBox, % JEE_ProcessGetGDIHandles(vPID) ;list all (with labels)
;MsgBox, % JEE_ProcessGetGDIHandles(vPID, "`n", 10, 0) ;list hFonts only (no labels)
;return

;based on:
;c++ - How to get list of GDI handles - Stack Overflow
;https://stackoverflow.com/questions/13905661/how-to-get-list-of-gdi-handles
;see also:
;GDIView - View GDI handles/resources list and detect GDI leaks
;http://www.nirsoft.net/utils/gdi_handles.html

JEE_ProcessGetGDIHandles(vPID, vSep:="`n", vKeepType:=-1, vIncLabel:=1)
{
	;PROCESS_QUERY_INFORMATION := 0x400 ;PROCESS_VM_READ := 0x10
	if !hProc := DllCall("kernel32\OpenProcess", UInt,0x410, Int,0, UInt,vPID, Ptr)
		return
	vGdiSharedHandleTableOffset := A_Is64bitOS ? 0xF8 : 0x94
	vCountTable := 16384
	vSizePEB := vGdiSharedHandleTableOffset+8
	VarSetCapacity(PEB, vSizePEB, 0)

	vSizePBI := A_Is64bitOS?48:24
	;ProcessBasicInformation := 0
	VarSetCapacity(PROCESS_BASIC_INFORMATION, vSizePBI, 0)

	if A_Is64bitOS && (A_PtrSize = 4)
	{
		vNtQueryInformationProcess := "ntdll\NtWow64QueryInformationProcess64"
		vNtReadVirtualMemory := "ntdll\NtWow64ReadVirtualMemory64"
	}
	else
	{
		vNtQueryInformationProcess := "ntdll\NtQueryInformationProcess"
		vNtReadVirtualMemory := "ntdll\NtReadVirtualMemory"
	}

	if DllCall(vNtQueryInformationProcess, Ptr,hProc, UInt,0, Ptr,&PROCESS_BASIC_INFORMATION, UInt,vSizePBI, Ptr,0)
	{
		DllCall("kernel32\CloseHandle", Ptr,hProc)
		return
	}
	vPebBaseAddress := NumGet(PROCESS_BASIC_INFORMATION, 8, "Int64") ;PebBaseAddress

	if DllCall(vNtReadVirtualMemory, Ptr,hProc, Int64,vPebBaseAddress, Ptr,&PEB, UInt,vSizePEB, Ptr,0)
	{
		DllCall("kernel32\CloseHandle", Ptr,hProc)
		return
	}
	pGdiTable := NumGet(PEB, vGdiSharedHandleTableOffset, "Int64")

	vSizeCell := A_Is64bitOS?24:16
	vSizeTable := vSizeCell * vCountTable
	VarSetCapacity(ArrayGDICELL, vSizeTable, 0)
	if DllCall(vNtReadVirtualMemory, Ptr,hProc, Int64,pGdiTable, Ptr,&ArrayGDICELL, UInt, vSizeTable, Ptr,0)
	{
		DllCall("kernel32\CloseHandle", Ptr,hProc)
		return
	}
	DllCall("kernel32\CloseHandle", Ptr,hProc)

	vOutput := ""
	VarSetCapacity(vOutput, 100000*2)
	vOffset := &ArrayGDICELL-vSizeCell
	oType := {0:"Unknown type",1:"DC",4:"Region",5:"Bitmap",8:"Palette",10:"Font",16:"Brush",48:"Pen"}
	Loop, % vCountTable
	{
		vOffset += vSizeCell
		vPID2 := NumGet(vOffset+0, A_Is64bitOS?8:4, "UShort") ;wProcessId
		vUpper := NumGet(vOffset+0, A_Is64bitOS?12:8, "UShort") ;wUpper
		vType := NumGet(vOffset+0, A_Is64bitOS?14:10, "UShort") ;wType
		if !(vPID2 = vPID)
			continue
		vGdiHandle := (vUpper << 16) + A_Index - 1
		vType &= 0x7F
		if (vKeepType >= 0) && !(vKeepType = vType)
			continue
		if !oType.HasKey(vType)
			vType := 0
		if vIncLabel
			vOutput .= oType[vType] " handle:" Format("0x{:08X}", vGdiHandle) vSep
		else
			vOutput .= Format("0x{:08X}", vGdiHandle) vSep
	}
	return SubStr(vOutput, 1, -StrLen(vSep))
}
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Ask For Help”

Who is online

Users browsing this forum: Bill, Bing [Bot], RinkaDink, Strahan and 161 guests