如何在我的 C# 程序面板中运行另一个应用程序?
题
我已经阅读了大量有关如何从 C# 程序 (Process.Start()) 内部触发应用程序的文章,但我无法找到有关如何在 C# 程序的面板中运行此新应用程序的任何信息。例如,我希望单击按钮在我的应用程序内(而不是外部)打开 notepad.exe。
解决方案
我不知道这是否仍是推荐使用的事情,但“对象链接和嵌入”框架允许你对某些对象/控件直接嵌入到应用程序。这可能仅适用于某些应用程序中工作,我不知道,如果记事本就是其中之一。对于像记事本真的简单的事情,你可能有一个更容易的时间正好与任何媒介你使用(如的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 窗体中。例如记事本、Excel、word、Acrobat reader 等等...
但它不适用于某些应用程序。有时当您启动某些应用程序的过程时......等待空闲时间...并尝试获取其 mainWindowHandle...直到主窗口句柄变为空......
所以我做了一个技巧来解决这个问题
如果主窗口句柄为空...然后搜索系统上所有正在运行的进程并找到您的进程...然后获取进程的主进程并将设置面板作为其父进程。
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);
}
另一个有趣的解决方案与LUCH一个WinForm容器的exeternal应用是如下:
[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.Normal ProcessWindowStyle.Minimized
除去恼人的延迟。
如果你想运行你的应用程序中的记事本,你很可能是与文本编辑器组件更好。有明显附带的WinForms一个基本的文本框,但我怀疑提供记事本的功能(或更好)更先进的组件都可以在interweb找到。
我知道如果其他应用程序可以将自身附加到 win32 窗口句柄,这是可能的。例如,我们有一个单独的 C# 应用程序,在其窗口之一内托管 DirectX 应用程序。我不熟悉其实现方式的确切细节,但我认为只是通过 win32 Handle
您的面板与其他应用程序的连接足以让该应用程序附加其 DirectX 表面。
我注意到,所有的现有答案使用旧的Win32用户库函数来做到这一点。我认为这会工作中的最的情况下,反而会减少工作可靠随着时间的推移。
现在,不是在做这件事,我不能告诉你将如何很好地工作,但我确实知道,当前的Windows技术可能是一个更好的解决方案:的桌面窗口管理器API 。
DWM是相同的技术,可以让你看到使用任务栏和任务切换UI应用程序的实时缩略图预览。我相信这是密切相关的远程终端服务。
我认为,当你强迫一个应用程序,可能会发生一个可能的问题是,是不是桌面窗口父窗口的孩子,一些应用程序开发人员发出关于设备上下文(DC),指针假设(鼠标)的位置,屏幕宽度等,这可能引起不稳定的或有问题的行为时,它被在主窗口中“嵌入”。
我怀疑,你可以在很大程度上消除依靠DWM这些问题,以帮助您管理需要有一个应用程序的窗口可靠地呈现,并与内另一个应用程序的容器窗口交互。翻译
在文档假定C ++编程,但我发现谁制作了他所宣称一个人是一个开源的C#包装库:的 https://bytes.com/topic/c-sharp/answers/823547-desktop-window-manager-wrapper 。该职位是旧的,而且来源不是在一个大仓库一样的GitHub,到位桶,或SourceForge上,所以我不知道它是多么的电流。
没有
稍短的答案:只有当其他应用程序被设计为允许它通过提供组件为你添加到自己的应用程序。