| File: System\Windows\Forms\Control.ControlNativeWindow.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.Runtime.InteropServices; namespace System.Windows.Forms; public partial class Control { internal sealed class ControlNativeWindow : NativeWindow, IWindowTarget { private readonly Control _control; private GCHandle _rootRef; // We will root the control when we do not want to be eligible for garbage collection. internal ControlNativeWindow(Control control) { _control = control.OrThrowIfNull(); WindowTarget = this; } internal Control GetControl() { return _control; } protected override void OnHandleChange() { WindowTarget.OnHandleChange(Handle); } // IWindowTarget method public void OnHandleChange(IntPtr newHandle) { _control.SetHandle(newHandle); } internal void LockReference(bool locked) { if (locked) { if (!_rootRef.IsAllocated) { _rootRef = GCHandle.Alloc(GetControl(), GCHandleType.Normal); } } else { if (_rootRef.IsAllocated) { _rootRef.Free(); } } } protected override void OnThreadException(Exception e) { if (!_control.SuppressApplicationOnThreadException(e)) { Application.OnThreadException(e); } } // IWindowTarget method public void OnMessage(ref Message m) { _control.WndProc(ref m); } internal IWindowTarget WindowTarget { get; set; } #if DEBUG // We override ToString so in debug asserts that fire for // non-released controls will show what control wasn't released. public override string ToString() { return _control.GetType().FullName!; } #endif protected override void WndProc(ref Message m) { // There are certain messages that we want to process // regardless of what window target we are using. These // messages cause other messages or state transitions // to occur within control. switch (m.MsgInternal) { case PInvokeCore.WM_MOUSELEAVE: _control.UnhookMouseEvent(); break; case PInvokeCore.WM_MOUSEMOVE: if (!_control.GetState(States.TrackingMouseEvent)) { _control.HookMouseEvent(); if (!_control.GetState(States.MouseEnterPending)) { PInvokeCore.SendMessage(_control, RegisteredMessage.WM_MOUSEENTER); } else { _control.SetState(States.MouseEnterPending, false); } } break; case PInvokeCore.WM_MOUSEWHEEL: // TrackMouseEvent's mousehover implementation doesn't watch the wheel // correctly... _control.ResetMouseEventArgs(); break; } WindowTarget.OnMessage(ref m); } } }