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

dig*_*tai 5 c# visual-studio winforms

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

这个话题在很多年前就已经被解决过。这是我找到的最好的答案:

如何在我的 C# 程序面板中运行另一个应用程序?

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

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

甚至发现一个OP需要启动IE的帖子,但同样的结果,IE在表单之外启动。

阅读和阅读相关主题,我发现使用称为EnumWindows的东西可能可以解决这个问题。我对 C# 很陌生,我通常使用 Python。我什至不是 Windows 本地人,必须将其安装在虚拟机中。

我正在使用 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);
        }
    }
  }
Run Code Online (Sandbox Code Playgroud)

}

运行代码时,.exe 在窗体外部打开。但如果我让它打开 notepad.exe,它会在特定面板和表单内打开。这表明目标已很好地映射到方法。

这里有什么问题吗?如何让.exe在面板和窗体中运行?

Jcl*_*Jcl 5

这取决于你的具体流程。当它空闲时,它可能没有主窗口句柄(这并不常见,但可能会发生),或者它可能有几个“主窗口”。

等待进程第一个进程的正确方法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);
Run Code Online (Sandbox Code Playgroud)

如果您的进程实际上生成了多个“主窗口”,那么您需要篡改它(等待第二个MainWindowHandle

至于你的具体问题,EnumWindows只需列出进程生成的窗口...如果你的进程有多个窗口并且你想将它们全部托管在 winforms 中,这可能会很有用,但它几乎是特定于进程的(您更有可能还需要EnumChildWindowsEnumThreadWindows并枚举所有进程以使其通用,再加上特定的需求(如果您需要在自己的窗口中托管窗口,则需要特定的 UI)。


小智 2

尝试在调用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:\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);
        }
Run Code Online (Sandbox Code Playgroud)