2

I'm ultimately looking for a way to set up an automated alert that will warn me if a process's GDI Object count is approaching the default 10,000 limit. I have a known issue with some software our company uses that causes explorer.exe to have the count build up until it crashes without warning - there's apparently a fix for this in a later version of the software, but we cannot upgrade for reasons beyond my control. My idea is to create a background program/script that will pop up an alert when it sees a GDI count approaching the 10,000 limit. However, the only ways I can seem to view the GDI count is through a GUI either in task manager or Process Explorer - if I could somehow just dump that to a text file automatically I'd be set, but I don't know if that's possible.

I've tried the GDIView software, but our company Antivirus flags it and that is outside my control.

I've downloaded sysinterals, but I can't figure out any way to get one of the command line tools to echo the GDI count I can get in Process Explorer. I've also tried tasklist, but similarly can't find a way to get GDI count out of it.

For reference, I'm on a Windows 10 machine here. I also have the linux subsystem enabled and have the ability to run Ubuntu through that. I am open to doing something in batch or python if that's of any use - though it seems powershell is blocked from running scripts (I might be able to get around that though).

1 Answers1

1

I found a small section of Powershell code that will give you the per process count by Rudolf at Getting GDI object count per process in Powershell

"Number of GUI handles per process"
$sig = @'
[DllImport("User32.dll")]
public static extern int GetGuiResources(IntPtr hProcess, int uiFlags);
'@

Add-Type -MemberDefinition $sig -name NativeMethods -namespace Win32

$processes = [System.Diagnostics.Process]::GetProcesses()
[int]$gdiHandleCount = 0
ForEach ($p in $processes)
{
    try{
        $gdiHandles = [Win32.NativeMethods]::GetGuiResources($p.Handle, 0)
        $gdiHandleCount += $gdiHandles
        $p.Name + " : " + $gdiHandles.ToString()   
    }
    catch {
        #"Error accessing " + $p.Name
    }
}
"Total number of GDI handles " + $gdiHandleCount.ToString()

It should be possible to modify the commands within the try ... Catch statement to add an if statement that matches your explorer name and posts a message box.

Mokubai
  • 89,133
  • 25
  • 207
  • 233
  • Unless you do fix this in the mean time I will look into modifying the code to more precisely answer the question when I have access to a full computer. – Mokubai Mar 23 '20 at 14:22
  • Thanks I'll give that a shot and comment back if it's worked for me. – Ian McKenzie Mar 24 '20 at 12:49
  • Yep that's done what I needed - I'm going to periodically run this script in the background and alert if $gdiHandles is ever over 9000. I did find [here](https://stackoverflow.com/questions/4037939/powershell-says-execution-of-scripts-is-disabled-on-this-system) though that I need to call this script from cmd like this in order to bypass execution policies: powershell -ExecutionPolicy ByPass -File GDIStuff.ps1 – Ian McKenzie Mar 24 '20 at 13:01
  • Just a note: `[System.Diagnostics.Process]::GetProcesses()` returns the same objects as the `Get-Process` cmdlet, so the later can be used, e.g. via the pipeline, to query the handles of just a subset of processes we're interested in. Adding a NoteProperty to the Process objects could be handy. – efotinis Sep 21 '22 at 09:00