使用EnumWindows在WinForm的Panel中启动.exe应用程序 - 而不是记事本

时间:2016-03-08 04:09:39

标签: c# winforms visual-studio

我需要启动一些Windows应用程序才能在表单中运行。我正在使用VS-15 IDE在C#上开发Windows桌面应用程序。

很多年前,这个话题已经解决了。这是我找到的最佳答案:

How can I run another application within a panel of my C# program?

然而,所有示例都涉及启动记事本,它可以正常工作。我确实可以在目标形式的目标面板内启动和运行记事本,并且运行良好。

但我不需要启动记事本,我需要启动其他已安装的应用程序,并且发现了令人沮丧的现实,即无法在目标面板/表单内启动所需的应用程序。它只是在表单之外打开。

甚至找到了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在表单外打开。但是,如果我把它打开notepad.exe,它会在特定的面板和窗体中打开。这表示目标已很好地映射到方法。

这里有什么问题?如何使.exe在面板和表单内运行?

3 个答案:

答案 0 :(得分:2)

这取决于您的具体流程。它闲置时可能没有主窗口处理(它不常见,但可能会发生),或者它可能有几个主窗口#34;。

等待进程拥有第一个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);

如果您的流程实际上产生了多个&#34;主窗口&#34;,那么您需要篡改它(等待第二个MainWindowHandle

至于你的具体问题,EnumWindows只列出了进程产生的窗口......如果你的进程有多个窗口而你想在winforms中托管所有窗口,这可能很有用,但它&# 39; d几乎是特定于流程的(您更可能还需要EnumChildWindowsEnumThreadWindows并枚举所有流程以使某些内容具有通用性,以及需要特定UI的特定需求如果你需要自己托管窗户。)

答案 1 :(得分:0)

在调用 WaitForInputIdle 方法后尝试添加 sleep

样品:

[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:\test\SampleWinForm2.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);
        }

答案 2 :(得分:0)

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);
}