// This routine handles the following cases: // 1) a parent window is present, build the child window // 2) a parent is present, reparent the child window to it // 3) a parent window is not present, hide the child window by parenting it to SystemResources.Hwnd window. private void BuildOrReparentWindow() { DemandIfUntrusted(); // Verify the thread has access to the context. // VerifyAccess(); // Prevent reentry while building a child window, // also prevent the reconstruction of Disposed objects. if (_isBuildingWindow || _isDisposed) { return; } _isBuildingWindow = true; // Find the source window, this must be the parent window of // the child window. IntPtr hwndParent = IntPtr.Zero; PresentationSource source = PresentationSource.CriticalFromVisual(this, false /* enable2DTo3DTransition */); if (source != null) { HwndSource hwndSource = source as HwndSource; if (hwndSource != null) { hwndParent = hwndSource.CriticalHandle; } } else { // attempt to also walk through 3D - if we get a non-null result then we know we are inside of // a 3D scene which is not supported PresentationSource goingThrough3DSource = PresentationSource.CriticalFromVisual(this, true /* enable2DTo3DTransition */); if (goingThrough3DSource != null) { if (TraceHwndHost.IsEnabled) { TraceHwndHost.Trace(TraceEventType.Warning, TraceHwndHost.HwndHostIn3D); } } } try { if (hwndParent != IntPtr.Zero) { if (_hwnd.Handle == IntPtr.Zero) { // We now have a parent window, so we can create the child // window. BuildWindow(new HandleRef(null, hwndParent)); this.LayoutUpdated += _handlerLayoutUpdated; this.IsEnabledChanged += _handlerEnabledChanged; this.IsVisibleChanged += _handlerVisibleChanged; } else if (hwndParent != UnsafeNativeMethods.GetParent(_hwnd)) { // We have a different parent window. Just reparent the // child window under the new parent window. UnsafeNativeMethods.SetParent(_hwnd, new HandleRef(null, hwndParent)); } } else { // Reparent the window to notification-only window provided by SystemResources // This keeps the child window around, but it is not visible. We can reparent the // window later when a new parent is available var hwnd = SystemResources.GetDpiAwarenessCompatibleNotificationWindow(_hwnd); UnsafeNativeMethods.SetParent(_hwnd, new HandleRef(null, hwnd.Handle)); // ...But we have a potential problem: If the SystemResources listener window gets // destroyed ahead of the call to HwndHost.OnDispatcherShutdown(), the HwndHost's window // will be destroyed too, before the "logical" Dispose has had a chance to do proper // shutdown. This turns out to be very significant for WebBrowser/ActiveXHost, which shuts // down the hosted control through the COM interfaces, and the control destroys its // window internally. Evidently, the WebOC fails to do full, proper cleanup if its // window is destroyed unexpectedly. // To avoid this situation, we make sure SystemResources responds to the Dispatcher // shutdown event after this HwndHost. SystemResources.DelayHwndShutdown(); } } finally { // Be careful to clear our guard bit. _isBuildingWindow = false; } }
private void BuildOrReparentWindow() { this.DemandIfUntrusted(); if (this._isBuildingWindow || this._isDisposed) { return; } this._isBuildingWindow = true; IntPtr intPtr = IntPtr.Zero; PresentationSource presentationSource = PresentationSource.CriticalFromVisual(this, false); if (presentationSource != null) { HwndSource hwndSource = presentationSource as HwndSource; if (hwndSource != null) { intPtr = hwndSource.CriticalHandle; } } else { PresentationSource presentationSource2 = PresentationSource.CriticalFromVisual(this, true); if (presentationSource2 != null && TraceHwndHost.IsEnabled) { TraceHwndHost.Trace(TraceEventType.Warning, TraceHwndHost.HwndHostIn3D); } } try { if (intPtr != IntPtr.Zero) { if (this._hwnd.Handle == IntPtr.Zero) { this.BuildWindow(new HandleRef(null, intPtr)); base.LayoutUpdated += this._handlerLayoutUpdated; base.IsEnabledChanged += this._handlerEnabledChanged; base.IsVisibleChanged += this._handlerVisibleChanged; } else if (intPtr != UnsafeNativeMethods.GetParent(this._hwnd)) { UnsafeNativeMethods.SetParent(this._hwnd, new HandleRef(null, intPtr)); } } else { IntPtr value = (!FrameworkAppContextSwitches.DisableDevDiv1035544) ? this.Handle : this._hwnd.Handle; if (value != IntPtr.Zero) { HwndWrapper dpiAwarenessCompatibleNotificationWindow = SystemResources.GetDpiAwarenessCompatibleNotificationWindow(this._hwnd); if (dpiAwarenessCompatibleNotificationWindow != null) { UnsafeNativeMethods.SetParent(this._hwnd, new HandleRef(null, dpiAwarenessCompatibleNotificationWindow.Handle)); SystemResources.DelayHwndShutdown(); } else { Trace.WriteLineIf(dpiAwarenessCompatibleNotificationWindow == null, string.Format("- Warning - Notification Window is null\n{0}", new StackTrace(true).ToString())); } } } } finally { this._isBuildingWindow = false; } }