/// <summary> /// Override for the main forms WndProc method /// This is used to intercept the forms movement so that we can move /// blended background form at the same time, as well as check for /// when the form is activated so we can ensure the Z-order of our /// forms remains intact. /// </summary> /// <param name="m">Windows Message</param> protected override void WndProc(ref Message m) { if (this.DesignMode) { base.WndProc(ref m); return; } Win32.Message msgId = (Win32.Message)m.Msg; bool UseBase = true; switch (msgId) { case Win32.Message.WM_LBUTTONUP: { //Just in case if (Win32.GetCapture() != IntPtr.Zero) { Win32.ReleaseCapture(); } } break; case Win32.Message.WM_ENTERSIZEMOVE: { } break; case Win32.Message.WM_EXITSIZEMOVE: { //We've stopped dragging the form, so lets make sure that our values are correct m_isDown.Left = false; m_moving = false; if (m_enhanced) { this.SuspendLayout(); foreach (Control ctrl in m_hiddenControls) { ctrl.Visible = true; } m_hiddenControls.Clear(); this.ResumeLayout(); updateLayeredBackground(this.ClientSize.Width, this.ClientSize.Height, m_layeredWnd.LayeredPos, false); } } break; case Win32.Message.WM_MOUSEMOVE: //It's unlikely that we will get here unless this we really have captured the mouse //because the entire thing is transparent, but we check anyway just to make sure if (Win32.GetCapture() != IntPtr.Zero && m_moving) { //In enhanced mode we draw the main window to the layered window and then hide the main //window. This is so that we can have perfectly smooth motion when dragging the form, as //we cannot gurantee that the forms will ever be moved together otherwise if (m_enhanced) { //Setup the device contexts we are going to use IntPtr hdcScreen = Win32.GetWindowDC(m_layeredWnd.Handle); //Screen DC that the layered window will draw to IntPtr windowDC = Win32.GetDC(this.Handle); //Window DC that we are going to copy IntPtr memDC = Win32.CreateCompatibleDC(windowDC); //Temporary DC that we draw to IntPtr BmpMask = Win32.CreateBitmap(this.ClientSize.Width, this.ClientSize.Height, 1, 1, IntPtr.Zero); //Mask bitmap so that we only draw areas of the form that are visible Bitmap backImage = m_useBackgroundEx ? m_backgroundFull : m_background; IntPtr BmpBack = backImage.GetHbitmap(Color.FromArgb(0)); //Background Image //Create mask Win32.SelectObject(memDC, BmpMask); uint oldCol = Win32.SetBkColor(windowDC, 0x00FF00FF); Win32.BitBlt(memDC, 0, 0, this.ClientSize.Width, this.ClientSize.Height, windowDC, 0, 0, Win32.TernaryRasterOperations.SRCCOPY); Win32.SetBkColor(windowDC, oldCol); //Blit window to background image using mask //We need to use the SPno raster operation with a white brush to combine our window //with a black backround before putting it onto the 32-bit background image, otherwise //we end up with blending issues (source and destination colours are ANDed together) Win32.SelectObject(memDC, BmpBack); IntPtr brush = Win32.CreateSolidBrush(0x00FFFFFF); Win32.SelectObject(memDC, brush); Win32.MaskBlt(memDC, 0, 0, backImage.Width, backImage.Height, windowDC, 0, 0, BmpMask, 0, 0, 0xCFAA0020); //Win32.BitBlt(memDC, 0, 0, backImage.Width, backImage.Height, windowDC, m_offX, m_offY, Win32.TernaryRasterOperations.SRCCOPY); Point zero = new Point(0, 0); Size size = m_layeredWnd.LayeredSize; Point pos = m_layeredWnd.LayeredPos; Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION(); blend.AlphaFormat = (byte)Win32.BlendOps.AC_SRC_ALPHA; blend.BlendFlags = (byte)Win32.BlendFlags.None; blend.BlendOp = (byte)Win32.BlendOps.AC_SRC_OVER; blend.SourceConstantAlpha = (byte)(this.Opacity * 255); Win32.UpdateLayeredWindow(m_layeredWnd.Handle, hdcScreen, ref pos, ref size, memDC, ref zero, 0, ref blend, Win32.BlendFlags.ULW_ALPHA); //Clean up Win32.ReleaseDC(IntPtr.Zero, hdcScreen); Win32.ReleaseDC(this.Handle, windowDC); Win32.DeleteDC(memDC); Win32.DeleteObject(brush); Win32.DeleteObject(BmpMask); Win32.DeleteObject(BmpBack); //Hide controls that are visible this.SuspendLayout(); foreach (Control ctrl in this.Controls) { if (ctrl.Visible) { m_hiddenControls.Add(ctrl); ctrl.Visible = false; } } this.ResumeLayout(); } //If we do not release the mouse then Windows will not start dragging the form, also //it will mess up mouse input to any border on our form and other windows on the desktop Win32.ReleaseCapture(); Win32.SendMessage(this.Handle, (int)Win32.Message.WM_NCLBUTTONDOWN, (int)Win32.Message.HTCAPTION, 0); } break; case Win32.Message.WM_SIZE: { //The updateLayeredSize function will check the width and height //we pass in, so we don't need to worry about updating the window //with the same size it already had int width = m.LParam.ToInt32() & 0xFFFF; int height = m.LParam.ToInt32() >> 16; this.updateLayeredSize(width, height); } break; case Win32.Message.WM_WINDOWPOSCHANGING: { Win32.WINDOWPOS posInfo = (Win32.WINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(Win32.WINDOWPOS)); //We will cancel this movement, and send our own messages to position both forms //this way we can ensure that both forms are moved together and that //the Z order is unchanged. Win32.WindowPosFlags move_size = Win32.WindowPosFlags.SWP_NOMOVE | Win32.WindowPosFlags.SWP_NOSIZE; if ((posInfo.flags & move_size) != move_size) { //Check for my own messages, which I do by setting to hwndInsertAfter to our //own window, which from what I can gather only happens when you resize your //window, never when you move it if (posInfo.hwndInsertAfter != this.Handle) { IntPtr hwdp = Win32.BeginDeferWindowPos(2); if (hwdp != IntPtr.Zero) { hwdp = Win32.DeferWindowPos(hwdp, m_layeredWnd.Handle, this.Handle, posInfo.x + m_offX, posInfo.y + m_offY, 0, 0, (uint)(posInfo.flags | Win32.WindowPosFlags.SWP_NOSIZE | Win32.WindowPosFlags.SWP_NOZORDER)); } if (hwdp != IntPtr.Zero) { hwdp = Win32.DeferWindowPos(hwdp, this.Handle, this.Handle, posInfo.x, posInfo.y, posInfo.cx, posInfo.cy, (uint)(posInfo.flags | Win32.WindowPosFlags.SWP_NOZORDER)); } if (hwdp != IntPtr.Zero) { Win32.EndDeferWindowPos(hwdp); } m_layeredWnd.LayeredPos = new Point(posInfo.x + m_offX, posInfo.y + m_offY); //Update the flags so that the form will not move with this message posInfo.flags |= Win32.WindowPosFlags.SWP_NOMOVE; Marshal.StructureToPtr(posInfo, m.LParam, true); } if ((posInfo.flags & Win32.WindowPosFlags.SWP_NOSIZE) == 0) { //Form was also resized int diffX = posInfo.cx - this.Size.Width; int diffY = posInfo.cy - this.Size.Height; if (diffX != 0 || diffY != 0) { this.updateLayeredSize(this.ClientSize.Width + diffX, this.ClientSize.Height + diffY); } } UseBase = false; } } break; case Win32.Message.WM_ACTIVATE: { //If WParam is Zero then the form is deactivating and we don't need to do anything //Otherwise we need to make sure that the background form is positioned just behind //the main form. if (m.WParam != IntPtr.Zero) { //Check for any visible windows between the background and main windows IntPtr prevWnd = Win32.GetWindow(m_layeredWnd.Handle, Win32.GetWindow_Cmd.GW_HWNDPREV); while (prevWnd != IntPtr.Zero) { //If we find a visiable window, we stop if (Win32.IsWindowVisible(prevWnd)) { break; } prevWnd = Win32.GetWindow(prevWnd, Win32.GetWindow_Cmd.GW_HWNDPREV); } //If the visible window isn't ours reset the position of the background form if (prevWnd != this.Handle) { Win32.SetWindowPos(m_layeredWnd.Handle, this.Handle, 0, 0, 0, 0, (uint)(Win32.WindowPosFlags.SWP_NOSENDCHANGING | Win32.WindowPosFlags.SWP_NOACTIVATE | Win32.WindowPosFlags.SWP_NOSIZE | Win32.WindowPosFlags.SWP_NOMOVE)); } } } break; } if (UseBase) { base.WndProc(ref m); } }
protected override void WndProc(ref Message m) { if (this.DesignMode) { base.WndProc(ref m); return; } Win32.Message msgId = (Win32.Message)m.Msg; bool UseBase = true; switch (msgId) { case Win32.Message.WM_LBUTTONUP: { if (Win32.GetCapture() != IntPtr.Zero) { Win32.ReleaseCapture(); } } break; case Win32.Message.WM_ENTERSIZEMOVE: { } break; case Win32.Message.WM_EXITSIZEMOVE: { m_isDown.Left = false; m_moving = false; if (m_enhanced) { this.SuspendLayout(); foreach (Control ctrl in m_hiddenControls) { ctrl.Visible = true; } m_hiddenControls.Clear(); this.ResumeLayout(); updateLayeredBackground(this.ClientSize.Width, this.ClientSize.Height, m_layeredWnd.LayeredPos, false); } } break; case Win32.Message.WM_MOUSEMOVE: if (Win32.GetCapture() != IntPtr.Zero && m_moving) { if (m_enhanced) { IntPtr hdcScreen = Win32.GetWindowDC(m_layeredWnd.Handle); IntPtr windowDC = Win32.GetDC(this.Handle); IntPtr memDC = Win32.CreateCompatibleDC(windowDC); IntPtr BmpMask = Win32.CreateBitmap(this.ClientSize.Width, this.ClientSize.Height, 1, 1, IntPtr.Zero); Bitmap backImage = m_useBackgroundEx ? m_backgroundFull : m_background; IntPtr BmpBack = backImage.GetHbitmap(Color.FromArgb(0)); Win32.SelectObject(memDC, BmpMask); uint oldCol = Win32.SetBkColor(windowDC, 0x00FF00FF); Win32.BitBlt(memDC, 0, 0, this.ClientSize.Width, this.ClientSize.Height, windowDC, 0, 0, Win32.TernaryRasterOperations.SRCCOPY); Win32.SetBkColor(windowDC, oldCol); Win32.SelectObject(memDC, BmpBack); IntPtr brush = Win32.CreateSolidBrush(0x00FFFFFF); Win32.SelectObject(memDC, brush); Win32.MaskBlt(memDC, 0, 0, backImage.Width, backImage.Height, windowDC, 0, 0, BmpMask, 0, 0, 0xCFAA0020); Point zero = new Point(0, 0); Size size = m_layeredWnd.LayeredSize; Point pos = m_layeredWnd.LayeredPos; Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION(); blend.AlphaFormat = (byte)Win32.BlendOps.AC_SRC_ALPHA; blend.BlendFlags = (byte)Win32.BlendFlags.None; blend.BlendOp = (byte)Win32.BlendOps.AC_SRC_OVER; blend.SourceConstantAlpha = (byte)(this.Opacity * 255); Win32.UpdateLayeredWindow(m_layeredWnd.Handle, hdcScreen, ref pos, ref size, memDC, ref zero, 0, ref blend, Win32.BlendFlags.ULW_ALPHA); Win32.ReleaseDC(IntPtr.Zero, hdcScreen); Win32.ReleaseDC(this.Handle, windowDC); Win32.DeleteDC(memDC); Win32.DeleteObject(brush); Win32.DeleteObject(BmpMask); Win32.DeleteObject(BmpBack); this.SuspendLayout(); foreach (Control ctrl in this.Controls) { if (ctrl.Visible) { m_hiddenControls.Add(ctrl); ctrl.Visible = false; } } this.ResumeLayout(); } Win32.ReleaseCapture(); Win32.SendMessage(this.Handle, (int)Win32.Message.WM_NCLBUTTONDOWN, (int)Win32.Message.HTCAPTION, 0); } break; case Win32.Message.WM_SIZE: { int width = m.LParam.ToInt32() & 0xFFFF; int height = m.LParam.ToInt32() >> 16; this.updateLayeredSize(width, height); } break; case Win32.Message.WM_WINDOWPOSCHANGING: { Win32.WINDOWPOS posInfo = (Win32.WINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(Win32.WINDOWPOS)); Win32.WindowPosFlags move_size = Win32.WindowPosFlags.SWP_NOMOVE | Win32.WindowPosFlags.SWP_NOSIZE; if ((posInfo.flags & move_size) != move_size) { if (posInfo.hwndInsertAfter != this.Handle) { IntPtr hwdp = Win32.BeginDeferWindowPos(2); if (hwdp != IntPtr.Zero) { hwdp = Win32.DeferWindowPos(hwdp, m_layeredWnd.Handle, this.Handle, posInfo.x + m_offX, posInfo.y + m_offY, 0, 0, (uint)(posInfo.flags | Win32.WindowPosFlags.SWP_NOSIZE | Win32.WindowPosFlags.SWP_NOZORDER)); } if (hwdp != IntPtr.Zero) { hwdp = Win32.DeferWindowPos(hwdp, this.Handle, this.Handle, posInfo.x, posInfo.y, posInfo.cx, posInfo.cy, (uint)(posInfo.flags | Win32.WindowPosFlags.SWP_NOZORDER)); } if (hwdp != IntPtr.Zero) { Win32.EndDeferWindowPos(hwdp); } m_layeredWnd.LayeredPos = new Point(posInfo.x + m_offX, posInfo.y + m_offY); posInfo.flags |= Win32.WindowPosFlags.SWP_NOMOVE; Marshal.StructureToPtr(posInfo, m.LParam, true); } if ((posInfo.flags & Win32.WindowPosFlags.SWP_NOSIZE) == 0) { int diffX = posInfo.cx - this.Size.Width; int diffY = posInfo.cy - this.Size.Height; if (diffX != 0 || diffY != 0) { this.updateLayeredSize(this.ClientSize.Width + diffX, this.ClientSize.Height + diffY); } } UseBase = false; } } break; case Win32.Message.WM_ACTIVATE: { if (m.WParam != IntPtr.Zero) { IntPtr prevWnd = Win32.GetWindow(m_layeredWnd.Handle, Win32.GetWindow_Cmd.GW_HWNDPREV); while (prevWnd != IntPtr.Zero) { if (Win32.IsWindowVisible(prevWnd)) { break; } prevWnd = Win32.GetWindow(prevWnd, Win32.GetWindow_Cmd.GW_HWNDPREV); } if (prevWnd != this.Handle) { Win32.SetWindowPos(m_layeredWnd.Handle, this.Handle, 0, 0, 0, 0, (uint)(Win32.WindowPosFlags.SWP_NOSENDCHANGING | Win32.WindowPosFlags.SWP_NOACTIVATE | Win32.WindowPosFlags.SWP_NOSIZE | Win32.WindowPosFlags.SWP_NOMOVE)); } } } break; } if (UseBase) { base.WndProc(ref m); } }