【问题标题】:Embed the main window of a qt/C++ application in a wpf/mvvm application在 wpf/mvvm 应用程序中嵌入 qt/C++ 应用程序的主窗口
【发布时间】:2020-02-13 14:22:14
【问题描述】:

我需要在 wpf mvvm 应用程序中嵌入一个 qt/c++ 应用程序。这个qt/C++的窗口必须集成在一个wpf页面中显示在一个tab页中。

页面控件如下:

<page x:Class="Wpf_HostExe.Page1"
    xmlns:="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Page1"
    Loaded="OnLoaded">
    <Grid>
        <Border x:Name="HostUi" Background="White"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch"  />
    </Grid>
</Page>

我按照以下说明启动要托管的应用程序:

public static Process StartProcess()
{
    System.Diagnostics.ProcessStartInfo processStartInfo = new System.Diagnostics.ProcessStartInfo();
    processStartInfo.WorkingDirectory = "C:\\ChildApp\\";
    processStartInfo.fileName = "ChildApp.exe";
    processStartInfo.Arguments = "";

    System.Diagnostics.Process proc = System.Diagnostics.Process.Start(processStartInfo);
    proc.WaitForInputIdle();

    return proc;
}

外部窗口由以下说明重新设置:

public class ApplicationHost : HwndHost
{
    private const uint LBS_NOTIFY = 0x00000001;
    private const uint WS_BORDER = 0x00800000;
    private const int SWP_NO_ACTIVATE = 0x0010;
    private const int GWL_STYLE = -16;
    private const int WS_CAPTION = 0x00C00000;
    private const int WS_THICKFRAME = 0x00040000;
    private const uint WS_VISIBLE = 0x10000000;


    [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.dll")]
    private static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent);

    [DllImport("user32.dll")]
    private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);

    public IntPtr ApplicationHandle { get; set; }
    ...
    protected override HandleRef BuildWindowCore (HandleRef hwndParent)
    {
        var result = new HandleRef(this, ApplicationHandle);
        if (ApplicationHandle.ToInt32() == 0)
        {
            return result;
        }

        var oldParent = SetParent(ApplicationHandle, hwndParent.Handle);

        var styles = GetWindowLong(ApplicationHandle, GWL_STYLE);
        styles |= WS_CHILD | WS_VISIBLE | WS_BORDER | LBS_NOTIFY;
        styles &= ~WS_CAPTION;
        SetWindowLong32(ApplicationHandle, GWL_STYLE, styles);

        return result;
    }
    ...
}

我也试过以下版本:

    ...
    protected override HandleRef BuildWindowCore (HandleRef hwndParent)
    {
        SetParent(ApplicationHandle, hwndParent.Handle);

        int style = GetWindowLong(ApplicationHandle, GWL_STYLE);
        style = style & ~WS_CAPTION & ~WS_THICKFRAME;
        SetWindowLong(ApplicationHandle, GWL_STYLE, style);
    }
    ...

要托管的应用程序的进程开始时没有问题,但 SetParent 似乎不起作用,我收到以下消息,而方法 BuildWindowCore 已通过 setParent 的任何方式:

"An unhandled exception of type 'System.InvalidOperationException' occured in PresentationFramework.dll"
Additional Information : Hosted HWND must be a child window of the specified parent. "

我尝试了很多在 stackoverflow 上发现的东西,但我仍然抛出了同样的 InvalidOperationException 并且不知道如何解决这个问题。

你能帮帮我吗?

问候,

【问题讨论】:

  • 从一个进程中嵌入一个窗口作为另一个进程中的一个窗口的子级,本质上是你不能指望成功的事情。这需要双方的充分合作,以及对win32的深刻理解。以这种方式结合 Qt 和 WPF 的成功前景基本上为零。寻找其他解决方案。
  • Is it legal to have a cross-process parent/child or owner/owned window relationship? 这是重要的收获:“如果您创建跨进程的父/子或所有者/拥有关系,后果可能非常难以管理。并且 如果涉及的一个或两个窗口不知道它正在参与跨进程窗口树,则它们几乎无法管理。” WPF 和 Qt 都没有为此特技做好准备。

标签: c# .net wpf qt winapi


【解决方案1】:

我假设您有 Qt 应用程序的源代码。在该代码中,您必须创建一个函数,该函数将 render() 上的小部件 QImage。从 WPF 调用该函数,并将图像从 QImage 的data() 复制到WriteableBitmap,并使用控件显示。您也可以将鼠标和键盘的点击往相反的方向转发,并有一个功能,然后合成QEvents 以与小部件进行交互。

【讨论】:

    猜你喜欢
    • 2017-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-20
    • 1970-01-01
    • 2016-07-07
    相关资源
    最近更新 更多