将窗口附加到另一个进程的窗口上

4
我的WPF应用程序有多个窗口,我想将其中一些窗口附加到另一个进程的窗口上。我的问题是,一旦我附加了我的窗口,它就变得不可见了。
我正在尝试使用以下代码:
public static bool setParentWindow(IntPtr hWndChild, IntPtr hWndNewParent)
    {
    IntPtr previousParent = SetParent(hWndChild, hWndNewParent);
    return (previousParent == null ? false : true);
}

[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

setParentWindow(myWindowHwnd, newParentHwnd);

所以,上述代码成功地附加了窗口,但不幸的是使其不可见。

我这样做的原因是我正在尝试通过构建“小部件”来扩展应用程序,我的小部件将钩入并向用户显示额外的信息。

两个窗口都具有以下样式:WS_OVERLAPPEDWINDOW、WS_OVERLAPPED、WS_VISIBLE、WS_CLIPSIBLINGS、WS_CLIPCHILDREN。


附加窗口是什么意思?涉及的窗口有哪些窗口样式? - Neil
@Neil:我已经在我的问题末尾添加了样式,所谓的“附加”,是指我希望我的WPF窗口成为新窗口的子窗口。 - Drahcir
将窗口重新父化到其他进程中非常困难。我建议采用不同的解决方案。 - David Heffernan
@DavidHeffernan:我的窗口需要成为一个子窗口,或者在用户看来只是一个子窗口。你知道如何实现后一种情况吗? - Drahcir
你能控制另一个应用程序吗?如果是这样,就在那个应用程序中进行编码。如果不行,那么你认为你有什么办法将另一个进程的窗口(特别是WPF窗口)推到另一个应用程序中呢? - David Heffernan
我无法控制该应用程序。我认为这是可能的,因为窗口已经成功地重新父化,我可以使用Spy++看到我的窗口在那里,只是不可见。 - Drahcir
3个回答

7

我发现可以不使用setParent方法就能实现这一点。我使用了HwndSource类,如下所示:

MyWindow window = new MyWindow();
window.ShowActivated = true;

HwndSourceParameters parameters = new HwndSourceParameters();

parameters.WindowStyle = 0x10000000 | 0x40000000;
parameters.SetPosition(0, 0);
parameters.SetSize((int)window.Width, (int)window.Height);
parameters.ParentWindow = newParent;
parameters.UsesPerPixelOpacity = true;
HwndSource src = new HwndSource(parameters);

src.CompositionTarget.BackgroundColor = Colors.Transparent;
src.RootVisual = (Visual)window.Content;

这个现在运行得很好,没有任何问题。

1
嗨@Gerve。你的例子是我能找到的唯一一个与我尝试做的事情相似的,但它对我不起作用。Spy++告诉我,在我的情况下,MyWindow不是newParent的子级。我的问题是:a)在MyWindow.xaml中,您为WindowStyle、AllowsTransparency和Background属性设置了什么值?b)您是否在窗口上调用Show()?如果是这样,那么在上面的代码之前或之后执行它是否重要?c)在我的情况下,MyWindow获得了WS_EX_LAYERED扩展样式,我读到它与子窗口不兼容。不确定原因。d)您是否使用SetWindowLong()设置任何其他样式? - Udi Bar-On
我的WPF窗口始终有黑色背景(无论我将其背景颜色设置为透明(并允许透明)还是设置为颜色)... - 91378246

1

我不确定您需要如何处理重叠的窗口,但根据MSDN:

出于兼容性原因,SetParent 不会修改其父级正在更改的窗口的 WS_CHILDWS_POPUP 窗口样式。因此,如果 hWndNewParentNULL,则在调用 SetParent 后,您还应清除 WS_CHILD 位并设置 WS_POPUP 样式。相反,如果 hWndNewParent 不是 NULL 并且该窗口以前是桌面的子级,则在调用 SetParent 之前应清除 WS_POPUP 样式并设置 WS_CHILD 样式。


0
private void TryToAttach(IntPtr ownerHandle)
{
    if(ownerHandle == IntPtr.Zero)
    {
        return;
    }
    try
    {
        var helper = new WindowInteropHelper(window) { Owner = ownerHandle };
    }
    catch(Exception e)
    {
        Logger.Error(e, "Could not attach window.");
    }
}

虽然这可能回答了问题,但它没有提供任何上下文来解释如何或为什么。考虑添加一两句话来解释你的答案。 - Joey Harwood
WindowInteropHelper 是来自 System.Windows.Interop 命名空间的一个类。它可协助 Windows Presentation Foundation(WPF)与 Win32 代码之间进行互操作。 - ggJa
很高兴看到你在努力改进你的回答,通常情况下,你应该通过编辑来添加类似的澄清内容,而不是在评论中。评论可能会被清理掉,而且并不是每个人都会阅读它们,所以你的澄清可能会被忽略。 - Joey Harwood

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