Option Explicit
#If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)
Private Declare PtrSafe Function FindExecutable Lib "shell32.dll" Alias "FindExecutableA" (ByVal lpFile As String, ByVal lpDirectory As String, ByVal lpResult As String) As Long
Private Declare PtrSafe Function GetDesktopWindow Lib "user32" () As LongPtr
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As Any) As LongPtr
Private Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare PtrSafe Function GetWindow Lib "user32" (ByVal hWnd As LongPtr, ByVal wCmd As Long) As LongPtr
Private Declare PtrSafe Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hWnd As LongPtr, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare PtrSafe Function IsWindow Lib "user32.dll" (ByVal hWnd As LongPtr) As Long
Private Declare PtrSafe Function WaitMessage Lib "user32.dll" () As Long
#Else
Private Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)
Private Declare Function FindExecutable Lib "shell32.dll" Alias "FindExecutableA" (ByVal lpFile As String, ByVal lpDirectory As String, ByVal lpResult As String) As Long
Private Declare Function GetDesktopWindow Lib "user32" () As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As Any) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindow Lib "user32" (ByVal hWnd As Long, ByVal wCmd As Long) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function IsWindow Lib "user32.dll" (ByVal hWnd As Long) As Long
Private Declare Function WaitMessage Lib "user32.dll" () As Long
#End If
Private Const WM_CLOSE = &H10
Private Const GW_HWNDNEXT = 2
Private Const GW_CHILD = 5
'This is called from Sheet's Worksheet_FollowHyperlink
Public Sub Open_PDF_At_Page(PDFfullName As String, Optional page As String = "1")
Dim PDFexe As String
Dim AdobeCommand As String
Dim PDFfile As String, p As Long
If Dir(PDFfullName) <> vbNullString Then
PDFexe = Get_ExePath(PDFfullName)
AdobeCommand = " /a ""page=" & page & "=Open Actions"" "
p = InStrRev(PDFfullName, "\")
PDFfile = Mid(PDFfullName, p + 1)
'Worksheet_FollowHyperlink opens the PDF automatically at page 1, if not already open. The PDF must be closed before opening it at the specified page,
'otherwise it will stay open at the current page
'Find and close the PDF's window using Windows API functions
Find_and_Close_Window PDFfile
'Open the PDF at the specified page
Shell Chr(34) & PDFexe & Chr(34) & AdobeCommand & Chr(34) & PDFfullName & Chr(34), vbNormal
Else
MsgBox PDFfullName & " doesn't exist", vbExclamation
End If
End Sub
Private Function Get_ExePath(lpFile As String) As String
Dim lpDirectory As String, sExePath As String, rc As Long
lpDirectory = "\"
sExePath = Space(255)
rc = FindExecutable(lpFile, lpDirectory, sExePath)
Get_ExePath = Left$(sExePath, InStr(sExePath, Chr$(0)) - 1)
End Function
Private Sub Find_and_Close_Window(windowTitle As String)
#If VBA7 Then
Dim hWnd As LongPtr
#Else
Dim hWnd As Long
#End If
Dim thisWindowTitle As String, thisClassName As String
Dim textLen As Long
Dim foundWindow As Boolean
Dim n As Long
Const AcrobatClassName = "AcrobatSDIWindow"
'Loop through all open windows
foundWindow = False
hWnd = GetWindow(GetDesktopWindow(), GW_CHILD)
n = 0
Do Until hWnd = 0 Or foundWindow
n = n + 1
thisWindowTitle = Space(256)
textLen = GetWindowText(hWnd, thisWindowTitle, Len(thisWindowTitle))
If textLen Then
'Close the window if its title matches the one being sought and is an Acrobat window
thisWindowTitle = Left(thisWindowTitle, textLen)
thisClassName = Space(256)
textLen = GetClassName(hWnd, thisClassName, Len(thisClassName))
thisClassName = Left(thisClassName, textLen)
If InStr(1, thisWindowTitle, windowTitle, vbTextCompare) And thisClassName = AcrobatClassName Then
PostMessage hWnd, WM_CLOSE, 0, 0
'Wait until the window has closed
While IsWindow(hWnd)
WaitMessage
DoEvents
Sleep 20
Wend
foundWindow = True
End If
End If
hWnd = GetWindow(hWnd, GW_HWNDNEXT)
Loop
End Sub