Hosting external window in WPF's HwndHost: how to prevent movement

55 views Asked by At

I'm using the HwndHost class to host the window of an external program in my WPF app (in this case it is the Microsoft Report Builder, which will become relevant later.

Here's the basic implementation of my class:

internal class Win32ControlHost : HwndHost
{
    private readonly IntPtr _childHandle;

    public Win32ControlHost(IntPtr childHandle)
    {
        _childHandle = childHandle;
    }

    protected override HandleRef BuildWindowCore(HandleRef hwndParent)
    {
        var childRef = new HandleRef();

        if (_childHandle != IntPtr.Zero)
        {
            var childStyle = WindowStyles.WS_CHILD |
                                WindowStyles.WS_BORDER |
                                WindowStyles.WS_CLIPCHILDREN |
                                WindowStyles.WS_VISIBLE |
                                WindowStyles.WS_MAXIMIZE;

            childRef = new HandleRef(this, _childHandle);
            SetWindowLongPtr(childRef, GWL_STYLE, (IntPtr)childStyle);
            SetParent(_childHandle, hwndParent.Handle);
        }

        return childRef;
    }

    protected override void DestroyWindowCore(HandleRef hwnd)
    {
    }
}

The problem that I am having is that, no matter what I try, I am not able to prevent the app from being moved around by the user when he clicks and drags on the window title, as you can see in this GIF:

https://gifyu.com/image/SRtZ0

I've tried overriding the WndProc method to explicitly stop moving events, like this:

protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{

    switch (msg)
    {
        case WM_SYSCOMMAND:
            int command = wParam.ToInt32() & 0xfff0;
            if (command == SC_MOVE)
            {
                handled = true;
            }
            break;
        default:
            break;
    }
    return IntPtr.Zero;
}

but it has absolutely no effect, the method is never called when I move the window around.

Also, you may notice from the gif I posted above that the window also shows the close/minimize/maximize buttons, even though the style I applied doesn't include them.

What I suspect is that this particular app (as I said, it is the Microsoft Report Builder app) doesn't really have a traditional "standard" window title bar and border, but the title bar is a custom component drawn by the app itself, and thus ignores the styling and uses internal events to move around rather than the system events, which is why the WndProc method isn't called.

I'm searching for possible workarounds for this. What I'm thinking is:

  • Is there a way to prevent the window from moving?
  • If not, is there a way to make the top bar non-interactable, maybe by drawing an overlay on top of it?
  • Is there a way I can crop the hosted window, so that the title bar isn't even in view?

I didn't have any luck implementing any of those 3 possible solutions, any help is appreciated.

0

There are 0 answers