How to make drawings in a PictureBox underneath a transparent custom control

68 views Asked by At

I have a problem that is either quite easy to solve or is too complex, and I am already going crazy with it.... Next, I am developing an application in VB.NET (WindowsForms) to take screenshots and be able to select part of the screen. I'm using a custom user control to select the part of the screen, so far so good, my problem is that when arrow, rectangle or freehand drawings are made, these drawings do not appear in the selected frame, as it is underneath and not It is possible to see the drawings, because the control, even though it has transparency, and has captured the contents of the picture box, it does not show the drawings that are made in the Paint event of the picture box. One option I was trying to implement was to make the drawings in the control itself, however, when I would save the clipping, the drawings did not appear, as they were in the control and not in the picture box...... kind of confusing, right? LOL

This is my code for capturing the image using user control.

Imports System.Drawing.Drawing2D
Imports Controle_Customizado_PictureBox
Imports FontAwesome.Sharp

Public Class frm_transp_form
    Private imgInput As Image
    Private EndLocation As Point
    Private StartLocation As Point
    Private rect As Rectangle
    Private IsMouseDown As Boolean = False
    Private ctrlResize As New FrameControl()
    Private currentBtn As IconButton
    Private BottomBoardBtn As Panel
    Private ToolTipPersonal As New ToolTip

    'desenho linha freehand
    Private freehand As Boolean = False
    Private linefreehand As New GraphicsPath()

    Sub New()
        ' Esta chamada é requerida pelo designer.
        InitializeComponent()

        ' Adicione qualquer inicialização após a chamada InitializeComponent().
        BottomBoardBtn = New Panel With {
            .Size = New Size(15, 1)
        }
        pnl_menu.Controls.Add(BottomBoardBtn)
    End Sub

    Private Sub frm_transp_form_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Size = New Size(Screen.AllScreens.Sum(Function(s As Screen) s.Bounds.Width), Screen.AllScreens.Max(Function(s As Screen) s.Bounds.Height))
        Me.MaximumSize = New Size(Me.Width, Me.Height)
        Me.MinimumSize = Me.MaximumSize

        pb_screen.Dock = DockStyle.Fill
        pb_screen.SendToBack()
        Dim bmp As Bitmap = New Bitmap(Screen.AllScreens.Sum(Function(s As Screen) s.Bounds.Width), Screen.AllScreens.Max(Function(s As Screen) s.Bounds.Height))
        Using g As Graphics = Graphics.FromImage(bmp)
            g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
            g.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
            g.CopyFromScreen(SystemInformation.VirtualScreen.X, SystemInformation.VirtualScreen.Y, 0, 0, SystemInformation.VirtualScreen.Size, CopyPixelOperation.SourceCopy)
            'Me.BackgroundImage = bmp
            pb_screen.BackgroundImage = bmp
        End Using

        Me.Location = New Point(0, 0)
        Me.Cursor = Cursors.Arrow
        ctrlResize.DashNodeColor = Color.Gainsboro
        ctrlResize.Size = New Size(0, 0)
        ctrlResize.Location = New Point(0, 0)
        ctrlResize.DrawingcColor = pb_color.BackColor
        ctrlResize.BackColor = Color.Transparent
        pb_screen.Controls.Add(ctrlResize)
    End Sub

    Private Sub ActivateButton(senderBtn As Object, customcolor As Color)
        If senderBtn IsNot Nothing Then
            DisableButton()
            currentBtn = CType(senderBtn, IconButton)
            currentBtn.IconColor = customcolor
            BottomBoardBtn.BackColor = customcolor
            BottomBoardBtn.Location = New Point(currentBtn.Location.X + ((pnl_menu.Width - BottomBoardBtn.Width) / 2), currentBtn.Bottom)
            BottomBoardBtn.Visible = True
            BottomBoardBtn.BringToFront()
        End If
    End Sub

    Private Sub DisableButton()
        If currentBtn IsNot Nothing Then
            currentBtn.IconColor = Color.FromArgb(78, 78, 78)
        End If
    End Sub

    Private Sub Resetbutton()
        DisableButton()
        BottomBoardBtn.Visible = False
    End Sub

    Private Sub pb_screen_MouseDown(sender As Object, e As MouseEventArgs) Handles pb_screen.MouseDown
        IsMouseDown = True
        StartLocation = e.Location
        With ctrlResize
            .CanMove = True
            .DrawArrow = False
            .DrawHand = False
            .DrawRect = False
        End With
        pnl_menu.Visible = False

        If freehand Then
            linefreehand.StartFigure()
        End If

        Console.WriteLine("Startlocation: " & StartLocation.ToString)
    End Sub

    Private Sub pb_screen_MouseMove(sender As Object, e As MouseEventArgs) Handles pb_screen.MouseMove
        If IsMouseDown = True Then
            EndLocation = e.Location
            GetRectangle()
            Application.DoEvents()
            ctrlResize.Size = New Size(rect.Size)
            ctrlResize.Location = New Point((StartLocation.X), (StartLocation.Y))
            lbl_position.Text = ctrlResize.Width & "x" & ctrlResize.Height
            pnl_menu.Location = New Point(EndLocation.X + 5, EndLocation.Y - pnl_menu.Height)
            Application.DoEvents()

            If freehand Then
                linefreehand.AddLine(e.X, e.Y, e.X, e.Y)
            End If
            pb_screen.Controls(0).Invalidate()
            pb_screen.Invalidate()
        End If
    End Sub

    Private Sub pb_screen_Paint(sender As Object, e As PaintEventArgs) Handles pb_screen.Paint
        e.Graphics.ExcludeClip(ctrlResize.Bounds)
        Using b = New SolidBrush(Color.FromArgb(100, Color.Black))
            e.Graphics.FillRectangle(b, pb_screen.ClientRectangle)
        End Using

        If freehand Then
            DrawShapes(e.Graphics)
        End If
    End Sub

    Private Sub pb_screen_MouseUp(sender As Object, e As MouseEventArgs) Handles pb_screen.MouseUp
        If IsMouseDown = True Then
            EndLocation = e.Location
            IsMouseDown = False

            Console.WriteLine("Retangulo: " & rect.Size.ToString)
            pnl_menu.Visible = True
        End If
    End Sub

    Private Sub DrawShapes(ByVal g As Graphics)
        Try
            g.SmoothingMode = SmoothingMode.AntiAlias
            g.SmoothingMode = SmoothingMode.HighQuality
            g.SmoothingMode = SmoothingMode.HighSpeed

            Dim linecolor As Color = Color.Red
            Dim linepen As Single = 0.3F

            ''DESENHO FREEHAND
            Using handpen As Pen = New Pen(linecolor, linepen)
                g.DrawPath(handpen, linefreehand)
            End Using
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If freehand = False Then
            With ctrlResize
                .CanMove = False
                .DrawArrow = False
                .DrawHand = False
                .DrawRect = False
            End With
            freehand = True
        End If
    End Sub

    Private Function GetRectangle() As Rectangle
        rect = New Rectangle With {
            .X = Math.Min(StartLocation.X, EndLocation.X),
            .Y = Math.Min(StartLocation.Y, EndLocation.Y),
            .Width = Math.Abs(StartLocation.X - EndLocation.X),
            .Height = Math.Abs(StartLocation.Y - EndLocation.Y)
        }

        Return rect
    End Function

    Protected Overrides ReadOnly Property CreateParams As CreateParams
        Get
            Dim cp As CreateParams = MyBase.CreateParams
            cp.ExStyle = cp.ExStyle Or &H2000000
            Return cp
        End Get
    End Property

    Private Sub pb_color_Click(sender As Object, e As EventArgs) Handles pb_color.Click
        'ColorDialog1.ShowDialog()
        If ColorDialog1.ShowDialog <> DialogResult.Cancel Then
            pb_color.BackColor = ColorDialog1.Color
            ctrlResize.DrawingcColor = ColorDialog1.Color
        End If
    End Sub

    Private Sub btn_arrow_Click(sender As Object, e As EventArgs) Handles btn_arrow.Click
        ActivateButton(sender, Color.FromArgb(78, 78, 78))

        With ctrlResize
            .CanMove = False
            .DrawArrow = True
            .DrawHand = False
            .DrawRect = False
        End With
    End Sub

    Private Sub btn_freehand_Click(sender As Object, e As EventArgs) Handles btn_freehand.Click
        ActivateButton(sender, Color.FromArgb(78, 78, 78))
        With ctrlResize
            .CanMove = False
            .DrawArrow = False
            .DrawHand = True
            .DrawRect = False
        End With
    End Sub

    Private Sub btn_rect_Click(sender As Object, e As EventArgs) Handles btn_rect.Click
        ActivateButton(sender, Color.FromArgb(78, 78, 78))
        With ctrlResize
            .CanMove = False
            .DrawArrow = False
            .DrawHand = False
            .DrawRect = True
        End With
    End Sub

    Private Sub btn_copy_Click(sender As Object, e As EventArgs) Handles btn_copy.Click
        ActivateButton(sender, Color.FromArgb(78, 78, 78))

        Dim selectedRectangle = New Rectangle(StartLocation.X, StartLocation.Y, ctrlResize.ClientRectangle.Width, ctrlResize.ClientRectangle.Height)
        Dim result = GetRectangeOnImage(pb_screen, selectedRectangle)
        Console.WriteLine("VALORES DO RETANGULO: " & selectedRectangle.ToString)
        Using bm = New Bitmap(CInt(result.Width), CInt(result.Height))

            Using g = Graphics.FromImage(bm)
                g.SmoothingMode = SmoothingMode.HighQuality
                g.CompositingQuality = CompositingQuality.HighQuality
                g.DrawImage(pb_screen.Image, 0, 0, result, GraphicsUnit.Pixel)
            End Using
            Dim img As Image = CType(bm.Clone(), Image)
            PictureBox1.Size = New Size(ctrlResize.Size)
            PictureBox1.Image = img
            PictureBox1.Visible = True
        End Using
    End Sub

    Public Function GetRectangeOnImage(ByVal p As PictureBox, ByVal selectionRect As Rectangle) As RectangleF
        Dim method = GetType(PictureBox).GetMethod("ImageRectangleFromSizeMode", System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.Instance)
        Dim imageRect = CType(method.Invoke(p, New Object() {p.SizeMode}), Rectangle)
        If p.Image Is Nothing Then Return selectionRect
        Dim cx = CSng(p.Image.Width) / CSng(imageRect.Width)
        Dim cy = CSng(p.Image.Height) / CSng(imageRect.Height)
        Dim r2 = Rectangle.Intersect(imageRect, selectionRect)
        r2.Offset(-imageRect.X, -imageRect.Y)
        Return New RectangleF(r2.X * cx, r2.Y * cy, r2.Width * cx, r2.Height * cy)
    End Function

    Private Sub btn_fechar_Click(sender As Object, e As EventArgs) Handles btn_fechar.Click
        ActivateButton(sender, Color.FromArgb(78, 78, 78))
        End
    End Sub
