SystemProcessInformation

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

SystemProcessInformation

22 Mar 2019, 09:03

SystemProcessInformation

Description:
These structures contain information about the resource usage of each process, including the number of threads and handles used by the process, the peak page-file usage, and the number of memory pages that the process has allocated.

Github:
...todo

Source:

Code: Select all

SystemProcessInformation()
{
	static SYSTEM_INFORMATION_CLASS := 0x5

	if (DllCall("ntdll\NtQuerySystemInformation", "int", SYSTEM_INFORMATION_CLASS, "ptr", 0, "uint", 0, "uint*", size) != 0) {
		size := VarSetCapacity(buf, size, 0)
		if (DllCall("ntdll\NtQuerySystemInformation", "int", SYSTEM_INFORMATION_CLASS, "ptr", &buf, "uint", size, "uint*", 0) != 0)
			return (ErrorLevel := 2) & 0
		addr := &buf, SYSTEM_PROCESS_INFORMATION := {}
		while (addr)
		{
			SYSTEM_PROCESS_INFORMATION[A_Index, "NumberOfThreads"]              :=        NumGet(addr +   4, "uint" )                             ;   4 |   4
			SYSTEM_PROCESS_INFORMATION[A_Index, "WorkingSetPrivateSize"]        :=        NumGet(addr +   8, "int64")                             ;   8 |   8
			SYSTEM_PROCESS_INFORMATION[A_Index, "HardFaultCount"]               :=        NumGet(addr +  16, "uint" )                             ;  16 |  16
			SYSTEM_PROCESS_INFORMATION[A_Index, "NumberOfThreadsHighWatermark"] :=        NumGet(addr +  20, "uint" )                             ;  20 |  20
			SYSTEM_PROCESS_INFORMATION[A_Index, "CycleTime"]                    :=        NumGet(addr +  24, "int64")                             ;  24 |  24
			SYSTEM_PROCESS_INFORMATION[A_Index, "CreateTime"]                   :=        NumGet(addr +  32, "int64")                             ;  32 |  32
			SYSTEM_PROCESS_INFORMATION[A_Index, "UserTime"]                     :=        NumGet(addr +  40, "int64")                             ;  40 |  40
			SYSTEM_PROCESS_INFORMATION[A_Index, "KernelTime"]                   :=        NumGet(addr +  48, "int64")                             ;  48 |  48
			SYSTEM_PROCESS_INFORMATION[A_Index, "ImageName"]                    := StrGet(NumGet(addr +  56 + A_PtrSize *  1, "ptr"  ), "utf-16") ;  60 |  64
			SYSTEM_PROCESS_INFORMATION[A_Index, "BasePriority"]                 :=        NumGet(addr +  56 + A_PtrSize *  2, "int"  )            ;  64 |  72
			SYSTEM_PROCESS_INFORMATION[A_Index, "UniqueProcessId"]              :=        NumGet(addr +  56 + A_PtrSize *  3, "ptr"  )            ;  68 |  80
			SYSTEM_PROCESS_INFORMATION[A_Index, "InheritedFromUniqueProcessId"] :=        NumGet(addr +  56 + A_PtrSize *  4, "ptr*" )            ;  72 |  88
			SYSTEM_PROCESS_INFORMATION[A_Index, "HandleCount"]                  :=        NumGet(addr +  56 + A_PtrSize *  5, "uint" )            ;  76 |  96
			SYSTEM_PROCESS_INFORMATION[A_Index, "SessionId"]                    :=        NumGet(addr +  60 + A_PtrSize *  5, "uint" )            ;  80 | 100
			SYSTEM_PROCESS_INFORMATION[A_Index, "UniqueProcessKey"]             :=        NumGet(addr +  64 + A_PtrSize *  5, "ptr*" )            ;  84 | 104
			SYSTEM_PROCESS_INFORMATION[A_Index, "PeakVirtualSize"]              :=        NumGet(addr +  64 + A_PtrSize *  6, "uptr" )            ;  88 | 112
			SYSTEM_PROCESS_INFORMATION[A_Index, "VirtualSize"]                  :=        NumGet(addr +  64 + A_PtrSize *  7, "uptr" )            ;  92 | 120
			SYSTEM_PROCESS_INFORMATION[A_Index, "PageFaultCount"]               :=        NumGet(addr +  64 + A_PtrSize *  8, "uint" )            ;  96 | 128
			SYSTEM_PROCESS_INFORMATION[A_Index, "PeakWorkingSetSize"]           :=        NumGet(addr +  64 + A_PtrSize *  9, "uptr" )            ; 100 | 136
			SYSTEM_PROCESS_INFORMATION[A_Index, "WorkingSetSize"]               :=        NumGet(addr +  64 + A_PtrSize * 10, "uptr" )            ; 104 | 144
			SYSTEM_PROCESS_INFORMATION[A_Index, "QuotaPeakPagedPoolUsage"]      :=        NumGet(addr +  64 + A_PtrSize * 11, "ptr*" )            ; 108 | 152
			SYSTEM_PROCESS_INFORMATION[A_Index, "QuotaPagedPoolUsage"]          :=        NumGet(addr +  64 + A_PtrSize * 12, "uptr" )            ; 112 | 160
			SYSTEM_PROCESS_INFORMATION[A_Index, "QuotaPeakNonPagedPoolUsage"]   :=        NumGet(addr +  64 + A_PtrSize * 13, "ptr*" )            ; 116 | 168
			SYSTEM_PROCESS_INFORMATION[A_Index, "QuotaNonPagedPoolUsage"]       :=        NumGet(addr +  64 + A_PtrSize * 14, "uptr" )            ; 120 | 176
			SYSTEM_PROCESS_INFORMATION[A_Index, "PagefileUsage"]                :=        NumGet(addr +  64 + A_PtrSize * 15, "uptr" )            ; 124 | 184
			SYSTEM_PROCESS_INFORMATION[A_Index, "PeakPagefileUsage"]            :=        NumGet(addr +  64 + A_PtrSize * 16, "uptr" )            ; 128 | 192
			SYSTEM_PROCESS_INFORMATION[A_Index, "PrivatePageCount"]             :=        NumGet(addr +  64 + A_PtrSize * 17, "uptr" )            ; 132 | 200
			SYSTEM_PROCESS_INFORMATION[A_Index, "ReadOperationCount"]           :=        NumGet(addr +  64 + A_PtrSize * 18, "int64")            ; 136 | 208
			SYSTEM_PROCESS_INFORMATION[A_Index, "WriteOperationCount"]          :=        NumGet(addr +  72 + A_PtrSize * 18, "int64")            ; 144 | 216
			SYSTEM_PROCESS_INFORMATION[A_Index, "OtherOperationCount"]          :=        NumGet(addr +  80 + A_PtrSize * 18, "int64")            ; 152 | 224
			SYSTEM_PROCESS_INFORMATION[A_Index, "ReadTransferCount"]            :=        NumGet(addr +  88 + A_PtrSize * 18, "int64")            ; 160 | 232
			SYSTEM_PROCESS_INFORMATION[A_Index, "WriteTransferCount"]           :=        NumGet(addr +  96 + A_PtrSize * 18, "int64")            ; 168 | 240
			SYSTEM_PROCESS_INFORMATION[A_Index, "OtherTransferCount"]           :=        NumGet(addr + 104 + A_PtrSize * 18, "int64")            ; 176 | 248

			if !(NumGet(addr + 0, "uint"))
				break
			addr += NumGet(addr + 0, "uint")
		}
		return SYSTEM_PROCESS_INFORMATION
	}
	return (ErrorLevel := 1) & 0
}
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: SystemProcessInformation

