From a6e811841ba54720f3237565d73a1a11535599b2 Mon Sep 17 00:00:00 2001 From: Sergey Smirnov Date: Mon, 22 Feb 2021 12:30:44 +0300 Subject: [PATCH] Move sub-classes of "UpDownBase", "WebBrowser" and "WebBrowserBase" classes to their own files (#4579) --- ...eObject.DirectionButtonAccessibleObject.cs | 98 +++++ ...wnButtons.UpDownButtonsAccessibleObject.cs | 164 +++++++ .../Windows/Forms/UpDownBase.UpDownButtons.cs | 224 +--------- .../Forms/WebBrowser.WebBrowserEvent.cs | 232 ++++++++++ .../Forms/WebBrowser.WebBrowserSite.cs | 201 +++++++++ .../src/System/Windows/Forms/WebBrowser.cs | 407 +----------------- ...bBrowserBase.WebBrowserBaseNativeWindow.cs | 62 +++ .../System/Windows/Forms/WebBrowserBase.cs | 50 +-- 8 files changed, 760 insertions(+), 678 deletions(-) create mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.UpDownButtons.UpDownButtonsAccessibleObject.DirectionButtonAccessibleObject.cs create mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.UpDownButtons.UpDownButtonsAccessibleObject.cs create mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/WebBrowser.WebBrowserEvent.cs create mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/WebBrowser.WebBrowserSite.cs create mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserBase.WebBrowserBaseNativeWindow.cs diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.UpDownButtons.UpDownButtonsAccessibleObject.DirectionButtonAccessibleObject.cs b/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.UpDownButtons.UpDownButtonsAccessibleObject.DirectionButtonAccessibleObject.cs new file mode 100644 index 00000000000..7ec703854aa --- /dev/null +++ b/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.UpDownButtons.UpDownButtonsAccessibleObject.DirectionButtonAccessibleObject.cs @@ -0,0 +1,98 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using System.Drawing; +using static Interop; + +namespace System.Windows.Forms +{ + public abstract partial class UpDownBase + { + internal partial class UpDownButtons + { + internal partial class UpDownButtonsAccessibleObject : ControlAccessibleObject + { + internal class DirectionButtonAccessibleObject : AccessibleObject + { + private readonly bool _up; + private readonly UpDownButtonsAccessibleObject _parent; + + public DirectionButtonAccessibleObject(UpDownButtonsAccessibleObject parent, bool up) + { + _parent = parent; + _up = up; + } + + /// + /// Gets the runtime ID. + /// + internal override int[] RuntimeId => new int[] + { + _parent.RuntimeId[0], + _parent.RuntimeId[1], + _parent.RuntimeId[2], + _up ? 1 : 0 + }; + + internal override object GetPropertyValue(UiaCore.UIA propertyID) => propertyID switch + { + UiaCore.UIA.NamePropertyId => Name, + UiaCore.UIA.RuntimeIdPropertyId => RuntimeId, + UiaCore.UIA.ControlTypePropertyId => UiaCore.UIA.ButtonControlTypeId, + UiaCore.UIA.BoundingRectanglePropertyId => Bounds, + UiaCore.UIA.LegacyIAccessibleStatePropertyId => State, + UiaCore.UIA.LegacyIAccessibleRolePropertyId => Role, + _ => base.GetPropertyValue(propertyID), + }; + + internal override UiaCore.IRawElementProviderFragment FragmentNavigate( + UiaCore.NavigateDirection direction) => direction switch + { + UiaCore.NavigateDirection.Parent => Parent, + UiaCore.NavigateDirection.NextSibling => _up ? Parent.GetChild(1) : null, + UiaCore.NavigateDirection.PreviousSibling => _up ? null : Parent.GetChild(0), + _ => base.FragmentNavigate(direction), + }; + + internal override UiaCore.IRawElementProviderFragmentRoot FragmentRoot => Parent; + + public override Rectangle Bounds + { + get + { + if (!_parent.Owner.IsHandleCreated) + { + return Rectangle.Empty; + } + + // Get button bounds + Rectangle bounds = ((UpDownButtons)_parent.Owner).Bounds; + bounds.Height /= 2; + + if (!_up) + { + bounds.Y += bounds.Height; + } + + // Convert to screen co-ords + return (((UpDownButtons)_parent.Owner).ParentInternal).RectangleToScreen(bounds); + } + } + + public override string Name + { + get => _up ? SR.UpDownBaseUpButtonAccName : SR.UpDownBaseDownButtonAccName; + set { } + } + + public override AccessibleObject Parent => _parent; + + public override AccessibleRole Role => AccessibleRole.PushButton; + } + } + } + } +} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.UpDownButtons.UpDownButtonsAccessibleObject.cs b/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.UpDownButtons.UpDownButtonsAccessibleObject.cs new file mode 100644 index 00000000000..c9d4effbf42 --- /dev/null +++ b/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.UpDownButtons.UpDownButtonsAccessibleObject.cs @@ -0,0 +1,164 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using System.Diagnostics; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Windows.Forms.VisualStyles; +using static Interop; + +namespace System.Windows.Forms +{ + public abstract partial class UpDownBase + { + internal partial class UpDownButtons + { + internal partial class UpDownButtonsAccessibleObject : ControlAccessibleObject + { + private DirectionButtonAccessibleObject upButton; + private DirectionButtonAccessibleObject downButton; + + private UpDownButtons _owner; + + public UpDownButtonsAccessibleObject(UpDownButtons owner) : base(owner) + { + _owner = owner; + } + + internal override UiaCore.IRawElementProviderFragment ElementProviderFromPoint(double x, double y) + { + AccessibleObject element = HitTest((int)x, (int)y); + + if (element != null) + { + return element; + } + + return base.ElementProviderFromPoint(x, y); + } + + internal override UiaCore.IRawElementProviderFragment FragmentNavigate( + UiaCore.NavigateDirection direction) => direction switch + { + UiaCore.NavigateDirection.FirstChild => GetChild(0), + UiaCore.NavigateDirection.LastChild => GetChild(1), + _ => base.FragmentNavigate(direction), + }; + + internal override UiaCore.IRawElementProviderFragmentRoot FragmentRoot => this; + + private DirectionButtonAccessibleObject UpButton + => upButton ??= new DirectionButtonAccessibleObject(this, true); + + private DirectionButtonAccessibleObject DownButton + => downButton ??= new DirectionButtonAccessibleObject(this, false); + + public override AccessibleObject GetChild(int index) => index switch + { + 0 => UpButton, + 1 => DownButton, + _ => null, + }; + + public override int GetChildCount() => 2; + + internal override object GetPropertyValue(UiaCore.UIA propertyID) => propertyID switch + { + UiaCore.UIA.NamePropertyId => Name, + UiaCore.UIA.RuntimeIdPropertyId => RuntimeId, + UiaCore.UIA.BoundingRectanglePropertyId => Bounds, + UiaCore.UIA.LegacyIAccessibleStatePropertyId => State, + UiaCore.UIA.LegacyIAccessibleRolePropertyId => Role, + _ => base.GetPropertyValue(propertyID), + }; + + public override AccessibleObject HitTest(int x, int y) + { + if (UpButton.Bounds.Contains(x, y)) + { + return UpButton; + } + + if (DownButton.Bounds.Contains(x, y)) + { + return DownButton; + } + + return null; + } + + internal override UiaCore.IRawElementProviderSimple HostRawElementProvider + { + get + { + if (HandleInternal == IntPtr.Zero) + { + return null; + } + + UiaCore.UiaHostProviderFromHwnd(new HandleRef(this, HandleInternal), out UiaCore.IRawElementProviderSimple provider); + return provider; + } + } + + public override string Name + { + get + { + string baseName = base.Name; + if (string.IsNullOrEmpty(baseName)) + { + return SR.DefaultUpDownButtonsAccessibleName; + } + + return baseName; + } + set => base.Name = value; + } + + public override AccessibleObject Parent => _owner.AccessibilityObject; + + public override AccessibleRole Role + { + get + { + AccessibleRole role = Owner.AccessibleRole; + if (role != AccessibleRole.Default) + { + return role; + } + + return AccessibleRole.SpinButton; + } + } + + /// + /// Gets the runtime ID. + /// + internal override int[] RuntimeId + { + get + { + if (_owner is null) + { + return base.RuntimeId; + } + + // We need to provide a unique ID others are implementing this in the same manner first item + // is static - 0x2a (RuntimeIDFirstItem) second item can be anything, but here it is a hash. + + var runtimeId = new int[3]; + runtimeId[0] = RuntimeIDFirstItem; + runtimeId[1] = (int)(long)_owner.InternalHandle; + runtimeId[2] = _owner.GetHashCode(); + + return runtimeId; + } + } + } + } + } +} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.UpDownButtons.cs b/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.UpDownButtons.cs index d8f207a4835..c678af967cd 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.UpDownButtons.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/UpDownBase.UpDownButtons.cs @@ -20,7 +20,7 @@ public abstract partial class UpDownBase /// handled. The control sends UpDownEventArgss to the parent UpDownBase class when a button is pressed, or /// when the acceleration determines that another event should be generated. /// - internal class UpDownButtons : Control + internal partial class UpDownButtons : Control { private readonly UpDownBase _parent; @@ -413,228 +413,6 @@ private void TimerHandler(object source, EventArgs args) _timer.Interval = _timerInterval; } } - - internal class UpDownButtonsAccessibleObject : ControlAccessibleObject - { - private DirectionButtonAccessibleObject upButton; - private DirectionButtonAccessibleObject downButton; - - private UpDownButtons _owner; - - public UpDownButtonsAccessibleObject(UpDownButtons owner) : base(owner) - { - _owner = owner; - } - - internal override UiaCore.IRawElementProviderFragment ElementProviderFromPoint(double x, double y) - { - AccessibleObject element = HitTest((int)x, (int)y); - - if (element != null) - { - return element; - } - - return base.ElementProviderFromPoint(x, y); - } - - internal override UiaCore.IRawElementProviderFragment FragmentNavigate( - UiaCore.NavigateDirection direction) => direction switch - { - UiaCore.NavigateDirection.FirstChild => GetChild(0), - UiaCore.NavigateDirection.LastChild => GetChild(1), - _ => base.FragmentNavigate(direction), - }; - - internal override UiaCore.IRawElementProviderFragmentRoot FragmentRoot => this; - - private DirectionButtonAccessibleObject UpButton - => upButton ??= new DirectionButtonAccessibleObject(this, true); - - private DirectionButtonAccessibleObject DownButton - => downButton ??= new DirectionButtonAccessibleObject(this, false); - - public override AccessibleObject GetChild(int index) => index switch - { - 0 => UpButton, - 1 => DownButton, - _ => null, - }; - - public override int GetChildCount() => 2; - - internal override object GetPropertyValue(UiaCore.UIA propertyID) => propertyID switch - { - UiaCore.UIA.NamePropertyId => Name, - UiaCore.UIA.RuntimeIdPropertyId => RuntimeId, - UiaCore.UIA.BoundingRectanglePropertyId => Bounds, - UiaCore.UIA.LegacyIAccessibleStatePropertyId => State, - UiaCore.UIA.LegacyIAccessibleRolePropertyId => Role, - _ => base.GetPropertyValue(propertyID), - }; - - public override AccessibleObject HitTest(int x, int y) - { - if (UpButton.Bounds.Contains(x, y)) - { - return UpButton; - } - - if (DownButton.Bounds.Contains(x, y)) - { - return DownButton; - } - - return null; - } - - internal override UiaCore.IRawElementProviderSimple HostRawElementProvider - { - get - { - if (HandleInternal == IntPtr.Zero) - { - return null; - } - - UiaCore.UiaHostProviderFromHwnd(new HandleRef(this, HandleInternal), out UiaCore.IRawElementProviderSimple provider); - return provider; - } - } - - public override string Name - { - get - { - string baseName = base.Name; - if (string.IsNullOrEmpty(baseName)) - { - return SR.DefaultUpDownButtonsAccessibleName; - } - - return baseName; - } - set => base.Name = value; - } - - public override AccessibleObject Parent => _owner.AccessibilityObject; - - public override AccessibleRole Role - { - get - { - AccessibleRole role = Owner.AccessibleRole; - if (role != AccessibleRole.Default) - { - return role; - } - - return AccessibleRole.SpinButton; - } - } - - /// - /// Gets the runtime ID. - /// - internal override int[] RuntimeId - { - get - { - if (_owner is null) - { - return base.RuntimeId; - } - - // We need to provide a unique ID others are implementing this in the same manner first item - // is static - 0x2a (RuntimeIDFirstItem) second item can be anything, but here it is a hash. - - var runtimeId = new int[3]; - runtimeId[0] = RuntimeIDFirstItem; - runtimeId[1] = (int)(long)_owner.InternalHandle; - runtimeId[2] = _owner.GetHashCode(); - - return runtimeId; - } - } - - internal class DirectionButtonAccessibleObject : AccessibleObject - { - private readonly bool _up; - private readonly UpDownButtonsAccessibleObject _parent; - - public DirectionButtonAccessibleObject(UpDownButtonsAccessibleObject parent, bool up) - { - _parent = parent; - _up = up; - } - - /// - /// Gets the runtime ID. - /// - internal override int[] RuntimeId => new int[] - { - _parent.RuntimeId[0], - _parent.RuntimeId[1], - _parent.RuntimeId[2], - _up ? 1 : 0 - }; - - internal override object GetPropertyValue(UiaCore.UIA propertyID) => propertyID switch - { - UiaCore.UIA.NamePropertyId => Name, - UiaCore.UIA.RuntimeIdPropertyId => RuntimeId, - UiaCore.UIA.ControlTypePropertyId => UiaCore.UIA.ButtonControlTypeId, - UiaCore.UIA.BoundingRectanglePropertyId => Bounds, - UiaCore.UIA.LegacyIAccessibleStatePropertyId => State, - UiaCore.UIA.LegacyIAccessibleRolePropertyId => Role, - _ => base.GetPropertyValue(propertyID), - }; - - internal override UiaCore.IRawElementProviderFragment FragmentNavigate( - UiaCore.NavigateDirection direction) => direction switch - { - UiaCore.NavigateDirection.Parent => Parent, - UiaCore.NavigateDirection.NextSibling => _up ? Parent.GetChild(1) : null, - UiaCore.NavigateDirection.PreviousSibling => _up ? null : Parent.GetChild(0), - _ => base.FragmentNavigate(direction), - }; - - internal override UiaCore.IRawElementProviderFragmentRoot FragmentRoot => Parent; - - public override Rectangle Bounds - { - get - { - if (!_parent.Owner.IsHandleCreated) - { - return Rectangle.Empty; - } - - // Get button bounds - Rectangle bounds = ((UpDownButtons)_parent.Owner).Bounds; - bounds.Height /= 2; - - if (!_up) - { - bounds.Y += bounds.Height; - } - - // Convert to screen co-ords - return (((UpDownButtons)_parent.Owner).ParentInternal).RectangleToScreen(bounds); - } - } - - public override string Name - { - get => _up ? SR.UpDownBaseUpButtonAccName : SR.UpDownBaseDownButtonAccName; - set { } - } - - public override AccessibleObject Parent => _parent; - - public override AccessibleRole Role => AccessibleRole.PushButton; - } - } } } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowser.WebBrowserEvent.cs b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowser.WebBrowserEvent.cs new file mode 100644 index 00000000000..fc666f6e8b6 --- /dev/null +++ b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowser.WebBrowserEvent.cs @@ -0,0 +1,232 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.InteropServices; +using static Interop; + +namespace System.Windows.Forms +{ + public partial class WebBrowser + { + [ClassInterface(ClassInterfaceType.None)] + private class WebBrowserEvent : StandardOleMarshalObject, SHDocVw.DWebBrowserEvents2 + { + private readonly WebBrowser _parent; + private bool _haveNavigated; + + public WebBrowserEvent(WebBrowser parent) + { + _parent = parent; + } + + public bool AllowNavigation { get; set; } + + public void CommandStateChange(SHDocVw.CSC command, bool enable) + { + if (command == SHDocVw.CSC.NAVIGATEBACK) + { + _parent.CanGoBackInternal = enable; + } + else if (command == SHDocVw.CSC.NAVIGATEFORWARD) + { + _parent.CanGoForwardInternal = enable; + } + } + + public void BeforeNavigate2(object pDisp, ref object urlObject, ref object flags, ref object targetFrameName, ref object postData, ref object headers, ref bool cancel) + { + Debug.Assert(_parent != null, "Parent should have been set"); + //Note: we want to allow navigation if we haven't already navigated. + if (AllowNavigation || !_haveNavigated) + { + Debug.Assert(urlObject is null || urlObject is string, "invalid url type"); + Debug.Assert(targetFrameName is null || targetFrameName is string, "invalid targetFrameName type"); + Debug.Assert(headers is null || headers is string, "invalid headers type"); + // + // If during running interop code, the variant.bstr value gets set + // to -1 on return back to native code, if the original value was null, we + // have to set targetFrameName and headers to string.Empty. + if (targetFrameName is null) + { + targetFrameName = string.Empty; + } + if (headers is null) + { + headers = string.Empty; + } + + string urlString = urlObject is null ? string.Empty : (string)urlObject; + WebBrowserNavigatingEventArgs e = new WebBrowserNavigatingEventArgs( + new Uri(urlString), targetFrameName is null ? string.Empty : (string)targetFrameName); + _parent.OnNavigating(e); + cancel = e.Cancel; + } + else + { + cancel = true; + } + } + + public void DocumentComplete(object pDisp, ref object urlObject) + { + Debug.Assert(urlObject is null || urlObject is string, "invalid url"); + _haveNavigated = true; + if (_parent.documentStreamToSetOnLoad != null && (string)urlObject == "about:blank") + { + HtmlDocument htmlDocument = _parent.Document; + if (htmlDocument != null) + { + Ole32.IPersistStreamInit psi = htmlDocument.DomDocument as Ole32.IPersistStreamInit; + Debug.Assert(psi != null, "The Document does not implement IPersistStreamInit"); + Ole32.IStream iStream = (Ole32.IStream)new Ole32.GPStream( + _parent.documentStreamToSetOnLoad); + psi.Load(iStream); + htmlDocument.Encoding = "unicode"; + } + _parent.documentStreamToSetOnLoad = null; + } + else + { + string urlString = urlObject is null ? string.Empty : urlObject.ToString(); + WebBrowserDocumentCompletedEventArgs e = new WebBrowserDocumentCompletedEventArgs( + new Uri(urlString)); + _parent.OnDocumentCompleted(e); + } + } + + public void TitleChange(string text) + { + _parent.OnDocumentTitleChanged(EventArgs.Empty); + } + + public void SetSecureLockIcon(int secureLockIcon) + { + _parent.encryptionLevel = (WebBrowserEncryptionLevel)secureLockIcon; + _parent.OnEncryptionLevelChanged(EventArgs.Empty); + } + + public void NavigateComplete2(object pDisp, ref object urlObject) + { + Debug.Assert(urlObject is null || urlObject is string, "invalid url type"); + string urlString = urlObject is null ? string.Empty : (string)urlObject; + WebBrowserNavigatedEventArgs e = new WebBrowserNavigatedEventArgs( + new Uri(urlString)); + _parent.OnNavigated(e); + } + + public void NewWindow2(ref object ppDisp, ref bool cancel) + { + CancelEventArgs e = new CancelEventArgs(); + _parent.OnNewWindow(e); + cancel = e.Cancel; + } + + public void ProgressChange(int progress, int progressMax) + { + WebBrowserProgressChangedEventArgs e = new WebBrowserProgressChangedEventArgs(progress, progressMax); + _parent.OnProgressChanged(e); + } + + public void StatusTextChange(string text) + { + _parent.statusText = text ?? string.Empty; + _parent.OnStatusTextChanged(EventArgs.Empty); + } + + public void DownloadBegin() => _parent.OnFileDownload(EventArgs.Empty); + + public void FileDownload(ref bool cancel) + { + } + + public void PrivacyImpactedStateChange(bool bImpacted) + { + } + + public void UpdatePageStatus(object pDisp, ref object nPage, ref object fDone) + { + } + + public void PrintTemplateTeardown(object pDisp) + { + } + + public void PrintTemplateInstantiation(object pDisp) + { + } + + public void NavigateError(object pDisp, ref object url, ref object frame, ref object statusCode, ref bool cancel) + { + } + + public void ClientToHostWindow(ref long cX, ref long cY) + { + } + + public void WindowClosing(bool isChildWindow, ref bool cancel) + { + } + + public void WindowSetHeight(int height) + { + } + + public void WindowSetWidth(int width) + { + } + + public void WindowSetTop(int top) + { + } + + public void WindowSetLeft(int left) + { + } + + public void WindowSetResizable(bool resizable) + { + } + + public void OnTheaterMode(bool theaterMode) + { + } + + public void OnFullScreen(bool fullScreen) + { + } + + public void OnStatusBar(bool statusBar) + { + } + + public void OnMenuBar(bool menuBar) + { + } + + public void OnToolBar(bool toolBar) + { + } + + public void OnVisible(bool visible) + { + } + + public void OnQuit() + { + } + + public void PropertyChange(string szProperty) + { + } + + public void DownloadComplete() + { + } + } + } +} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowser.WebBrowserSite.cs b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowser.WebBrowserSite.cs new file mode 100644 index 00000000000..ebb86d1d9c8 --- /dev/null +++ b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowser.WebBrowserSite.cs @@ -0,0 +1,201 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using System.Drawing; +using static Interop; +using static Interop.Mshtml; +using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; + +namespace System.Windows.Forms +{ + public partial class WebBrowser + { + /// + /// Provides a default WebBrowserSite implementation for use in the CreateWebBrowserSite + /// method in the WebBrowser class. + /// + protected class WebBrowserSite : WebBrowserSiteBase, IDocHostUIHandler + { + /// + /// Creates an instance of the class. + /// + public WebBrowserSite(WebBrowser host) : base(host) + { + } + + // IDocHostUIHandler Implementation + unsafe HRESULT IDocHostUIHandler.ShowContextMenu(uint dwID, Point* pt, object pcmdtReserved, object pdispReserved) + { + WebBrowser wb = (WebBrowser)Host; + + if (wb.IsWebBrowserContextMenuEnabled) + { + // let MSHTML display its UI + return HRESULT.S_FALSE; + } + + if (pt is null) + { + return HRESULT.E_INVALIDARG; + } + + if (pt->X == 0 && pt->Y == 0) + { + // IDocHostUIHandler::ShowContextMenu sends (0,0) when the context menu is invoked via the keyboard + // make it (-1, -1) for the WebBrowser::ShowContextMenu method + pt->X = -1; + pt->Y = -1; + } + wb.ShowContextMenu(pt->X, pt->Y); + // MSHTML should not display its context menu because we displayed ours + return HRESULT.S_OK; + } + + unsafe HRESULT IDocHostUIHandler.GetHostInfo(DOCHOSTUIINFO* pInfo) + { + if (pInfo is null) + { + return HRESULT.E_POINTER; + } + + WebBrowser wb = (WebBrowser)Host; + + pInfo->dwDoubleClick = DOCHOSTUIDBLCLK.DEFAULT; + pInfo->dwFlags = DOCHOSTUIFLAG.NO3DOUTERBORDER | + DOCHOSTUIFLAG.DISABLE_SCRIPT_INACTIVE; + + if (wb.ScrollBarsEnabled) + { + pInfo->dwFlags |= DOCHOSTUIFLAG.FLAT_SCROLLBAR; + } + else + { + pInfo->dwFlags |= DOCHOSTUIFLAG.SCROLL_NO; + } + + if (Application.RenderWithVisualStyles) + { + pInfo->dwFlags |= DOCHOSTUIFLAG.THEME; + } + else + { + pInfo->dwFlags |= DOCHOSTUIFLAG.NOTHEME; + } + + return HRESULT.S_OK; + } + + HRESULT IDocHostUIHandler.EnableModeless(BOOL fEnable) + { + return HRESULT.E_NOTIMPL; + } + + HRESULT IDocHostUIHandler.ShowUI( + uint dwID, + Ole32.IOleInPlaceActiveObject activeObject, + Ole32.IOleCommandTarget commandTarget, + Ole32.IOleInPlaceFrame frame, + Ole32.IOleInPlaceUIWindow doc) + { + return HRESULT.S_FALSE; + } + + HRESULT IDocHostUIHandler.HideUI() + { + return HRESULT.E_NOTIMPL; + } + + HRESULT IDocHostUIHandler.UpdateUI() + { + return HRESULT.E_NOTIMPL; + } + + HRESULT IDocHostUIHandler.OnDocWindowActivate(BOOL fActivate) + { + return HRESULT.E_NOTIMPL; + } + + HRESULT IDocHostUIHandler.OnFrameWindowActivate(BOOL fActivate) + { + return HRESULT.E_NOTIMPL; + } + + unsafe HRESULT IDocHostUIHandler.ResizeBorder(RECT* rect, Ole32.IOleInPlaceUIWindow doc, BOOL fFrameWindow) + { + return HRESULT.E_NOTIMPL; + } + + HRESULT IDocHostUIHandler.GetOptionKeyPath(string[] pbstrKey, uint dw) + { + return HRESULT.E_NOTIMPL; + } + + HRESULT IDocHostUIHandler.GetDropTarget(Ole32.IDropTarget pDropTarget, out Ole32.IDropTarget ppDropTarget) + { + // Set to null no matter what we return, to prevent the marshaller + // from having issues if the pointer points to random stuff. + ppDropTarget = null; + return HRESULT.E_NOTIMPL; + } + + HRESULT IDocHostUIHandler.GetExternal(out object ppDispatch) + { + WebBrowser wb = (WebBrowser)Host; + ppDispatch = wb.ObjectForScripting; + return HRESULT.S_OK; + } + + unsafe HRESULT IDocHostUIHandler.TranslateAccelerator(User32.MSG* lpMsg, Guid* pguidCmdGroup, uint nCmdID) + { + if (lpMsg is null || pguidCmdGroup is null) + { + return HRESULT.E_POINTER; + } + + // Returning S_FALSE will allow the native control to do default processing, + // i.e., execute the shortcut key. Returning S_OK will cancel the shortcut key. + WebBrowser wb = (WebBrowser)Host; + if (!wb.WebBrowserShortcutsEnabled) + { + int keyCode = (int)lpMsg->wParam | (int)Control.ModifierKeys; + if (lpMsg->message != User32.WM.CHAR && Enum.IsDefined(typeof(Shortcut), (Shortcut)keyCode)) + { + return HRESULT.S_OK; + } + } + + return HRESULT.S_FALSE; + } + + HRESULT IDocHostUIHandler.TranslateUrl(uint dwTranslate, string strUrlIn, out string pstrUrlOut) + { + // Set to null no matter what we return, to prevent the marshaller + // from having issues if the pointer points to random stuff. + pstrUrlOut = null; + return HRESULT.S_FALSE; + } + + HRESULT IDocHostUIHandler.FilterDataObject(IComDataObject pDO, out IComDataObject ppDORet) + { + // Set to null no matter what we return, to prevent the marshaller + // from having issues if the pointer points to random stuff. + ppDORet = null; + return HRESULT.S_FALSE; + } + + // + // Internal methods + // + internal override void OnPropertyChanged(Ole32.DispatchID dispid) + { + if (dispid != Ole32.DispatchID.READYSTATE) + { + base.OnPropertyChanged(dispid); + } + } + } + } +} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowser.cs b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowser.cs index 7300683241a..943be5ac214 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowser.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowser.cs @@ -12,7 +12,6 @@ using System.Text; using static Interop; using static Interop.Mshtml; -using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; namespace System.Windows.Forms { @@ -24,7 +23,7 @@ namespace System.Windows.Forms [Docking(DockingBehavior.AutoDock)] [SRDescription(nameof(SR.DescriptionWebBrowser))] [Designer("System.Windows.Forms.Design.WebBrowserDesigner, " + AssemblyRef.SystemDesign)] - public class WebBrowser : WebBrowserBase + public partial class WebBrowser : WebBrowserBase { // Reference to the native ActiveX control's IWebBrowser2 // Do not reference this directly. Use the AxIWebBrowser2 @@ -1435,409 +1434,5 @@ private Mshtml.IWebBrowser2 AxIWebBrowser2 return axIWebBrowser2; } } - - // - // WebBrowserSite class: - // - /// - /// Provides a default WebBrowserSite implementation for use in the CreateWebBrowserSite - /// method in the WebBrowser class. - /// - protected class WebBrowserSite : WebBrowserSiteBase, IDocHostUIHandler - { - /// - /// Creates an instance of the class. - /// - public WebBrowserSite(WebBrowser host) : base(host) - { - } - - // IDocHostUIHandler Implementation - unsafe HRESULT IDocHostUIHandler.ShowContextMenu(uint dwID, Point* pt, object pcmdtReserved, object pdispReserved) - { - WebBrowser wb = (WebBrowser)Host; - - if (wb.IsWebBrowserContextMenuEnabled) - { - // let MSHTML display its UI - return HRESULT.S_FALSE; - } - - if (pt is null) - { - return HRESULT.E_INVALIDARG; - } - - if (pt->X == 0 && pt->Y == 0) - { - // IDocHostUIHandler::ShowContextMenu sends (0,0) when the context menu is invoked via the keyboard - // make it (-1, -1) for the WebBrowser::ShowContextMenu method - pt->X = -1; - pt->Y = -1; - } - wb.ShowContextMenu(pt->X, pt->Y); - // MSHTML should not display its context menu because we displayed ours - return HRESULT.S_OK; - } - - unsafe HRESULT IDocHostUIHandler.GetHostInfo(DOCHOSTUIINFO* pInfo) - { - if (pInfo is null) - { - return HRESULT.E_POINTER; - } - - WebBrowser wb = (WebBrowser)Host; - - pInfo->dwDoubleClick = DOCHOSTUIDBLCLK.DEFAULT; - pInfo->dwFlags = DOCHOSTUIFLAG.NO3DOUTERBORDER | - DOCHOSTUIFLAG.DISABLE_SCRIPT_INACTIVE; - - if (wb.ScrollBarsEnabled) - { - pInfo->dwFlags |= DOCHOSTUIFLAG.FLAT_SCROLLBAR; - } - else - { - pInfo->dwFlags |= DOCHOSTUIFLAG.SCROLL_NO; - } - - if (Application.RenderWithVisualStyles) - { - pInfo->dwFlags |= DOCHOSTUIFLAG.THEME; - } - else - { - pInfo->dwFlags |= DOCHOSTUIFLAG.NOTHEME; - } - - return HRESULT.S_OK; - } - - HRESULT IDocHostUIHandler.EnableModeless(BOOL fEnable) - { - return HRESULT.E_NOTIMPL; - } - - HRESULT IDocHostUIHandler.ShowUI( - uint dwID, - Ole32.IOleInPlaceActiveObject activeObject, - Ole32.IOleCommandTarget commandTarget, - Ole32.IOleInPlaceFrame frame, - Ole32.IOleInPlaceUIWindow doc) - { - return HRESULT.S_FALSE; - } - - HRESULT IDocHostUIHandler.HideUI() - { - return HRESULT.E_NOTIMPL; - } - - HRESULT IDocHostUIHandler.UpdateUI() - { - return HRESULT.E_NOTIMPL; - } - - HRESULT IDocHostUIHandler.OnDocWindowActivate(BOOL fActivate) - { - return HRESULT.E_NOTIMPL; - } - - HRESULT IDocHostUIHandler.OnFrameWindowActivate(BOOL fActivate) - { - return HRESULT.E_NOTIMPL; - } - - unsafe HRESULT IDocHostUIHandler.ResizeBorder(RECT* rect, Ole32.IOleInPlaceUIWindow doc, BOOL fFrameWindow) - { - return HRESULT.E_NOTIMPL; - } - - HRESULT IDocHostUIHandler.GetOptionKeyPath(string[] pbstrKey, uint dw) - { - return HRESULT.E_NOTIMPL; - } - - HRESULT IDocHostUIHandler.GetDropTarget(Ole32.IDropTarget pDropTarget, out Ole32.IDropTarget ppDropTarget) - { - // Set to null no matter what we return, to prevent the marshaller - // from having issues if the pointer points to random stuff. - ppDropTarget = null; - return HRESULT.E_NOTIMPL; - } - - HRESULT IDocHostUIHandler.GetExternal(out object ppDispatch) - { - WebBrowser wb = (WebBrowser)Host; - ppDispatch = wb.ObjectForScripting; - return HRESULT.S_OK; - } - - unsafe HRESULT IDocHostUIHandler.TranslateAccelerator(User32.MSG* lpMsg, Guid* pguidCmdGroup, uint nCmdID) - { - if (lpMsg is null || pguidCmdGroup is null) - { - return HRESULT.E_POINTER; - } - - // Returning S_FALSE will allow the native control to do default processing, - // i.e., execute the shortcut key. Returning S_OK will cancel the shortcut key. - WebBrowser wb = (WebBrowser)Host; - if (!wb.WebBrowserShortcutsEnabled) - { - int keyCode = (int)lpMsg->wParam | (int)Control.ModifierKeys; - if (lpMsg->message != User32.WM.CHAR && Enum.IsDefined(typeof(Shortcut), (Shortcut)keyCode)) - { - return HRESULT.S_OK; - } - } - - return HRESULT.S_FALSE; - } - - HRESULT IDocHostUIHandler.TranslateUrl(uint dwTranslate, string strUrlIn, out string pstrUrlOut) - { - // Set to null no matter what we return, to prevent the marshaller - // from having issues if the pointer points to random stuff. - pstrUrlOut = null; - return HRESULT.S_FALSE; - } - - HRESULT IDocHostUIHandler.FilterDataObject(IComDataObject pDO, out IComDataObject ppDORet) - { - // Set to null no matter what we return, to prevent the marshaller - // from having issues if the pointer points to random stuff. - ppDORet = null; - return HRESULT.S_FALSE; - } - - // - // Internal methods - // - internal override void OnPropertyChanged(Ole32.DispatchID dispid) - { - if (dispid != Ole32.DispatchID.READYSTATE) - { - base.OnPropertyChanged(dispid); - } - } - } - - [ClassInterface(ClassInterfaceType.None)] - private class WebBrowserEvent : StandardOleMarshalObject, SHDocVw.DWebBrowserEvents2 - { - private readonly WebBrowser _parent; - private bool _haveNavigated; - - public WebBrowserEvent(WebBrowser parent) - { - _parent = parent; - } - - public bool AllowNavigation { get; set; } - - public void CommandStateChange(SHDocVw.CSC command, bool enable) - { - if (command == SHDocVw.CSC.NAVIGATEBACK) - { - _parent.CanGoBackInternal = enable; - } - else if (command == SHDocVw.CSC.NAVIGATEFORWARD) - { - _parent.CanGoForwardInternal = enable; - } - } - - public void BeforeNavigate2(object pDisp, ref object urlObject, ref object flags, ref object targetFrameName, ref object postData, ref object headers, ref bool cancel) - { - Debug.Assert(_parent != null, "Parent should have been set"); - //Note: we want to allow navigation if we haven't already navigated. - if (AllowNavigation || !_haveNavigated) - { - Debug.Assert(urlObject is null || urlObject is string, "invalid url type"); - Debug.Assert(targetFrameName is null || targetFrameName is string, "invalid targetFrameName type"); - Debug.Assert(headers is null || headers is string, "invalid headers type"); - // - // If during running interop code, the variant.bstr value gets set - // to -1 on return back to native code, if the original value was null, we - // have to set targetFrameName and headers to "". - if (targetFrameName is null) - { - targetFrameName = string.Empty; - } - if (headers is null) - { - headers = string.Empty; - } - - string urlString = urlObject is null ? "" : (string)urlObject; - WebBrowserNavigatingEventArgs e = new WebBrowserNavigatingEventArgs( - new Uri(urlString), targetFrameName is null ? "" : (string)targetFrameName); - _parent.OnNavigating(e); - cancel = e.Cancel; - } - else - { - cancel = true; - } - } - - public void DocumentComplete(object pDisp, ref object urlObject) - { - Debug.Assert(urlObject is null || urlObject is string, "invalid url"); - _haveNavigated = true; - if (_parent.documentStreamToSetOnLoad != null && (string)urlObject == "about:blank") - { - HtmlDocument htmlDocument = _parent.Document; - if (htmlDocument != null) - { - Ole32.IPersistStreamInit psi = htmlDocument.DomDocument as Ole32.IPersistStreamInit; - Debug.Assert(psi != null, "The Document does not implement IPersistStreamInit"); - Ole32.IStream iStream = (Ole32.IStream)new Ole32.GPStream( - _parent.documentStreamToSetOnLoad); - psi.Load(iStream); - htmlDocument.Encoding = "unicode"; - } - _parent.documentStreamToSetOnLoad = null; - } - else - { - string urlString = urlObject is null ? "" : urlObject.ToString(); - WebBrowserDocumentCompletedEventArgs e = new WebBrowserDocumentCompletedEventArgs( - new Uri(urlString)); - _parent.OnDocumentCompleted(e); - } - } - - public void TitleChange(string text) - { - _parent.OnDocumentTitleChanged(EventArgs.Empty); - } - - public void SetSecureLockIcon(int secureLockIcon) - { - _parent.encryptionLevel = (WebBrowserEncryptionLevel)secureLockIcon; - _parent.OnEncryptionLevelChanged(EventArgs.Empty); - } - - public void NavigateComplete2(object pDisp, ref object urlObject) - { - Debug.Assert(urlObject is null || urlObject is string, "invalid url type"); - string urlString = urlObject is null ? "" : (string)urlObject; - WebBrowserNavigatedEventArgs e = new WebBrowserNavigatedEventArgs( - new Uri(urlString)); - _parent.OnNavigated(e); - } - - public void NewWindow2(ref object ppDisp, ref bool cancel) - { - CancelEventArgs e = new CancelEventArgs(); - _parent.OnNewWindow(e); - cancel = e.Cancel; - } - - public void ProgressChange(int progress, int progressMax) - { - WebBrowserProgressChangedEventArgs e = new WebBrowserProgressChangedEventArgs(progress, progressMax); - _parent.OnProgressChanged(e); - } - - public void StatusTextChange(string text) - { - _parent.statusText = text ?? string.Empty; - _parent.OnStatusTextChanged(EventArgs.Empty); - } - - public void DownloadBegin() => _parent.OnFileDownload(EventArgs.Empty); - - public void FileDownload(ref bool cancel) - { - } - - public void PrivacyImpactedStateChange(bool bImpacted) - { - } - - public void UpdatePageStatus(object pDisp, ref object nPage, ref object fDone) - { - } - - public void PrintTemplateTeardown(object pDisp) - { - } - - public void PrintTemplateInstantiation(object pDisp) - { - } - - public void NavigateError(object pDisp, ref object url, ref object frame, ref object statusCode, ref bool cancel) - { - } - - public void ClientToHostWindow(ref long cX, ref long cY) - { - } - - public void WindowClosing(bool isChildWindow, ref bool cancel) - { - } - - public void WindowSetHeight(int height) - { - } - - public void WindowSetWidth(int width) - { - } - - public void WindowSetTop(int top) - { - } - - public void WindowSetLeft(int left) - { - } - - public void WindowSetResizable(bool resizable) - { - } - - public void OnTheaterMode(bool theaterMode) - { - } - - public void OnFullScreen(bool fullScreen) - { - } - - public void OnStatusBar(bool statusBar) - { - } - - public void OnMenuBar(bool menuBar) - { - } - - public void OnToolBar(bool toolBar) - { - } - - public void OnVisible(bool visible) - { - } - - public void OnQuit() - { - } - - public void PropertyChange(string szProperty) - { - } - - public void DownloadComplete() - { - } - } } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserBase.WebBrowserBaseNativeWindow.cs b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserBase.WebBrowserBaseNativeWindow.cs new file mode 100644 index 00000000000..f4436aa9082 --- /dev/null +++ b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserBase.WebBrowserBaseNativeWindow.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using System.Drawing; +using static Interop; + +namespace System.Windows.Forms +{ + public partial class WebBrowserBase + { + /// + /// Defines a window that the ActiveX window is attached to so that we can override it's wndproc. + /// + private class WebBrowserBaseNativeWindow : NativeWindow + { + private readonly WebBrowserBase WebBrowserBase; + + public WebBrowserBaseNativeWindow(WebBrowserBase ax) + { + WebBrowserBase = ax; + } + + /// + /// Pass messages on to the NotifyIcon object's wndproc handler. + /// + protected override void WndProc(ref Message m) + { + switch ((User32.WM)m.Msg) + { + case User32.WM.WINDOWPOSCHANGING: + WmWindowPosChanging(ref m); + break; + default: + base.WndProc(ref m); + break; + } + } + + private unsafe void WmWindowPosChanging(ref Message m) + { + User32.WINDOWPOS* wp = (User32.WINDOWPOS*)m.LParam; + wp->x = 0; + wp->y = 0; + Size s = WebBrowserBase.webBrowserBaseChangingSize; + if (s.Width == -1) + { // Invalid value. Use WebBrowserBase.Bounds instead, when this is the case. + wp->cx = WebBrowserBase.Width; + wp->cy = WebBrowserBase.Height; + } + else + { + wp->cx = s.Width; + wp->cy = s.Height; + } + m.Result = (IntPtr)0; + } + } + } +} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserBase.cs b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserBase.cs index 959ec82c45b..d2820456864 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserBase.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserBase.cs @@ -33,7 +33,7 @@ namespace System.Windows.Forms [DefaultProperty(nameof(Name))] [DefaultEvent(nameof(Enter))] [Designer("System.Windows.Forms.Design.AxDesigner, " + AssemblyRef.SystemDesign)] - public class WebBrowserBase : Control + public partial class WebBrowserBase : Control { private WebBrowserHelper.AXState axState = WebBrowserHelper.AXState.Passive; private WebBrowserHelper.AXState axReloadingState = WebBrowserHelper.AXState.Passive; @@ -1824,53 +1824,5 @@ public override string Text add => throw new NotSupportedException(string.Format(SR.AXAddInvalidEvent, "StyleChanged")); remove { } } - - /// - /// Defines a window that the ActiveX window is attached to so that we can override it's wndproc. - /// - private class WebBrowserBaseNativeWindow : NativeWindow - { - private readonly WebBrowserBase WebBrowserBase; - - public WebBrowserBaseNativeWindow(WebBrowserBase ax) - { - WebBrowserBase = ax; - } - - /// - /// Pass messages on to the NotifyIcon object's wndproc handler. - /// - protected override void WndProc(ref Message m) - { - switch ((User32.WM)m.Msg) - { - case User32.WM.WINDOWPOSCHANGING: - WmWindowPosChanging(ref m); - break; - default: - base.WndProc(ref m); - break; - } - } - - private unsafe void WmWindowPosChanging(ref Message m) - { - User32.WINDOWPOS* wp = (User32.WINDOWPOS*)m.LParam; - wp->x = 0; - wp->y = 0; - Size s = WebBrowserBase.webBrowserBaseChangingSize; - if (s.Width == -1) - { // Invalid value. Use WebBrowserBase.Bounds instead, when this is the case. - wp->cx = WebBrowserBase.Width; - wp->cy = WebBrowserBase.Height; - } - else - { - wp->cx = s.Width; - wp->cy = s.Height; - } - m.Result = (IntPtr)0; - } - } } }