protected override void WndProc(ref Message m) { switch (m.Msg) { case NativeMethods.WM_COMMAND + NativeMethods.WM_REFLECT: WmReflectCommand(ref m); break; case NativeMethods.WM_NOTIFY: case NativeMethods.WM_NOTIFY + NativeMethods.WM_REFLECT: NativeMethods.NMHDR note = (NativeMethods.NMHDR) m.GetLParam(typeof(NativeMethods.NMHDR)); switch (note.code) { case NativeMethods.TTN_NEEDTEXTA: // MSDN: // Setting the max width has the added benefit of enabling multiline // tool tips! // // [....]: temporarily commenting out this code to fix Pri0 bug 152233 // UnsafeNativeMethods.SendMessage(new HandleRef(note, note.hwndFrom), NativeMethods.TTM_SETMAXTIPWIDTH, 0, SystemInformation.MaxWindowTrackSize.Width); WmNotifyNeedTextA(ref m); m.Result = (IntPtr)1; return; case NativeMethods.TTN_NEEDTEXTW: // On Win 98/IE 5,we still get W messages. If we ignore them, it will send the A version. if (Marshal.SystemDefaultCharSize == 2) { // MSDN: // Setting the max width has the added benefit of enabling multiline // tool tips! // // [....]: temporarily commenting out this code to fix Pri0 bug 152233 // UnsafeNativeMethods.SendMessage(new HandleRef(note, note.hwndFrom), NativeMethods.TTM_SETMAXTIPWIDTH, 0, SystemInformation.MaxWindowTrackSize.Width); WmNotifyNeedText(ref m); m.Result = (IntPtr)1; return; } break; case NativeMethods.TTN_SHOW: // VSWhidbey 177016: Prevent the tooltip from displaying in the upper left corner of the // desktop when the control is nowhere near that location. NativeMethods.WINDOWPLACEMENT wndPlacement = new NativeMethods.WINDOWPLACEMENT(); int nRet = UnsafeNativeMethods.GetWindowPlacement(new HandleRef(null, note.hwndFrom), ref wndPlacement); // Is this tooltip going to be positioned in the upper left corner of the display, // but nowhere near the toolbar button? if (wndPlacement.rcNormalPosition_left == 0 && wndPlacement.rcNormalPosition_top == 0 && this.hotItem != -1) { // Assume that we're going to vertically center the tooltip on the right edge of the current // hot item. // Where is the right edge of the current hot item? int buttonRight = 0; for(int idx = 0; idx <= this.hotItem; idx++) { // How wide is the item at this index? (It could be a separator, and therefore a different width.) buttonRight += buttonsCollection[idx].GetButtonWidth(); } // Where can we place this tooltip so that it will be completely visible on the current display? int tooltipWidth = wndPlacement.rcNormalPosition_right - wndPlacement.rcNormalPosition_left; int tooltipHeight = wndPlacement.rcNormalPosition_bottom - wndPlacement.rcNormalPosition_top; // We'll need screen coordinates of this position for setting the tooltip's position int x = this.Location.X + buttonRight + 1; int y = this.Location.Y + (this.ButtonSize.Height / 2); NativeMethods.POINT leftTop = new NativeMethods.POINT(x, y); UnsafeNativeMethods.ClientToScreen(new HandleRef(this, this.Handle), leftTop); // Will the tooltip bleed off the top? if (leftTop.y < SystemInformation.WorkingArea.Y) { // Reposition the tooltip to be displayed below the button leftTop.y += (this.ButtonSize.Height / 2) + 1; } // Will the tooltip bleed off the bottom? if (leftTop.y + tooltipHeight > SystemInformation.WorkingArea.Height) { // Reposition the tooltip to be displayed above the button leftTop.y -= ((this.ButtonSize.Height / 2) + tooltipHeight + 1); } // Will the tooltip bleed off the right edge? if (leftTop.x + tooltipWidth > SystemInformation.WorkingArea.Right) { // Move the tooltip far enough left that it will display in the working area leftTop.x -= (this.ButtonSize.Width + tooltipWidth + 2); } SafeNativeMethods.SetWindowPos(new HandleRef(null, note.hwndFrom), NativeMethods.NullHandleRef, leftTop.x, leftTop.y, 0, 0, NativeMethods.SWP_NOSIZE | NativeMethods.SWP_NOZORDER | NativeMethods.SWP_NOACTIVATE); m.Result = (IntPtr)1; return; } break; case NativeMethods.TBN_HOTITEMCHANGE: WmNotifyHotItemChange(ref m); break; case NativeMethods.TBN_QUERYINSERT: m.Result = (IntPtr)1; break; case NativeMethods.TBN_DROPDOWN: WmNotifyDropDown(ref m); break; } break; } base.WndProc(ref m); }
/// <devdoc> /// Updated the window state from the handle, if created. /// </devdoc> /// <internalonly/> // // This function is called from all over the place, including my personal favorite, // WM_ERASEBKGRND. Seems that's one of the first messages we get when a user clicks the min/max // button, even before WM_WINDOWPOSCHANGED. private void UpdateWindowState() { if (IsHandleCreated) { FormWindowState oldState = WindowState; NativeMethods.WINDOWPLACEMENT wp = new NativeMethods.WINDOWPLACEMENT(); wp.length = Marshal.SizeOf(typeof(NativeMethods.WINDOWPLACEMENT)); UnsafeNativeMethods.GetWindowPlacement(new HandleRef(this, Handle), ref wp); switch (wp.showCmd) { case NativeMethods.SW_NORMAL: case NativeMethods.SW_RESTORE: case NativeMethods.SW_SHOW: case NativeMethods.SW_SHOWNA: case NativeMethods.SW_SHOWNOACTIVATE: if (formState[FormStateWindowState] != (int)FormWindowState.Normal) { formState[FormStateWindowState] = (int)FormWindowState.Normal; } break; case NativeMethods.SW_SHOWMAXIMIZED: if (formState[FormStateMdiChildMax] == 0) { formState[FormStateWindowState] = (int)FormWindowState.Maximized; } break; case NativeMethods.SW_SHOWMINIMIZED: case NativeMethods.SW_MINIMIZE: case NativeMethods.SW_SHOWMINNOACTIVE: if (formState[FormStateMdiChildMax] == 0) { formState[FormStateWindowState] = (int)FormWindowState.Minimized; } break; case NativeMethods.SW_HIDE: default: break; } // If we used to be normal and we just became minimized or maximized, // stash off our current bounds so we can properly restore. // if (oldState == FormWindowState.Normal && WindowState != FormWindowState.Normal) { if (WindowState == FormWindowState.Minimized) { SuspendLayoutForMinimize(); } restoredWindowBounds.Size = ClientSize; formStateEx[FormStateExWindowBoundsWidthIsClientSize] = 1; formStateEx[FormStateExWindowBoundsHeightIsClientSize] = 1; restoredWindowBoundsSpecified = BoundsSpecified.Size; restoredWindowBounds.Location = Location; restoredWindowBoundsSpecified |= BoundsSpecified.Location; //stash off restoreBounds As well... restoreBounds.Size = Size; restoreBounds.Location = Location; } // If we just became normal or maximized resume if (oldState == FormWindowState.Minimized && WindowState != FormWindowState.Minimized) { ResumeLayoutFromMinimize(); } switch (WindowState) { case FormWindowState.Normal: SetState(STATE_SIZELOCKEDBYOS, false); break; case FormWindowState.Maximized: case FormWindowState.Minimized: SetState(STATE_SIZELOCKEDBYOS, true); break; } if (oldState != WindowState) { AdjustSystemMenu(); } } }
/// <include file='doc\MDIClient.uex' path='docs/doc[@for="MdiClient.SetBoundsCore"]/*' /> /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) { ISite site = (ParentInternal == null) ? null : ParentInternal.Site; if (IsHandleCreated && (site == null || !site.DesignMode)) { Rectangle oldBounds = Bounds; base.SetBoundsCore(x, y, width, height, specified); Rectangle newBounds = Bounds; int yDelta = oldBounds.Height - newBounds.Height; if (yDelta != 0) { // NOTE: This logic is to keep minimized MDI children anchored to // the bottom left of the client area, normally they are anchored // to the top right which just looks wierd! // NativeMethods.WINDOWPLACEMENT wp = new NativeMethods.WINDOWPLACEMENT(); wp.length = Marshal.SizeOf(typeof(NativeMethods.WINDOWPLACEMENT)); for (int i=0; i < Controls.Count; i++) { Control ctl = Controls[i]; if (ctl != null && ctl is Form) { Form child = (Form)ctl; // VSWhidbey 93551: Only adjust the window position for visible MDI Child windows to prevent // them from being re-displayed. if (child.CanRecreateHandle() && child.WindowState == FormWindowState.Minimized) { UnsafeNativeMethods.GetWindowPlacement(new HandleRef(child, child.Handle), ref wp); wp.ptMinPosition_y -= yDelta; if (wp.ptMinPosition_y == -1) { if (yDelta < 0) { wp.ptMinPosition_y = 0; } else { wp.ptMinPosition_y = -2; } } wp.flags = NativeMethods.WPF_SETMINPOSITION; UnsafeNativeMethods.SetWindowPlacement(new HandleRef(child, child.Handle), ref wp); wp.flags = 0; } } } } } else { base.SetBoundsCore(x, y, width, height, specified); } }
internal override void RecreateHandleCore() { //Debug.Assert( CanRecreateHandle(), "Recreating handle when form is not ready yet." ); NativeMethods.WINDOWPLACEMENT wp = new NativeMethods.WINDOWPLACEMENT(); FormStartPosition oldStartPosition = FormStartPosition.Manual; if (!IsMdiChild && (WindowState == FormWindowState.Minimized || WindowState == FormWindowState.Maximized)) { wp.length = Marshal.SizeOf(typeof(NativeMethods.WINDOWPLACEMENT)); UnsafeNativeMethods.GetWindowPlacement(new HandleRef(this, Handle), ref wp); } if (StartPosition != FormStartPosition.Manual) { oldStartPosition = StartPosition; // Set the startup postion to manual, to stop the form from // changing position each time RecreateHandle() is called. StartPosition = FormStartPosition.Manual; } EnumThreadWindowsCallback etwcb = null; SafeNativeMethods.EnumThreadWindowsCallback callback = null; if (IsHandleCreated) { // First put all the owned windows into a list etwcb = new EnumThreadWindowsCallback(); if (etwcb != null) { callback = new SafeNativeMethods.EnumThreadWindowsCallback(etwcb.Callback); UnsafeNativeMethods.EnumThreadWindows(SafeNativeMethods.GetCurrentThreadId(), new NativeMethods.EnumThreadWindowsCallback(callback), new HandleRef(this, this.Handle)); // Reset the owner of the windows in the list etwcb.ResetOwners(); } } base.RecreateHandleCore(); if (etwcb != null) { // Set the owner of the windows in the list back to the new Form's handle etwcb.SetOwners(new HandleRef(this, this.Handle)); } if (oldStartPosition != FormStartPosition.Manual) { StartPosition = oldStartPosition; } if (wp.length > 0) { UnsafeNativeMethods.SetWindowPlacement(new HandleRef(this, Handle), ref wp); } if (callback != null) { GC.KeepAlive(callback); } }
/// <summary> /// Send mouse click to relative position in the client window. /// </summary> /// <param name="client">Target client.</param> /// <param name="button">System.Windows.Forms.MouseButtons to click.</param> /// <param name="x">X position of point to click relative to client window's X position.</param> /// <param name="y">Y position of point to click relative to client window's Y position.</param> /// <param name="doubleClick">True for double click, false for single click.</param> /// <returns>True on success.</returns> public static bool SendMouseClick(int client, MouseButtons button, int x, int y, bool doubleClick) { ClientInfo ci; if (ClientInfoCollection.GetClient(client, out ci)) { NativeMethods.INPUT[] inputs = new NativeMethods.INPUT[2]; NativeMethods.MOUSEINPUT mi = new NativeMethods.MOUSEINPUT(); inputs[0].type = NativeMethods.INPUT_MOUSE; inputs[1].type = NativeMethods.INPUT_MOUSE; mi.dx = 0; mi.dy = 0; switch (button) { case MouseButtons.None: return false; case MouseButtons.Left: mi.dwFlags = NativeMethods.MOUSEEVENTF_LEFTDOWN; inputs[0].mkhi.mi = mi; mi.dwFlags = NativeMethods.MOUSEEVENTF_LEFTUP; inputs[1].mkhi.mi = mi; break; case MouseButtons.Right: mi.dwFlags = NativeMethods.MOUSEEVENTF_RIGHTDOWN; inputs[0].mkhi.mi = mi; mi.dwFlags = NativeMethods.MOUSEEVENTF_RIGHTUP; inputs[1].mkhi.mi = mi; break; case MouseButtons.Middle: mi.dwFlags = NativeMethods.MOUSEEVENTF_MIDDLEDOWN; inputs[0].mkhi.mi = mi; mi.dwFlags = NativeMethods.MOUSEEVENTF_MIDDLEUP; inputs[1].mkhi.mi = mi; break; case MouseButtons.XButton1: mi.mouseData = NativeMethods.XBUTTON1; mi.dwFlags = NativeMethods.MOUSEEVENTF_XDOWN; inputs[0].mkhi.mi = mi; mi.dwFlags = NativeMethods.MOUSEEVENTF_XUP; inputs[1].mkhi.mi = mi; break; case MouseButtons.XButton2: mi.mouseData = NativeMethods.XBUTTON2; mi.dwFlags = NativeMethods.MOUSEEVENTF_XDOWN; inputs[0].mkhi.mi = mi; mi.dwFlags = NativeMethods.MOUSEEVENTF_XUP; inputs[1].mkhi.mi = mi; break; } if (!ci.PrepareWindowForInput()) { ci.DetachFromWindow(); return false; } NativeMethods.WINDOWPLACEMENT wp = new NativeMethods.WINDOWPLACEMENT(); if (NativeMethods.GetWindowPlacement(ci.WindowHandle, ref wp)) { /*int screenX = wp.rcNormalPosition.X + x; int screenY = wp.rcNormalPosition.Y + y; int absX = (screenX * 65536 / Screen.PrimaryScreen.Bounds.Width); int absY = (screenY * 65536 / Screen.PrimaryScreen.Bounds.Height); inputs[0].mkhi.mi.dx = absX; inputs[1].mkhi.mi.dx = absX; inputs[0].mkhi.mi.dy = absY; inputs[1].mkhi.mi.dy = absY;*/ // using this method because absolute position is always off by a pixel or 2 if (!NativeMethods.SetCursorPos(x + wp.rcNormalPosition.X, y + wp.rcNormalPosition.Y)) return false; } else return false; uint success = NativeMethods.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(inputs[0])); if (doubleClick && success == inputs.Length) { success = NativeMethods.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(inputs[0])); } ci.DetachFromWindow(); return success == inputs.Length; } return false; }