26

I'm trying to drop a shadow around the whole form just like the first picture, except that that is a WPF, not a WinForm. now I want to drop the same shadow on a winform.

This is what I want..¬

Windows Form Shadow

Not this..¬

Windows Form Shadow

Jaymin
  • 2,879
  • 3
  • 19
  • 35
Sam Oyl
  • 361
  • 1
  • 5
  • 12
  • http://stackoverflow.com/questions/3372303/dropshadow-for-wpf-borderless-window – Nikhil Agrawal May 11 '13 at 04:29
  • Have you seen this link http://stackoverflow.com/questions/2463519/drop-shadow-in-winforms-controls by trying to override the createparams ? – Edper May 11 '13 at 04:29
  • 1
    @Edper overriding the cp will give the shadow in the second picture – Sam Oyl May 11 '13 at 04:46
  • 1
    You can achieve the desired effect by using layered windows. – User 12345678 May 11 '13 at 05:38
  • I see a difference between the first and second examples, but it's the background (a picture vs white) and the foreground color of the window (white vs light blue). Neither of those has anything to do with the drop shadow. **What exactly is wrong with the second example?** – Cody Gray - on strike May 11 '13 at 07:56
  • 2
    @CodyGray You are incorrect, sir. The dropshadow in the first sample is also visible at the left and top of the window (the shadow goes all the way around the control - as if the sun was looking at the window) but in the second sample, it's as if the sun is on the left, and so you can only see the shadow to the bottom and right of the second sample window. – SE13013 Jul 17 '15 at 08:34

5 Answers5

50

In WinForms, you can just override the form's protected CreateParams property and add the CS_DROPSHADOW flag to the class styles. For example:

public class ShadowedForm : Form {
    protected override CreateParams CreateParams {
        get {
            const int CS_DROPSHADOW = 0x20000;
            CreateParams cp = base.CreateParams;
            cp.ClassStyle |= CS_DROPSHADOW;
            return cp;
        }
    }

    // ... other code ...
}

But, a couple of caveats…

  1. This flag works only on top-level windows. In Win32-speak, that means overlapped and popup windows. It has no effect on child windows (e.g. controls). I thought I remembered hearing somewhere that this limitation had been removed from Windows 8, but I can't find a link confirming this and I don't have Windows 8 installed for testing purposes.

  2. It is possible that the user has disabled this feature altogether. If so, you won't get drop shadows, no matter how you ask for them. That's by design. Your application should not try and override this request. You can determine whether drop shadows are enabled or disabled by P/Invoking the SystemParametersInfo function and passing the SPI_GETDROPSHADOW flag.

  3. The Aero theme also adds shadows to top-level windows. This effect is separate and distinct from CS_DROPSHADOW, and works only when Aero is enabled. There's no way to turn it off and on for individual windows. Moreover, since the Aero theme has been removed from Windows 8, it won't ever have these shadows.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • He already has that dropshadow. The DWM pinvoke works just as well in Winforms, use OnHandleCreated. All of it looks *very* poor in Win8. – Hans Passant May 11 '13 at 08:41
  • 1
    well as @HansPassant said and again the cp gives same shadow like the second picture – Sam Oyl May 11 '13 at 19:26
  • this is simple and works good! however, imho, the shadow is not as pretty as the solution posted by @Ryan Loggerythm.. it just has less spread, and maybe a little darker than his.. but great answer, and great option.. – Heriberto Lugo Jul 27 '19 at 20:11
24

Here's my C# implementation. It's similar to Al. Petro's, but you'll notice that when you lose focus and regain focus, the shadow repaints itself.

I've also added code to allow mouse-dragging.

public partial class Form1: Form
{
    [DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
    private static extern IntPtr CreateRoundRectRgn
    (
        int nLeftRect, // x-coordinate of upper-left corner
        int nTopRect, // y-coordinate of upper-left corner
        int nRightRect, // x-coordinate of lower-right corner
        int nBottomRect, // y-coordinate of lower-right corner
        int nWidthEllipse, // height of ellipse
        int nHeightEllipse // width of ellipse
     );        

    [DllImport("dwmapi.dll")]
    public static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);