End Class

this is my user control code

Imports System.ComponentModel
Imports System.Drawing.Drawing2D
Imports System.Windows

Partial Public Class FrameControl
    Inherits UserControl

    <DefaultValue(True)>
    Public Property CanMove As Boolean = True
    <DefaultValue(False)>
    Public Property DrawArrow As Boolean = False
    <DefaultValue(False)>
    Public Property DrawHand As Boolean = False
    <DefaultValue(False)>
    Public Property DrawRect As Boolean = False
    Public Property DrawingcColor As Color = Color.LightGreen
    Public Property PenSize As Single = 3.0F
    Public Property DashNodeColor As Color = Color.Black

    Public Event DrawUndoClicked As EventHandler
    Dim btn As Button
    Const WM_NCHITTEST As Integer = 132
    Const WM_SETCURSOR As Integer = 32
    Const WM_MOUSEMOVE As Integer = 32
    Const WM_NCLBUTTONDBLCLK As Integer = 163
    Private isMouseDown As Boolean

    'desenho flecha
    Private m_StartX, m_StartY, m_CurX, m_CurY As Single
    Dim MyLineArrows As New List(Of LineList)

    'desenho retangulo
    Private SelectedColor As Color = Color.LightGreen
    Private drawingRects As List(Of DrawingRectangle) = New List(Of DrawingRectangle)()

    'desenho linha freehand
    Private linefreehand As New GraphicsPath()

    Private sizeNodeRect As Integer = 7
    Private nodeSelected As PosSizableRect = PosSizableRect.None
    Public rect As Rectangle

    Private Enum PosSizableRect
        UpMiddle
        LeftMiddle
        LeftBottom
        LeftUp
        RightUp
        RightMiddle
        RightBottom
        BottomMiddle
        None
    End Enum

    Public Sub New()
        InitializeComponent()
        rect = ClientRectangle
        SetStyle(ControlStyles.SupportsTransparentBackColor, True)

        DoubleBuffered = True
        ResizeRedraw = True
        BackColor = Color.Transparent
        Timer1.Enabled = True
    End Sub

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        MyBase.OnPaint(e)
        Try
            Using p = New Pen(DashNodeColor, 2)
                Using b = New SolidBrush(DashNodeColor)
                    p.DashStyle = Drawing2D.DashStyle.Dash
                    e.Graphics.DrawRectangle(p, 0, 0, Width - 1, Height - 1)

                    For Each pos As PosSizableRect In [Enum].GetValues(GetType(PosSizableRect))
                        e.Graphics.DrawRectangle(p, GetRect(pos))
                        e.Graphics.FillRectangle(b, GetRect(pos))
                    Next
                End Using
            End Using

            If CanMove = False Then
                DrawShapes(e.Graphics)

            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Protected Overrides Sub WndProc(ByRef m As Message)
        Try
            Dim borderWidth As Integer = 10
            If m.Msg = WM_SETCURSOR Then
                If (m.LParam.ToInt32() And 65535) = 2 Then
                    Cursor.Current = If(CanMove, Cursors.SizeAll, Cursors.Arrow)
                    m.Result = CType(1, IntPtr)
                    Return
                End If
            End If
            If m.Msg = WM_MOUSEMOVE Then
                If (m.LParam.ToInt32() And 65535) = 2 Then
                    Cursor.Current = Cursors.Arrow
                    m.Result = CType(1, IntPtr)
                    Return
                End If
            End If
            If m.Msg = WM_NCLBUTTONDBLCLK Then
                m.Result = CType(1, IntPtr)
                Return
            End If
            MyBase.WndProc(m)
            If m.Msg = WM_NCHITTEST Then
                Dim pos = PointToClient(New Point(m.LParam.ToInt32() And 65535, m.LParam.ToInt32() >> 16))
                If (pos.X <= (ClientRectangle.Left + borderWidth)) AndAlso (pos.Y <= (ClientRectangle.Top + borderWidth)) Then
                    m.Result = New IntPtr(13)
                Else
                    If (pos.X >= (ClientRectangle.Right - borderWidth)) AndAlso (pos.Y <= (ClientRectangle.Top + borderWidth)) Then
                        m.Result = New IntPtr(14)
                    Else
                        If (pos.X <= (ClientRectangle.Left + borderWidth)) AndAlso (pos.Y >= (ClientRectangle.Bottom - borderWidth)) Then
                            m.Result = New IntPtr(16)
                        Else
                            If (pos.X >= (ClientRectangle.Right - borderWidth)) AndAlso (pos.Y >= (ClientRectangle.Bottom - borderWidth)) Then
                                m.Result = New IntPtr(17)
                            Else
                                If pos.X <= (ClientRectangle.Left + borderWidth) Then
                                    m.Result = New IntPtr(10)
                                Else
                                    If pos.Y <= (ClientRectangle.Top + borderWidth) Then
                                        m.Result = New IntPtr(12)
                                    Else
                                        If pos.X >= (ClientRectangle.Right - borderWidth) Then
                                            m.Result = New IntPtr(11)
                                        Else
                                            If pos.Y >= (ClientRectangle.Bottom - borderWidth) Then
                                                m.Result = New IntPtr(15)
                                            Else
                                                m.Result = (If(CanMove, New IntPtr(2), IntPtr.Zero))
                                            End If
                                        End If
                                    End If
                                End If
                            End If
                        End If
                    End If
                End If
            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Private Sub FrameControl_MouseDown(sender As Object, e As MouseEventArgs) Handles MyBase.MouseDown
        Try
            isMouseDown = True
            If DrawArrow Then
                m_StartX = e.X
                m_StartY = e.Y
                m_CurX = e.X
                m_CurY = e.Y

            ElseIf DrawRect Then
                drawingRects.Add(New DrawingRectangle() With {
                .Location = e.Location,
                .Size = Size.Empty,
                .StartPosition = e.Location,
                .DrawingcRectColor = DrawingcColor,
                .PenRectSize = PenSize
                })

            ElseIf DrawHand Then
                linefreehand.StartFigure()

            End If
        Catch ex As Exception
            Throw ex
        End Try

        '.Owner = CType(sender, Control),
    End Sub

    Private Sub FrameControl_MouseMove(sender As Object, e As MouseEventArgs) Handles MyBase.MouseMove
        Try
            If isMouseDown Then
                If DrawArrow Then
                    m_CurX = e.X
                    m_CurY = e.Y

                ElseIf DrawRect Then
                    Dim dr = drawingRects(drawingRects.Count - 1)

                    If e.Y < dr.StartPosition.Y Then
                        dr.Location = New Point(dr.Rect.Location.X, e.Y)
                    End If

                    If e.X < dr.StartPosition.X Then
                        dr.Location = New Point(e.X, dr.Rect.Location.Y)
                    End If

                    dr.Size = New Size(Math.Abs(dr.StartPosition.X - e.X), Math.Abs(dr.StartPosition.Y - e.Y))
                ElseIf DrawHand Then
                    linefreehand.AddLine(e.X, e.Y, e.X, e.Y)
                End If

                Me.Invalidate()
            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Private Sub FrameControl_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        UseDoubleBuffer()
    End Sub

    Private Sub FrameControl_MouseUp(sender As Object, e As MouseEventArgs) Handles MyBase.MouseUp
        Try
            isMouseDown = False
            If DrawArrow Then
                Dim DrawLine As New LineList
                DrawLine.X1 = m_StartX
                DrawLine.Y1 = m_StartY
                DrawLine.X2 = m_CurX
                DrawLine.Y2 = m_CurY
                MyLineArrows.Add(DrawLine)

            ElseIf DrawRect Then
                Dim dr = drawingRects.Last()
            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        Try
            If CanMove Then
                linefreehand.Reset()
                drawingRects.Clear()
                MyLineArrows.Clear()
                Me.Invalidate()

            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Private Sub DrawShapes(ByVal g As Graphics)
        Try
            g.SmoothingMode = SmoothingMode.AntiAlias
            g.SmoothingMode = SmoothingMode.HighQuality
            g.SmoothingMode = SmoothingMode.HighSpeed

            'DESENHO DO RETANGULO
            For Each dr In drawingRects
                Using pen As Pen = New Pen(DrawingcColor, PenSize)
                    g.DrawRectangle(pen, dr.Rect)
                End Using
            Next

            'DESENHO DA FLECHA
            Dim x1, y1, x2, y2 As Integer
            Dim linecolor As Color = DrawingcColor
            Dim linepen As Single = PenSize

            For Each line In MyLineArrows
                x1 = line.X1 : x2 = line.X2
                y1 = line.Y1 : y2 = line.Y2
                Using Arrow1 As New Pen(linecolor, linepen)
                    Arrow1.EndCap = LineCap.Custom
                    Arrow1.CustomEndCap = New AdjustableArrowCap(2, 2, False)
                    g.DrawLine(Arrow1, x1, y1, x2, y2)
                End Using
            Next

            If isMouseDown Then
                Using Arrow As Pen = New Pen(linecolor, linepen)
                    Arrow.EndCap = LineCap.Custom
                    Arrow.CustomEndCap = New AdjustableArrowCap(2, 2, False)
                    g.DrawLine(Arrow, m_StartX, m_StartY, m_CurX, m_CurY)
                End Using
            End If
            'DESENHO FREEHAND
            Using handpen As Pen = New Pen(linecolor, linepen)
                g.DrawPath(handpen, linefreehand)
            End Using
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Private Sub UseDoubleBuffer()
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or
                     ControlStyles.UserPaint Or
                     ControlStyles.OptimizedDoubleBuffer, True)
    End Sub

    Private Function CreateRectSizableNode(ByVal x As Integer, ByVal y As Integer) As Rectangle
        Return New Rectangle(x - sizeNodeRect / 2, y - sizeNodeRect / 2, sizeNodeRect, sizeNodeRect)
    End Function

    Private Function GetRect(ByVal p As PosSizableRect) As Rectangle
        Select Case p
            Case PosSizableRect.LeftUp
                Return CreateRectSizableNode(ClientRectangle.X, ClientRectangle.Y)
            Case PosSizableRect.LeftMiddle
                Return CreateRectSizableNode(ClientRectangle.X, ClientRectangle.Y + +ClientRectangle.Height / 2)
            Case PosSizableRect.LeftBottom
                Return CreateRectSizableNode(ClientRectangle.X, ClientRectangle.Y + ClientRectangle.Height)
            Case PosSizableRect.BottomMiddle
                Return CreateRectSizableNode(ClientRectangle.X + ClientRectangle.Width / 2, ClientRectangle.Y + ClientRectangle.Height)
            Case PosSizableRect.RightUp
                Return CreateRectSizableNode(ClientRectangle.X + ClientRectangle.Width, ClientRectangle.Y)
            Case PosSizableRect.RightBottom
                Return CreateRectSizableNode(ClientRectangle.X + ClientRectangle.Width, ClientRectangle.Y + ClientRectangle.Height)
            Case PosSizableRect.RightMiddle
                Return CreateRectSizableNode(ClientRectangle.X + ClientRectangle.Width, ClientRectangle.Y + ClientRectangle.Height / 2)
            Case PosSizableRect.UpMiddle
                Return CreateRectSizableNode(ClientRectangle.X + ClientRectangle.Width / 2, ClientRectangle.Y)
            Case Else
                Return New Rectangle()
        End Select
    End Function

    Private Function GetNodeSelectable(ByVal p As Point) As PosSizableRect
        For Each r As PosSizableRect In [Enum].GetValues(GetType(PosSizableRect))

            If GetRect(r).Contains(p) Then
                Return r
            End If
        Next

        Return PosSizableRect.None
    End Function


