Option Explicit
#If Win64 Then
Private Const NULL_PTR = 0^
#Else
Private Const NULL_PTR = 0&
#End If
#If VBA7 Then
#If Win64 Then
Private Declare PtrSafe Function AccessibleObjectFromPoint Lib "oleacc" (ByVal arg1 As LongPtr, ppacc As Any, pvarChild As Variant) As Long
#Else
Private Declare PtrSafe Function AccessibleObjectFromPoint Lib "oleacc" (ByVal X As Long, ByVal Y As Long, ppacc As Any, pvarChild As Variant) As Long
#End If
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Private Declare PtrSafe Function IUnknown_GetWindow Lib "shlwapi" Alias "#172" (ByVal pIUnk As IUnknown, hUF As LongPtr) As Long
Private Declare PtrSafe Function PeekMessage Lib "user32" Alias "PeekMessageA" (lpMsg As Msg, ByVal Hwnd As LongPtr, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
Private Declare PtrSafe Function WaitMessage Lib "user32" () As Long
Private Declare PtrSafe Function GetClientRect Lib "user32.dll" (ByVal Hwnd As LongPtr, lpRect As RECT) As Long
Private Declare PtrSafe Function GetDC Lib "user32" (ByVal Hwnd As LongPtr) As LongPtr
Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal Hwnd As LongPtr, ByVal hDC As LongPtr) As Long
Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hDC As LongPtr, ByVal nIndex As Long) As Long
#Else
Private Enum LongPtr
[_]
End Enum
Private Declare Function AccessibleObjectFromPoint Lib "oleacc" (ByVal X As Long, ByVal Y As Long, ppacc As Any, pvarChild As Variant) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Private Declare Function IUnknown_GetWindow Lib "shlwapi" Alias "#172" (ByVal pIUnk As IUnknown, hUF As LongPtr) As Long
Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" (lpMsg As Msg, ByVal Hwnd As LongPtr, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
Private Declare Function WaitMessage Lib "user32" () As Long
Private Declare Function GetClientRect Lib "user32.dll" (ByVal Hwnd As LongPtr, lpRect As RECT) As Long
Private Declare Function GetDC Lib "user32" (ByVal Hwnd As LongPtr) As LongPtr
Private Declare Function ReleaseDC Lib "user32" (ByVal Hwnd As LongPtr, ByVal hDC As LongPtr) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDC As LongPtr, ByVal nIndex As Long) As Long
#End If
Private Type POINTAPI
X As Long
Y As Long
End Type
Private Type Msg
Hwnd As LongPtr
message As Long
wParam As LongPtr
lParam As LongPtr
time As Long
pt As POINTAPI
End Type
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private oWIA As Object, oImg As Object, oImagesStack As Object
Private nMaxWidth As Long, nMaxHeight As Long
Private sngOldX As Single, sngOldY As Single
Private sngZoomPointX As Single, sngZoomPointY As Single
Private bLooping As Boolean, bPanning As Boolean
Private Const IMAGE_PATH_NAME = "C:\Users\hp\Downloads\math.png" ' <== change as required.
Private Sub UserForm_Initialize()
Dim Hwnd As LongPtr, hFrame As LongPtr
Set oImagesStack = CreateObject("Scripting.Dictionary")
Call IUnknown_GetWindow(Me, Hwnd)
hFrame = Frame1.[_GethWnd]
With Image1
.Left = 0
.Top = 0
.Width = Frame1.Width
.Height = Frame1.Height
End With
LoadWIAImage Image1, hFrame, IMAGE_PATH_NAME
End Sub
Private Sub UserForm_Activate()
Call MonitorMouseWheel
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
bLooping = False
' CleanUp
Set oWIA = Nothing
Set oImg = Nothing
Set oImagesStack = Nothing
End Sub
Private Sub Image1_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
If Button = 1 Then
bPanning = True
sngOldX = X
sngOldY = Y
End If
End Sub
Private Sub image1_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
bPanning = False
End Sub
Private Sub Image1_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Dim sngCurLeft As Single, sngCurTop As Single
If Button = 1 And bPanning Then
With Image1
sngCurLeft = .Left + (X - sngOldX)
sngCurTop = .Top + (Y - sngOldY)
If (sngCurLeft < 0 And sngCurLeft > Frame1.InsideWidth - .Width) And _
(sngCurTop < 0 And sngCurTop > Frame1.InsideHeight - .Height) Then
.Left = .Left - sngOldX + X
.Top = .Top - sngOldY + Y
End If
End With
End If
End Sub
Private Sub ZoomIn()
Const sngZoomFactor = 2&
Dim OldWidth As Single, oldHeight As Single
With Image1
oImagesStack.Add .Picture, .Left & "|" & .Top & "|" & .Width & "|" & .Height
OldWidth = .Width
oldHeight = .Height
.Width = .Width * sngZoomFactor
.Height = .Height * sngZoomFactor
With oWIA.Filters(1)
.Properties("MaximumWidth") = nMaxWidth * sngZoomFactor
.Properties("MaximumHeight") = nMaxHeight * sngZoomFactor
.Properties("PreserveAspectRatio") = False
Set Image1.Picture = oWIA.Apply(oImg).FileData.Picture
End With
.Left = .Left - sngZoomPointX
.Top = .Top - sngZoomPointY
nMaxWidth = PTtoPX(.Width, False)
nMaxHeight = PTtoPX(.Height, True)
End With
End Sub
Private Sub ZoomOut()
Dim sImgDimensions As String
If oImagesStack.Count Then
With Image1
sImgDimensions = oImagesStack.Items()(oImagesStack.Count - 1&)
Set .Picture = oImagesStack.Keys()(oImagesStack.Count - 1&)
.Left = Split(sImgDimensions, "|")(0&)
.Top = Split(sImgDimensions, "|")(1&)
.Width = Split(sImgDimensions, "|")(2&)
.Height = Split(sImgDimensions, "|")(3&)
nMaxWidth = PTtoPX(.Width, False)
nMaxHeight = PTtoPX(.Height, True)
End With
oImagesStack.Remove oImagesStack.Keys()(oImagesStack.Count - 1&)
End If
End Sub
Private Sub LoadWIAImage(ByVal img As Image, ByVal hImgContainer As LongPtr, ByVal imageFilePathName As String)
Dim uRect As RECT
Call GetClientRect(hImgContainer, uRect)
With uRect
nMaxWidth = .Right - .Left
nMaxHeight = .Bottom - .Top
End With
Set oWIA = CreateObject("WIA.ImageProcess")
Set oImg = CreateObject("WIA.ImageFile")
oImg.LoadFile imageFilePathName
oWIA.Filters.Add oWIA.FilterInfos.Item("Scale").FilterID
With oWIA.Filters(1)
.Properties("MaximumWidth") = nMaxWidth
.Properties("MaximumHeight") = nMaxHeight
.Properties("PreserveAspectRatio") = False
Set img.Picture = oWIA.Apply(oImg).FileData.Picture
End With
End Sub
Private Sub MonitorMouseWheel()
Const WHEEL_DELTA = 120&, WM_MOUSEWHEEL = &H20A, PM_NOREMOVE = &H0&
Dim tMsg As Msg
Dim lDelta As Integer, lAccumulatedDelta As Long
Dim X As Long, Y As Long
Dim oiAcc As IAccessible
Dim nLeft As Long, nTop As Long
Do
bLooping = True
Call WaitMessage
If PeekMessage(tMsg, NULL_PTR, WM_MOUSEWHEEL, WM_MOUSEWHEEL, PM_NOREMOVE) Then
X = tMsg.pt.X: Y = tMsg.pt.Y
#If Win64 Then
Dim lPt As LongLong
Call CopyMemory(lPt, tMsg.pt, LenB(lPt))
Call AccessibleObjectFromPoint(lPt, oiAcc, 0&)
#Else
Call AccessibleObjectFromPoint(X, Y, oiAcc, 0&)
#End If
Call oiAcc.accLocation(nLeft, nTop, 0&, 0&)
lDelta = HiWord(tMsg.wParam)
If lDelta * lAccumulatedDelta > 0& Then
lAccumulatedDelta = lAccumulatedDelta + lDelta
Else
lAccumulatedDelta = lDelta
End If
If oiAcc.accRole(0&) = 40& Then
If lAccumulatedDelta > 0& Then
sngZoomPointX = PXtoPT(X - nLeft, False)
sngZoomPointY = PXtoPT(Y - nTop, True)
Call ZoomIn
Else
sngZoomPointX = PXtoPT(nLeft - X, False)
sngZoomPointY = PXtoPT(nTop - Y, True)
Call ZoomOut
End If
End If
End If 'End of PeekMessage
DoEvents
Loop Until bLooping = False
End Sub
Function ScreenDPI(ByVal bVert As Boolean) As Long
Const LOGPIXELSX As Long = 88&, LOGPIXELSY As Long = 90&
Static lDPI(1) As Long, hDC As LongPtr
If lDPI(0&) = 0& Then
hDC = GetDC(NULL_PTR)
lDPI(0&) = GetDeviceCaps(hDC, LOGPIXELSX)
lDPI(1&) = GetDeviceCaps(hDC, LOGPIXELSY)
hDC = ReleaseDC(NULL_PTR, hDC)
End If
ScreenDPI = lDPI(Abs(bVert))
End Function
Function PXtoPT(ByVal Pixels As Long, ByVal bVert As Boolean) As Single
Const POINTSPERINCH As Long = 72&
PXtoPT = (Pixels * POINTSPERINCH) / ScreenDPI(bVert)
End Function
Private Function PTtoPX(Points As Single, bVert As Boolean) As Long
Const POINTS_PER_INCH = 72&
PTtoPX = Points * ScreenDPI(bVert) / POINTS_PER_INCH
End Function
Private Function HiWord(Param As LongPtr) As Integer
Call CopyMemory(HiWord, ByVal VarPtr(Param) + 2&, 2&)
End Function