我已经读了很多有关如何从C#程序(Process.Start())内触发应用程序的信息,但是我还无法找到有关如何在C#程序的面板中运行此新应用程序的任何信息。 。例如,我想单击按钮以在我的应用程序内部而不是外部打开notepad.exe。
Answers:
我不知道这是否仍然是推荐使用的东西,但是“对象链接和嵌入”框架允许您将某些对象/控件直接嵌入到应用程序中。这可能仅适用于某些应用程序,我不确定记事本是否是其中之一。对于诸如记事本之类的非常简单的事情,您可能会更轻松地使用由您使用的任何媒体(例如WinForms)提供的文本框控件。
这是开始OLE信息的链接:
使用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应用程序
此代码帮助我将某些可执行文件停靠在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);
}
下面是另一个使用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到的步骤 消除了烦人的延迟。
我注意到所有以前的答案都使用较旧的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)上,所以我不知道它的最新程度。
如果您想在应用程序内部运行记事本,则最好使用文本编辑器组件。显然,WinForms附带了一个基本的文本框,但我怀疑可以在Internet上找到提供记事本功能(或更高级)的更高级的组件。
没有
不足的答案:仅当其他应用程序被设计为允许它时,通过提供组件供您添加到自己的应用程序中。