End Class

This is an example of the capture screen with user control capture screen

I accept suggestions in both C# and VB.net

Update:
I just put some Invalidade() methods in my code, but the result is still not what I expected, below is a new screenshot with the program running

new_screenshot

Update 2: I discovered that what was causing the problem was actually the ExcludeClip, which does not update the user control. By removing the ExcludeClip from the Paint method of the main picturebox, User Control can view the entire process normally. Now my question is: How can I leave my User Control with the same characteristics as ExcludeClip but without using it, is that possible???

new_screenshot

My problem now is in this part of the code,

Any suggestions to solve it????

 Private Sub pb_screen_Paint(sender As Object, e As PaintEventArgs) Handles pb_screen.Paint
    ---> e.Graphics.ExcludeClip(ctrlResize.Bounds) <-----
    Using b = New SolidBrush(Color.FromArgb(100, Color.Black))
        e.Graphics.FillRectangle(b, pb_screen.ClientRectangle)
    End Using

    If freehand Then
        DrawShapes(e.Graphics)
    End If
End Sub
1

There are 1 answers

1
Joel Coehoorn On

Not a full answer, so just community wiki, but I wanted to suggest an improvement to the deeply-nested If/Else section (the WndProc() method) of the user control:

Protected Overrides Sub WndProc(ByRef m As Message)

    Dim borderWidth As Integer = 10
    If m.Msg = WM_SETCURSOR AndAlso (m.LParam.ToInt32() And 65535) = 2 Then
        Cursor.Current = If(CanMove, Cursors.SizeAll, Cursors.Arrow)
        m.Result = CType(1, IntPtr)
        Return
    End If

    If m.Msg = WM_MOUSEMOVE AndAlso (m.LParam.ToInt32() And 65535) = 2 Then
        Cursor.Current = Cursors.Arrow
        m.Result = CType(1, IntPtr)
        Return
    End If

    If m.Msg = WM_NCLBUTTONDBLCLK Then
        m.Result = CType(1, IntPtr)
        Return
    End If
    MyBase.WndProc(m)

    If m.Msg <> WM_NCHITTEST Then Return

    Dim pos = PointToClient(New Point(m.LParam.ToInt32() And 65535, m.LParam.ToInt32() >> 16))
    If pos.X <= (ClientRectangle.Left + borderWidth) AndAlso pos.Y <= (ClientRectangle.Top + borderWidth) Then
         m.Result = New IntPtr(13)
    ElseIf pos.X >= (ClientRectangle.Right - borderWidth) AndAlso pos.Y <= (ClientRectangle.Top + borderWidth) Then
        m.Result = New IntPtr(14)
    ElseIf pos.X <= (ClientRectangle.Left + borderWidth) AndAlso pos.Y >= (ClientRectangle.Bottom - borderWidth) Then
        m.Result = New IntPtr(16)
    ElseIf pos.X >= (ClientRectangle.Right - borderWidth) AndAlso pos.Y >= (ClientRectangle.Bottom - borderWidth) Then
        m.Result = New IntPtr(17)
    ElseIf pos.X <= (ClientRectangle.Left + borderWidth) Then
        m.Result = New IntPtr(10)
    ElseIf pos.Y <= (ClientRectangle.Top + borderWidth) Then
        m.Result = New IntPtr(12)
    ElseIf pos.X >= (ClientRectangle.Right - borderWidth) Then
        m.Result = New IntPtr(11)
    ElseIf pos.Y >= (ClientRectangle.Bottom - borderWidth) Then
        m.Result = New IntPtr(15)
    Else
        m.Result = If(CanMove, New IntPtr(2), IntPtr.Zero)
    End If
