Solved

A tiny issue with ".NET Snap To Screen Form"

Posted on 2007-12-05
5
676 Views
Last Modified: 2013-12-16
Hi,

The code here is working very good when the ForBorderStyle is NOT set to "None":

http://www.codeproject.com/KB/vb/SnapForm.aspx

In my application, it's set to None... And I move the form by holding down the right mouse button and moving it. The code still partially work, but when I approach the taskbar from the clock side it's not completely sticked to the corners.

I tried to figure out what wrong with code but no luck (and no experience).

The complete code is attached. Just create a new project and paste it.

Your help would be greatly appreciated.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
 
namespace WindowsFormsApplication11
{
    public partial class Form1 : Form
    {
        public const int WM_NCLBUTTONDOWN = 0xA1;
        public const int HT_CAPTION = 0x2;
 
        [DllImportAttribute("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd,
                         int Msg, int wParam, int lParam);
        [DllImportAttribute("user32.dll")]
        public static extern bool ReleaseCapture();
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
 
        }
 
        # region SnapToDesktopBorder
 
        private const int mSnapOffset = 35;
        private const int WM_WINDOWPOSCHANGING = 70;
 
        [StructLayout(LayoutKind.Sequential)]
        public struct WINDOWPOS
        {
            public IntPtr hwnd;
            public IntPtr hwndInsertAfter;
            public int x;
            public int y;
            public int cx;
            public int cy;
            public int flags;
        }
 
        protected override void WndProc(ref Message m)
        {
            // Listen for operating system messages
            switch (m.Msg)
            {
                case WM_WINDOWPOSCHANGING:
                    {
                        SnapToDesktopBorder(this, m.LParam, 0);
                    }
                    break;
            }
 
            base.WndProc(ref m);
        }
 
        public static void SnapToDesktopBorder(Form clientForm, IntPtr LParam, int widthAdjustment)
        {
            if (clientForm == null)
            {
                // Satisfies rule: Validate parameters
                throw new ArgumentNullException("clientForm");
            }
 
            // Snap client to the top, left, bottom or right desktop border
            // as the form is moved near that border.
 
            try
            {
                // Marshal the LPARAM value which is a WINDOWPOS struct
                WINDOWPOS NewPosition = new WINDOWPOS();
                NewPosition = (WINDOWPOS)System.Runtime.InteropServices.Marshal.PtrToStructure(LParam, typeof(WINDOWPOS));
 
                if (NewPosition.y == 0 || NewPosition.x == 0)
                {
                    return;
                    // Nothing to do!
                }
 
                // Adjust the client size for borders and caption bar
                Rectangle ClientRect = clientForm.RectangleToScreen(clientForm.ClientRectangle);
                ClientRect.Width += SystemInformation.FrameBorderSize.Width - widthAdjustment;
                ClientRect.Height += (SystemInformation.FrameBorderSize.Height + SystemInformation.CaptionHeight);
 
                // Now get the screen working area (without taskbar)
                Rectangle WorkingRect = Screen.GetWorkingArea(clientForm.ClientRectangle);
 
                // Left border
                if (NewPosition.x >= WorkingRect.X - mSnapOffset && NewPosition.x <= WorkingRect.X + mSnapOffset)
                {
                    NewPosition.x = WorkingRect.X;
                }
 
                // Get screen bounds and taskbar height
                // (when taskbar is horizontal)
                Rectangle ScreenRect = Screen.GetBounds(Screen.PrimaryScreen.Bounds);
                int TaskbarHeight = ScreenRect.Height - WorkingRect.Height;
 
                // Top border (check if taskbar is on top
                // or bottom via WorkingRect.Y)
                if (NewPosition.y >= -mSnapOffset && (WorkingRect.Y > 0 && NewPosition.y <= (TaskbarHeight + mSnapOffset)) || (WorkingRect.Y <= 0 && NewPosition.y <= (mSnapOffset)))
                {
                    if (TaskbarHeight > 0)
                    {
                        NewPosition.y = WorkingRect.Y;
                        // Horizontal Taskbar
                    }
                    else
                    {
                        NewPosition.y = 0;
                        // Vertical Taskbar
                    }
                }
 
                // Right border
                if (NewPosition.x + ClientRect.Width <= WorkingRect.Right + mSnapOffset && NewPosition.x + ClientRect.Width >= WorkingRect.Right - mSnapOffset)
                {
                    NewPosition.x = WorkingRect.Right - (ClientRect.Width + SystemInformation.FrameBorderSize.Width);
                }
 
                // Bottom border
                if (NewPosition.y + ClientRect.Height <= WorkingRect.Bottom + mSnapOffset && NewPosition.y + ClientRect.Height >= WorkingRect.Bottom - mSnapOffset)
                {
                    NewPosition.y = WorkingRect.Bottom - (ClientRect.Height + SystemInformation.FrameBorderSize.Height);
                }
 
                // Marshal it back
                System.Runtime.InteropServices.Marshal.StructureToPtr(NewPosition, LParam, true);
            }
            catch (ArgumentException ex)
            {
            }
        }
 
 
        # endregion
 
        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                ReleaseCapture();
                SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
            }
        }
    }
}

Open in new window

0
Comment
Question by:EEssam
  • 3
  • 2
5 Comments
 
LVL 29

Expert Comment

by:anarki_jimbel
ID: 20417110
OK, I spend hal an hour playing with your application and coud not find any wrong.
It sticks well from what I see (didn't use glasses however so could miss something).
Eventually if you have some extra gap/overlapping  -  just add/subtract couple of pixels.
0
 

Author Comment

by:EEssam
ID: 20417301
I'm using Windows XP SP2, not Vista. The problem is happening only when:

1. FormBorderStyle is set to "None":
2. The form is moved to the corner of Windows clock.
0
 
LVL 29

Expert Comment

by:anarki_jimbel
ID: 20422729
I'm using XP.
Did you wrote any code to move your form? Can you show it?
0
 

Author Comment

by:EEssam
ID: 20423078
The code to move the form is:

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                ReleaseCapture();
                SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
            }
        }
0
 
LVL 29

Accepted Solution

by:
anarki_jimbel earned 500 total points
ID: 20424934
Try this code. For me it works fine.

It's pretty hard to explain why I use '-=" bordersize. However form with borders has
width = "form width without borders" plus
"border width" multiplied by 2. If in the firs case (your original code) we add
border width just once to get width (height) then "borderless" form should be
that minus "border width" multiplied by 2. It was just some logical conclusion.
                // Adjust the client size for borders and caption bar
                Rectangle ClientRect = clientForm.RectangleToScreen(clientForm.ClientRectangle);
                if (clientForm.FormBorderStyle != FormBorderStyle.None)
                {
                    ClientRect.Width += SystemInformation.FrameBorderSize.Width - widthAdjustment;
                    ClientRect.Height += (SystemInformation.FrameBorderSize.Height + SystemInformation.CaptionHeight);
 
                }
                else
                {
                    ClientRect.Width -= SystemInformation.FrameBorderSize.Width - widthAdjustment;
                    ClientRect.Height -= (SystemInformation.FrameBorderSize.Height);
 
                }

Open in new window

0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In my previous two articles we discussed Binary Serialization (http://www.experts-exchange.com/A_4362.html) and XML Serialization (http://www.experts-exchange.com/A_4425.html). In this article we will try to know more about SOAP (Simple Object Acces…
This article aims to explain the working of CircularLogArchiver. This tool was designed to solve the buildup of log file in cases where systems do not support circular logging or where circular logging is not enabled
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

828 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question