private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case NativeMethods.WM_SETTEXT: case NativeMethods.WM_SETICON: { bool modified = ModifyStyle(NativeMethods.WS_VISIBLE, 0); // Setting the caption text and icon cause Windows to redraw the caption. // Letting the default WndProc handle the message without the WS_VISIBLE // style applied bypasses the redraw. IntPtr lRet = NativeMethods.DefWindowProc(handle, msg, wParam, lParam); // Put back the style we removed. if (modified) { ModifyStyle(0, NativeMethods.WS_VISIBLE); } handled = true; return lRet; } case NativeMethods.WM_NCACTIVATE: { // Despite MSDN's documentation of lParam not being used, // calling DefWindowProc with lParam set to -1 causes Windows not to draw over the caption. // Directly call DefWindowProc with a custom parameter // which bypasses any other handling of the message. IntPtr lRet = NativeMethods.DefWindowProc(handle, NativeMethods.WM_NCACTIVATE, wParam, new IntPtr(-1)); IsNonClientAreaActive = (wParam != IntPtr.Zero); handled = true; return lRet; } case NativeMethods.WM_NCCALCSIZE: { if (WindowState == WindowState.Maximized) { NativeMethods.APPBARDATA abd = new NativeMethods.APPBARDATA(); int temp = NativeMethods.SHAppBarMessage(4, ref abd); if (temp == 1) { NativeMethods.NCCALCSIZE_PARAMS ncParams = (NativeMethods.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(lParam, typeof(NativeMethods.NCCALCSIZE_PARAMS)); ncParams.rect0.Bottom -= 9; Marshal.StructureToPtr(ncParams, lParam, false); } } handled = true; return new IntPtr(NativeMethods.WVR_REDRAW); } case NativeMethods.WM_NCHITTEST: { return DoHitTest(msg, wParam, lParam, out handled); } case NativeMethods.WM_NCRBUTTONUP: { // Emulate the system behavior of clicking the right mouse button over the caption area // to bring up the system menu. if (NativeMethods.HTCAPTION == wParam.ToInt32()) { ShowSystemMenuPhysicalCoordinates(new Point(NativeMethods.LowWord(lParam), NativeMethods.HiWord(lParam))); } handled = false; return IntPtr.Zero; } case NativeMethods.WM_SIZE: { const int SIZE_MAXIMIZED = 2; // Force when maximized. // We can tell what's happening right now, but the Window doesn't yet know it's // maximized. Not forcing this update will eventually cause the // default caption to be drawn. WindowState? state = null; if (wParam.ToInt32() == SIZE_MAXIMIZED) { state = WindowState.Maximized; } UpdateSystemMenu(state); // Still let the default WndProc handle this. handled = false; return IntPtr.Zero; } case NativeMethods.WM_WINDOWPOSCHANGED: { if (!IsDwmEnabled) { var wp = (NativeMethods.WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(NativeMethods.WINDOWPOS)); //ModifyStyle(NativeMethods.WS_VISIBLE, 0); SetRoundingRegion(wp); //ModifyStyle(0, NativeMethods.WS_VISIBLE); } // Still want to pass this to DefWndProc handled = false; return IntPtr.Zero; } case NativeMethods.WM_DWMCOMPOSITIONCHANGED: { IsDwmEnabled = NativeMethods.IsDwmEnabled(); UpdateFrameState(false); handled = false; return IntPtr.Zero; } } if (FrameworkHelper.PresentationFrameworkVersion < new Version("4.0")) { switch (msg) { case NativeMethods.WM_SETTINGCHANGE: { FixFrameworkIssues(); handled = false; return IntPtr.Zero; } case NativeMethods.WM_ENTERSIZEMOVE: { isUserResizing = true; if (WindowState != WindowState.Maximized) { // Check for the docked window case. The window can still be restored when it's in this position so // try to account for that and not update the start position. if (!IsWindowDocked) { windowPosAtStartOfUserMove = new Point(Left, Top); } // Realistically we also don't want to update the start position when moving from one docked state to another (or to and from maximized), // but it's tricky to detect and this is already a workaround for a bug that's fixed in newer versions of the framework. // Not going to try to handle all cases. } handled = false; return IntPtr.Zero; } case NativeMethods.WM_EXITSIZEMOVE: { isUserResizing = false; // On Win7 the user can change the Window's state by dragging the window to the top of the monitor. // If they did that, then we need to try to update the restore bounds or else WPF will put the window at the maximized location (e.g. (-8,-8)). if (WindowState == WindowState.Maximized) { Top = windowPosAtStartOfUserMove.Y; Left = windowPosAtStartOfUserMove.X; } handled = false; return IntPtr.Zero; } case NativeMethods.WM_MOVE: { if (isUserResizing) { hasUserMovedWindow = true; } handled = false; return IntPtr.Zero; } } } return IntPtr.Zero; }
private void FixClientRect(IntPtr lParam) { if (WindowState == WindowState.Maximized) { var abd = new NativeMethods.APPBARDATA(); var temp = NativeMethods.SHAppBarMessage(4, ref abd); if (temp == 1) { var ncParams = (NativeMethods.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(lParam, typeof(NativeMethods.NCCALCSIZE_PARAMS)); ncParams.rect0.Bottom -= 9; Marshal.StructureToPtr(ncParams, lParam, false); } } // below code should fix issue 18229, but causes the minimize, restore and close button to be unreachable when window is maximized ////// Fixes the client rect to render edge to edge on one display if maximized ////// Issue fixed with this method: ////// http://fluent.codeplex.com/workitem/18229 ////// "When maximized, client area goes 8px offscreen, killing perf on multimonitor" ////if (this.WindowState == WindowState.Maximized) ////{ //// var ncParams = (NativeMethods.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(lParam, typeof(NativeMethods.NCCALCSIZE_PARAMS)); //// ncParams.rect0.Left += 8; //// ncParams.rect0.Top += 8; //// ncParams.rect0.Right -= 8; //// ncParams.rect0.Bottom -= 8; //// Marshal.StructureToPtr(ncParams, lParam, false); //// if (VisualTreeHelper.GetChildrenCount(this) != 0) //// { //// var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(this, 0); //// rootElement.Margin = new Thickness(-8); //// } ////} ////else ////{ //// if (VisualTreeHelper.GetChildrenCount(this) != 0) //// { //// var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(this, 0); //// rootElement.Margin = new Thickness(0); //// } ////} }