2016-10-16 10 views
0

크기를 조정할 때 종횡비를 유지하는 WPF 창을 현재 만들고 있습니다.lParam (Resize Rectangle)을 변경할 때 AccessViolationException이 발생했습니다.

첫 번째 아이디어는 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 
+1

이 폭탄을 매우 하드에 제대로 RECT를 선언하지 않았기 때문에 방법을 진단 할 수 있습니다. 게시 된 VB6 선언은 VB.NET에서 멤버가 정수가 아니라 Long이 아닙니다. 너무 많은 데이터를 쓰는 것에 의한 메모리 손상은 디버그하기가 대단히 어렵습니다. 괜찮은 선언을 찾으려면 pinvoke.net 웹 사이트를 사용하십시오. 또한 컴파일러가 작은 실수를 처리하는 데 도움이되도록 Option Strict를 소스 파일의 맨 위에 두는 것이 좋습니다. –

답변

-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