Dervall
Dervall

Reputation: 5744

MFC-hosted WPF usercontrol how to close parent window on button press

I'm trying to get a legacy MFC application and a new WPF usercontrol to shut down a dialog window based on a button press in the WPF usercontrol. In essence, I would like some tips on how I can get the DoModal() function of MFC return.

For various reasons the dialog is a MFC CDialog started via DoModal, which hosts a single WPF component and nothing else. This component then has a button which will need to close the CDialog after doing some various tasks. This application is an.. exiting.. case of legacy and it's really hard to track control flow and where the actual message pumps driving this thing resides. It's also full of #defines that makes everything twice as difficult as it should be. I think I have identified the message pump, so I think I can insert something into that to make it close - if I can get to that from the WPF control.

I do not know how to send a windows message out from the usercontrol to the host, or how to get the HWND of the host from the usercontrol. I'm sure there is a way to get that, or another better way of communicating?

Is the correct approach to send a WM_CLOSE message to the parent HWND? Or perhaps I can send a WM_USER to the dialog pump and handle the actual closing there?

Upvotes: 0

Views: 2115

Answers (3)

Sheng Jiang 蒋晟
Sheng Jiang 蒋晟

Reputation: 15271

Declare a close event in the control. Raise the event when the close button is closed.

In your CDialog-derived class, subscribe to the event, then call EngDialog in the event handler.

Upvotes: 2

Stephen Holt
Stephen Holt

Reputation: 2368

Try this. It should work for any WPF element (if it's a Visual), by finding it's containing HWND, tracing up the HWND tree until it finds the root parent, then sending that a WM_CLOSE message.

   [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

   [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
    private static extern IntPtr GetParent(IntPtr hWnd);

    //I'd double check this constant, just in case
    static uint WM_CLOSE = 0x10;

    private void CloseContainingWindow(Visual visual)
    {
        // Find the containing HWND for the Visual in question
        HwndSource wpfHandle = PresentationSource.FromVisual(this) as HwndSource;
        if (wpfHandle == null)
        {
            throw new Exception("Could not find Window handle");
        }

        // Trace up the window chain, to find the ultimate parent
        IntPtr hWindow = wpfHandle.Handle;
        while (true)
        {
            IntPtr parentHWindow = GetParent(hWindow);
            if (parentHWindow == (IntPtr)0) break;
            hWindow = parentHWindow;
        }

        // Now send the containing window a close message
        SendMessage(hWindow, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
    }

Upvotes: 4

Dan
Dan

Reputation: 1959

WM_CLOSE should work, but you have to try it. Another approach is to post a WM_COMMAND message to the parent dialog. Sending a WM_USER looks too complicated.

Upvotes: 0

Related Questions