    [DllImport("dwmapi.dll")]
    public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);

    [DllImport("dwmapi.dll")]
    public static extern int DwmIsCompositionEnabled(ref int pfEnabled);

    private bool m_aeroEnabled;                     // variables for box shadow
    private const int CS_DROPSHADOW = 0x00020000;
    private const int WM_NCPAINT = 0x0085;
    private const int WM_ACTIVATEAPP = 0x001C;

    public struct MARGINS                           // struct for box shadow
    {
        public int leftWidth;
        public int rightWidth;
        public int topHeight;
        public int bottomHeight;
    }

    private const int WM_NCHITTEST = 0x84;          // variables for dragging the form
    private const int HTCLIENT = 0x1;
    private const int HTCAPTION = 0x2;

    protected override CreateParams CreateParams
    {
        get
        {
            m_aeroEnabled = CheckAeroEnabled();

            CreateParams cp = base.CreateParams;
            if (!m_aeroEnabled)
                cp.ClassStyle |= CS_DROPSHADOW;

            return cp;
        }
    }

    private bool CheckAeroEnabled()
    {
        if (Environment.OSVersion.Version.Major >= 6)
        {
            int enabled = 0;
            DwmIsCompositionEnabled(ref enabled);
            return (enabled == 1) ? true : false;
        }
        return false;
    }

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case WM_NCPAINT:                        // box shadow
                if (m_aeroEnabled)
                {
                    var v = 2;
                    DwmSetWindowAttribute(this.Handle, 2, ref v, 4);
                    MARGINS margins = new MARGINS()
                    {
                        bottomHeight = 1,
                        leftWidth = 1,
                        rightWidth = 1,
                        topHeight = 1
                    };
                    DwmExtendFrameIntoClientArea(this.Handle, ref margins);

                }
                break;
            default:
                break;
        }
        base.WndProc(ref m);

        if (m.Msg == WM_NCHITTEST && (int)m.Result == HTCLIENT)     // drag the form
            m.Result = (IntPtr)HTCAPTION;

    }

    public Form1()
    {
        m_aeroEnabled = false;

        this.FormBorderStyle = FormBorderStyle.None;

        InitializeComponent();
    }
}
Jaymin
  • 2,879
  • 3
  • 19
  • 35
