如何在 C# 程序的面板中运行另一个应用程序?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/758494/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I run another application within a panel of my C# program?
提问by Alex
I've been reading lots on how to trigger an application from inside a C# program (Process.Start()), but I haven t been able to find any information on how to have this new application run within a panel of my C# program. For example, I'd like a button click to open a notepad.exe WITHIN my application, not externally.
我一直在阅读有关如何从 C# 程序 (Process.Start()) 内部触发应用程序的大量信息,但我无法找到有关如何在我的 C# 程序面板中运行此新应用程序的任何信息. 例如,我希望单击按钮以在我的应用程序内而不是外部打开 notepad.exe。
采纳答案by Andy White
I don't know if this is still the recommended thing to use but the "Object Linking and Embedding" framework allows you to embed certain objects/controls directly into your application. This will probably only work for certain applications, I'm not sure if Notepad is one of them. For really simple things like notepad, you'll probably have an easier time just working with the text box controls provided by whatever medium you're using (e.g. WinForms).
我不知道这是否仍然是推荐使用的东西,但“对象链接和嵌入”框架允许您将某些对象/控件直接嵌入到您的应用程序中。这可能仅适用于某些应用程序,我不确定记事本是否是其中之一。对于像记事本这样非常简单的东西,您可能会更轻松地使用由您使用的任何媒体(例如 WinForms)提供的文本框控件。
Here's a link to OLE info to get started:
以下是 OLE 信息的链接以开始使用:
回答by Samuel
No
不
简答:Only if the other application is designed to allow it, by providing components for you to add into your own application.
仅当其他应用程序被设计为允许时,通过提供组件供您添加到您自己的应用程序中。
回答by Steve
If you want to run notepad inside your app you would probably be better of with a text editor component. There's obviously a basic text box that comes with WinForms, but I suspect more advanced components that offer Notepad functionality (or better) can be found on the interweb.
如果你想在你的应用程序中运行记事本,你可能会更好地使用文本编辑器组件。显然,WinForms 附带了一个基本的文本框,但我怀疑可以在 Internet 上找到提供记事本功能(或更好)的更高级组件。
回答by Anthony Brien
I know this is possible if the other application can attach itself to a win32 window handle. For example, we have a separate C# application that hosts a DirectX application inside one of its windows. I'm not familiar with the exact details of how this is implemented, but I think just passing the win32 Handle
of your panel to the other application is enough for that application to attach its DirectX surface.
我知道如果其他应用程序可以将自己附加到 win32 窗口句柄,这是可能的。例如,我们有一个单独的 C# 应用程序,它在它的一个窗口内托管一个 DirectX 应用程序。我不熟悉这是如何实现的确切细节,但我认为只需将Handle
面板的 win32 传递给另一个应用程序就足以让该应用程序附加其 DirectX 表面。
回答by Luke Quinane
Using the win32 API it is possible to "eat" another application. Basically you get the top window for that application and set it's parent to be the handle of the panel you want to place it in. If you don't want the MDI style effect you also have to adjust the window style to make it maximised and remove the title bar.
使用 win32 API 可以“吃掉”另一个应用程序。基本上,您会获得该应用程序的顶部窗口,并将其父窗口设置为要放置它的面板的句柄。如果您不想要 MDI 样式效果,您还必须调整窗口样式以使其最大化并删除标题栏。
Here is some simple sample code where I have a form with a button and a panel:
这是一些简单的示例代码,其中我有一个带有按钮和面板的表单:
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);
}
}
I just saw another example where they called WaitForInputIdle instead of sleeping. So the code would be like this:
我刚刚看到另一个例子,他们调用 WaitForInputIdle 而不是 sleep。所以代码会是这样的:
Process p = Process.Start("notepad.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, panel1.Handle);
The Code Project has a good article one the whole process: Hosting EXE Applications in a WinForm project
Code Project 有一篇很好的文章介绍了整个过程:Hosting EXE Applications in a WinForm project
回答by Saurabh Raoot
- Adding some solution in Answer..**
- 在答案中添加一些解决方案..**
This code has helped me to dock some executable in windows form. like NotePad, Excel, word, Acrobat reader n many more...
这段代码帮助我以 Windows 形式停靠了一些可执行文件。像记事本、Excel、word、Acrobat 阅读器等等……
But it wont work for some applications. As sometimes when you start process of some application.... wait for idle time... and the try to get its mainWindowHandle.... till the time the main window handle becomes null.....
但它不适用于某些应用程序。有时当您启动某个应用程序的进程时....等待空闲时间...并尝试获取其 mainWindowHandle.... 直到主窗口句柄变为空.....
so I have done one trick to solve this
所以我做了一个技巧来解决这个问题
If you get main window handle as null... then search all the runnning processes on sytem and find you process ... then get the main hadle of the process and the set panel as its parent.
如果您将主窗口句柄设为空...然后在系统上搜索所有正在运行的进程并找到您的进程...然后获取进程的主窗口并将设置面板作为其父进程。
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);
}
回答by Alan McBee - MSFT
I notice that all the prior answers use older Win32 User library functions to accomplish this. I think this will work in mostcases, but will work less reliably over time.
我注意到所有先前的答案都使用较旧的 Win32 用户库函数来完成此操作。我认为这在大多数情况下都会起作用,但随着时间的推移会变得不那么可靠。
Now, not having done this, I can't tell you how well it will work, but I do know that a current Windows technology might be a better solution: the Desktop Windows Manager API.
现在,没有这样做,我无法告诉您它的工作效果如何,但我知道当前的 Windows 技术可能是更好的解决方案:桌面 Windows 管理器 API。
DWM is the same technology that lets you see live thumbnail previews of apps using the taskbar and task switcher UI. I believe it is closely related to Remote Terminal services.
DWM 是相同的技术,可让您使用任务栏和任务切换器 UI 查看应用程序的实时缩略图预览。我相信它与远程终端服务密切相关。
I think that a probable problem that might happen when you force an app to be a child of a parent window that is not the desktop window is that some application developers will make assumptions about the device context (DC), pointer (mouse) position, screen widths, etc., which may cause erratic or problematic behavior when it is "embedded" in the main window.
我认为,当您强制应用程序成为不是桌面窗口的父窗口的子窗口时,可能会发生的一个问题是,某些应用程序开发人员会对设备上下文 (DC)、指针(鼠标)位置做出假设,屏幕宽度等,当它“嵌入”在主窗口中时可能会导致不稳定或有问题的行为。
I suspect that you can largely eliminate these problems by relying on DWM to help you manage the translations necessary to have an application's windows reliably be presented and interacted with inside another application's container window.
我怀疑您可以通过依赖 DWM 来帮助您管理必要的转换,从而在另一个应用程序的容器窗口中可靠地呈现和交互应用程序的窗口,从而在很大程度上消除这些问题。
The documentation assumes C++ programming, but I found one person who has produced what he claims is an open source C# wrapper library: https://bytes.com/topic/c-sharp/answers/823547-desktop-window-manager-wrapper. The post is old, and the source is not on a big repository like GitHub, bitbucket, or sourceforge, so I don't know how current it is.
该文档假定 C++ 编程,但我发现有人已经制作了他声称的开源 C# 包装器库:https: //bytes.com/topic/c-sharp/answers/823547-desktop-window-manager-wrapper. 帖子很旧,而且源不在像 GitHub、bitbucket 或 sourceforge 这样的大型存储库中,所以我不知道它的最新情况。
回答by daniele3004
Another interesting solution to luch an exeternal application with a WinForm container is the follow:
使用 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;
}
The step to ProcessWindowStyle.Minimized
from ProcessWindowStyle.Normal remove the annoying delay.
ProcessWindowStyle.Minimized
从 ProcessWindowStyle.Normal到的步骤 消除了烦人的延迟。