6
votes

I have a WPF window which has to behave as an overlay of a window in a third-party running application. My WPF window must be mostly transparent with some visible controls, always be positioned right on top of the other window in the z-order, move with it, etc. In short: I want it to behave like a child window.

I have reviewed the techniques offered here (WPF HwndSource technique) and here (WPF SetParent technique). The HwndSource technique doesn't work at all. The SetParent technique works on Windows 7, but only with the basic theme. With Windows 7 Aero themes, it doesn't work: my child window is invisible.

I am looking for a solution that will work on all Windows 7 themes.

My test application creates a test window and calls SetParent to make it a child window of a (hard-coded HWND to) a Notepad window.

Under the basic theme, it looks like so:

Basic Theme

Under the Windows 7 theme, I don't see it:

Aero Theme

Child window XAML:

<Window x:Class="WpfApplication22.TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TestWindow" Height="300" Width="300" Background="#63000000" ShowInTaskbar="False" WindowStyle="None" Initialized="Window_Initialized" Loaded="Window_Loaded" AllowsTransparency="True">
    <Grid>
        <Ellipse Height="87" HorizontalAlignment="Left" Margin="12,12,0,0" Name="ellipse1" Stroke="Black" VerticalAlignment="Top" Width="167" Fill="#FFBE3A3A" />
    </Grid>
</Window>

The child window form load handler code:

    var parentHwnd = new IntPtr(0x01DE0DFC); // Running Notepad
    var guestHandle = new WindowInteropHelper(this).Handle;

    var style = WS_VISIBLE | WS_CLIPSIBLINGS | WS_CHILD | WS_POPUP;
    SetWindowLong(guestHandle, GWL_STYLE, (int)(style));
    SetParent(guestHandle, parentHwnd);

(I've tried un-setting the WS_POPUP style. It has no effect.)

1
Just a thought, have you tried testing with any window (say calc.exe) other than Notepad? I don't have access to a Windows 7 PC right now, but I can reproduce the problem with notepad but not with calc.exe, using exactly your code on Windows 8. On Win8, with your code, the child window appears in notepad, but as soon as I activate notepad's window, the child window becomes invisible, so I'm thinking maybe notepad does something to keep its textbox on top of everything other children.Andrei Pana
Hmmm... thank you for this thought, @AndreiPana. I will test with other windows, and check out how this works in Windows 8 as well.Udi Bar-On

1 Answers

3
votes

Instead of using SetParent, set WindowInteropHelper.Owner of your WPF "child" window to the window you want to display above.

Note that in .NET 3.5, if you do this in any of the "child" window's event handlers, even as early as OnSourceInitialized, the window owner doesn't really get set. Apparently it's too late to set an owner at that point.

Instead, set the Owner in the code that creates the window, before you call Show(). .NET 4 seems to allow setting the Owner from within SourceInitialized.

  • Jack