如何在C#程序的面板中运行另一个应用程序?


75

我已经读了很多有关如何从C#程序(Process.Start())内触发应用程序的信息,但是我还无法找到有关如何在C#程序的面板中运行此新应用程序的任何信息。 。例如,我想单击按钮以在我的应用程序内部而不是外部打开notepad.exe。

Answers:


17

我不知道这是否仍然是推荐使用的东西,但是“对象链接和嵌入”框架允许您将某些对象/控件直接嵌入到应用程序中。这可能仅适用于某些应用程序,我不确定记事本是否是其中之一。对于诸如记事本之类的非常简单的事情,您可能会更轻松地使用由您使用的任何媒体(例如WinForms)提供的文本框控件。

这是开始OLE信息的链接:

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


106

使用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);

代码项目在整个过程中有一篇不错的文章:在WinForm项目中托管EXE应用程序


17
超级有帮助!链接未显示其功能的dll导入,因此我认为id在此处共享它们。[DllImport(“ user32.dll”)] [DllImport(“ user32.dll”)]静态外部int SetWindowLong(IntPtr hWnd,int nIndex,int dwNewLong); [DllImport(“ user32.dll”)]静态外部布尔MoveWindow(IntPtr句柄,整数x,整数y,整数w,整数h,布尔重画);
hrh 2012年

当我将其与IE或Chrome一起使用时,浏览器的顶部显示为黑色。有没有一种方法可以将其更改为透明,以便显示主窗口的颜色?
2015年

所引用的文章/代码平面对我不起作用(也许因为我正在使用WPF?)。必须使用此:stackoverflow.com/questions/5836176/…。另外,对于pinvoke导入,pinvoke.net总是有用的。
dudeNumber4 '16

1
是的,经验丰富的Windows程序员使用WaitForInputIdle。Windows程序员应始终对使用睡眠的代码进行两次或多次检查。
user34660

如果要最大化窗口:[DllImport(“ user32.dll”)]私有静态外部布尔ShowWindowAsync(IntPtr hWnd,int nCmdShow); social.msdn.microsoft.com/Forums/vstudio/en-US/…–
camino

6
  • 在Answer .. **中添加一些解决方案

此代码帮助我将某些可执行文件停靠在Windows窗体中。像NotePad,Excel,Word,Acrobat Reader等。

但是它不适用于某些应用程序。有时,当您启动某个应用程序的处理时……等待空闲时间……并尝试获取其mainWindowHandle……直到主窗口句柄变为空时……

所以我做了一个技巧来解决这个问题

如果您将主窗口句柄设置为null ...,然后在系统上搜索所有正在运行的进程,然后找到您的进程...,然后获取该进程的主框架和将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);
     }

6

下面是另一个使用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到的步骤 消除了烦人的延迟。

在此处输入图片说明


不要睡觉等待在实时平台上没有在预期的预期时间内执行的事件
Lodewijk

2

我注意到所有以前的答案都使用较旧的Win32用户库函数来完成此操作。我认为这在大多数情况下都会有效,但随着时间的推移,可靠性会降低。

现在,我没有告诉您它的运行效果如何,但是我知道当前的Windows技术可能是更好的解决方案:Desktop Windows Manager API

DWM是一项使您可以使用任务栏和任务切换器UI实时查看应用程序缩略图的技术。我相信它与远程终端服务密切相关。

我认为,当您将某个应用强制为非桌面窗口的父窗口的子窗口时,可能会出现一些问题,即某些应用程序开发人员将对设备上下文(DC),指针(鼠标)的位置,屏幕宽度等,将其“嵌入”在主窗口中时可能会导致不稳定或有问题的行为。

我怀疑您可以依靠DWM来帮助您管理必要的翻译,以可靠地显示应用程序的窗口并与另一个应用程序的容器窗口进行交互,从而在很大程度上消除这些问题。

该文档假设使用C ++编程,但是我发现一个产生他声称是开源C#包装器库的人:https : //bytes.com/topic/c-sharp/answers/823547-desktop-window-manager-wrapper。该帖子很旧,并且源代码不在大型存储库(如GitHub,bitbucket或sourceforge)上,所以我不知道它的最新程度。


1

如果您想在应用程序内部运行记事本,则最好使用文本编辑器组件。显然,WinForms附带了一个基本的文本框,但我怀疑可以在Internet上找到提供记事本功能(或更高级)的更高级的组件。


记事本只是用于测试目的的示例!
Fernando Vieira

1

我知道如果其他应用程序可以将自身附加到Win32窗口句柄,则这是可能的。例如,我们有一个单独的C#应用​​程序,在其中一个窗口中托管DirectX应用程序。我不知道具体如何实现的详细信息,但是我认为仅将Handle面板的win32传递给另一个应用程序就足以使该应用程序附加其DirectX表面。


-1
简短答案:

没有

不足的答案:

仅当其他应用程序被设计为允许它时,通过提供组件供您添加到自己的应用程序中。


3
@PaulSonier-即使简短答案完全错误?;-)简短的答案是肯定的
克里斯·罗杰斯

在现实世界中,我们经常不得不适应一些并非为此而造的东西。
ViniciusGonçalves18年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.