0
런타임에 사용자 지정 컨트롤에서 wndproc 주소를 성공적으로 변경했습니다. 하지만 내 문제는 디자인 타임에 이것을 구현하려고 할 때 발생합니다. 컨트롤을 Visual Studio (2008) 양식에 놓으면 충돌이 발생합니다. (주춤 5.0 CF 2.0)wndproc의 디자인 타임 변경으로 인해 Visual Studio가 손상됩니다.
의 Win32 공간
(실시 예 만)
Friend Class NativeMethods
Friend Shared ReadOnly Property IsDesignTime() As Boolean
Friend Shared ReadOnly Property IsRunTime() As Boolean
Friend Shared Function GetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer
If (NativeMethods.IsDesignTime) Then
Return user32.GetWindowLong(hWnd, nIndex)
ElseIf (NativeMethods.IsRunTime) Then
Return coredll.GetWindowLong(hWnd, nIndex)
Else
Throw New Exception()
End If
End Function
Private Class coredll
<DllImport(DLLNAME, EntryPoint:="GetWindowLongW", CharSet:=CharSet.Auto, SetLastError:=True)> _
Friend Shared Function GetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer
End Function
Friend Const DLLNAME As String = "coredll.dll"
End Class
Private Class user32
<DllImport(DLLNAME, CharSet:=CharSet.Auto, SetLastError:=True)> _
Friend Shared Function GetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer
End Function
Friend Const DLLNAME As String = "user32.dll"
End Class
End Class
IsDesignTime IsRunTime 및 복귀 모두 올바른 값.
마지막으로
Public Class SystemControl
Inherits System.Windows.Forms.Control
Friend Sub New()
Me.m_borderStyle = Windows.Forms.BorderStyle.None
Me.m_isDisposed = False
Me.m_isHandleCreated = False
End Sub
Public Property BorderStyle() As BorderStyle
Get
Return Me.m_borderStyle
End Get
Set(ByVal value As BorderStyle)
If (value <> Me.m_borderStyle) Then
Me.m_borderStyle = value
Me.UpdateStyles()
End If
End Set
End Property
Public ReadOnly Property DesignMode() As Boolean
Get
Return (((Not Me.Site Is Nothing) AndAlso Me.Site.DesignMode) OrElse StaticMethods.IsDesignMode(MyBase.Parent))
End Get
End Property
Public ReadOnly Property IsDisposed() As Boolean
Get
Return Me.m_isDisposed
End Get
End Property
Public ReadOnly Property IsHandleCreated() As Boolean
Get
Return Me.m_isHandleCreated
End Get
End Property
Private Function Callback(ByVal hWnd As IntPtr, ByVal msg As UInteger, ByVal wparam As IntPtr, ByVal lparam As IntPtr) As IntPtr
Dim m As Microsoft.WindowsCE.Forms.Message = Microsoft.WindowsCE.Forms.Message.Create(hWnd, CInt(msg), wparam, lparam)
Me.WndProc(m)
Return m.Result
End Function
Public Sub DefWndProc(ByRef m As Microsoft.WindowsCE.Forms.Message)
If (Me.windowProcHandle = IntPtr.Zero) Then
m.Result = Win32.NativeMethods.DefWindowProc(m.HWnd, CUInt(m.Msg), m.WParam, m.LParam)
Else
m.Result = Win32.NativeMethods.CallWindowProc(Me.windowProcHandle, m.HWnd, CUInt(m.Msg), m.WParam, m.LParam)
End If
End Sub
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Me.UnhookWindoProc()
Me.m_isDisposed = True
MyBase.Dispose(disposing)
End Sub
Private Sub HookWindowProc()
Me.UnhookWindoProc()
Dim hWnd As IntPtr = MyBase.Handle
If (hWnd <> IntPtr.Zero) Then
Dim [error] As Exception = Nothing
SyncLock Me
Me.windowProcHandle = Win32.NativeMethods.GetWindowLongPtr(hWnd, Win32.GWL.WNDPROC)
If (Me.windowProcHandle <> IntPtr.Zero) Then
Try
Me.windowProcDelegate = New Win32.WindowProc(AddressOf Me.Callback)
Me.windowProcRoot = GCHandle.Alloc(Me.windowProcDelegate)
Win32.NativeMethods.SetWindowLongDlg(hWnd, Win32.GWL.WNDPROC, Me.windowProcDelegate)
Me.windowProcHWnd = hWnd
Me.windowProcHooked = True
Catch ex As Exception
Me.windowProcRoot.Free()
Me.windowProcDelegate = Nothing
Me.windowProcHandle = IntPtr.Zero
Me.windowProcHWnd = IntPtr.Zero
Me.windowProcHooked = False
[error] = ex
End Try
End If
End SyncLock
If (Not [error] Is Nothing) Then
Throw [error]
End If
End If
End Sub
Protected Overrides Sub OnHandleCreated(ByVal e As System.EventArgs)
Me.m_isHandleCreated = True
MyBase.OnHandleCreated(e)
End Sub
Protected Overrides Sub OnHandleDestroyed(ByVal e As System.EventArgs)
Me.m_isHandleCreated = False
MyBase.OnHandleDestroyed(e)
End Sub
Protected Overrides Sub OnParentChanged(ByVal e As System.EventArgs)
Me.UnhookWindoProc()
If (Me.DesignMode) Then
'TODO: Uncomment to make Visal Studio crash.
'Me.HookWindowProc()
Else
Me.HookWindowProc()
End If
Me.UpdateStyles()
MyBase.OnParentChanged(e)
End Sub
Private Function ShouldSerializeBorderStyle() As Boolean
Return (Me.m_borderStyle <> Windows.Forms.BorderStyle.None)
End Function
Public Sub UpdateStyles()
Dim hWnd As IntPtr = MyBase.Handle
If (hWnd <> IntPtr.Zero) Then
Dim style As Win32.WS = DirectCast(CUInt(Win32.NativeMethods.GetWindowLong(hWnd, Win32.GWL.STYLE)), Win32.WS)
Dim exStyle As Win32.WS_EX = DirectCast(CUInt(Win32.NativeMethods.GetWindowLong(hWnd, Win32.GWL.EXSTYLE)), Win32.WS_EX)
style = (style And Not Win32.WS.BORDER)
exStyle = (exStyle And Not Win32.WS_EX.CLIENTEDGE)
Select Case Me.m_borderStyle
Case Windows.Forms.BorderStyle.Fixed3D
exStyle = (exStyle Or Win32.WS_EX.CLIENTEDGE)
Exit Select
Case Windows.Forms.BorderStyle.FixedSingle
style = (style Or Win32.WS.BORDER)
Exit Select
Case Else
Exit Select
End Select
Win32.NativeMethods.SetWindowLong(hWnd, Win32.GWL.STYLE, CInt(style))
Win32.NativeMethods.SetWindowLong(hWnd, Win32.GWL.EXSTYLE, CInt(exStyle))
Win32.NativeMethods.SetWindowPos(hWnd, New IntPtr(Win32.HWND.TOP), 0, 0, 0, 0, (Win32.SWP.DRAWFRAME Or (Win32.SWP.NOACTIVATE Or (Win32.SWP.NOZORDER Or (Win32.SWP.NOMOVE Or Win32.SWP.NOSIZE)))))
End If
End Sub
Private Sub UnhookWindoProc()
If (Me.windowProcHooked) Then
Dim [error] As Exception = Nothing
SyncLock Me
Try
Win32.NativeMethods.SetWindowLongPtr(Me.windowProcHWnd, Win32.GWL.WNDPROC, Me.windowProcHandle)
Catch ex As Exception
[error] = ex
Finally
Me.windowProcRoot.Free()
Me.windowProcDelegate = Nothing
Me.windowProcHandle = IntPtr.Zero
Me.windowProcHooked = False
End Try
End SyncLock
If (Not [error] Is Nothing) Then
Throw [error]
End If
End If
End Sub
Protected Overridable Sub WndProc(ByRef m As Microsoft.WindowsCE.Forms.Message)
Me.DefWndProc(m)
End Sub
Private windowProcDelegate As Win32.WindowProc
Private windowProcHandle As IntPtr
Private windowProcHWnd As IntPtr
Private windowProcRoot As GCHandle
Private windowProcHooked As Boolean
Private m_borderStyle As BorderStyle
Private m_isDisposed As Boolean
Private m_isHandleCreated As Boolean
End Class
다시 VS를 시작하여 진단 및 +가 프로세스에 연결 도구로 1 차 인스턴스에 연결합니다. 이것은 위험해야하며 디자이너가 창을 하위 클래스로 분류 할 가능성이 매우 높습니다. –
한번 시도해 보겠습니다. 디자인 타임에 VS에 표시되는 컨트롤은 CF 버전을 사용하고 있지만 사실은 .net 2.0 컨트롤 (PublicKeyToken = b77a5c561934e089)입니다. 윈도우가 호출하는 스레드와 같은 프로세스에 속하지 않으면 "이 속성 (GWL_WNDPROC)을 변경할 수 없다"는 MSDN을 읽었습니다. 그래서 이것이 사실이라면 VS 충돌을 일으킬 것이라고 생각합니까? –
다른 프로세스에서 실행되지 않습니다. 디자인 타임에 데스크톱에 대한 하드 충돌은 거의 항상 StackOverflowException btw입니다. 서브 클래 싱 된 WndProc가 서브 클래 싱 된 WndProc을 다시 호출하는 원래의 WndProc을 호출 할 때 하나를 얻습니다. 윈도우가 두 번 이상 서브 클래스 화되는 경우 드문 일이 아니며 순서가 중요합니다. 따라서 다시 서브 클래 싱을 취소하면 너무 자주 잘못됩니다. –