End Sub

By regrouping equal conditions, you can simplify the If/Else section even further and eliminate some AndAlso. Since all the cases execute the same statement with a different number, we just assign the number in the If/Else section and execute the statement afterwards:

Dim n As Integer
If pos.X <= (ClientRectangle.Left + borderWidth) Then
    If pos.Y <= (ClientRectangle.Top + borderWidth) Then
        n = 13 ' Top Left
    ElseIf pos.Y >= (ClientRectangle.Bottom - borderWidth) Then
        n = 16 ' Bottom Left
    Else Then
        n = 10 ' Middle Left
    End If
ElseIf pos.X >= (ClientRectangle.Right - borderWidth) Then
    If pos.Y <= (ClientRectangle.Top + borderWidth) Then
        n = 14 ' Top Right
    ElseIf pos.Y >= (ClientRectangle.Bottom - borderWidth) Then
        n = 17 ' Bottom Right
    Else
        n = 11 ' Middle Right
    End If
Else
    If pos.Y <= (ClientRectangle.Top + borderWidth) Then
        n = 12 ' Top Middle
    ElseIf pos.Y >= (ClientRectangle.Bottom - borderWidth) Then
        n = 15 ' Bottom Middle
    Else
        n = If(CanMove, 2, 0) ' In the window
    End If
End If
m.Result = New IntPtr(n)

Again, as indicated in the comment, the Try/Catch in the original method was not only unhelpful, but actively made things worse, so I just removed it. This also greatly reduces nesting/indentation, which allowed removing a bunch of End If lines and made the code MUCH easier to follow.

I suspect it's also possible to convert this to find the correct integer values (from 11 to 17) for the IntPtr() call via a Dictionary lookup, which would be even better. But as there are two sets of inputs (X vs Y), this could trickier than it first seems.