Server Resources Overloaded by C# Script

49 Views Asked by At

I have a program that runs on a Terminal server. The server has roughly 40 thin clients.

The program's core function locks the desktop icons in a specified layout, and if they are moved, they will "snap" back into place.

The issue is within the infinite loop that constantly moves the icons back in place. I currently have the loop end each cycle with a

Thread.Sleep(100);

When I change the sleep to

Thread.Sleep(10000);

Then the CPU usage dramatically decreases. (the contents within the loop eats the resources)

What I need is to optimize this loop so that when the loop runs, it uses less CPU resources.

Please let me know if you need any other information.

Edit: The script is deployed as a .exe that runs on user login. The user is blocked from ending the service.

Here is the loop:

    while (true)
        {
            try
            {
                // Refresh desktop handle in case explorer instance changed. 
                DesktopHandle = FindWindow("Progman", null);
                if (DesktopHandle == IntPtr.Zero)
                {
                    continue;
                }
                DesktopHandle = FindWindowEx(DesktopHandle, IntPtr.Zero, "SHELLDLL_DefView", null);
                if (DesktopHandle == IntPtr.Zero)
                {
                    continue;
                }
                DesktopHandle = FindWindowEx(DesktopHandle, IntPtr.Zero, "SysListView32", null);
                if (DesktopHandle == IntPtr.Zero)
                {
                    continue;
                }

                // Get the collection of list items in the SysListView32 control woooo scaryyyyy.
                AutomationElement sysListView = AutomationElement.FromHandle(DesktopHandle);
                AutomationElementCollection listItems = sysListView.FindAll(
                    TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem));

                // Clear the Ico2Idx dictionary and rebuild it to reflect the current state
                Ico2Idx.Clear();
                for (int i = 0; i < listItems.Count; i++)
                {
                    Ico2Idx.Add(listItems[i].Current.Name, i);
                }

                foreach (string Icon in Icons)
                {
                    // Check if the icon exists on the desktop before trying to move it.
                    if (Ico2Idx.ContainsKey(Icon))
                    {
                        // Move icon by name
                        if (ListView_SetItemPosition(DesktopHandle, Ico2Idx[Icon], Ico2Coord[Icon].X, Ico2Coord[Icon].Y) != null)
                        {
                            // Console.WriteLine(String.Format("Icon \"{0}\" should be set now!", Icon));
                        }
                        // *May* need to slow here, test and see.
                    }
                }
                Thread.Sleep(10000);

            }
            catch (Exception ex)
            {
                // Log the exception and continue with the loop.
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
        }
1

There are 1 best solutions below

0
Stammenator On

Pulled the Ico2Coord.Add and Icons.Add out of the loop, increased thread sleep time to 5 minutes. There will be much variation in when Thin Client Remote Server Session user accounts login, so the .exe will re-update the icon positions at "random" intervals, once every 5 minutes. CPU usage has dropped significantly with these two changes

Here is the updated code:

//this code is now outside the main loop
   foreach (var (iconName, x, y) in iconData)
        {
            Icons.Add(iconName);
            Ico2Coord.Add(iconName, new Point(x, y));
        }
//start of main loop
        while (true)
        {
            try
            {
                DateTime now = DateTime.Now;
                if ((now - LastRefreshTime).TotalSeconds > 60)  // Refresh every 60 seconds
                {
                    DesktopHandle = FindWindow("Progman", null);
                    if (DesktopHandle != IntPtr.Zero)
                    {
                        DesktopHandle = FindWindowEx(DesktopHandle, IntPtr.Zero, "SHELLDLL_DefView", null);
                    }
                    if (DesktopHandle != IntPtr.Zero)
                    {
                        DesktopHandle = FindWindowEx(DesktopHandle, IntPtr.Zero, "SysListView32", null);
                    }

                    if (DesktopHandle == IntPtr.Zero)
                    {
                        Thread.Sleep(5000);  // Wait for 5 seconds before trying again
                        continue;
                    }

                    PreviousDesktopHandle = DesktopHandle;
                    LastRefreshTime = now;
                }
                else
                {
                    DesktopHandle = PreviousDesktopHandle;  // Use the previously found handle
                }

                // Get the collection of list items in the SysListView32 control woooo scaryyyyy.
                AutomationElement sysListView = AutomationElement.FromHandle(DesktopHandle);
                AutomationElementCollection listItems = sysListView.FindAll(
                    TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem));

                // Refresh the Ico2Idx dictionary only if the number of list items has changed
                if (Ico2Idx.Count != listItems.Count)
                {
                    Ico2Idx.Clear();
                    for (int i = 0; i < listItems.Count; i++)
                    {
                        Ico2Idx.Add(listItems[i].Current.Name, i);
                    }
                }

                foreach (string Icon in Icons)
                {
                    // Check if the icon exists on the desktop before trying to move it.
                    if (Ico2Idx.ContainsKey(Icon))
                    {
                        // Move icon by name
                        if (ListView_SetItemPosition(DesktopHandle, Ico2Idx[Icon], Ico2Coord[Icon].X, Ico2Coord[Icon].Y) != null)
                        {
                            // Console.WriteLine(String.Format("Icon \"{0}\" should be set now!", Icon));
                        }
                    }
                }
                Thread.Sleep(300000);  // Lower sleep time for responsiveness, change as needed
            }
            catch (Exception ex)
            {
                // Log the exception and continue with the loop.
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
        }
    }