Search code examples
c#wpf

Wanting to fetch process ID to set non controlled applications to front in windows


A customer wants an overlay program that's always on top and that has 2 buttons that opens their programs.

If one of their programs is already open then my program should set their program on top of everything else (i.e switch to it and not open a new instance).

Essentially I find a process by the processname, then try to set it on top using the process, but it doesn't work for everything. For things like Notepad++ it works fine, but other programs that have have subprocesses it doesn't work, most likely because the main program starts child processes that I don't have access to?

I got the following code to find a process by processname, and send it on top in windows.

        static Process FindProcess(string ProcessName)
        {
            Process[] targetProcesses = Process.GetProcessesByName(ProcessName);
            Process targetProgram = null;
            if(targetProcesses.Count() > 0)
            {
                targetProgram = targetProcesses[0];
            }
            return targetProgram;
        }

Then in a later section I take the process, and try to put it on top using this code:

        static void SendWindowToFront(Process SProcess)
        {
            try
            {
                AutomationElement aelement = AutomationElement.FromHandle(SProcess.MainWindowHandle);
                if (aelement != null)
                {
                    ShowWindow(SProcess.MainWindowHandle, SW_SHOWWINDOWED);
                    aelement.SetFocus();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("SendWindowToFront error: " + ex.Message);
            }
        }

But as I said, it doesn't work for all programs.

enter image description here

For example, the above program have processname "QuickDesign" (excuse the Swedish), but I can't use my code to switch to it, most likely because it creates a subprocess when starting that I don't have access to?

What I want to do with my program is essentially just the "Place above". It's not specifically for that program in the picture, that's just an example I have to work.

I tried this code to find childprocesses, but it only returns an empty list:

   public static class ProcessExtensions
   {
        public static IList<Process> GetChildProcesses(this Process process)
=> new ManagementObjectSearcher(
$"Select * From Win32_Process Where ParentProcessID={process.Id}")
.Get()
.Cast<ManagementObject>()
.Select(mo =>
Process.GetProcessById(Convert.ToInt32(mo["ProcessID"])))
.ToList();
    }

Is this something that can be solved?


Solution

  • So I found an alternate way for this problem by following this guide:

    http://weimenglee.blogspot.com/2007/01/programmatically-switch-to-another.html

    Using the following code:

        [DllImport("user32.dll")]
        private static extern bool
        SetForegroundWindow(IntPtr hWnd);
        [DllImport("user32.dll")]
        private static extern bool ShowWindowAsync(
        IntPtr hWnd, int nCmdShow);
        private const int SW_RESTORE = 9;
        private void SwitchToProgram(string programName)
        {
            Process[] procs = Process.GetProcesses();
            if (procs.Length != 0)
            {
                for (int i = 0; i < procs.Length; i++)
                {
                    try
                    {
                        if (procs[i].MainModule.ModuleName ==
                            programName)
                        {
                            IntPtr hwnd =
                                procs[i].MainWindowHandle;
                            ShowWindowAsync(hwnd, SW_RESTORE);
                            SetForegroundWindow(hwnd);
                            return;
                        }
                    }
                    catch(Exception e)
                    {
                        Console.WriteLine("ERROR SwitchToProgram in loop: " + e.Message);
                    }
                }
            }
            else
            {
                Console.WriteLine("ERROR SwitchToProgram: No processes running.");
                return;
            }
            Console.WriteLine("ERROR SwitchToProgram: " + programName + " isn't running.");
        }
    

    I can just give a pathname like "programname.start" to the function and it will send it to the front if it finds it.

    It works perfect on the customer computer, while slow at my own. But that's because my work computer has a bunch of restrictions that slows down everything a bit.