22 Mar 2019, 09:04

Examples:

Returns an array of SYSTEM_PROCESS_INFORMATION structures, one for each process running in the system.

Code: Select all

PrintArr(SystemProcessInformation())

PrintArr(Arr, Option := "w1200 h800", GuiNum := 90)
{
	for index, obj in Arr {
		if (A_Index = 1) {
			for k, v in obj {
				Columns .= k "|"    
				cnt++
			}
			Gui, %GuiNum%: Margin, 5, 5
			Gui, %GuiNum%: Add, ListView, %Option%, % Columns
		}
		RowNum := A_Index        
		Gui, %GuiNum%: default
		LV_Add("")
		for k, v in obj {
			LV_GetText(Header, 0, A_Index)
			if (k <> Header) {    
				FoundHeader := False
				loop % LV_GetCount("Column") {
					LV_GetText(Header, 0, A_Index)
					if (k <> Header)
						continue
					else {
						FoundHeader := A_Index
						break
					}
				}
				if !(FoundHeader) {
					LV_InsertCol(cnt + 1, "", k)
					cnt++
					ColNum := "Col" cnt
				} else
					ColNum := "Col" FoundHeader
			} else
				ColNum := "Col" A_Index
			LV_Modify(RowNum, ColNum, (IsObject(v) ? "Object()" : v))
		}
	}
	loop % LV_GetCount("Column")
		LV_ModifyCol(A_Index, "AutoHdr")
	Gui, %GuiNum%: Show,, Array
}
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
Cerberus
Posts: 172
Joined: 12 Jan 2016, 15:46

