Nikita B Nikita B - 3 months ago 75
C# Question

WinForms main window handle

In my winforms application I am trying to get a main window handle, so I can set it as parent to my wpf modal window. I am not too experienced with winforms, so after a bit of googling I found two ways to get it.


  1. System.Windows.Forms.Application.OpenForms[0].Handle

  2. System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle



(1) seems to always return the same value which appears to be correct (at least my modal window behaves as expected), while (2) sometimes returns the same value as (1), but sometimes - an entirely different pointer, which does not seem to work (my modal window appears on top of every other window, not just the parent window).

Can someone explain the difference between the two methods? Is it normal that sometimes they return different results?

Edit:

In case anyone else is wondering: once you get the handle, you can use by creating
WindowInteropHelper
class:

public static void SetWpfInteropParentHandle(Window window, IntPtr handle)
{
new WindowInteropHelper(window) { Owner = handle };
}

Answer

It is certainly not unusual for Process.MainWindowHandle to return the wrong handle. The Process class has to make a guess at which window is the "main" one. There is no mechanism in the native winapi to designate a window as such. So Process makes a guess that the first window is the main one. This has a knack for going wrong in apps that use a splash screen or a login dialog, etc, or create a window on another thread.

Application.OpenForms doesn't have this problem, but has a failure mode, it will lose track of a window when it is recreated. Which happens when the program changes certain properties of the Form that can only be specified when the window is created. The ShowInTaskbar, TransparencyKey and Opacity properties are the most common troublemakers.

The most reliable way is to override the OnHandleCreated() method of the form you want to be the parent. Which is called whenever the Handle property changes. Do note that you want to make sure that this doesn't happen while your WPF window is active, that will kill the WPF window as well. Otherwise easy to observe of course :)

    protected override void OnHandleCreated(EventArgs e) {
        base.OnHandleCreated(e);
        SetWpfInteropParentHandle(this.Handle);
    }