Ответы с форумов MSDN

WINAPI - Использование фунции SetParent с окном другого приложения

Date: 17.08.2019 16:15:33

Функция SetParent работает и с окнами других процессов, поэтому привязать окно другого приложения к своему, в принципе, возможно (исключение - если процессы находятся в разных режимах DPI Awareness, в этом случае один из них упадет). Основная сложность - определить дескриптор окна, которое нужно привязывать и дождаться момента его загрузки, ведь приложение может иметь несколько разных окон, которые загружаются не сразу. Вот пример, который вроде работает в большинстве простых случаев:

XAML

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        Title="My desktop" Height="350" Width="620.522" Closed="Window_Closed_1">
    <Grid  >
        <ListBox x:Name="listbox" HorizontalAlignment="Left"  Margin="30,55,0,9.8" VerticalAlignment="Stretch" 
                 Width="220" DisplayMemberPath="ProcessName" MouseDoubleClick="listbox_MouseDoubleClick"/>
        <TextBox x:Name="tbCommand" HorizontalAlignment="Left" Height="23" Margin="30,10,0,0" TextWrapping="Wrap" 
                 Text="notepad" VerticalAlignment="Top" Width="220"/>
        <Button x:Name="bBrowse" Content="Обзор" HorizontalAlignment="Left" Height="23" Margin="266,10,0,0" 
                VerticalAlignment="Top" Width="73" Click="bBrowse_Click" />
        <Button x:Name="bRun" Content="Выполнить" HorizontalAlignment="Left" Height="23" Margin="367,10,0,0" 
                VerticalAlignment="Top" Width="73" Click="bRun_Click"/>

    </Grid>
</Window>

C#

using System;
using System.Collections.ObjectModel;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Windows;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Interop;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        [DllImport("user32.dll")]
        public static extern int SetParent(IntPtr hWnd, IntPtr NewParent);

        [DllImport("user32.dll")]
        static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool IsWindowVisible(IntPtr hWnd);

        const int SW_SHOW = 5;
        const int SW_HIDE = 0;

        ObservableCollection<Process> applist = new ObservableCollection<Process>();       
        
        public MainWindow()
        {
            InitializeComponent();
            listbox.ItemsSource = applist;            
        }

        bool WaitMainWindow(Process pr)
        {
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                try
                {
                    if (pr.MainWindowHandle != IntPtr.Zero)
                    {
                        return true;
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.ToString());
                }
            }
            return false;
        }

        private async void bRun_Click(object sender, RoutedEventArgs e)
        {
            WindowInteropHelper h = new WindowInteropHelper(this); //получаем дескриптор этого окна
            Process pr = Process.Start(tbCommand.Text);//запускаем процесс
            if (pr == null)
            {
                MessageBox.Show("Не удалось запустить процесс");
                return;
            }
                        
            //ожидаем запуска цикла обработки сообщений...
            try
            {
                pr.WaitForInputIdle();
            }
            catch (InvalidOperationException ex)
            {
                Debug.WriteLine(ex.ToString());
            }

            if (pr.MainWindowHandle != IntPtr.Zero)
            {                
                //если главное окно уже доступно, связываем с нашим окном
                SetParent(pr.MainWindowHandle, h.Handle);
                applist.Add(pr);
            }
            else
            {
                //ожидаем загрузки главного окна...
                bool res = false;
                await Task.Run(() =>
                {
                    res = WaitMainWindow(pr);
                });

                if (res)
                {
                    SetParent(pr.MainWindowHandle, h.Handle);
                    applist.Add(pr);
                }
            }
        }

        private void listbox_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Process pr = listbox.SelectedItem as Process;
            if (pr == null) return;

            //показываем или скрываем окно
            if (IsWindowVisible(pr.MainWindowHandle)) ShowWindow(pr.MainWindowHandle, SW_HIDE);
            else ShowWindow(pr.MainWindowHandle, SW_SHOW);
        }

        private void bBrowse_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new Microsoft.Win32.OpenFileDialog();
            bool? res = dialog.ShowDialog(this);
            if (res.HasValue)
            {
                if (res.Value)
                {
                    tbCommand.Text = dialog.FileName;
                }
            }
        }

        private void Window_Closed_1(object sender, EventArgs e)
        {
            //при закрытии окна закрываем все связанные окна
            foreach (Process pr in applist)
            {
                try
                {
                    if (!pr.HasExited)
                    {
                        pr.CloseMainWindow();
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.ToString());
                }
            }
        }             
    }  
}







Автор: VadimTagil

Главная страница - Список тем - Репозиторий на GitHub