Re: SystemProcessInformation

22 Mar 2019, 09:58

Impressive. This will be quite useful.
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: SystemProcessInformation

11 Jan 2022, 21:33

@jNizM, Thank you for sharing the original post. Based on your function, I wrote the following to get the WorkingSetPrivateSize value from a process PID. It's the closest thing to the memory values shown in the Task Manager.

Code: Select all

#NoEnv

; Note: See https://stackoverflow.com/a/42986966/12364306 to understand the difference between WorkingSetPrivateSize
; and the value shown in Task Manager under the "Memory (active private working set)" column in the Details tab.

PID := DllCall("GetCurrentProcessId")
Loop {
   SizeInKB := GetWorkingSetPrivateSize(PID) // 1024
   ToolTip, % PID ": " SizeInKB " KB"
   Sleep, 250
}
Esc::ExitApp

GetWorkingSetPrivateSize(PID) {
   static SYSTEM_INFORMATION_CLASS := 0x5
   if (DllCall("Ntdll\NtQuerySystemInformation", "UInt", SYSTEM_INFORMATION_CLASS, "Ptr", 0, "UInt", 0, "UInt*", Size, "Int") != 0) {
      VarSetCapacity(SYSTEM_PROCESS_INFORMATION, Size), Offset := 0
      if (DllCall("Ntdll\NtQuerySystemInformation", "UInt", SYSTEM_INFORMATION_CLASS, "Ptr", &SYSTEM_PROCESS_INFORMATION, "UInt", Size, "UInt*", 0, "Int") = 0) {
         Loop {
            WorkingSetPrivateSize := NumGet(SYSTEM_PROCESS_INFORMATION, Offset + 8, "Int64")
            UniqueProcessId := NumGet(SYSTEM_PROCESS_INFORMATION, Offset + 56 + 3 * A_PtrSize, "Ptr")
            if (UniqueProcessId = PID)
               return WorkingSetPrivateSize
            NextEntryOffset := NumGet(SYSTEM_PROCESS_INFORMATION, Offset, "UInt")
            Offset += NextEntryOffset
         } Until !NextEntryOffset
      }
   }
}
I hope others find it useful.
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
chaoscreater
Posts: 60
Joined: 12 Sep 2019, 21:15

Re: SystemProcessInformation

15 Mar 2024, 10:08

iPhilip wrote:
11 Jan 2022, 21:33
@jNizM, Thank you for sharing the original post. Based on your function, I wrote the following to get the WorkingSetPrivateSize value from a process PID. It's the closest thing to the memory values shown in the Task Manager.

Code: Select all

#NoEnv

; Note: See https://stackoverflow.com/a/42986966/12364306 to understand the difference between WorkingSetPrivateSize
; and the value shown in Task Manager under the "Memory (active private working set)" column in the Details tab.

PID := DllCall("GetCurrentProcessId")
Loop {
   SizeInKB := GetWorkingSetPrivateSize(PID) // 1024
   ToolTip, % PID ": " SizeInKB " KB"
   Sleep, 250
}
Esc::ExitApp

GetWorkingSetPrivateSize(PID) {
   static SYSTEM_INFORMATION_CLASS := 0x5
   if (DllCall("Ntdll\NtQuerySystemInformation", "UInt", SYSTEM_INFORMATION_CLASS, "Ptr", 0, "UInt", 0, "UInt*", Size, "Int") != 0) {
      VarSetCapacity(SYSTEM_PROCESS_INFORMATION, Size), Offset := 0
      if (DllCall("Ntdll\NtQuerySystemInformation", "UInt", SYSTEM_INFORMATION_CLASS, "Ptr", &SYSTEM_PROCESS_INFORMATION, "UInt", Size, "UInt*", 0, "Int") = 0) {
         Loop {
            WorkingSetPrivateSize := NumGet(SYSTEM_PROCESS_INFORMATION, Offset + 8, "Int64")
            UniqueProcessId := NumGet(SYSTEM_PROCESS_INFORMATION, Offset + 56 + 3 * A_PtrSize, "Ptr")
            if (UniqueProcessId = PID)
               return WorkingSetPrivateSize
            NextEntryOffset := NumGet(SYSTEM_PROCESS_INFORMATION, Offset, "UInt")
            Offset += NextEntryOffset
         } Until !NextEntryOffset
      }
   }
}
I hope others find it useful.

