使用 EnumWindows 在 WinForm 的面板中启动.exe应用程序(而不是记事本)



我需要启动一些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 中,这可能很有用,但它几乎是特定于进程的(您更有可能还需要EnumChildWindowsEnumThreadWindows并枚举所有进程以制作通用内容,再加上如果您需要在自己的窗口中托管窗口,则需要特定 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);
}

相关内容

最新更新