(c) 2002 Visual Studio Magazine
Fawcette Technical Publications

Issue: September 2002
Section: Q&A
Authors: Karl E. Peterson, Juval Lwy, Mattias Sjgren

VB5, VB6	Intercept and Adjust Window Movements
Listing 1	You can alter the position displayed as the user drags a window about the screen. Intercept the WM_MOVING message and alter the contents of the rectangle structure used by Windows to position the window's drag rectangle.

Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" _
	Alias "RtlMoveMemory" (Destination As Any, _
	Source As Any, ByVal Length As Long)

Private Const WM_MOVING As Long = &H216

Private Type RECT
	Left As Long
	Top As Long
	Right As Long
	Bottom As Long
End Type

' ********************************************
'  Subclassing
' ********************************************
Friend Function WindowProc(hWnd As Long, _
	Msg As Long, wParam As Long, lParam As Long) _
		As Long
	Dim Result As Long
	Dim r As RECT
	Dim dX As Long
	Dim dY As Long

	' Precalculate screen dimensions.
	dX = Screen.Width \ Screen.TwipsPerPixelX
	dY = Screen.Height \ Screen.TwipsPerPixelY

	Select Case Msg
		Case WM_MOVING
			' Grab screen coordinates of drag 
			' rectangle.
			Call CopyMemory(r, ByVal lParam, _
				Len(r))
			' Adjust to prevent window from going 
			' offscreen.
			If r.Left < 0 Then
				r.Right = r.Right - r.Left
				r.Left = 0
			End If
			If r.Top < 0 Then
				r.Bottom = r.Bottom - r.Top
				r.Top = 0
			End If
			If r.Right > dX Then
				r.Left = dX - (r.Right - r.Left)
				r.Right = dX
			End If
			If r.Bottom > dY Then
				r.Top = dY - (r.Bottom - r.Top)
				r.Bottom = dY
			End If
			' Update drag rectangle for Windows.
			Call CopyMemory(ByVal lParam, r, _
				Len(r))
			' Let Windows know we've handled this.
			Result = True

		Case Else
			' Pass along to default window 
			' procedure.
			Result = InvokeWindowProc(hWnd, Msg, _
				wParam, lParam)
	End Select

	' Return desired result code to Windows.
	WindowProc = Result
End Function

VB.NET	Compare Const With ReadOnly
Listing 2	You use constants for only simple, static values. The ReadOnly keyword offers more flexibility, in that it allows you to initialize the variable in a constructor, based on calculations and parameters. 

Class Ball

	Private Const PI As Double = 3.14159265

	' The following doesn't work
	' Public Const SmallBall As New Ball( 5 )

	Public Shared ReadOnly SmallBall As New Ball _
		( 5 )
	Public Shared ReadOnly BigBall As New Ball _
		( 20 )

	Public ReadOnly Radius As Integer
	Public ReadOnly Volume As Double

	Public Sub New(ByVal radius As Integer)
		Me.Radius = radius
		Volume = 4 / 3 * PI * radius^3
	End Sub

End Class
