Solved

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

Posted on 2007-12-05
5
674 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

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

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

Suggested Solutions

Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
The article shows the basic steps of integrating an HTML theme template into an ASP.NET MVC project
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

776 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