4
votes

My WPF application has more than one window, I want to attach some of these windows to a window of another process. My problem is that once I attach my window it becomes invisible.

I'm trying this with the following code:

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

So, the above code successfully attaches the window, but unfortunately makes it invisible.

My reason for doing this is that I'm trying to extend an application by building "Widgets" for it, my widgets will hook in and show the user extra information.

Both windows have the following styles: WS_OVERLAPPEDWINDOW, WS_OVERLAPPED, WS_VISIBLE, WS_CLIPSIBLINGS, WS_CLIPCHILDREN.

3
What do you mean by attaching a window? What are the window styles of the windows that are involved?Neil
@Neil: I've added the styles to the end of my question, by attach I mean that I want my WPF window to be a child of the new window.Drahcir
Re-parenting windows into other processes is extremely hard. I'd recommend a different solution.David Heffernan
@DavidHeffernan: My window needs to either be a child, or just appear (to the user) to be a child. Do you know anyway to do the latter.Drahcir
Do you have control of the other app? If so, then do the coding in that other app. If not then what makes you think that you can push another processes window, and a WPF one at that, into this other app?David Heffernan

3 Answers

7
votes

I found that I could do this without even using the setParent call. I used HwndSource class as follows:

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;

This is working great now without any problems.

1
votes

I'm not sure what you need to do with overlapped windows, but from MSDN:

For compatibility reasons, SetParent does not modify the WS_CHILD or WS_POPUP window styles of the window whose parent is being changed. Therefore, if hWndNewParent is NULL, you should also clear the WS_CHILD bit and set the WS_POPUP style after calling SetParent. Conversely, if hWndNewParent is not NULL and the window was previously a child of the desktop, you should clear the WS_POPUP style and set the WS_CHILD style before calling SetParent.

0
votes
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.");
    }
}