C# Process.MainWindowHandle always returns IntPtr Zero

29,428

Solution 1

The main window is the window opened by the process that currently has the focus (the TopLevel form). You must use the Refresh method to refresh the Process object to get the current main window handle if it has changed.

You can get the MainWindowHandle property only for processes that are running on the local computer. The MainWindowHandle property is a value that uniquely identifies the window that is associated with the process.

A process has a main window associated with it only if the process has a graphical interface. If the associated process does not have a main window, the MainWindowHandle value is zero. The value is also zero for processes that have been hidden, that is, processes that are not visible in the taskbar. This can be the case for processes that appear as icons in the notification area, at the far right of the taskbar.

If you have just started a process and want to use its main window handle, consider using the WaitForInputIdle method to allow the process to finish starting, ensuring that the main window handle has been created. Otherwise, an exception will be thrown.

Solution 2

A workaround is to enumerate through all top-level windows and examine their process ids until you find a match...


    [DllImport("user32.dll")]
    public static extern IntPtr FindWindowEx(IntPtr parentWindow, IntPtr previousChildWindow, string windowClass, string windowTitle);

    [DllImport("user32.dll")]
    private static extern IntPtr GetWindowThreadProcessId(IntPtr window, out int process);

    private IntPtr[] GetProcessWindows(int process) {
        IntPtr[] apRet = (new IntPtr[256]);
        int iCount = 0;
        IntPtr pLast = IntPtr.Zero;
        do {
            pLast = FindWindowEx(IntPtr.Zero, pLast, null, null);
            int iProcess_;
            GetWindowThreadProcessId(pLast, out iProcess_);
            if(iProcess_ == process) apRet[iCount++] = pLast;
        } while(pLast != IntPtr.Zero);
        System.Array.Resize(ref apRet, iCount);
        return apRet;
    }

Solution 3

while (!proc.HasExited)
{
    proc.Refresh();
    if (proc.MainWindowHandle.ToInt32() != 0)
    {
        return proc.MainWindowHandle;
    }
}
Share:
29,428
Kfir Eichenblat
Author by

Kfir Eichenblat

Updated on August 06, 2020

Comments

  • Kfir Eichenblat
    Kfir Eichenblat over 3 years

    this is my code:

                using (Process game = Process.Start(new ProcessStartInfo() { 
            FileName="DatabaseCheck.exe",
            RedirectStandardOutput = true,
            CreateNoWindow = true,
            UseShellExecute = false }))
            {
                lblLoad.Text = "Loading";
                int Switch = 0;
    
                while (game.MainWindowHandle == IntPtr.Zero)
                {
                    Switch++;
                    if (Switch % 1000 == 0)
                    {
                        lblLoad.Text += ".";
                        if (lblLoad.Text.Contains("...."))
                            lblLoad.Text = "Loading.";
    
                        lblLoad.Update();
                        game.Refresh();
                    }
                }
    

    Problem is, that game.MainWindowHandle is always IntPtr.Zero. I need to find the IntPtr of the ran process to confirm that the game was started by the launcher, so I made the game send it's IntPtr and let the launcher respond if it's okay. But for that, I must know the IntPtr of the ran process specifically.

    Thanks in advance!

  • Kfir Eichenblat
    Kfir Eichenblat almost 11 years
    Will try that when I'm home. Thanks
  • Ben
    Ben over 10 years
    Hi, your post has been flagged as "low quality", probably because it consists solely of code. You could massively improve your answer by providing an explanation of exactly how and why this answers the question?
  • Basic
    Basic about 10 years
    Note that on 4.5 this is no longer required (anecdotal - my code worked on 4.5 and failed when I dropped down to 3.5 until I added .Refresh())
  • dkrprasetya
    dkrprasetya almost 6 years
    Just want to mention, for looking up other process' window, this workaround works very well on Unity (while using Refresh + MainWindowHandle always gave me zero pointer)
  • David Bentley
    David Bentley almost 6 years
    For anyone reading this old post...I recall reading someplace that using something similar to this was not a good idea due to x64 vs x86. It might be better to use IntPtr.Zero != proc.MainWindowHandle instead.