2016-10-16 11 views
0

В настоящее время я создаю окно WPF, которое сохраняет пропорции при изменении размера.AccessViolationException при смене lParam (Resize Rectangle)

Моей первой идеей было обработать сообщение WM_SIZE и установить размер там, но это вызвало раздражающее мерцание. Итак, я попытался изменить lParam WM_Size, который создал AccessViolationExceptions. То же самое происходит при манипулировании lParam на WM_SIZING.

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 
+1

It бомба очень трудно диагностировать путь, потому что вы не объявляли RECT правильно. Это объявление VB6, как указано в VB.NET, члены являются «Integer», а не Long. Повреждение памяти, вызванное написанием слишком большого количества данных, крайне сложно отлаживать. Используйте сайт pinvoke.net, чтобы найти достойные декларации. Вы также * действительно * хотите поставить Option Strict On в верхней части исходного файла, чтобы компилятор мог помочь вам получить мелкие ошибки, о которых позаботились. –

ответ

-1

решаемых с его обработкой 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