| File: System\Windows\Forms\Controls\WebBrowser\WebBrowserSiteBase.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms\System.Windows.Forms.csproj (System.Windows.Forms) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel.Design; using System.Runtime.InteropServices; using Windows.Win32.System.Com; using Windows.Win32.System.Ole; namespace System.Windows.Forms; /// <summary> /// This class implements the necessary interfaces required for an ActiveX site. /// /// This class is public, but has an internal constructor so that external /// users can only reference the Type (cannot instantiate it directly). /// Other classes have to inherit this class and expose it to the outside world. /// /// This class does not have any public property/method/event by itself. /// All implementations of the site interface methods are private, which /// means that inheritors who want to override even a single method of one /// of these interfaces will have to implement the whole interface. /// </summary> public unsafe class WebBrowserSiteBase : IOleControlSite.Interface, IOleInPlaceSite.Interface, IOleWindow.Interface, IOleClientSite.Interface, ISimpleFrameSite.Interface, IPropertyNotifySink.Interface, IDisposable { private readonly WebBrowserBase _host; private AxHost.ConnectionPointCookie? _connectionPoint; // // The constructor takes an WebBrowserBase as a parameter, so unfortunately, // this cannot be used as a standalone site. It has to be used in conjunction // with WebBrowserBase. Perhaps we can change it in future. // internal WebBrowserSiteBase(WebBrowserBase h) => _host = h.OrThrowIfNull(); /// <summary> /// Dispose(release the cookie) /// </summary> public void Dispose() { Dispose(true); } /// <summary> /// Release the cookie if we're disposing /// </summary> protected virtual void Dispose(bool disposing) { if (disposing) { StopEvents(); } } /// <summary> /// Retrieves the WebBrowserBase object set in the constructor. /// </summary> internal WebBrowserBase Host => _host; // IOleControlSite methods: HRESULT IOleControlSite.Interface.OnControlInfoChanged() => HRESULT.S_OK; HRESULT IOleControlSite.Interface.LockInPlaceActive(BOOL fLock) => HRESULT.E_NOTIMPL; HRESULT IOleControlSite.Interface.GetExtendedControl(IDispatch** ppDisp) { if (ppDisp is null) { return HRESULT.E_POINTER; } *ppDisp = null; return HRESULT.E_NOTIMPL; } HRESULT IOleControlSite.Interface.TransformCoords(POINTL* pPtlHimetric, PointF* pPtfContainer, uint dwFlags) { if (pPtlHimetric is null || pPtfContainer is null) { return HRESULT.E_POINTER; } XFORMCOORDS coordinates = (XFORMCOORDS)dwFlags; if (coordinates.HasFlag(XFORMCOORDS.XFORMCOORDS_HIMETRICTOCONTAINER)) { if (coordinates.HasFlag(XFORMCOORDS.XFORMCOORDS_SIZE)) { pPtfContainer->X = WebBrowserHelper.HM2Pix(pPtlHimetric->x, WebBrowserHelper.LogPixelsX); pPtfContainer->Y = WebBrowserHelper.HM2Pix(pPtlHimetric->y, WebBrowserHelper.LogPixelsY); } else if (coordinates.HasFlag(XFORMCOORDS.XFORMCOORDS_POSITION)) { pPtfContainer->X = WebBrowserHelper.HM2Pix(pPtlHimetric->x, WebBrowserHelper.LogPixelsX); pPtfContainer->Y = WebBrowserHelper.HM2Pix(pPtlHimetric->y, WebBrowserHelper.LogPixelsY); } else { return HRESULT.E_INVALIDARG; } } else if (coordinates.HasFlag(XFORMCOORDS.XFORMCOORDS_CONTAINERTOHIMETRIC)) { if (coordinates.HasFlag(XFORMCOORDS.XFORMCOORDS_SIZE)) { pPtlHimetric->x = WebBrowserHelper.Pix2HM((int)pPtfContainer->X, WebBrowserHelper.LogPixelsX); pPtlHimetric->y = WebBrowserHelper.Pix2HM((int)pPtfContainer->Y, WebBrowserHelper.LogPixelsY); } else if (coordinates.HasFlag(XFORMCOORDS.XFORMCOORDS_POSITION)) { pPtlHimetric->x = WebBrowserHelper.Pix2HM((int)pPtfContainer->X, WebBrowserHelper.LogPixelsX); pPtlHimetric->y = WebBrowserHelper.Pix2HM((int)pPtfContainer->Y, WebBrowserHelper.LogPixelsY); } else { return HRESULT.E_INVALIDARG; } } else { return HRESULT.E_INVALIDARG; } return HRESULT.S_OK; } HRESULT IOleControlSite.Interface.TranslateAccelerator(MSG* pMsg, KEYMODIFIERS grfModifiers) { if (pMsg is null) { return HRESULT.E_POINTER; } Debug.Assert(!Host.GetAXHostState(WebBrowserHelper.s_siteProcessedInputKey), "Re-entering IOleControlSite.TranslateAccelerator!!!"); Host.SetAXHostState(WebBrowserHelper.s_siteProcessedInputKey, true); Message msg = Message.Create(pMsg); try { bool f = Host.PreProcessControlMessage(ref msg) == PreProcessControlState.MessageProcessed; return f ? HRESULT.S_OK : HRESULT.S_FALSE; } finally { Host.SetAXHostState(WebBrowserHelper.s_siteProcessedInputKey, false); } } HRESULT IOleControlSite.Interface.OnFocus(BOOL fGotFocus) => HRESULT.S_OK; HRESULT IOleControlSite.Interface.ShowPropertyFrame() => HRESULT.E_NOTIMPL; // IOleClientSite methods: HRESULT IOleClientSite.Interface.SaveObject() => HRESULT.E_NOTIMPL; HRESULT IOleClientSite.Interface.GetMoniker(uint dwAssign, uint dwWhichMoniker, IMoniker** ppmk) { if (ppmk is null) { return HRESULT.E_POINTER; } *ppmk = null; return HRESULT.E_NOTIMPL; } HRESULT IOleClientSite.Interface.GetContainer(IOleContainer** ppContainer) { if (ppContainer is null) { return HRESULT.E_POINTER; } *ppContainer = ComHelpers.GetComPointer<IOleContainer>(Host.GetParentContainer()); return HRESULT.S_OK; } HRESULT IOleClientSite.Interface.ShowObject() { if (Host.ActiveXState >= WebBrowserHelper.AXState.InPlaceActive) { HWND hwnd = HWND.Null; if (Host.AXInPlaceObject!.GetWindow(&hwnd).Succeeded) { if (Host.GetHandleNoCreate() != hwnd) { if (!hwnd.IsNull) { Host.AttachWindow(hwnd); RECT posRect = Host.Bounds; OnActiveXRectChange(&posRect); } } } else if (Host.AXInPlaceObject is IOleInPlaceObjectWindowless.Interface) { throw new InvalidOperationException(SR.AXWindowlessControl); } } return HRESULT.S_OK; } HRESULT IOleClientSite.Interface.OnShowWindow(BOOL fShow) => HRESULT.S_OK; HRESULT IOleClientSite.Interface.RequestNewObjectLayout() => HRESULT.E_NOTIMPL; // IOleInPlaceSite methods: unsafe HRESULT IOleInPlaceSite.Interface.GetWindow(HWND* phwnd) { if (phwnd is null) { return HRESULT.E_POINTER; } *phwnd = PInvoke.GetParent(Host); return HRESULT.S_OK; } HRESULT IOleInPlaceSite.Interface.ContextSensitiveHelp(BOOL fEnterMode) => HRESULT.E_NOTIMPL; HRESULT IOleInPlaceSite.Interface.CanInPlaceActivate() => HRESULT.S_OK; HRESULT IOleInPlaceSite.Interface.OnInPlaceActivate() { Host.ActiveXState = WebBrowserHelper.AXState.InPlaceActive; RECT posRect = Host.Bounds; OnActiveXRectChange(&posRect); return HRESULT.S_OK; } HRESULT IOleInPlaceSite.Interface.OnUIActivate() { Host.ActiveXState = WebBrowserHelper.AXState.UIActive; Host.GetParentContainer().OnUIActivate(Host); return HRESULT.S_OK; } HRESULT IOleInPlaceSite.Interface.GetWindowContext( IOleInPlaceFrame** ppFrame, IOleInPlaceUIWindow** ppDoc, RECT* lprcPosRect, RECT* lprcClipRect, OLEINPLACEFRAMEINFO* lpFrameInfo) { if (ppFrame is null || lprcPosRect is null || lprcClipRect is null) { return HRESULT.E_POINTER; } if (ppDoc is not null) { *ppDoc = null; } *ppFrame = ComHelpers.GetComPointer<IOleInPlaceFrame>(Host.GetParentContainer()); *lprcPosRect = Host.Bounds; *lprcClipRect = WebBrowserHelper.GetClipRect(); if (lpFrameInfo is not null) { lpFrameInfo->cb = (uint)Marshal.SizeOf<OLEINPLACEFRAMEINFO>(); lpFrameInfo->fMDIApp = false; lpFrameInfo->haccel = HACCEL.Null; lpFrameInfo->cAccelEntries = 0; lpFrameInfo->hwndFrame = Host.ParentInternal is { } parent ? parent.HWND : HWND.Null; } return HRESULT.S_OK; } HRESULT IOleInPlaceSite.Interface.Scroll(SIZE scrollExtant) => HRESULT.S_FALSE; HRESULT IOleInPlaceSite.Interface.OnUIDeactivate(BOOL fUndoable) { Host.GetParentContainer().OnUIDeactivate(Host); if (Host.ActiveXState > WebBrowserHelper.AXState.InPlaceActive) { Host.ActiveXState = WebBrowserHelper.AXState.InPlaceActive; } return HRESULT.S_OK; } HRESULT IOleInPlaceSite.Interface.OnInPlaceDeactivate() { if (Host.ActiveXState == WebBrowserHelper.AXState.UIActive) { ((IOleInPlaceSite.Interface)this).OnUIDeactivate(false); } Host.GetParentContainer().OnInPlaceDeactivate(Host); Host.ActiveXState = WebBrowserHelper.AXState.Running; return HRESULT.S_OK; } HRESULT IOleInPlaceSite.Interface.DiscardUndoState() => HRESULT.S_OK; HRESULT IOleInPlaceSite.Interface.DeactivateAndUndo() => Host.AXInPlaceObject!.UIDeactivate(); HRESULT IOleInPlaceSite.Interface.OnPosRectChange(RECT* lprcPosRect) => OnActiveXRectChange(lprcPosRect); // ISimpleFrameSite methods: HRESULT ISimpleFrameSite.Interface.PreMessageFilter( HWND hWnd, uint msg, WPARAM wp, LPARAM lp, LRESULT* plResult, uint* pdwCookie) => HRESULT.S_OK; HRESULT ISimpleFrameSite.Interface.PostMessageFilter( HWND hWnd, uint msg, WPARAM wp, LPARAM lp, LRESULT* plResult, uint dwCookie) => HRESULT.S_FALSE; // IPropertyNotifySink methods: HRESULT IPropertyNotifySink.Interface.OnChanged(int dispid) { // Some controls fire OnChanged() notifications when getting values of some properties. // To prevent this kind of recursion, we check to see if we are already inside a OnChanged() call. if (Host.NoComponentChangeEvents != 0) { return HRESULT.S_OK; } Host.NoComponentChangeEvents++; try { OnPropertyChanged(dispid); } catch (Exception t) { Debug.Fail(t.ToString()); throw; } finally { Host.NoComponentChangeEvents--; } return HRESULT.S_OK; } HRESULT IPropertyNotifySink.Interface.OnRequestEdit(int dispid) => HRESULT.S_OK; internal virtual void OnPropertyChanged(int dispid) { if (Host.Site.TryGetService(out IComponentChangeService? changeService)) { try { changeService.OnComponentChanging(Host); changeService.OnComponentChanged(Host); } catch (CheckoutException e) when (e == CheckoutException.Canceled) { return; } } } internal void StartEvents() { if (_connectionPoint is not null) { return; } object? nativeObject = Host._activeXInstance; if (nativeObject is not null) { try { _connectionPoint = new AxHost.ConnectionPointCookie(nativeObject, this, typeof(IPropertyNotifySink.Interface)); } #if DEBUG catch (Exception) { throw; } #else catch (Exception ex) when (!ex.IsCriticalException()) { } #endif } } internal void StopEvents() { _connectionPoint?.Disconnect(); _connectionPoint = null; } private unsafe HRESULT OnActiveXRectChange(RECT* lprcPosRect) { if (lprcPosRect is null) { return HRESULT.E_INVALIDARG; } RECT posRect = new(0, 0, lprcPosRect->right - lprcPosRect->left, lprcPosRect->bottom - lprcPosRect->top); RECT clipRect = WebBrowserHelper.GetClipRect(); Host.AXInPlaceObject!.SetObjectRects(&posRect, &clipRect); Host.MakeDirty(); return HRESULT.S_OK; } HRESULT IOleWindow.Interface.GetWindow(HWND* phwnd) => ((IOleInPlaceSite.Interface)this).GetWindow(phwnd); HRESULT IOleWindow.Interface.ContextSensitiveHelp(BOOL fEnterMode) => ((IOleInPlaceSite.Interface)this).ContextSensitiveHelp(fEnterMode); }