Как я могу запустить другое приложение на панели моей программы на C #? - PullRequest
66 голосов
/ 17 апреля 2009

Я много читал о том, как вызвать приложение из программы на C # (Process.Start ()), но я не смог найти никакой информации о том, как запустить это новое приложение на панели моя программа на C # Например, я хочу, чтобы щелкнул кнопкой мыши, чтобы открыть notepad.exe В МОЕМ приложении, а не снаружи.

Ответы [ 8 ]

97 голосов
/ 17 апреля 2009

Используя win32 API, можно «съесть» другое приложение. По сути, вы получаете верхнее окно для этого приложения и задаете его родительский дескриптор панели, в которую хотите поместить его. Если вам не нужен эффект стиля MDI, вам также нужно настроить стиль окна, чтобы сделать его максимально развернутым и удалить строку заголовка.

Вот простой пример кода, где у меня есть форма с кнопкой и панелью:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Process p = Process.Start("notepad.exe");
            Thread.Sleep(500); // Allow the process to open it's window
            SetParent(p.MainWindowHandle, panel1.Handle);
        }

        [DllImport("user32.dll")]
        static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
    }
}

Я только что видел другой пример, где они вызывали WaitForInputIdle вместо сна. Так что код будет выглядеть так:

Process p = Process.Start("notepad.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, panel1.Handle);

В Code Project есть хорошая статья, посвященная всему процессу: Размещение приложений EXE в проекте WinForm

14 голосов
/ 17 апреля 2009

Я не знаю, рекомендуется ли это использовать, но инфраструктура «Связывание и внедрение объектов» позволяет вам встраивать определенные объекты / элементы управления непосредственно в ваше приложение. Это, вероятно, будет работать только для определенных приложений, я не уверен, является ли Блокнот одним из них. Для действительно простых вещей, таких как блокнот, вам, вероятно, будет проще работать с элементами управления текстовым полем, предоставляемыми любым используемым средством (например, WinForms).

Вот ссылка на информацию OLE, чтобы начать:

http://en.wikipedia.org/wiki/Object_Linking_and_Embedding

4 голосов
/ 28 июня 2013
  • Добавление решения в ответе. **

Этот код помог мне закрепить исполняемый файл в форме Windows. например, NotePad, Excel, Word, Acrobat Reader и многие другие ...

Но это не будет работать для некоторых приложений. Как иногда, когда вы запускаете процесс какого-то приложения .... ждите простоя ... и попробуйте получить его mainWindowHandle .... до тех пор, пока дескриптор главного окна не станет нулевым .....

поэтому я сделал один трюк, чтобы решить это

Если вы получаете дескриптор главного окна как ноль ..., тогда ищите все запущенные процессы в sytem и находите ваш процесс ... затем получите главный хэдл процесса и панель set в качестве его родителя.

        ProcessStartInfo info = new ProcessStartInfo();
        info.FileName = "xxxxxxxxxxxx.exe";
        info.Arguments = "yyyyyyyyyy";
        info.UseShellExecute = true;
        info.CreateNoWindow = true;
        info.WindowStyle = ProcessWindowStyle.Maximized;
        info.RedirectStandardInput = false;
        info.RedirectStandardOutput = false;
        info.RedirectStandardError = false;

        System.Diagnostics.Process p = System.Diagnostics.Process.Start(info); 

        p.WaitForInputIdle();
        Thread.Sleep(3000);

        Process[] p1 ;
    if(p.MainWindowHandle == null)
    {
        List<String> arrString = new List<String>();
        foreach (Process p1 in Process.GetProcesses())
        {
            // Console.WriteLine(p1.MainWindowHandle);
            arrString.Add(Convert.ToString(p1.ProcessName));
        }
        p1 = Process.GetProcessesByName("xxxxxxxxxxxx");
        //p.WaitForInputIdle();
        Thread.Sleep(5000);
      SetParent(p1[0].MainWindowHandle, this.panel2.Handle);

    }
    else
    {
     SetParent(p.MainWindowHandle, this.panel2.Handle);
     }
3 голосов
/ 29 июня 2017

Другое интересное решение для внешнего приложения с контейнером WinForm:

[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);


private void Form1_Load(object sender, EventArgs e)
{
    ProcessStartInfo psi = new ProcessStartInfo("notepad.exe");
    psi.WindowStyle = ProcessWindowStyle.Minimized;
    Process p = Process.Start(psi);
    Thread.Sleep(500);
    SetParent(p.MainWindowHandle, panel1.Handle);
    CenterToScreen();
    psi.WindowStyle = ProcessWindowStyle.Normal;
}

Шаг к ProcessWindowStyle.Minimized из ProcessWindowStyle.Normal удалить раздражающую задержку.

enter image description here

1 голос
/ 17 декабря 2015

Я заметил, что все предыдущие ответы используют более старые функции библиотеки пользователя Win32 для достижения этой цели. Я думаю, что это будет работать в большинстве случаев, но со временем будет работать менее надежно.

Теперь, не сделав этого, я не могу сказать вам, насколько хорошо это будет работать, но я знаю, что текущая технология Windows могла бы быть лучшим решением: Desktop Windows Manager API .

DWM - это та же технология, которая позволяет просматривать в реальном времени эскизы приложений с помощью панели задач и интерфейса переключателя задач. Я считаю, что это тесно связано со службами удаленного терминала.

Я думаю, что вероятная проблема, которая может возникнуть, когда вы заставляете приложение быть дочерним по отношению к родительскому окну, не являющемуся окном рабочего стола, состоит в том, что некоторые разработчики приложений делают предположения относительно контекста устройства (DC), указателя (мыши) ) положение, ширину экрана и т. д., что может привести к ошибочному или проблематичному поведению, когда оно «встроено» в главное окно.

Я подозреваю, что вы можете в значительной степени устранить эти проблемы, полагаясь на DWM, который поможет вам управлять переводами, необходимыми для надежного представления окон приложения и взаимодействия с ними внутри окна контейнера другого приложения.

Документация предполагает программирование на C ++, но я нашел одного человека, который создал то, что, как он утверждает, является библиотекой оболочки C # с открытым исходным кодом: https://bytes.com/topic/c-sharp/answers/823547-desktop-window-manager-wrapper. Пост старый, а исходный код находится не в большом репозитории, таком как GitHub. , bitbucket или sourceforge, так что я не знаю, насколько это актуально.

1 голос
/ 17 апреля 2009

Я знаю, что это возможно, если другое приложение может присоединиться к дескриптору окна win32. Например, у нас есть отдельное приложение C #, которое размещает приложение DirectX в одном из своих окон. Я не знаком с точными деталями того, как это реализовано, но я думаю, что достаточно просто передать win32 Handle вашей панели другому приложению, чтобы приложение прикрепило свою поверхность DirectX.

1 голос
/ 17 апреля 2009

Если вы хотите запустить блокнот внутри своего приложения, вам, вероятно, лучше использовать компонент текстового редактора. Очевидно, что есть базовое текстовое поле, которое поставляется с WinForms, но я подозреваю, что более сложные компоненты, которые предлагают функциональность Notepad (или лучше), можно найти на веб-сайте.

0 голосов
/ 17 апреля 2009
Короткий ответ: нет

Нет

Короткий ответ:

Только если другое приложение предназначено для этого, предоставляя компоненты для добавления в собственное приложение.

...