Ryan Loggerythm
  • 2,877
  • 3
  • 31
  • 39
  • Note. if you set the MARGINS struct to -1 on all edges, and call CreateRoundRectRgn from your OnSizeChanged method, you can achieve rounded edges as well - however this causes the drop shadow to disappear when the form loses focus...any ideas? – Matthew Layton Jan 28 '15 at 15:18
  • 1
    This is easier for mouse control and dragging on a border less form. -- protected override void WndProc(ref Message m) { if (m.Msg == 0x0084 /*WM_NCHITTEST*/) { m.Result = (IntPtr)2; // HTCLIENT return; } base.WndProc(ref m); } – MarkKiessling Aug 19 '18 at 11:37
  • This code works, but I get error "Cross-thread operation not valid: Control 'MainWindow' accessed from a thread other than the thread it was created on" near `CreateParams cp = base.CreateParams;` Any ideas how to solve this? – Pavel Sep 23 '20 at 17:51
  • 1
    Works like a dream! Thanks a lot – WiiLF Dec 09 '21 at 00:51
9

Humm ,,, Just past the code and you will get the windows 7 Drop Shadow like this >>> http://marcin.floryan.pl/wp-content/uploads/2010/08/WPF-Window-native-shadow.png

Imports System.Runtime.InteropServices

Public Class IMSS_SplashScreen
    Private aeroEnabled As Boolean
    Protected Overrides ReadOnly Property CreateParams() As CreateParams
        Get
            CheckAeroEnabled()
            Dim cp As CreateParams = MyBase.CreateParams
            If Not aeroEnabled Then
                cp.ClassStyle = cp.ClassStyle Or NativeConstants.CS_DROPSHADOW
                Return cp
            Else
                Return cp
            End If
        End Get
    End Property
    Protected Overrides Sub WndProc(ByRef m As Message)
        Select Case m.Msg
            Case NativeConstants.WM_NCPAINT
                Dim val = 2
                If aeroEnabled Then
                    NativeMethods.DwmSetWindowAttribute(Handle, 2, val, 4)
                    Dim bla As New NativeStructs.MARGINS()
                    With bla
                        .bottomHeight = 1
                        .leftWidth = 1
                        .rightWidth = 1
                        .topHeight = 1
                    End With
                    NativeMethods.DwmExtendFrameIntoClientArea(Handle, bla)
                End If
                Exit Select
        End Select
        MyBase.WndProc(m)
    End Sub
    Private Sub CheckAeroEnabled()
        If Environment.OSVersion.Version.Major >= 6 Then
            Dim enabled As Integer = 0
            Dim response As Integer = NativeMethods.DwmIsCompositionEnabled(enabled)
            aeroEnabled = (enabled = 1)
        Else
            aeroEnabled = False
        End If
    End Sub
End Class
Public Class NativeStructs
    Public Structure MARGINS
        Public leftWidth As Integer
        Public rightWidth As Integer
        Public topHeight As Integer
        Public bottomHeight As Integer
    End Structure
End Class
Public Class NativeMethods
    <DllImport("dwmapi")> _
    Public Shared Function DwmExtendFrameIntoClientArea(ByVal hWnd As IntPtr, ByRef pMarInset As NativeStructs.MARGINS) As Integer
    End Function
    <DllImport("dwmapi")> _
    Friend Shared Function DwmSetWindowAttribute(ByVal hwnd As IntPtr, ByVal attr As Integer, ByRef attrValue As Integer, ByVal attrSize As Integer) As Integer
    End Function
    <DllImport("dwmapi.dll")> _
    Public Shared Function DwmIsCompositionEnabled(ByRef pfEnabled As Integer) As Integer
    End Function
End Class
Public Class NativeConstants
    Public Const CS_DROPSHADOW As Integer = &H20000
    Public Const WM_NCPAINT As Integer = &H85
End Class
Al.Pertro
  • 175
  • 1
  • 6
  • Great implementation, but it seems to lose it's drop shadow when the control loses/gains focus, or upon interacting with other windows. Do you know how to solve this? – Matthew Layton Nov 10 '14 at 09:16
  • @seriesOne sounds like you just need to handle the form resize event and call this.Update() or this.Refresh(). so the window is "forced" to repaint itself thus also repainting the shadow. I haven't even tried this code yet, but I'm guessing that's why. – SE13013 Jul 17 '15 at 08:37
6

I already answered it here: Drop shadow on Borderless Winform-No flicker or disappearance

Here's my answer:

Pls try the below steps and revert back for any errors:

Add the below code to a new code file named DropShadow.cs;

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Core
{
    public class DropShadow
    {
        #region Shadowing

        #region Fields

        private bool _isAeroEnabled = false;
        private bool _isDraggingEnabled = false;
        private const int WM_NCHITTEST = 0x84;
        private const int WS_MINIMIZEBOX = 0x20000;
        private const int HTCLIENT = 0x1;
        private const int HTCAPTION = 0x2;
        private const int CS_DBLCLKS = 0x8;
        private const int CS_DROPSHADOW = 0x00020000;
        private const int WM_NCPAINT = 0x0085;
        private const int WM_ACTIVATEAPP = 0x001C;

        #endregion

        #region Structures

        [EditorBrowsable(EditorBrowsableState.Never)]
        public struct MARGINS
        {
            public int leftWidth;
            public int rightWidth;
            public int topHeight;
            public int bottomHeight;
        }

        #endregion

        #region Methods

        #region Public

        [DllImport("dwmapi.dll")]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);

        [DllImport("dwmapi.dll")]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);

        [DllImport("dwmapi.dll")]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static extern int DwmIsCompositionEnabled(ref int pfEnabled);

        [EditorBrowsable(EditorBrowsableState.Never)]
        public static bool IsCompositionEnabled()
        {
            if (Environment.OSVersion.Version.Major < 6) return false;

            bool enabled;
            DwmIsCompositionEnabled(out enabled);

            return enabled;
        }

        #endregion

        #region Private

        [DllImport("dwmapi.dll")]
        private static extern int DwmIsCompositionEnabled(out bool enabled);

        [DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
        private static extern IntPtr CreateRoundRectRgn
        (
            int nLeftRect,
            int nTopRect,
            int nRightRect,
            int nBottomRect,
            int nWidthEllipse,
            int nHeightEllipse
         );

        private bool CheckIfAeroIsEnabled()
        {
            if (Environment.OSVersion.Version.Major >= 6)
            {
                int enabled = 0;
                DwmIsCompositionEnabled(ref enabled);

                return (enabled == 1) ? true : false;
            }
            return false;
        }

        #endregion

        #region Overrides

        public void ApplyShadows(Form form)
        {
            var v = 2;

            DwmSetWindowAttribute(form.Handle, 2, ref v, 4);

            MARGINS margins = new MARGINS()
            {
                bottomHeight = 1,
                leftWidth = 0,
                rightWidth = 0,
                topHeight = 0
            };

            DwmExtendFrameIntoClientArea(form.Handle, ref margins);
        }

        #endregion

        #endregion

        #endregion
    }
}

In your form, add this line below InitializeComponent();

(new Core.DropShadow()).ApplyShadows(this);

Still, I would recommend switching to WPF. I was myself a user of WinForms for quite a long time, however WPF provides a lot better flexibility over designing the user interface. You can also customize all the controls yourself without needing any frameworks or packages. It does take some time to learn WPF, but it's worth it.

D J
  • 845
  • 1
  • 13
  • 27
  • This answer should be on the top. Gives the most natural result and easy to put in multiple forms – saksham Jun 12 '21 at 10:40
  • At the bottom of the form appears a thin line!!! It's because of the margins I think. Maybe isn't visible with the default `BackColor` but If you set a dark `BackColor`, for example `45; 45; 48`, you can see it. Is there any way to correct this? Thank you for your time!!! – Simos Sigma Oct 25 '22 at 12:42
0

As far as I know, there is no direct way of doing this in WinForms.

Instead, you can follow this step by step:

1) Create an image having the desired drop shadow using photoshop or any other tool.
2) Use this image as background image of your form.
3) Set FormBorderStyle property of the form to None.
4) You are done!
5) Note: Make sure to save the image in proper format(such as png) so that the drop shadow effect could work.

Amit Mittal
  • 1,129
  • 11
  • 30