如何在 WPF 应用程序中运行另一个应用程序?

19
我的问题是如何在WPF应用程序内运行一个应用程序(.exe)。我的意思是在应用程序的窗口内运行,而不是外部运行应用程序。
提前感谢:D

1
你为什么需要这样做呢?直接正常启动应用程序就可以了。我无法想象它需要在另一个应用程序的窗口内运行的任何可能原因。 - Cody Gray
谢谢您的回复 :) 我想在我的WPF应用程序中使用像记事本这样的应用程序。我已经找到了解决方案,但它是WinForm的示例。我不知道如何将其编写为WPF。有什么想法将不胜感激 :) - user617275
你为什么想要这样做? - svick
你正在寻找一个编辑控件。这就是记事本所包含的全部内容。在WinForms中,它被称为“TextBox”控件。我不确定在WPF中它被称为什么。如果你想要更多的功能(比如WordPad),你可以使用“RichTextBox”控件(同样,不确定WPF叫它什么)。你根本不需要在你的窗口内托管其他应用程序。 - Cody Gray
46
为什么你可能需要这样做?这种回答应该被禁止。请回答问题,而不是向人们讲授“如何做”和“不要做”的知识。如果你需要一个理由,我可以给你一个原因,其中之一是:在我的视频监控软件中,我有摄像头矩阵监控一个场地,但我想将一个矩阵(WPF网格)的单元格专门用于托管第三方Windows应用程序,例如允许命令该场地的加热和通风。 - Jean-Marie
1个回答

21
你想要做的是完全可行的,但其中也存在一些错误,所以不要期望轻松完成。你需要创建一个继承自 HwndHost 并且重写 BuildWindowCore() 方法的类。请看 Microsoft 的示例,链接为 http://msdn.microsoft.com/en-us/library/ms752055.aspx
在上述示例中,他们给出了在 WPF 表单中放置 Win32 控件的概念,但你可以使用相同的架构将创建的记事本进程的 MainWindowhandle 加载到边框的子级中。像这样:
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
    {
        ProcessStartInfo psi = new ProcessStartInfo("notepad.exe");
        psi.WindowStyle = ProcessWindowStyle.Minimized;
        _process = Process.Start(psi);
        _process.WaitForInputIdle();

        // The main window handle may be unavailable for a while, just wait for it
        while (_process.MainWindowHandle == IntPtr.Zero)
        {
            Thread.Yield();
        }

        IntPtr notepadHandle = _process.MainWindowHandle;

        int style = GetWindowLong(notepadHandle, GWL_STYLE);
        style = style & ~((int)WS_CAPTION) & ~((int)WS_THICKFRAME); // Removes Caption bar and the sizing border
        style |= ((int)WS_CHILD); // Must be a child window to be hosted

        SetWindowLong(notepadHandle, GWL_STYLE, style);
        SetParent(notepadHandle, hwndParent.Handle);

        this.InvalidateVisual();

        HandleRef hwnd = new HandleRef(this, notepadHandle);
        return hwnd;
    }

请记住,您需要从User32.dll中导入一些函数才能设置窗口的样式并设置其父窗口句柄:
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

[DllImport("user32")]
private static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent);

同时确保您包含以下内容:

using System.Windows.Interop;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

这是我在论坛上的第一个回答,如果需要改进请告诉我。还可以参考将外部应用程序托管在WPF窗口中,但不必担心DwayneNeed的东西。只需像我代码中所示使用SetParent()即可。但是,如果您尝试将应用程序嵌入选项卡页中,请小心。您会在那里遇到一些有趣的问题。


1
谢谢你。不过我有一个问题:我有一个主窗口打开另一个窗口,该窗口显示托管的窗口。我的问题是,我的主窗口冻结了,因为它似乎卡在 while 循环中... 顺便说一下,这在我的示例应用程序中不起作用,但在记事本中可以。 - LMeyer
6
常量是在哪里定义的? - Karl Gjertsen
这个答案中的BuildWindowCore方法似乎是从这里的答案中获取的;该链接具有完整的类,但继承自HwndHostEx而不是HwndHost - somethingRandom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接