CPF/CPF.Windows/WindowImpl.cs

1938 lines
78 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<SendOrPostData> invokeQueue = new ConcurrentQueue<SendOrPostData>();
public ConcurrentQueue<SendOrPostData> asyncQueue = new ConcurrentQueue<SendOrPostData>();
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必须设置线程STAMain方法上加[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(out var e) == 0 && e == 1 && !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<PixelPoint> PositionChanged { get; set; }
public event Action Move;
public Action<Size> Resized { get; set; }
public Action WindowStateChanged { get; set; }
public Action ScalingChanged { get; set; }
public Action Activated { get; set; }
public Func<bool> 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;
/// <summary>
/// 为了防止多屏幕拖动的时候抖动
/// </summary>
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<UnmanagedMethods.RECT>(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<TRACKMOUSEEVENT>(),
#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:
Closed?.Invoke();
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;
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);
/// <summary>
/// 处理WindowProc
/// </summary>
public Func<IntPtr, WindowsMessage, IntPtr, IntPtr, IntPtr?> 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);
// }
//}
}
}
/// <summary>
/// RenderToBitmap=true图像渲染到这个位图里界面将不显示
/// </summary>
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<IntPtr>(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<Point>();
// 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;
}
/// <summary>
/// 窗体位置和尺寸,屏幕像素
/// </summary>
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)
{
if (canActivate && GetFocus() != handle)
{
SetFocus(handle);
}
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;
}
}