Thank you so much for sharing this. I actually wanted something like this over a year ago and I asked for help and searched everywhere for a solution but couldn't figure it out. I still don't know much about getting this working with Windows API, I only just dabble a bit into coding but it's not my forte. Anyways, I wanted something that can show the total RAM usage as per Task Manager. Your script actually helps me achieve that.

Here's an example of my script. It basically checks a specific process (thorium.exe) to see if the RAM usage is > 5000MB and if yes, it'll show a tooltip popup. Since Thorium comprises of multiple child processes, I'm combining all of them together to form the total RAM usage. This actually very closely matches what's shown in Task Manager. Hopefully it helps someone:

Code: Select all

SetTimer, Check_Browser_RAM_Usage, 10000


Check_Browser_RAM_Usage:
{	
	TotalRam := ""
	
	for Process in ComObjGet("winmgmts:").ExecQuery("select * from Win32_Process where name = 'thorium.exe'")
	{
		TotalRam += GetWorkingSetPrivateSize(Process.ProcessId) // 1024 // 1024
	}
	
	
	if (TotalRam > 5000)
	{
	
		ToolTipColor("Red", "White")
		tooltipText := "Browser RAM usage is too damn high !!!" "`nTotal RAM: " TotalRam " MB"
		Tooltip(tooltipText, DummyXLocation, DummyYLocation, 13, true)

		RemoveToolTip_Module(3000,13)
		
	}
	
}
return



GetWorkingSetPrivateSize(PID) {
   static SYSTEM_INFORMATION_CLASS := 0x5
   if (DllCall("Ntdll\NtQuerySystemInformation", "UInt", SYSTEM_INFORMATION_CLASS, "Ptr", 0, "UInt", 0, "UInt*", Size, "Int") != 0) {
      VarSetCapacity(SYSTEM_PROCESS_INFORMATION, Size), Offset := 0
      if (DllCall("Ntdll\NtQuerySystemInformation", "UInt", SYSTEM_INFORMATION_CLASS, "Ptr", &SYSTEM_PROCESS_INFORMATION, "UInt", Size, "UInt*", 0, "Int") = 0) {
         Loop {
            WorkingSetPrivateSize := NumGet(SYSTEM_PROCESS_INFORMATION, Offset + 8, "Int64")
            UniqueProcessId := NumGet(SYSTEM_PROCESS_INFORMATION, Offset + 56 + 3 * A_PtrSize, "Ptr")
            if (UniqueProcessId = PID)
               return WorkingSetPrivateSize
            NextEntryOffset := NumGet(SYSTEM_PROCESS_INFORMATION, Offset, "UInt")
            Offset += NextEntryOffset
         } Until !NextEntryOffset
      }
   }
}


RemoveToolTip_Module(Period, WhichToolTip)
{
	if (Period = "timer")
	{
		ToolTip,,,, WhichToolTip
		;msgbox %WhichToolTip%
	}else{
		timer := Func(A_ThisFunc).Bind("timer", WhichToolTip)
		SetTimer, % timer, -%Period%
	}
}




Tooltip(tooltip_message, tooltip_X_location, tooltip_Y_location, tooltip_array_channel, tooltip_dummy_text_toggle)
{
	
	;CoordMode, ToolTip, Window
	CoordMode, ToolTip, Screen
	
	;msgbox % tooltip_X_location
	;msgbox % tooltip_Y_location
	
	if (tooltip_dummy_text_toggle = true)
	{
		;tooltip ".", %tooltip_dummy_dot_2nd_monitor_location_X%, %tooltip_dummy_dot_2nd_monitor_bottom_right_location_Y% ; this is a dummy tooltip to address the stupid bug
		tooltip ".", %tooltip_dummy_dot_2nd_monitor_location_X%, %tooltip_dummy_dot_2nd_monitor_bottom_right_location_Y%, %tooltip_array_channel% ; this is a dummy tooltip to address the stupid bug
		;sleep, 150
		
		;CoordMode, ToolTip, Window
	}
		

	if (tooltip_array_channel = "")
	{
		
		;msgbox "hi"
		
		tooltip %tooltip_message%, %tooltip_X_location%, %tooltip_Y_location%
		
	}else{
	
		;msgbox %tooltip_array_channel%
		
		tooltip %tooltip_message%, %tooltip_X_location%, %tooltip_Y_location%, %tooltip_array_channel%
		

	}
	
}	
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: SystemProcessInformation

15 Mar 2024, 11:03

:thumbup:
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 194 guests