using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using static CPF.Windows.UnmanagedMethods; using CPF; using System.Threading; using System.IO; using CPF.Threading; using System.Collections.Concurrent; using CPF.Drawing; using CPF.Input; using System.Linq; using CPF.Controls; using CPF.Platform; using CPF.Shapes; using CPF.Animation; using System.Diagnostics; using System.Text; using CPF.Design; using CPF.Windows.OpenGL; using CPF.OpenGL; //using System.Runtime.InteropServices.ComTypes; namespace CPF.Windows { public class WindowImpl : IWindowImpl { internal static int threadCallbackMessage; public ConcurrentQueue invokeQueue = new ConcurrentQueue(); public ConcurrentQueue asyncQueue = new ConcurrentQueue(); float scaling = 1; internal static WindowImpl Window; const double wheelDelta = 120.0; private bool _trackingMouse; DispatcherTimer timer; View root; public View Root { get { return root; } } WindowState windowState = WindowState.Normal; WindowState oldwindowState = WindowState.Normal; //bool isFirst = true; private string _className; static WindowImpl() { threadCallbackMessage = RegisterWindowMessage("CPF_ThreadCallbackMessage"); if (WindowsPlatform.registerForMarshalling) { #if NET5_0_OR_GREATER ComWrappers.RegisterForMarshalling(ComWrapper.CpfComWrappers.Instance); #endif } HRESULT res = UnmanagedMethods.OleInitialize(IntPtr.Zero); if (res != HRESULT.S_OK && res != HRESULT.S_FALSE /*already initialized*/) throw new Win32Exception((int)res, "Failed to initialize OLE:必须设置线程STA,Main方法上加[STAThread]"); } static IntPtr moduleHandle; public static IntPtr ModuleHandle { get { if (moduleHandle == IntPtr.Zero) { moduleHandle = GetModuleHandle(null); } return moduleHandle; } } WNDCLASSEX wc = new WNDCLASSEX(); bool touchMsg; public WindowImpl() { if (Window == null) { Window = this; } posttime = Application.Elapsed; var v = System.Environment.OSVersion.Version; if (v.Major >= 6 && DwmIsCompositionEnabled() && !Application.DesignMode) { } else { isLayered = true; } if ((v.Major == 6 && v.Minor < 2)) { touchMsg = RegisterTouchWindow(handle, RegisterTouchFlags.TWF_NONE); } _className = "CPFWindow-" + Guid.NewGuid(); // 初始化窗口类结构 wc.cbSize = Marshal.SizeOf(typeof(WNDCLASSEX)); //wc.style = (int)ClassStyles.CS_DBLCLKS; wc.lpfnWndProc = WndProc; wc.hInstance = ModuleHandle; wc.hbrBackground = IntPtr.Zero; wc.lpszClassName = _className; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hIcon = IntPtr.Zero; wc.hCursor = DefaultCursor; wc.lpszMenuName = ""; // 注册窗口类 RegisterClassEx(ref wc); // 创建并显示窗口 handle = CreateWindowEx((int)ExStyle, _className, "窗体标题", (uint)Style, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, IntPtr.Zero, IntPtr.Zero, ModuleHandle, null); //timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(1), IsEnabled = true }; //timer.Tick += Timer_Tick; if (UnmanagedMethods.ShCoreAvailable) { uint dpix, dpiy; var monitor = UnmanagedMethods.MonitorFromWindow( handle, UnmanagedMethods.MONITOR.MONITOR_DEFAULTTONEAREST); if (UnmanagedMethods.GetDpiForMonitor != null) { if (UnmanagedMethods.GetDpiForMonitor( monitor, UnmanagedMethods.MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, out dpix, out dpiy) == 0) { scaling = (float)(dpix / 96.0); } } } scaling = Application.BaseScale * scaling; //scaling = 1; imeCentext = ImmGetContext(handle); if (imeCentext == IntPtr.Zero) { imeCentext = ImmCreateContext(); //ImmAssociateContext(handle, imeCentext); createimeCentext = true; } dropTarget = new OleDropTarget(this); var r = UnmanagedMethods.RegisterDragDrop(handle, dropTarget); //UnmanagedMethods.RegisterDragDrop(handle, Marshal.GetComInterfaceForObject(dropTarget, typeof(IDropTarget))); //UpdateWindow(handle); useGPU = Application.GetDrawingFactory().UseGPU; if (!isLayered && useGPU) { wglContext = new WglContext(handle); if (wglContext.RC == IntPtr.Zero) { //useGPU = false; wglContext.Dispose(); wglContext = null; isLayered = true; SetWindowLong(handle, (int)WindowLongParam.GWL_EXSTYLE, (uint)ExStyle); } } if (!isLayered) { DWM_BLURBEHIND dwm = new DWM_BLURBEHIND(); dwm.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; dwm.fEnable = true; dwm.hRegionBlur = CreateRectRgn(0, 0, -1, -1); DwmEnableBlurBehindWindow(handle, ref dwm); DeleteObject(dwm.hRegionBlur); //MARGINS sRT = new MARGINS(); //sRT.Right = sRT.Left = sRT.Top = sRT.Bottom = -1; //DwmExtendFrameIntoClientArea(handle, ref sRT); } } bool useGPU; CPF.Windows.OpenGL.WglContext wglContext; //[DllImport("QCall")] //private static extern void SetGlobalInstanceRegisteredForMarshalling(long id); OleDropTarget dropTarget; public static readonly IntPtr DefaultCursor = LoadCursor(IntPtr.Zero, new IntPtr((int)UnmanagedMethods.Cursor.IDC_ARROW)); protected virtual WindowStyles ExStyle { get { var style = WindowStyles.WS_EX_LEFT; if (isLayered) { style |= WindowStyles.WS_EX_LAYERED; } return style; } } protected bool isLayered; protected virtual WindowStyles Style { get { return WindowStyles.WS_CLIPCHILDREN | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_POPUP | //WindowStyles.WS_BORDER | //WindowStyles.WS_THICKFRAME | WindowStyles.WS_MINIMIZEBOX ; } } public void DragMove() { SendMessage(handle, (int)WindowsMessage.WM_SYSCOMMAND, (IntPtr)SystemCommand.SC_MOUSEMOVE, IntPtr.Zero); BeginInvoke(a => { SendMessage(handle, (int)WindowsMessage.WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero); }, null); } public void Invoke(SendOrPostCallback callback, object data) { if (Dispatcher.MainThread.CheckAccess()) { callback(data); } else { var invokeMre = new ManualResetEvent(false); invokeQueue.Enqueue(new SendOrPostData { Data = data, SendOrPostCallback = callback, ManualResetEvent = invokeMre }); PostMessage(handle, (uint)threadCallbackMessage, IntPtr.Zero, IntPtr.Zero); invokeMre.WaitOne(); } } TimeSpan posttime; public void BeginInvoke(SendOrPostCallback callback, object data) { var time = Application.Elapsed; asyncQueue.Enqueue(new SendOrPostData { Data = data, SendOrPostCallback = callback }); if (asyncQueue.Count <= 1 || (time.TotalMilliseconds - posttime.TotalMilliseconds) > 10) { PostMessage(handle, (uint)threadCallbackMessage, (IntPtr)1, IntPtr.Zero); } posttime = time; } bool canResize; public bool CanResize { get { return canResize; } set { canResize = value; var ex = GetWindowLong(handle, (int)WindowLongParam.GWL_STYLE); if (value) { SetWindowLong(handle, (int)WindowLongParam.GWL_STYLE, ex | (uint)WindowStyles.WS_MAXIMIZEBOX); } else { SetWindowLong(handle, (int)WindowLongParam.GWL_STYLE, ex ^ (uint)WindowStyles.WS_MAXIMIZEBOX); } } } public Action PositionChanged { get; set; } public event Action Move; public Action Resized { get; set; } public Action WindowStateChanged { get; set; } public Action ScalingChanged { get; set; } public Action Activated { get; set; } public Func Closing { get; set; } public Action Closed { get; set; } public Action Deactivated { get; set; } public IntPtr Handle { get { return handle; } } IntPtr handle; IntPtr hBitmap; Size oldSize; IntPtr ppvBits; /// /// 为了防止多屏幕拖动的时候抖动 /// PixelPoint? ScalingChangedPosition; //bool cc; // 窗口过程 protected unsafe virtual IntPtr WndProc(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam) { if (msg == threadCallbackMessage) { if (wParam == IntPtr.Zero) { if (invokeQueue.TryDequeue(out SendOrPostData result)) { try { result.SendOrPostCallback(result.Data); } //catch (Exception e) //{ // throw new InvalidOperationException("Invoke操作异常", e); //} finally { result.ManualResetEvent.Set(); } } } else { while (asyncQueue.TryDequeue(out SendOrPostData data)) { data.SendOrPostCallback(data.Data); } } } if (WndPro != null) { var r = WndPro(hwnd, (WindowsMessage)msg, wParam, lParam); if (r != null) { return r.Value; } } InputModifiers modifiers; switch ((WindowsMessage)msg) { case WindowsMessage.WM_ACTIVATEAPP: //Debug.WriteLine(root.ToString() + "Deactivated"); //if (!cc) //{ // var s = Bounds; // InitOpenGLWin((int)s.Width, (int)s.Height, handle); //} //cc = true; break; case WindowsMessage.WM_CREATE: break; case UnmanagedMethods.WindowsMessage.WM_ACTIVATE: //{ //} //{ // var s = Bounds; // ChangeOpenGLWinSize((int)s.Width, (int)s.Height); //} var wa = (UnmanagedMethods.WindowActivate)(ToInt32(wParam) & 0xffff); //Debug.WriteLine(root.ToString() + " " + wa); switch (wa) { case UnmanagedMethods.WindowActivate.WA_ACTIVE: case UnmanagedMethods.WindowActivate.WA_CLICKACTIVE: Activated?.Invoke(); break; case UnmanagedMethods.WindowActivate.WA_INACTIVE: Deactivated?.Invoke(); //Debug.WriteLine(root.ToString() + "Deactivated"); //root.InputManager.KeyboardDevice.ProcessEvent(new KeyEventArgs(root, Keys.None, root.InputManager.KeyboardDevice.Modifiers, root.InputManager.KeyboardDevice), KeyEventType.LostFocus); break; } return IntPtr.Zero; //case WindowsMessage.WM_NCACTIVATE: // if (!canActivate) // { // Debug.WriteLine(root.ToString() + "WM_NCACTIVATE"); // if (((int)wParam & 0xFFFF) != (int)WindowActivate.WA_INACTIVE) // { // if (lParam != IntPtr.Zero) // { // SetActiveWindow(lParam); // } // else // { // SetActiveWindow(IntPtr.Zero); // } // } // } // break; case WindowsMessage.WM_MOUSEACTIVATE: if (!canActivate) { return new IntPtr(3); } break; case WindowsMessage.WM_DPICHANGED: var dpi = ToInt32(wParam) & 0xffff; #if Net4 var newDisplayRect = (UnmanagedMethods.RECT)Marshal.PtrToStructure(lParam, typeof(UnmanagedMethods.RECT)); #else var newDisplayRect = Marshal.PtrToStructure(lParam); #endif scaling = dpi / 96f; //SetWindowPos(hwnd, // IntPtr.Zero, // newDisplayRect.left, // newDisplayRect.top, // newDisplayRect.right - newDisplayRect.left, // newDisplayRect.bottom - newDisplayRect.top, // SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE); ScalingChangedPosition = new PixelPoint(newDisplayRect.left, newDisplayRect.top); ScalingChanged?.Invoke(); root.LayoutManager.ExecuteLayoutPass(); ScalingChangedPosition = null; return IntPtr.Zero; case WindowsMessage.WM_NCHITTEST: break; case WindowsMessage.WM_NCCALCSIZE: if (wParam != (IntPtr)0) { //var style = GetWindowLong(handle, (int)WindowLongParam.GWL_STYLE); //if ((style & (uint)WindowStyles.WS_THICKFRAME) == 0) //{ // SetWindowLong(handle, (int)WindowLongParam.GWL_STYLE, style | (uint)WindowStyles.WS_THICKFRAME); //} } //break; return (IntPtr)1; case WindowsMessage.WM_GETMINMAXINFO: WmGetMinMaxInfo(hwnd, lParam); //break; return IntPtr.Zero; case WindowsMessage.WM_NCLBUTTONDOWN: int test = (int)wParam; if (test == (int)HitTestValues.HTCLOSE || test == (int)HitTestValues.HTHELP || test == (int)HitTestValues.HTMINBUTTON || test == (int)HitTestValues.HTMAXBUTTON) { return IntPtr.Zero; } break; case WindowsMessage.WM_SYSCOMMAND: //if (wParam.ToInt32() == 61728) //{ // return 0; //} break; case UnmanagedMethods.WindowsMessage.WM_KEYDOWN: case UnmanagedMethods.WindowsMessage.WM_SYSKEYDOWN: GetKeyboardState(_keyStates); InputModifiers result = 0; if (IsDown(Keys.LeftAlt) || IsDown(Keys.RightAlt)) { result |= InputModifiers.Alt; } if (IsDown(Keys.LeftCtrl) || IsDown(Keys.RightCtrl)) { result |= InputModifiers.Control; } if (IsDown(Keys.LeftShift) || IsDown(Keys.RightShift)) { result |= InputModifiers.Shift; } if (IsDown(Keys.LWin) || IsDown(Keys.RWin)) { result |= InputModifiers.Windows; } root.InputManager.KeyboardDevice.Modifiers = result; if (isEnable) { root.InputManager.KeyboardDevice.ProcessEvent(new KeyEventArgs(root, KeyInterop.KeyFromVirtualKey(ToInt32(wParam)), ToInt32(wParam), root.InputManager.KeyboardDevice.Modifiers, root.InputManager.KeyboardDevice), KeyEventType.KeyDown); } //System.Diagnostics.Debug.WriteLine(root.ToString() + wParam + "|" + lParam); break; case UnmanagedMethods.WindowsMessage.WM_KEYUP: case UnmanagedMethods.WindowsMessage.WM_SYSKEYUP: InputModifiers result1 = 0; if (IsDown(Keys.LeftAlt) || IsDown(Keys.RightAlt)) { result1 |= InputModifiers.Alt; } if (IsDown(Keys.LeftCtrl) || IsDown(Keys.RightCtrl)) { result1 |= InputModifiers.Control; } if (IsDown(Keys.LeftShift) || IsDown(Keys.RightShift)) { result1 |= InputModifiers.Shift; } if (IsDown(Keys.LWin) || IsDown(Keys.RWin)) { result1 |= InputModifiers.Windows; } root.InputManager.KeyboardDevice.Modifiers = result1; //root.InputManager.KeyboardDevice.Modifiers = GetMouseModifiers(wParam); if (isEnable) { root.InputManager.KeyboardDevice.ProcessEvent(new KeyEventArgs(root, KeyInterop.KeyFromVirtualKey(ToInt32(wParam)), ToInt32(wParam), root.InputManager.KeyboardDevice.Modifiers, root.InputManager.KeyboardDevice), KeyEventType.KeyUp); } break; case UnmanagedMethods.WindowsMessage.WM_CHAR: // Ignore control chars if (ToInt32(wParam) >= 32 && isEnable) { var str = new string((char)ToInt32(wParam), 1); root.InputManager.KeyboardDevice.ProcessEvent(new TextInputEventArgs(root, root.InputManager.KeyboardDevice, str), KeyEventType.TextInput); } break; case WindowsMessage.WM_IME_SETCONTEXT: if (ToInt32(wParam) == 1) { var old = ImmAssociateContext(handle, imeCentext); } break; case WindowsMessage.WM_IME_STARTCOMPOSITION: break; case WindowsMessage.WM_IME_ENDCOMPOSITION: break; case WindowsMessage.WM_IME_NOTIFY: break; case WindowsMessage.WM_MOUSEMOVE: if (!_trackingMouse) { var tm = new TRACKMOUSEEVENT { #if Net4 cbSize = Marshal.SizeOf(typeof(TRACKMOUSEEVENT)), #else cbSize = Marshal.SizeOf(), #endif dwFlags = 2, hwndTrack = hwnd, dwHoverTime = 0, }; TrackMouseEvent(ref tm); } root.InputManager.KeyboardDevice.Modifiers = GetMouseModifiers(wParam); modifiers = root.InputManager.KeyboardDevice.Modifiers; if (isEnable) { root.InputManager.MouseDevice.ProcessEvent(new MouseEventArgs(root, modifiers.HasFlag(InputModifiers.LeftMouseButton), modifiers.HasFlag(InputModifiers.RightMouseButton), modifiers.HasFlag(InputModifiers.MiddleMouseButton), DipFromLParam(lParam), root.InputManager.MouseDevice, IsTouch()), root.LayoutManager.VisibleUIElements, EventType.MouseMove); } break; case WindowsMessage.WM_MOUSELEAVE: _trackingMouse = false; root.InputManager.KeyboardDevice.Modifiers = GetMouseModifiers(wParam); modifiers = root.InputManager.KeyboardDevice.Modifiers; if (isEnable) { root.InputManager.MouseDevice.ProcessEvent(new MouseEventArgs(root, modifiers.HasFlag(InputModifiers.LeftMouseButton), modifiers.HasFlag(InputModifiers.RightMouseButton), modifiers.HasFlag(InputModifiers.MiddleMouseButton), DipFromLParam(lParam), root.InputManager.MouseDevice, IsTouch()), root.LayoutManager.VisibleUIElements, EventType.MouseLeave); } break; case WindowsMessage.WM_MOUSEWHEEL: root.InputManager.KeyboardDevice.Modifiers = GetMouseModifiers(wParam); modifiers = root.InputManager.KeyboardDevice.Modifiers; if (isEnable) { root.InputManager.MouseDevice.ProcessEvent(new MouseWheelEventArgs(root, modifiers.HasFlag(InputModifiers.LeftMouseButton), modifiers.HasFlag(InputModifiers.RightMouseButton), modifiers.HasFlag(InputModifiers.MiddleMouseButton), PointToClient(PointFromLParam(lParam)), root.InputManager.MouseDevice, new Vector(0, (ToInt32(wParam) >> 16))), root.LayoutManager.VisibleUIElements, EventType.MouseWheel); } break; case WindowsMessage.WM_MBUTTONUP: case WindowsMessage.WM_RBUTTONUP: case WindowsMessage.WM_LBUTTONUP: MouseButton mouseButton = MouseButton.Left; if ((WindowsMessage)msg == WindowsMessage.WM_RBUTTONUP) { mouseButton = MouseButton.Right; } if ((WindowsMessage)msg == WindowsMessage.WM_MBUTTONUP) { mouseButton = MouseButton.Middle; } root.InputManager.KeyboardDevice.Modifiers = GetMouseModifiers(wParam); if (isEnable) { root.InputManager.MouseDevice.ProcessEvent(new MouseButtonEventArgs(root, root.InputManager.KeyboardDevice.Modifiers.HasFlag(InputModifiers.LeftMouseButton), root.InputManager.KeyboardDevice.Modifiers.HasFlag(InputModifiers.RightMouseButton), root.InputManager.KeyboardDevice.Modifiers.HasFlag(InputModifiers.MiddleMouseButton), DipFromLParam(lParam), root.InputManager.MouseDevice, mouseButton, IsTouch()), root.LayoutManager.VisibleUIElements, EventType.MouseUp); } break; case WindowsMessage.WM_MBUTTONDOWN: case WindowsMessage.WM_LBUTTONDOWN: case WindowsMessage.WM_RBUTTONDOWN: //Debug.WriteLine("触摸点击:" + IsTouch()); mouseButton = MouseButton.Left; if ((WindowsMessage)msg == WindowsMessage.WM_RBUTTONDOWN) { mouseButton = MouseButton.Right; } if ((WindowsMessage)msg == WindowsMessage.WM_MBUTTONDOWN) { mouseButton = MouseButton.Middle; } root.InputManager.KeyboardDevice.Modifiers = GetMouseModifiers(wParam); if (isEnable) { root.InputManager.MouseDevice.ProcessEvent(new MouseButtonEventArgs(root, root.InputManager.KeyboardDevice.Modifiers.HasFlag(InputModifiers.LeftMouseButton), root.InputManager.KeyboardDevice.Modifiers.HasFlag(InputModifiers.RightMouseButton), root.InputManager.KeyboardDevice.Modifiers.HasFlag(InputModifiers.MiddleMouseButton), DipFromLParam(lParam), root.InputManager.MouseDevice, mouseButton, IsTouch()), root.LayoutManager.VisibleUIElements, EventType.MouseDown); } break; case WindowsMessage.WM_LBUTTONDBLCLK: case WindowsMessage.WM_MBUTTONDBLCLK: case WindowsMessage.WM_RBUTTONDBLCLK: //Debug.WriteLine("DBLCLK"); break; case WindowsMessage.WM_MOVE: //var pos = new Point((short)(ToInt32(lParam) & 0xffff) / scaling, (short)(ToInt32(lParam) >> 16) / scaling); //var pos = Bounds.Location; if (Move != null) { Move(); } var pos = new PixelPoint((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)); //bounds = Bounds; PositionChanged?.Invoke(pos); break; case WindowsMessage.WM_SIZE: var size = (SizeCommand)wParam; if (Resized != null && (size == SizeCommand.Restored || size == SizeCommand.Maximized)) { var clientSize = new Size(ToInt32(lParam) & 0xffff, ToInt32(lParam) >> 16); Resized(clientSize / scaling); } var windowState = size == SizeCommand.Maximized ? WindowState.Maximized : (size == SizeCommand.Minimized ? WindowState.Minimized : WindowState.Normal); if (windowState != this.oldwindowState || this.windowState == WindowState.FullScreen) { if (this.windowState != WindowState.FullScreen) { this.windowState = windowState; oldwindowState = windowState; WindowStateChanged?.Invoke(); } else { if (oldwindowState != WindowState.FullScreen && windowState != WindowState.Normal) { oldwindowState = WindowState.FullScreen; WindowStateChanged?.Invoke(); } } } if (windowState != WindowState.Minimized) { RECT rr = new RECT(0, 0, LOWORD((int)lParam), HIWORD((int)lParam)); //Debug.WriteLine("WM_SIZE:" + rr.Width + "," + rr.Height); //InvalidateRect(handle, ref rr, false); if (root != null) { Invalidate(new Rect(new Point(), root.ActualSize)); } //if (root != null) //{ //System.Diagnostics.Debug.WriteLine(rr); //root.Width = rr.Width / scaling; //root.Height = rr.Height / scaling; //root.ActualSize = rr; //root.LayoutManager.ExecuteLayoutPass(); //} if (!isLayered) { RedrawWindow(handle, ref rr, IntPtr.Zero, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN); //UpdateWindow(handle); //InvalidateRect(handle, ref rr, false); } } break; case WindowsMessage.WM_NCUAHDRAWCAPTION: case WindowsMessage.WM_NCUAHDRAWFRAME: return IntPtr.Zero; case WindowsMessage.WM_ERASEBKGND: return (IntPtr)1; //case WindowsMessage.WM_NCACTIVATE: case WindowsMessage.WM_NCPAINT: //DrawBoder(hwnd); var _hdc = GetDC(hwnd); OnPaint(_hdc, new Rect(new Point(), Bounds.Size)); ReleaseDC(hwnd, _hdc); return (IntPtr)1; case WindowsMessage.WM_PAINT: PAINTSTRUCT ps = new PAINTSTRUCT(); IntPtr hdc = BeginPaint(hwnd, out ps); if (ps.rcPaint.Width > 0 && ps.rcPaint.Height > 0) { OnPaint(hdc, new Rect(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.Width, ps.rcPaint.Height)); } EndPaint(hwnd, ref ps); break; case WindowsMessage.WM_SHOWWINDOW: //System.Diagnostics.Debug.WriteLine(wParam); //if (wParam == (IntPtr)1) //{ // root.Visibility = Visibility.Visible; //} //else //{ // root.Visibility = Visibility.Collapsed; //} break; case WindowsMessage.WM_POINTERDOWN: case WindowsMessage.WM_POINTERUP: case WindowsMessage.WM_POINTERUPDATE: if (!touchMsg) { var id = GetPointerId(wParam); var position = GetPointerLocation(lParam); position = PointToClient(position); //Debug.WriteLine("id:" + id + " " + position); POINTER_INFO pi = new POINTER_INFO(); if (GetPointerInfo(id, ref pi)) { switch ((WindowsMessage)msg) { case WindowsMessage.WM_POINTERDOWN: //Debug.WriteLine("down"); root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = id, Position = position }, root.InputManager.TouchDevice, Root), root.LayoutManager.VisibleUIElements, EventType.TouchDown); break; case WindowsMessage.WM_POINTERUP: //Debug.WriteLine("up"); root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = id, Position = position }, root.InputManager.TouchDevice, Root), root.LayoutManager.VisibleUIElements, EventType.TouchUp); //root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = id, Position = position }, root.InputManager.TouchDevice, Root), root.LayoutManager.VisibleUIElements, EventType.TouchLeave); break; case WindowsMessage.WM_POINTERUPDATE: //Debug.WriteLine("update"); root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = id, Position = position }, root.InputManager.TouchDevice, Root), root.LayoutManager.VisibleUIElements, EventType.TouchMove); break; } } } break; case WindowsMessage.WM_POINTERWHEEL: Debug.WriteLine("WM_POINTERWHEEL"); break; case WindowsMessage.WM_GESTURE: Debug.WriteLine("WM_GESTURE"); break; case WindowsMessage.WM_TOUCH: if (touchMsg) { var touchInputCount = wParam.ToInt32(); var pTouchInputs = stackalloc TOUCHINPUT[touchInputCount]; if (GetTouchInputInfo(lParam, (uint)touchInputCount, pTouchInputs, Marshal.SizeOf(typeof(TOUCHINPUT)))) { for (int i = 0; i < touchInputCount; i++) { var input = pTouchInputs[i]; if ((input.Flags & TouchInputFlags.TOUCHEVENTF_DOWN) > 0) { Root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = (int)input.Id, Position = new Point((float)(input.X * 0.01), (float)(input.Y * 0.01)) }, Root.InputManager.TouchDevice, Root), Root.LayoutManager.VisibleUIElements, EventType.TouchDown); } else if ((input.Flags & TouchInputFlags.TOUCHEVENTF_UP) > 0) { Root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = (int)input.Id, Position = new Point((float)(input.X * 0.01), (float)(input.Y * 0.01)) }, Root.InputManager.TouchDevice, Root), Root.LayoutManager.VisibleUIElements, EventType.TouchUp); } else if ((input.Flags & TouchInputFlags.TOUCHEVENTF_MOVE) > 0) { Root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = (int)input.Id, Position = new Point((float)(input.X * 0.01), (float)(input.Y * 0.01)) }, Root.InputManager.TouchDevice, Root), Root.LayoutManager.VisibleUIElements, EventType.TouchMove); } } CloseTouchInputHandle(lParam); return IntPtr.Zero; } } break; case UnmanagedMethods.WindowsMessage.WM_CLOSE: bool? preventClosing = Closing?.Invoke(); if (preventClosing == true) { return IntPtr.Zero; } if (_parent != null) { //EnableWindow(_parent.handle, true); //_parent.SetEnable(true); _parent.Activate(); SetFocus(_parent.handle); SetWindowLongPtr(handle, (int)WindowLongParam.GWL_HWNDPARENT, IntPtr.Zero); //_parent.SetVisible(true); _parent = null; } break; case WindowsMessage.WM_DESTROY: if (handle != IntPtr.Zero) { try { RevokeDragDrop(handle); } catch (Exception e) { Debug.WriteLine(e.Message); } } if (imeCentext != IntPtr.Zero) { ImmReleaseContext(handle, imeCentext); if (createimeCentext) { ImmDestroyContext(imeCentext); } imeCentext = IntPtr.Zero; } if (ismain) { PostQuitMessage(0); } timer?.Dispose(); timer = null; wglContext?.Dispose(); wglContext = null; if (hBitmap != IntPtr.Zero) { DeleteObject(hBitmap); hBitmap = IntPtr.Zero; } //Dispose(); if (IconHandle != IntPtr.Zero) { DestroyIcon(IconHandle); IconHandle = IntPtr.Zero; } if (_className != null) { UnmanagedMethods.UnregisterClass(_className, ModuleHandle); _className = null; } if (RenderBitmap != null) { RenderBitmap.Dispose(); RenderBitmap = null; } handle = IntPtr.Zero; Closed?.Invoke(); foreach (var item in invokeQueue) { item.SendOrPostCallback(item.Data); item.ManualResetEvent.Set(); } if (ismain) { Window = null; } //GC.Collect(); break; } return DefWindowProc(hwnd, msg, wParam, lParam); } [DllImport("Native.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] public static extern void InitOpenGLWin(int width, int height, IntPtr pwin); [DllImport("Native.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] public static extern void ChangeOpenGLWinSize(int width, int height); /// /// 处理WindowProc /// public Func WndPro { get; set; } bool rendToBitmap; public bool RenderToBitmap { get { return rendToBitmap; } set { rendToBitmap = value; //if (value) //{ // if (!isLayered) // { // isLayered = true; // SetWindowLong(handle, (int)WindowLongParam.GWL_EXSTYLE, (uint)ExStyle); // ShowInTaskbar(false); // } //} } } /// /// RenderToBitmap=true,图像渲染到这个位图里,界面将不显示 /// public Bitmap RenderBitmap { get; private set; } public Action OnRenderedBitmap { get; set; } //int cc = 0; //void testPaint() //{ // OpenGl gl = new OpenGl(); // gl.Enable(OpenGl.GL_ALPHA_TEST); // gl.Enable(OpenGl.GL_DEPTH_TEST); // gl.Enable(OpenGl.GL_COLOR_MATERIAL); // gl.Enable(OpenGl.GL_LIGHTING); // gl.Enable(OpenGl.GL_LIGHT0); // gl.Enable(OpenGl.GL_BLEND); // gl.BlendFunc(OpenGl.GL_SRC_ALPHA, OpenGl.GL_ONE_MINUS_SRC_ALPHA); // gl.ClearColor(0, 0, 0, 0); // gl.Clear(OpenGl.GL_COLOR_BUFFER_BIT | OpenGl.GL_DEPTH_BUFFER_BIT); // gl.PushMatrix(); // gl.Color(0, 1, 1); // gl.Begin(OpenGl.GL_TRIANGLES); // Drawing Using Triangles // gl.Color(1.0f, 0.0f, 0.0f); // Set The Color To Red // gl.Vertex(0.0f, 1.0f, 0.0f); // Top // gl.Color(0.0f, 1.0f, 0.0f); // Set The Color To Green // gl.Vertex(-1.0f, -1.0f, 0.0f); // Bottom Left // gl.Color(0.0f, 0.0f, 1.0f); // Set The Color To Blue // gl.Vertex(1.0f, -1.0f, 0.0f); // Bottom Right // gl.End(); // gl.PopMatrix(); // gl.Flush(); //} void OnPaint(IntPtr hdc, Rect rect) { if (handle == IntPtr.Zero) { return; } var r = this.Bounds; root.LayoutManager.ExecuteLayoutPass(); if (RenderToBitmap) { if (RenderBitmap == null || oldSize != r.Size) { oldSize = r.Size; if (RenderBitmap != null) { RenderBitmap.Dispose(); } RenderBitmap = new Bitmap((int)r.Width, (int)r.Height); } if (root.LayoutManager.VisibleUIElements != null) { using (DrawingContext dc = DrawingContext.FromBitmap(RenderBitmap)) { root.RenderView(dc, rect); //DrawRenderRectangle(dc); } } if (OnRenderedBitmap != null) { //Debug.WriteLine(r.Size); OnRenderedBitmap(); } } else { IntPtr screenDC = IntPtr.Zero; IntPtr memDc = IntPtr.Zero; var oldBits = IntPtr.Zero; if (isLayered || !useGPU) { screenDC = GetDC(IntPtr.Zero); memDc = CreateCompatibleDC(screenDC); if (oldSize != r.Size || hBitmap == IntPtr.Zero) { oldSize = r.Size; if (hBitmap != IntPtr.Zero) { DeleteObject(hBitmap); } BITMAPINFOHEADER info = new BITMAPINFOHEADER(); info.biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); info.biBitCount = 32; info.biHeight = -(int)r.Height; info.biWidth = (int)r.Width; info.biPlanes = 1; hBitmap = CreateDIBSection(memDc, ref info, 0, out ppvBits, IntPtr.Zero, 0); } oldBits = SelectObject(memDc, hBitmap); } //Stopwatch stopwatch = new Stopwatch(); //stopwatch.Start(); wglContext?.MakeCurrent(); if (root.LayoutManager.VisibleUIElements != null) { IRenderTarget rt = new HDCRenderTarget((isLayered || !useGPU) ? memDc : hdc, (int)Bounds.Width, (int)Bounds.Height, !isLayered); if (wglContext != null) { wglContext.GetFramebufferInfo(out var fb, out var sam, out var sten); rt = new OpenGlRenderTarget(hdc, wglContext, (int)Bounds.Width, (int)Bounds.Height, fb, sam, sten); } //Console.WriteLine(rt + " " + isLayered + " " + useGPU + " " + memDc); using (DrawingContext dc = DrawingContext.FromRenderTarget(rt)) { root.RenderView(dc, rect); //DrawRenderRectangle(dc); } //testPaint(); } wglContext?.SwapBuffers(); //stopwatch.Stop(); //Debug.WriteLine(stopwatch.ElapsedMilliseconds); if (hdc != IntPtr.Zero) { //AlphaBlend(hdc, (int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height, memDc, (int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height, new BLENDFUNCTION { SourceConstantAlpha = 255, AlphaFormat = 1 }); if (!useGPU) { BitBlt(hdc, (int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height, memDc, (int)rect.X, (int)rect.Y, TernaryRasterOperations.SRCCOPY); } } else { if (isLayered) { if (windowState != WindowState.Minimized) { //Stopwatch stopwatch = new Stopwatch(); //stopwatch.Start(); BLENDFUNCTION blendFunc = new BLENDFUNCTION(); blendFunc.BlendOp = 0; blendFunc.SourceConstantAlpha = 255; blendFunc.AlphaFormat = 1; blendFunc.BlendFlags = 0; POINT topLoc = new POINT((int)r.Left, (int)r.Top); SIZE bitMapSize = new SIZE((int)r.Width, (int)r.Height); POINT srcLoc = new POINT(0, 0); var rr = UpdateLayeredWindow(handle, screenDC, ref topLoc, ref bitMapSize, memDc, ref srcLoc, 0, ref blendFunc, 2); //stopwatch.Stop(); //Debug.WriteLine(stopwatch.ElapsedMilliseconds); } } else { //UpdateWindow(handle); } } if (isLayered || !useGPU) { SelectObject(memDc, oldBits); ReleaseDC(IntPtr.Zero, screenDC); DeleteDC(memDc); } } } //private void DrawRenderRectangle(DrawingContext dc) //{ // if (renderRectElement != null) // { // var rect1 = renderRectElement.GetContentBounds(); // var points = new List(); // points.Add(new Point()); // points.Add(new Point((float)Math.Round(rect1.Width * scaling) / scaling, 0)); // points.Add(new Point((float)Math.Round(rect1.Width * scaling) / scaling, (float)Math.Round(rect1.Height * scaling) / scaling)); // points.Add(new Point(0, (float)Math.Round(rect1.Height * scaling) / scaling)); // for (int i = 0; i < points.Count; i++) // { // points[i] = renderRectElement.TransformPoint(points[i]); // } // var p = renderRectElement.Parent; // while (p != null && !p.IsRoot) // { // for (int i = 0; i < points.Count; i++) // { // points[i] = p.TransformPoint(points[i]); // } // p = p.Parent; // } // using (var brush = new SolidColorBrush(Color.FromRgb(255, 0, 0))) // { // var stroke = new Stroke(1); // for (int i = 0; i < points.Count; i++) // { // dc.DrawLine(stroke, brush, points[i] * scaling, points[i == 3 ? 0 : (i + 1)] * scaling); // } // } // } //} private Point PointFromLParam(IntPtr lParam) { return new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)); } public Point PointToClient(Point point) { var p = new POINT { X = (int)point.X, Y = (int)point.Y }; UnmanagedMethods.ScreenToClient(handle, ref p); return new Point(p.X, p.Y) / scaling; } //private Point DipFromLParam(IntPtr lParam) //{ // //var rect = WindowPixelRectangle; // Debug.WriteLine((ToInt32(lParam) & 0xffff)); // return new Point((ToInt32(lParam) & 0xffff), (ToInt32(lParam) >> 16)) / scaling; //} private Point DipFromLParam(IntPtr lParam) { return new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)) / RenderScaling; } public static int ToInt32(IntPtr ptr) { if (IntPtr.Size == 4) return ptr.ToInt32(); return (int)(ptr.ToInt64() & 0xffffffff); } public static int SignedHIWORD(int n) { int i = (int)(short)((n >> 16) & 0xffff); return i; } public static int SignedLOWORD(int n) { int i = (int)(short)(n & 0xFFFF); return i; } public static int SignedHIWORD(IntPtr n) { return SignedHIWORD(unchecked((int)(long)n)); } public static int SignedLOWORD(IntPtr n) { return SignedLOWORD(unchecked((int)(long)n)); } public bool IsTouch() { uint extra = GetMessageExtraInfo(); bool isTouchOrPen = ((extra & 0xFFFFFF00) == 0xFF515700); if (!isTouchOrPen) return false; bool isTouch = ((extra & 0x00000080) == 0x00000080); return isTouch; } public static int GetPointerId(IntPtr WParam) { return (short)WParam; } public static Point GetPointerLocation(IntPtr LParam) { var lowword = LParam.ToInt32(); return new Point() { X = (short)(lowword), Y = (short)(lowword >> 16), }; } private bool IsDown(Keys key) { return (GetKeyStates(key) & KeyStates.Down) != 0; } byte[] _keyStates = new byte[256]; private KeyStates GetKeyStates(Keys key) { int vk = KeyInterop.VirtualKeyFromKey(key); byte state = _keyStates[vk]; KeyStates result = 0; if ((state & 0x80) != 0) { result |= KeyStates.Down; } if ((state & 0x01) != 0) { result |= KeyStates.Toggled; } return result; } [Flags] public enum KeyStates : byte { None = 0, Down = 1, Toggled = 2, } InputModifiers GetMouseModifiers(IntPtr wParam) { GetKeyboardState(_keyStates); var keys = (ModifierKeys)ToInt32(wParam); //var modifiers = InputManager.KeyboardDevice.Modifiers; var modifiers = InputModifiers.None; if (keys.HasFlag(ModifierKeys.MK_LBUTTON)) modifiers |= InputModifiers.LeftMouseButton; if (keys.HasFlag(ModifierKeys.MK_RBUTTON)) modifiers |= InputModifiers.RightMouseButton; if (keys.HasFlag(ModifierKeys.MK_MBUTTON)) modifiers |= InputModifiers.MiddleMouseButton; if (keys.HasFlag(ModifierKeys.MK_CONTROL)) modifiers |= InputModifiers.Control; if (keys.HasFlag(ModifierKeys.MK_SHIFT)) modifiers |= InputModifiers.Shift; if (keys.HasFlag(ModifierKeys.MK_ALT) || IsDown(Keys.LeftAlt) || IsDown(Keys.RightAlt)) modifiers |= InputModifiers.Alt;//因为wParam获取不到alt键 return modifiers; } /// /// 窗体位置和尺寸,屏幕像素 /// public Rect Bounds { get { RECT r = new RECT(); GetWindowRect(handle, out r); return new Rect(r.left, r.top, r.Width, r.Height); } set { //bounds = value; if (ScalingChangedPosition.HasValue) { SetWindowPos(handle, IntPtr.Zero, ScalingChangedPosition.Value.X, ScalingChangedPosition.Value.Y, (int)value.Width, (int)value.Height, SetWindowPosFlags.SWP_NOACTIVATE); } else { SetWindowPos(handle, IntPtr.Zero, (int)value.Left, (int)value.Top, (int)value.Width, (int)value.Height, SetWindowPosFlags.SWP_NOACTIVATE); } } } //Rect? bounds; public PixelPoint Position { get { RECT r = new RECT(); GetWindowRect(handle, out r); return new PixelPoint(r.left, r.top); } set { RECT r = new RECT(); GetWindowRect(handle, out r); //bounds = new Rect(value.X, value.Y, r.Width, r.Height); SetWindowPos(handle, IntPtr.Zero, value.X, value.Y, r.Width, r.Height, SetWindowPosFlags.SWP_NOACTIVATE); } } public WindowState WindowState { get { var placement = default(UnmanagedMethods.WINDOWPLACEMENT); UnmanagedMethods.GetWindowPlacement(handle, ref placement); switch (placement.ShowCmd) { case ShowWindowCommand.ShowMaximized: if (windowState == WindowState.FullScreen) { return windowState; } return WindowState.Maximized; case ShowWindowCommand.ShowMinimized: return WindowState.Minimized; default: return WindowState.Normal; } } set { windowState = value; if (UnmanagedMethods.IsWindowVisible(handle)) { SetVisible(true); } } } private static bool multiMonitorSupport = (GetSystemMetrics(SystemMetric.SM_CMONITORS) != 0); private const int PRIMARY_MONITOR = unchecked((int)0xBAADF00D); public Screen Screen { get { if (multiMonitorSupport) { var sc = MonitorFromWindow(handle, MONITOR.MONITOR_DEFAULTTONEAREST); return ScreenImpl.FromMonitor(sc, IntPtr.Zero); } else { return ScreenImpl.FromMonitor((IntPtr)PRIMARY_MONITOR, IntPtr.Zero); } } } bool canActivate = true; public bool CanActivate { get { return canActivate; } set { if (canActivate != value) { canActivate = value; if (!value) { SetWindowLongPtr(handle, (int)WindowLongParam.GWL_EXSTYLE, (IntPtr)(ExStyle | WindowStyles.WS_EX_NOACTIVATE)); SetWindowLongPtr(handle, (int)WindowLongParam.GWL_STYLE, (IntPtr)(Style | WindowStyles.WS_CHILD)); } else { SetWindowLongPtr(handle, (int)WindowLongParam.GWL_EXSTYLE, (IntPtr)(ExStyle)); SetWindowLongPtr(handle, (int)WindowLongParam.GWL_STYLE, (IntPtr)(Style)); } } } } private void WmGetMinMaxInfo(IntPtr handle, IntPtr lParam) { // MINMAXINFO structure MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); // Get handle for nearest monitor to this window //WindowInteropHelper wih = new WindowInteropHelper(this); IntPtr hMonitor = MonitorFromWindow(handle, MONITOR.MONITOR_DEFAULTTONEAREST); // Get monitor info MONITORINFO monitorInfo = new MONITORINFO(); monitorInfo.cbSize = Marshal.SizeOf(monitorInfo); GetMonitorInfo(hMonitor, ref monitorInfo); //// Get HwndSource //HwndSource source = HwndSource.FromHwnd(wih.Handle); //if (source == null) // // Should never be null // throw new Exception("Cannot get HwndSource instance."); //if (source.CompositionTarget == null) // // Should never be null // throw new Exception("Cannot get HwndTarget instance."); //// Get transformation matrix //Matrix matrix = source.CompositionTarget.TransformFromDevice; // Convert working area RECT workingArea = monitorInfo.rcWork; //Point dpiIndependentSize = // matrix.Transform(new Point( // workingArea.Right - workingArea.Left, // workingArea.Bottom - workingArea.Top // )); //// Convert minimum size //Point dpiIndenpendentTrackingSize = matrix.Transform(new Point( // this.MinWidth, // this.MinHeight // )); // Set the maximized size of the window //mmi.ptMaxSize.x = (int)dpiIndependentSize.X; //mmi.ptMaxSize.y = (int)dpiIndependentSize.Y; if (windowState == WindowState.FullScreen) { mmi.ptMaxSize.X = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left; mmi.ptMaxSize.Y = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top; } else { mmi.ptMaxSize.X = workingArea.right - workingArea.left; mmi.ptMaxSize.Y = workingArea.bottom - workingArea.top; } ////mmi.ptMaxTrackSize.x = 1370; ////mmi.ptMaxTrackSize.y = 772; //// Set the position of the maximized window mmi.ptMaxPosition.X = windowState == WindowState.FullScreen ? 0 : workingArea.left - monitorInfo.rcMonitor.left; mmi.ptMaxPosition.Y = windowState == WindowState.FullScreen ? 0 : workingArea.top - monitorInfo.rcMonitor.top; // Set the minimum tracking size //mmi.ptMinTrackSize.X = 1;//(int)dpiIndenpendentTrackingSize.X; //mmi.ptMinTrackSize.Y = 1;//(int)dpiIndenpendentTrackingSize.Y; mmi.ptMinTrackSize.X = 0; mmi.ptMinTrackSize.Y = 0; Marshal.StructureToPtr(mmi, lParam, true); } public void SetCursor(Cursor cursor) { var hCursor = (IntPtr)cursor.PlatformCursor == IntPtr.Zero ? DefaultCursor : (IntPtr)cursor.PlatformCursor; UnmanagedMethods.SetClassLong(handle, UnmanagedMethods.ClassLongIndex.GCLP_HCURSOR, hCursor); //if (_owner.IsPointerOver) // UnmanagedMethods.SetCursor(hCursor); } public void SetRoot(View view) { root = view; root.LayoutUpdated += Root_LayoutUpdated; } private void Root_LayoutUpdated(object sender, RoutedEventArgs e) { var b = Bounds; var s = root.ActualSize; var l = root.ActualOffset; var src = root.Screen; if ((int)b.Width != (int)Math.Ceiling(s.Width * scaling) || (int)b.Height != (int)Math.Ceiling(s.Height * scaling) || (int)b.X != (int)(l.X * scaling + src.WorkingArea.X) || (int)b.Y != (int)(l.Y * scaling + src.WorkingArea.Y)) { Bounds = new Rect(l.X * scaling + src.WorkingArea.X, l.Y * scaling + src.WorkingArea.Y, (float)Math.Ceiling(s.Width * scaling), (float)Math.Ceiling(s.Height * scaling)); } //Debug.WriteLine("Root_LayoutUpdated" + s); } public float RenderScaling { get { return scaling; } } bool createimeCentext = false; IntPtr imeCentext; //public bool EnabledIME //{ // get { return ImmGetOpenStatus(imeCentext); } // set // { // ImmSetOpenStatus(imeCentext, value); // } //} public void SetIMEEnable(bool value) { ImmSetOpenStatus(imeCentext, value); if (IsTouch()) { string windir = Environment.GetEnvironmentVariable("WINDIR"); string osk = null; if (osk == null) { osk = System.IO.Path.Combine(System.IO.Path.Combine(windir, "sysnative"), "osk.exe"); if (!System.IO.File.Exists(osk)) osk = null; } if (osk == null) { osk = System.IO.Path.Combine(System.IO.Path.Combine(windir, "system32"), "osk.exe"); if (!System.IO.File.Exists(osk)) { osk = null; } } if (osk == null) osk = "osk.exe"; Process.Start(new ProcessStartInfo { UseShellExecute = true, FileName = osk }); } } bool ismain; public bool IsMain { get { return ismain; } set { ismain = value; if (value) { Window = this; } } } public void SetIMEPosition(Point point) { COMPOSITIONFORM cf = new COMPOSITIONFORM(); cf.dwStyle = 2; cf.ptCurrentPos = new POINT((int)(point.X * scaling), (int)(point.Y * scaling)); ImmSetCompositionWindow(imeCentext, ref cf); } public Point PointToScreen(Point point) { point *= scaling; var p = new POINT { X = (int)point.X, Y = (int)point.Y }; ClientToScreen(handle, ref p); return new Point(p.X, p.Y); } bool paint = false; Rect invalidateRect; public void Invalidate(in Rect rect) { Rect all = new Rect(new Point(), root.ActualSize);//控件区域 if ((all.Contains(rect) || rect.IntersectsWith(all) || all == rect || rect.Contains(all)) && !rect.IsEmpty && !all.IsEmpty) { //Debug.WriteLine(invalidateRect); if (invalidateRect.IsEmpty || rect.Contains(invalidateRect) || rect == invalidateRect)//如果更新区域大于原有失效区域,则当前失效区域设为更新区域 { invalidateRect = rect; } else if (invalidateRect.Contains(rect))//如果更新区域小于原来的失效区域,则失效区域不变 { } else if (invalidateRect.IsEmpty)//如果原来的失效区域为空 { invalidateRect = rect; } else {//如果两个区域没有关联或者相交 var minX = invalidateRect.X < rect.X ? invalidateRect.X : rect.X;//确定包含这两个矩形的最小矩形 var minY = invalidateRect.Y < rect.Y ? invalidateRect.Y : rect.Y; var maxW = (invalidateRect.Width + invalidateRect.X - minX) > (rect.Width + rect.X - minX) ? (invalidateRect.Width + invalidateRect.X - minX) : (rect.Width + rect.X - minX); var maxH = (invalidateRect.Height + invalidateRect.Y - minY) > (rect.Height + rect.Y - minY) ? (invalidateRect.Height + invalidateRect.Y - minY) : (rect.Height + rect.Y - minY); Rect min = new Rect(minX, minY, maxW, maxH); invalidateRect = min; } invalidateRect.Intersect(all);//最后失效区域为在控件区域里面的相交区域 } if (!paint && (timer == null))//&& isLayered { paint = true; BeginInvoke(a => { root.LayoutManager.ExecuteLayoutPass(); Rect rect1 = new Rect(((invalidateRect.X - 1) * scaling), ((invalidateRect.Y - 1) * scaling), ((invalidateRect.Width + 2) * scaling), ((invalidateRect.Height + 2) * scaling)); if (isLayered) { OnPaint(IntPtr.Zero, rect1); } else { RECT r = new RECT(rect1); //InvalidateRect(handle, ref r, false); RedrawWindow(handle, ref r, IntPtr.Zero, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW); } //System.Diagnostics.Debug.WriteLine(invalidateRect); invalidateRect = new Rect(); paint = false; }, null); } //if (timer == null && !isLayered) //{ // RECT r = new RECT((int)((rect.X - 1) * scaling), (int)((rect.Y - 1) * scaling), (int)((rect.Right + 2) * scaling), (int)((rect.Bottom + 2) * scaling)); // InvalidateRect(handle, ref r, false); //} } private void Timer_Tick(object sender, EventArgs e) { if (handle != IntPtr.Zero && IsWindowVisible(handle) && windowState != WindowState.Minimized && invalidateRect.Width > 0 && invalidateRect.Height > 0) { root.LayoutManager.ExecuteLayoutPass(); Rect rect1 = new Rect(((invalidateRect.X - 1) * scaling), ((invalidateRect.Y - 1) * scaling), ((invalidateRect.Width + 2) * scaling), ((invalidateRect.Height + 2) * scaling)); if (isLayered) { OnPaint(IntPtr.Zero, rect1); } else { RECT r = new RECT(rect1); //InvalidateRect(handle, ref r, false); RedrawWindow(handle, ref r, IntPtr.Zero, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW); } //System.Diagnostics.Debug.WriteLine(invalidateRect); invalidateRect = new Rect(); } } public void Activate() { UnmanagedMethods.SetActiveWindow(handle); } public void Capture() { SetCapture(handle); } WindowImpl _parent; public void ShowDialog(Window parent) { _parent = (WindowImpl)parent.ViewImpl; Show(); SetWindowLongPtr(handle, (int)WindowLongParam.GWL_HWNDPARENT, _parent.handle); } public void ReleaseCapture() { UnmanagedMethods.ReleaseCapture(); } public void Show() { //_parent = null; root.Visibility = Visibility.Visible; //if (isFirst) //{ // isFirst = false; //root.LayoutManager.ExecuteLayoutPass(); } public void Hide() { root.Visibility = Visibility.Collapsed; } public void Close() { SendMessage(handle, (int)WindowsMessage.WM_CLOSE, IntPtr.Zero, IntPtr.Zero); } public void SetTitle(string title) { UnmanagedMethods.SetWindowText(handle, title); } bool _taskbarIcon = true; public void ShowInTaskbar(bool value) { if (_taskbarIcon == value) { return; } _taskbarIcon = value; var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(handle, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); style &= ~(UnmanagedMethods.WindowStyles.WS_VISIBLE); style |= UnmanagedMethods.WindowStyles.WS_EX_TOOLWINDOW; if (value) style |= UnmanagedMethods.WindowStyles.WS_EX_APPWINDOW; else style &= ~(UnmanagedMethods.WindowStyles.WS_EX_APPWINDOW); WINDOWPLACEMENT windowPlacement = UnmanagedMethods.WINDOWPLACEMENT.Default; if (UnmanagedMethods.GetWindowPlacement(handle, ref windowPlacement)) { //Toggle to make the styles stick UnmanagedMethods.ShowWindow(handle, ShowWindowCommand.Hide); UnmanagedMethods.SetWindowLong(handle, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE, (uint)style); UnmanagedMethods.ShowWindow(handle, windowPlacement.ShowCmd); } } public bool IsTopMost { get { return _topmost; } } bool _topmost = false; public void TopMost(bool value) { if (value == _topmost) { return; } IntPtr hWndInsertAfter = value ? WindowPosZOrder.HWND_TOPMOST : WindowPosZOrder.HWND_NOTOPMOST; UnmanagedMethods.SetWindowPos(handle, hWndInsertAfter, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE); _topmost = value; } public void Dispose() { if (handle != IntPtr.Zero) { var h = handle; handle = IntPtr.Zero; UnmanagedMethods.DestroyWindow(h); } //if (Window == this) //{ // Window = null; //} } public void SetVisible(bool visible) { //var v = IsWindowVisible(handle); if (visible) { if (windowState == WindowState.Normal) { root.LayoutManager.ExecuteLayoutPass(); invalidateRect = new Rect(new Point(), root.ActualSize); if (isLayered) { OnPaint(IntPtr.Zero, new Rect((invalidateRect.X - 1) * scaling, (invalidateRect.Y - 1) * scaling, (invalidateRect.Width + 2) * scaling, (invalidateRect.Height + 2) * scaling)); } else { //UpdateWindow(handle); } invalidateRect = new Rect(); if (canActivate) { ShowWindow(handle, ShowWindowCommand.Normal); } else { ShowWindow(handle, ShowWindowCommand.ShowNoActivate); } //if (_parent != null) //{ // //EnableWindow(_parent.handle, false); // _parent.SetEnable(false); //} if (this is PopupImpl) { SetWindowPos(handle, WindowPosZOrder.HWND_TOP, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE); } } else if (windowState == WindowState.Maximized || windowState == WindowState.FullScreen) { root.LayoutManager.ExecuteLayoutPass(); invalidateRect = new Rect(new Point(), root.ActualSize); if (isLayered) { OnPaint(IntPtr.Zero, new Rect((invalidateRect.X - 1) * scaling, (invalidateRect.Y - 1) * scaling, (invalidateRect.Width + 2) * scaling, (invalidateRect.Height + 2) * scaling)); } else { } invalidateRect = new Rect(); if (windowState == WindowState.FullScreen) { var placement = default(UnmanagedMethods.WINDOWPLACEMENT); UnmanagedMethods.GetWindowPlacement(handle, ref placement); if (placement.ShowCmd == ShowWindowCommand.ShowMaximized) { ShowWindow(handle, ShowWindowCommand.Normal); } } ShowWindow(handle, ShowWindowCommand.Maximize); //if (_parent != null) //{ // //EnableWindow(_parent.handle, false); // _parent.SetEnable(false); //} } else { ShowWindow(handle, ShowWindowCommand.Minimize); //if (_parent != null) //{ // //EnableWindow(_parent.handle, false); // _parent.SetEnable(false); //} } //if (bounds.HasValue) //{ // Bounds = bounds.Value; //} //Show(); } else if (!visible) { //Hide(); ShowWindow(handle, ShowWindowCommand.Hide); } } //private static int bitDepth; IntPtr IconHandle = IntPtr.Zero; public unsafe void SetIcon(Image image) { var stream = image.SaveToStream(ImageFormat.Png); var states = GdipCreateBitmapFromStream(new GPStream(stream), out IntPtr bitmap); stream.Dispose(); GdipCreateHICONFromBitmap(bitmap, out IntPtr hIcon); GdipDisposeImage(bitmap); if (IconHandle != IntPtr.Zero) { DestroyIcon(IconHandle); } IconHandle = hIcon; PostMessage(handle, (int)WindowsMessage.WM_SETICON, new IntPtr((int)Icons.ICON_BIG), hIcon); } private unsafe short GetShort(byte* pb) { int retval = 0; if (0 != (unchecked((byte)pb) & 1)) { retval = *pb; pb++; retval = unchecked(retval | (*pb << 8)); } else { retval = unchecked((int)(*(short*)pb)); } return unchecked((short)retval); } private unsafe int GetInt(byte* pb) { int retval = 0; if (0 != (unchecked((byte)pb) & 3)) { retval = *pb; pb++; retval = retval | (*pb << 8); pb++; retval = retval | (*pb << 16); pb++; retval = unchecked(retval | (*pb << 24)); } else { retval = *(int*)pb; } return retval; } //bool fullscreen; //public void SetFullscreen(bool fullscreen) //{ // this.fullscreen = fullscreen; // if (fullscreen) // { // WindowState = WindowState.Maximized; // } // else // { // if (WindowState == WindowState.Maximized) // { // WindowState = WindowState.Normal; // } // } //} bool isEnable = true; public void SetEnable(bool enable) { isEnable = enable; //EnableWindow(handle, enable); } public float LayoutScaling { get { return scaling; } } } class PopupImpl : WindowImpl, IPopupImpl { protected override WindowStyles Style { get { return WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_POPUP; }// | WindowStyles.WS_MAXIMIZEBOX } protected override WindowStyles ExStyle { get { var style = WindowStyles.WS_EX_TOOLWINDOW | WindowStyles.WS_EX_TOPMOST; if (isLayered) { style |= WindowStyles.WS_EX_LAYERED; } return style; } } protected override IntPtr WndProc(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam) { switch ((WindowsMessage)msg) { case WindowsMessage.WM_ACTIVATE: var wa = (WindowActivate)(ToInt32(wParam) & 0xffff); switch (wa) { case WindowActivate.WA_INACTIVE: break; } break; default: break; } return base.WndProc(hwnd, msg, wParam, lParam); } } public class SendOrPostData { public SendOrPostCallback SendOrPostCallback; public object Data; public ManualResetEvent ManualResetEvent; } }