Skip to content

Instantly share code, notes, and snippets.

@gekka
Created December 21, 2023 10:05
Show Gist options
  • Save gekka/3a2e17a44420f829341376607fabfb96 to your computer and use it in GitHub Desktop.
Save gekka/3a2e17a44420f829341376607fabfb96 to your computer and use it in GitHub Desktop.

Wouldn't the behavior you want be achieved by setting the Owner property instead of setting the Topmost property for sub-window?

public partial class MainWindow : Window
{
    public MainWindow()
    {
        //InitializeComponent();
        this.Title = "MainWindow";
        this.Width = 400;
        this.Height = 400;
        this.Background = Brushes.LimeGreen;
        this.ShowInTaskbar = true;
            
        this.Loaded += MainWindow_Loaded;
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        Window subWindow = new Window();
        subWindow.Title = "SubWindow";
        subWindow.Width =300;
        subWindow.Height = 100;
        subWindow.Background = Brushes.Yellow;
        subWindow.ShowInTaskbar = false;
        //subWindow.Topmost = true; // not set Topmost
        subWindow.Owner = this; // set owner

        subWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
        subWindow.Show();
    }
}

Sample 2

For external processes, etc., the Owner must be changed using SetWindowLongPtr (Windows API).

using System;
using System.Windows;

public partial class App : Application
{
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern bool IsWindow(IntPtr hwnd);

    [System.Runtime.InteropServices.DllImport("User32.dll")]
    private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, GWL nIndex, IntPtr dwNewLong);

    enum GWL : int
    {
        GWL_HWNDPARENT = -8,
    }

    [System.Runtime.InteropServices.DllImport("User32.dll")]
    private static extern int SetParent(IntPtr hwndParent, IntPtr hwndChild);

    protected override void OnStartup(StartupEventArgs e)
    {
        System.Diagnostics.Debugger.Launch();
        System.Diagnostics.Debugger.Break();

        IntPtr hwndOnwer = IntPtr.Zero; ;

        if (e.Args.Length > 0)
        {   // receive Owner Window Handle
            if (long.TryParse(e.Args[0], System.Globalization.NumberStyles.HexNumber, null, out long number) && number > 0)
            {
                hwndOnwer = new IntPtr(number);
                if (!IsWindow(hwndOnwer))
                {
                    hwndOnwer = IntPtr.Zero;
                }
            }
        }

        var wnd = new Window();       //remove StartupUri from app.xaml

        if (hwndOnwer == IntPtr.Zero)
        {
            wnd.Title = "MainWindow";
            wnd.Width = 400;
            wnd.Height = 300;
            wnd.Background = System.Windows.Media.Brushes.LimeGreen;
            wnd.Loaded += (sender2, e2) =>
            {
                IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(wnd).Handle;

                var path = System.Environment.ProcessPath;
                System.Diagnostics.Process.Start(path, hwnd.ToString("X"));
            };
        }
        else
        {
            wnd.Title = "SubWindow";
            wnd.Width = 300;
            wnd.Height = 200;
            wnd.Background = System.Windows.Media.Brushes.Yellow;
            wnd.ShowInTaskbar = false;

            wnd.Loaded += (sender2, e2) =>
            {
                //Set Owner Window insted of Window.Owner property

                IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(wnd).Handle;
                SetWindowLongPtr(hwnd, GWL.GWL_HWNDPARENT, hwndOnwer);
            };
        }
        wnd.Show();
    }

}

[2023-12-21T18:30Z+9:00] Add sample 2

Added a sample of setting the owner from an external process window.

@Sana-Alshboul
Copy link

Sana-Alshboul commented Dec 21, 2023

Thank you so much for the answer.

Can you please help me how to implement the following:
When I create the external window i use the following code to clone a process for the external window. The process send 3 arguments (mmfName , semaphoreNameOut , and semaphoreNameIn ).

        string mmfName = "AO_MMF_" + groupData.id;
        string semaphoreNameOut = "AO_semOut_" + groupData.id;
        string semaphoreNameIn = "AO_semIn_" + groupData.id;
        //up to 7000 Bytes for each direction - up to three integers per channel * 512 + overhead for extra data.
        //the largest size is used for transfering the group settings
        MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen(mmfName, Constants.SharedMemoryTotalSize);
        Semaphore semOut = new Semaphore(0, Constants.MaxMessageCount, semaphoreNameOut); //For messages leaving the main UI
        Semaphore semIn = new Semaphore(0, Constants.MaxMessageCount, semaphoreNameIn); //For messages entering the main UI
        //Application argments
        string args = this+ mmfName + " "
                    + semaphoreNameOut + " "
                    + semaphoreNameIn + " ";
        //Filter Creation
        //create new process
        Process pipeClient = new Process();
        pipeClient.StartInfo.FileName = @"ExternalGroup.exe";
        pipeClient.StartInfo.Arguments = args;
        pipeClient.StartInfo.UseShellExecute = true;
        pipeClient.Start();

So the argument type that is sent by the process is string. How can I send the the main window as a parent to be read in this line of code as what you did:
if (long.TryParse(e.Args[0], System.Globalization.NumberStyles.HexNumber, null, out long number) && number > 0)

when arguments are received by the external window I read them as an array of strings as follows:
public ExternBuilder(string[] args)
{
if(args.length>=3)
{
//load main parameters through app arguments
string MMFName = args[0];
string SemaphoreNameIn = args[1];
string SemaphoreNameOut = args[2];
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment