我需要启动一些Windows应用程序才能在表单中运行。 我正在使用VS-15 IDE在C#上开发Windows桌面应用程序。
这个话题在很多年前就已经在SO中解决了。这是我找到的最佳答案:
如何在 C# 程序的面板中运行另一个应用程序?
但是,所有示例都涉及启动记事本,这工作正常。 我确实可以在目标面板内以目标形式启动和运行记事本,并且工作完美。
但是我不需要启动记事本,我需要启动其他已安装的应用程序,并且发现了令人沮丧的现实,即无法在目标面板/表单中启动所需的应用程序。 它只是在窗体外部打开。
甚至找到了一个 OP 需要启动 IE 的帖子,但相同的结果是,IE 在表单之外启动。
阅读和阅读相关主题,我发现使用称为EnumWindows的东西可以解决的可能性。 我真的是C#的新手,我通常与Python打交道。我什至不是Windows的本机,必须将其安装在VM中。
我正在使用Visual Studio 2015。 预期的输出是 Windows 7 和 8 计算机的桌面应用程序,64 位。
代码:
using System;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace < >
{
public partial class Form1:
{
private void btn_qui_Click(object sender, EventArgs e)
{
var postventa = new appUser("POSTVENTA", "",3);
try
{
frm_3.Show();
Process p = Process.Start("C://QuiterWeb/QuiterWeb.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, frm_3.panel_3.Handle);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
运行代码时,.exe将在窗体外部打开。 但是,如果我打开记事本.exe,它会在特定面板和表单中打开。 这表示目标已很好地映射到方法。
这是怎么回事? 如何使.exe在面板和表单内运行?
这取决于您的具体流程。它在空闲时可能没有主窗口句柄(这并不常见,但可能会发生),或者它可能有几个"主窗口"。
等待进程具有第一个MainWindowHandle
的正确方法是:
Process p = Process.Start("C://QuiterWeb/QuiterWeb.exe");
p.WaitForInputIdle();
while (p.MainWindowHandle == IntPtr.Zero)
{
Thread.Sleep(100); // Don't hog the CPU
p.Refresh(); // You need this since `MainWindowHandle` is cached
// do additional checks, or add a timeout in case the process is stalled
// or never creates a main window handle, etc.
}
SetParent(p.MainWindowHandle, frm_3.panel_3.Handle);
如果你的进程实际上生成了多个"主窗口",那么你需要篡改它(等待第二个MainWindowHandle
)
至于您的具体问题,EnumWindows
只是列出了该过程生成的窗口......如果您的进程有多个窗口,并且您希望将它们全部托管在 WinForms 中,这可能很有用,但它几乎是特定于进程的(您更有可能还需要EnumChildWindows
或EnumThreadWindows
并枚举所有进程以制作通用内容,再加上如果您需要在自己的窗口中托管窗口,则需要特定 UI)。
尝试在调用 WaitForInputIdle 方法后添加睡眠。
样本:
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
static extern bool MoveWindow(IntPtr Handle, int x, int y, int w, int h, bool repaint);
static readonly int GWL_STYLE = -16;
static readonly int WS_VISIBLE = 0x10000000;
private void button1_Click(object sender, EventArgs e)
{
Process p = Process.Start(@"C:testSampleWinForm2.exe");
p.WaitForInputIdle();
Thread.Sleep(3000); //sleep for 3 seconds
SetParent(p.MainWindowHandle, panel1.Handle);
SetWindowLong(p.MainWindowHandle, GWL_STYLE, WS_VISIBLE);
MoveWindow(p.MainWindowHandle, 0, 0, panel1.Width, panel1.Height, true);
}
private void button1_Click(object sender, EventArgs e)
{
Process p = Process.Start("<your exe name>");
p.WaitForInputIdle();
while (p.MainWindowHandle == IntPtr.Zero)
{
Thread.Sleep(100); // Don't hog the CPU
p.Refresh(); // You need this since `MainWindowHandle` is cached
}
SetParent(p.MainWindowHandle, Panel_1.Handle);
}