当改变lParam(调整矩形大小)时,AccessViolationException



我正在创建一个WPF窗口,它在调整大小时保持其长宽比

我的第一个想法是处理WM_SIZE消息并设置大小,但这会产生恼人的闪烁。所以我试图改变产生AccessViolationExceptions的WM_Size的lParam。在WM_SIZING上操作lParam也是如此。

AspectWindow.vb

Imports System.Runtime.InteropServices
Imports System.Windows.Interop

Public Class AspectWindow
    Inherits Window
    Private AspectRatio As Double
    Private ResizeDirection As Direction
    Enum Direction
        Horizontal
        Vertical
    End Enum
    Enum WM
        WM_SIZE = &H5
        WM_SIZING = &H214
        WM_EXITSIZEMOVE = &H232
        WM_NCCALCSIZE = &H83
    End Enum
    Enum WMSZ
        WMSZ_BOTTOM = &H6
        WMSZ_BOTTOMLEFT = &H7
        WMSZ_BOTTOMRIGHT = &H8
        WMSZ_LEFT = &H1
        WMSZ_RIGHT = &H2
        WMSZ_TOP = &H3
        WMSZ_TOPLEFT = &H4
        WMSZ_TOPRIGHT = &H5
    End Enum
    Enum WVR
        WVR_VALIDRECTS = &H400
    End Enum
    Enum IntPtrBool
        [True] = 1
        [False] = 0
    End Enum
    <StructLayout(LayoutKind.Sequential)>
    Friend Structure RECT
        Public left As Long
        Public top As Long
        Public right As Long
        Public bottom As Long
    End Structure
    Protected Overrides Sub OnSourceInitialized(e As EventArgs)
        AspectRatio = Me.ActualWidth / Me.ActualHeight
        MyBase.OnSourceInitialized(e)
        Dim source As HwndSource = TryCast(HwndSource.FromVisual(Me), HwndSource)
        If source IsNot Nothing Then
            source.AddHook(New HwndSourceHook(AddressOf WinProc))
        End If
    End Sub
    Private Function WinProc(hwnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr, ByRef handled As Boolean) As IntPtr
        Select Case msg
            Case WM.WM_SIZING
                Select Case wParam
                    Case WMSZ.WMSZ_BOTTOM, WMSZ.WMSZ_TOP
                        ResizeDirection = Direction.Vertical
                        Exit Select
                    Case WMSZ.WMSZ_LEFT, WMSZ.WMSZ_RIGHT
                        ResizeDirection = Direction.Horizontal
                        Exit Select
                End Select
                If Not lParam = Nothing Then
                    Dim Rect As RECT = Marshal.PtrToStructure(Of RECT)(lParam)
                    If ResizeDirection = Direction.Horizontal Then
                        Rect.bottom = Rect.top
                    Else
                        Rect.right = Rect.top
                    End If
                    'Manipulating Resize Rectangle
                    Rect.top = 1
                    Rect.bottom = 2
                    Rect.left = 3
                    Rect.right = 4 
                    Marshal.StructureToPtr(Of RECT)(Rect, lParam, False)
                End If
                Return IntPtrBool.True
        End Select
        Return IntPtr.Zero
    End Function

End Class

处理WM_WINDOWPOSCHANGING:

Imports System.Runtime.InteropServices
Imports System.Windows.Interop

Public Class AspectWindow
    Inherits Window
    Private AspectRatio As Double
    Private ResizeDirection As WMSZ
    Enum WM
        WM_SIZING = &H214
        WM_WINDOWPOSCHANGING = &H46
    End Enum
    Enum WMSZ
        WMSZ_BOTTOM = &H6
        WMSZ_BOTTOMLEFT = &H7
        WMSZ_BOTTOMRIGHT = &H8
        WMSZ_LEFT = &H1
        WMSZ_RIGHT = &H2
        WMSZ_TOP = &H3
        WMSZ_TOPLEFT = &H4
        WMSZ_TOPRIGHT = &H5
    End Enum
    Enum IntPtrBool
        [True] = 1
        [False] = 0
    End Enum
    <StructLayout(LayoutKind.Sequential)>
    Friend Structure WINDOWPOS
        Public hwnd As IntPtr
        Public hwndInsertAfter As IntPtr
        Public x As Integer
        Public y As Integer
        Public cx As Integer
        Public cy As Integer
        Public flags As Integer
    End Structure
    Protected Overrides Sub OnSourceInitialized(e As EventArgs)
        AspectRatio = Me.ActualWidth / Me.ActualHeight
        MyBase.OnSourceInitialized(e)
        Dim source As HwndSource = TryCast(HwndSource.FromVisual(Me), HwndSource)
        If source IsNot Nothing Then
            source.AddHook(New HwndSourceHook(AddressOf WinProc))
        End If
    End Sub
    Private Function WinProc(hwnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr, ByRef handled As Boolean) As IntPtr
        Select Case msg
            Case WM.WM_SIZING
                ResizeDirection = wParam
                Return IntPtrBool.True
            Case WM.WM_WINDOWPOSCHANGING
                Dim Pos = Marshal.PtrToStructure(Of WINDOWPOS)(lParam)
                Dim Last = Pos
                If Not ResizeDirection = WMSZ.WMSZ_TOP AndAlso Not ResizeDirection = WMSZ.WMSZ_BOTTOM Then
                    Pos.cy = Pos.cx / AspectRatio
                End If
                If Not ResizeDirection = WMSZ.WMSZ_RIGHT AndAlso Not ResizeDirection = WMSZ.WMSZ_LEFT Then
                    Pos.cx = Pos.cy * AspectRatio
                End If
                If ResizeDirection = WMSZ.WMSZ_TOPRIGHT OrElse ResizeDirection = WMSZ.WMSZ_TOPLEFT Then
                    Pos.y += Last.cy - Pos.cy
                End If

                Marshal.StructureToPtr(Of WINDOWPOS)(Pos, lParam, True)

        End Select
    End Function
End Class

相关内容

  • 没有找到相关文章

最新更新