Open a pdf file programmatically at a named destination

JeremyHigginson
JeremyHigginson used Ask the Experts™
on
I want to use VBA code to open a specific pdf file at a given location in response to a user's request.
According to info on the Adobe site, this can be achieved with the following code:
Acrobat.exe /A "nameddest=suppliedparameter=OpenActions" "Location\FileName.pdf"
I basically want to replicate this within VBA, but I'm not sure how to initiate this.
I've seen some info about how to open a pdf file at a given page number (http://www.experts-exchange.com/Microsoft/Development/MS_Access/Q_20949436.html) but I don't see how to swap the pageno reference for the nameddestination reference. Also, I'm not clear if the named destination is just any piece of text within the pdf file, or some translation of an underlying bookmark.

Currently I perform this function using a Word document with bookmarks (it is a help file and each bookmark represents the guidance for a specific form within the application). I just want to swap the editable Word document for an uneditable acrobat document (at the same time reducing the size of the underlying document).
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Dim AcroApp As CAcroApp
    Dim AVDoc As CAcroAVDoc
    Dim PDDoc As CAcroPDDoc
    Dim mypath As String
    Dim mystring As String
    Dim pg As Integer
    
 
     'you'll need to change this to an existing pdf file on your system
    mypath = "c:\yourfile.pdf"
     
    Set AcroApp = CreateObject("AcroExch.App")
    Set AVDoc = CreateObject("AcroExch.AVDoc")
     
    AVDoc.Open mypath, ""
    Set PDDoc = AVDoc.GetPDDoc
     
    If IsNull(Me.Jumpto) Then
    MsgBox ("enter a page to jump to")
    Else:
        pg = Me.Jumpto - 1
    'mystring = Me.findme 'InputBox("Enter text to search for:", "PDF Search")
    'AVDoc.FindText mystring, 0, 0, 0
    AVDoc.GetAVPageView.GoTo pg 'put whatever page you wanna goto there but keep in mind
' that page 1 is 0
    AcroApp.Show

Open in new window

Author

Commented:
Thanks for this suggestion. I have abbreviated the code as shown below, as I don't need to go to a page, just a piece of text, which is passed to the procedure as a parameter (pstrBookmark).

This runs OK, but the Acrobat Reader doesn't actually seem to materialise for some reason. It opens normally if I just double click the source pdf file, so there doesn't seem to be anything fundamentally wrong with Acrobat itself (and I rebooted the machine beforehand so there shouldn't be any bits lurking unseen in memory). The file string (strFileName) is correct, and includes the path and file plus .pdf extension.

Should any of the Dim statements be prefixed with "Acrobat." (they all were in the example I had seen which I referenced earlier)? I have checked the reference to Adobe Acrobat 8.0 Type Library - I assume that (a) this is necessary and (b) it is the right dll?


    Dim AcroApp As CAcroApp
    Dim AVDoc As CAcroAVDoc
    Dim PDDoc As CAcroPDDoc
 
    Set AcroApp = CreateObject("AcroExch.App")
    Set AVDoc = CreateObject("AcroExch.AVDoc")
    AVDoc.Open strFileName, ""
    Set PDDoc = AVDoc.GetPDDoc
    AVDoc.FindText pstrBookmark, 0, 0, 0
    AcroApp.Show

Open in new window

Author

Commented:
I've just realised that the code I'm running has error trapping switched off (a legacy of the Word code which needs to continue running if a Word app is already loaded). Now I've switched it on, I get an error "429: ActiveX component can't create object" when running the first line of Acrobat code -
  Set AcroApp = CreateObject("AcroExch.App")
This happens whether or not I prefix the Dim statements with Acrobat.xxx, so obviously I need to include a different Acrobat reference in my VBA - do you know what it is?
Success in ‘20 With a Profitable Pricing Strategy

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Jeremy,

My apologies for the delayed response, have been tied up.  Anyways, it appears you are just viewing the pdf and searching for a keyword, I was thing you needed to edit also.  My mistake!  The above code will only execute with the full version of Acrobat (not just the reader).  Let's try a different method:

In Access, open up your VBA window.  On the left hand side look for "Modules" (should be the next "+" after Microsoft Office Access Class Objects.  Right click Modules and create a new one.  Name it whatever you want.  Open the new module and insert this code:


Public Declare Function apiShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
 
Public Function GetFile(strFile As String) As Boolean
Dim fs As Object
Dim lResult As Long
 
Set fs = CreateObject("Scripting.filesystemobject")
If fs.FileExists(strFile) Then
    lResult = apiShellExecute(hWndAccessApp, vbNullString, strFile, vbNullString, vbNullString, 1)
    GetFile = (lResult > 32)
Else
    MsgBox "Cannot Open " & strFile & vbCrLf & "File is not found.", vbExclamation + vbOKOnly, "Get File:"
End If
Set fs = Nothing
End Function

Open in new window

After that code is in there, you will be able to use the GetFile command anywhere in your coding.  The code checks to make sure the file exists before executing the next step.

In this example, I am going to use a command button for the user to click to open the pdf, but you can use it however you choose (I can help if you tell me what you want.)


private sub command1_Click
 
GetFile "C:\where\the\pdf\is\mypdf.pdf#search="test""
 
end sub

Open in new window

Scrap that, give me a few minutes...program does not like the #search prefix.

Commented:
Why not use the shell command - something like the following?

Shell "Acrobat.exe /A nameddest=suppliedparameter=OpenActions Location\FileName.pdf"


Acrobat.exe /A "nameddest=suppliedparameter=OpenActions" "Location\FileName.pdf"

It looks like the path to Acrobat.exe has been set in DOS and whatever Location has been set to in Acrobat nails down the folder for Filename.pdf

Author

Commented:
Thanks - I have now tried this (I already had the ShellExecute function so have re-used it). Unfortunately the FileExists test uses the file name and also the search string, which it can't find, so I modified the code as shown. This now runs to completion but doesn't open the pdf file. Any ideas?
Public Function GetFile(pstrFile As String, Optional pstrSearch As String) As Boolean
    ' Comments  : Open a file using the ShellExecute function
    ' Parameters: pstrFile - the path & name of the destination file
    '             pstrSearch - the search string for pdf files
    ' Returns   : True if successful
    ' Created   : V04.04.03 21/07/09 21:09 JCH
    ' Modified  :
    '
    ' --------------------------------------------------
    On Error GoTo ErrPoint
    
    Dim fs As Object
    Dim lngResult As Long
    Dim strFileSearch As String
    
    If IsNull(pstrSearch) Then
        strFileSearch = pstrFile
    Else
        strFileSearch = pstrFile & pstrSearch
    End If
    Set fs = CreateObject("Scripting.filesystemobject")
    If fs.FileExists(pstrFile) Then
        lngResult = ShellExecute(hWndAccessApp, vbNullString, strFileSearch, vbNullString, vbNullString, 1)
        GetFile = (lngResult > 32)
    Else
        MsgBox "Cannot Open " & pstrFile & vbCrLf & "File is not found.", vbExclamation + vbOKOnly, "Get File:"
    End If
    Set fs = Nothing
    
ExitPoint:
    Exit Function
    
ErrPoint:
    HandleError Err.Number, Err.Description, Err.Source, "Module", "basGenericFileOps", _
        "GetFile"
    Resume ExitPoint
    
End Function
 
***********************
 
AcrobatHelp:
    strSearch = "#search=" & acbFixUp(pstrBookmark)
    GetFile strFileName, strSearch

Open in new window

Author

Commented:
My last comments overlapped with yours. I have now tried the Acrobat.exe approach, but I'm having trouble with getting the right quote marks in the right place.

The whole Shell command should presumably be in double quotes, but this means that the elements of the acrobat parameters must be in single quotes (I think), with the nameddest string itself not in quotes at all (it is bounded by two equality signs).

Shell "Acrobat.exe /A 'nameddest=frmMenuMainGeneral=OpenActions' 'D:\Data\...\CAMS User Guide.pdf'"

But unfortunately this doesn't seem to work, as I get a "53: File not found" error....

Commented:
Normally: Shell "Drive&PathToExe/MyExe.exe PathFile2Use/myFile.mdb"

Why not try:

Shell "c:\Path2Executable\Adobe.exe d:\path2file\CAMS User Guide.pdf"  for a start

Author

Commented:
I've tried the following:

    Debug.Print Dir(strFileName)
    Shell "AcroRd32.exe strFileName"

The Debug.Print statement returns the file name so I know that the string is valid, but the Shell statement still returns the error 53 file not found (I changed Acrobat.exe to AcroRd32.exe as I'm only trying to execute the reader not the full blown Acrobat product).

So I've reverted for now to using the ShellExecute statement, which seems to work if I only pass the filename as a parameter, and not the additional search string. I've attached the code below.

However, I'm still currently better off with opening the original Word version of the User Guide. With Word, I can use the bookmarks to make sure that the right page of the guide is dsiplayed for the form where the user clicked Help. The downside is that not everyone's Word has the same set of options set, so you cannot guarantee that the document will look as you expect it will (and you have to make sure that the file is read-only to prevent accidental updates).

I am surpised that this turns out to be so arcane for Acrobat - it's so easy in Word.
    DoCmd.Hourglass True
    'strFileName = strFileName & "#search=" & acbFixUp(pstrBookmark)
    Set fs = CreateObject("Scripting.filesystemobject")
    If fs.FileExists(strFileName) Then
        If ShellExecute(hWndAccessApp, vbNullString, strFileName, vbNullString, vbNullString, 1) <= 32 Then
            'Display error messaage
            DoCmd.Hourglass False
            GoTo ExitPoint
        End If
    Else
        'Display error messaage
        DoCmd.Hourglass False
        GoTo ExitPoint
    End If
    Set fs = Nothing
    DoCmd.Hourglass False

Open in new window

Whole new approach, Adobe Reader doesn't want to respond with simple shell commands....

Try this:

the webstring calls a url instead of a shell path.  In my example:  \\computer_name\drive letter\file.name

If you have the folder shared on a server, \\server_name\shared_directory\test.pdf

*Note*  I don't have any named destinations on my pdf file, so I tried the example with test.pdf#search='blah' and it worked like a champ.

We might have to play around with the syntax of the nameddest part, maybe take off the quotes?


webstring = "\\tamary-bell_an\c$\test.pdf#nameddest='dest1'"
    
    Application.FollowHyperlink strInput, , True
    GetUserAddress = True

Open in new window

Copied wrong code (original test was with an input box)

Use this:
webstring = "\\tamary-bell_an\c$\test.pdf#nameddest='dest1'"
    
    Application.FollowHyperlink webstring, , True
    GetUserAddress = True

Open in new window

Author

Commented:
Thnaks for the suggestion. I have used the code below which opens the pdf file OK, even with just a drive letter and absolute path, but I still can't get it to find the required text (although if I open the user guide directly in Acrobat Reader and use the Find or Search option it does work, so there can't be a problem with the text string per se). I have tried the text string with and without quotes. My Adobe Reader always comes up with a Content Preparation Progress message box and it insists on running through the doc doing something (which makes no visible difference to the presentation on the screen) - I don't know if this is significant, but I wouldn't be able to switch it on or off on other PCs so my search function would have to work irrespective. Any ideas?

(I will have no control over where the users of this app might store the files, but in many cases it is likely to be on the same PC, so the option to utilise a drive letter / absolute path is essential.)
    strFileName = "D:\Data\.....\CAMS User Guide.pdf#search='Welcome'"
    Application.FollowHyperlink strFileName, , True

Open in new window

Jeremy,

The content preperation progress box prepares a temporary file if you want Adobe to read the file out loud through the speakers (you'd think this would be disabled by default).

Without repackaging and reinstalling the software on all of the user's computers, there is no way that I know of to disable it through a script.  There are two options to stop it:

Browse to the Adobe folder in program files, find accessibility.api and readoutloud.api and delete or rename them to accessibility.old and readoutloud.old.

or:
   
Open Adobe Reader.  Goto Edit,  Preferences, Reading.  Under Screen Reader Options, select Only read the currently visible pages

---The Content Preperation should NOT block any parameters to be passes to adobe.-----

Ok, after reading a few articles, the application.followhyperlink is giving other people problems too.  Some people are saying it's bugged, others are not.  But anyways, let's just use a basic shell command as a building block.

Since this Adobe doesn't feel like playing nice, we'll start as easy as possible.  I know this line of code works.  Do you think everyone has Adobe installed at the same directory?  If not, we will work on that part next.
Shell "C:\Program Files\Adobe\Reader\AcroRd32.exe /a search=introduction C:\test.pdf", vbNormalFocus

Open in new window

Author

Commented:
Hi LAU
Thanks for explaining what the content preparation function does! If it doesn't interfere, that's fine.

The line of code works BUT
My version of AcroRd32.exe is in the folder C:\Program Files\Adobe\Reader 8.0\Reader (i.e. an extra level over yours - not knowingly my choice); therefore it seems likely that the location on user PCs will be random (my users will be dispersed across 250 sites throughout the UK, and I can guarantee that there will be no conformity in the location, or versions, of Acrobat reader files).

The file name works if there are no spaces in the path or filename; I tried putting single quotes round the 'spaced' location string but it wasn't happy with that. I cannot think of a way of incorporating the file string into the shell parameter without some form of quotation marks and I cannot force the file to reside only in a path with no spaces in it, as the users control where they want to put the application. I can't work out if this is an issue with the Shell command itself or Adobe Reader's parsing of the file string.

It also appears that the search string cannot contain spaces either (the single word Welcome is OK, but the phrase Welcome Page causes a problem). I could make sure that all phrases are concatenated, but this does mean there would be some strange words appearing on the page (since the search object would need to be visible).
Well, I can fix the location of Acrobat issue, but using more than one word for searching looks to be impossible from a shell command.  I've tried all combinations of quotes, along with using chr (30) and chr (34) commands.  I've read through the adobe reader parameter file a ton of times, it seems they lie about the capabilites of command line functions.  

If I understand correctly, it's not going to be a centralized pdf file.  Do we need to make the program hunt down the file on their computer?


Two code sections, one for a public function...the other for use on a form:

Function RegKeyRead(i_RegKey As String) As String
Dim myWS As Object
 
  On Error Resume Next
  'access Windows scripting
  Set myWS = CreateObject("WScript.Shell")
  'read key from registry
  RegKeyRead = myWS.RegRead(i_RegKey)
End Function
 
 
Private sub command0_click
 
  Dim strAcrobatLocation As String
  Dim strAcrobatPathRegKey As String
  Dim stAppName
 
  strAcrobatPathRegKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe\Path"
  strAcrobatLocation = RegKeyRead(strAcrobatPathRegKey) & "AcroRd32.exe"
 
  stAppName = strAcrobatLocation & " /A search=whatever C:\test.pdf"
 
 Shell stAppName, vbNormalFocus
 
 
End sub
 

Open in new window

You won't believe this one....

By loading the string down with quotes, I finally got it to search two words....BUT for some crazy backwards adobe reason, it searches each word independent.  Adobe's built in search searches the string...go figure.

Example:

IN ADOBE:  search:  forever after
results returned: 1

returned examples:
it seemed like forever after that


Shell search:  search:  forever after
results returned: 3

returned examples:
he ran forever
she left after
it seemed like forever after that


Craziness....

Might be better off just using the "page=" instead of "search="

Here's the code anyways:


Private Sub command1_Click()
  Dim stAppName
  
 
  Dim strAcrobatLocation As String
  Dim strAcrobatPathRegKey As String
 
  strAcrobatPathRegKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe\Path"
  strAcrobatLocation = RegKeyRead(strAcrobatPathRegKey) & "AcroRd32.exe"
 
  
  
  stAppName = strAcrobatLocation & " /A ""search=forever after"" ""C:\test.pdf"""
 Shell stAppName, vbNormalFocus
End Sub

Open in new window

Author

Commented:
Hi LAU

Sorry for the delay in replying - I've been away from my keyboard for a short while.

Thanks for all your research, your efforts are going beyond the call of duty. I thought that this would have been a regularly used option within Access for displaying the contents of an associated file, and I had thought that this would be simpler than using the Windows Help file route, which I haven't had time to udnerstand fully - but now I'm having my doubts!

Anyway, I've used your suggestions, and tweaked the quotation stacks to incorporate the variables that I need to use, so the code now appears as below - it took a while to work out how to get the quote counts right, but the debug statement now generates what I would want to see:

C:\Program Files\Adobe\Reader 8.0\Reader\AcroRd32.exe /A "search=Main Menu" "D:\Data\...\CAMS User Guide.pdf"

This opens the User Guide properly, but bizarrely when the search function in the Reader window is displayed the search string is shown as "MainMenu", without a space. However, I can probably work round this by thinking of a space-free string which I can insert into the document (e.g. the name of the form); I was trying to avoid meaningless phrases being displayed to the user, but this is a small price to pay.

Incidentally, I am assuming that this will work with any version of Acrobat Reader (as long as it uses the AcroRd32.exe program)? Also can you confirm that it is NOT necessary to include any Adobe Reader / Acrobat dlls in the References library? I have unchecked my use of the Adobe Acrobat 8.0 Type Library and it all seems to work fine (I think this was only necessary when I was trying to run the Acrobat program).
    strAcrobatPathRegKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe\Path"
    strAcrobatLocation = ReadRegKey(strAcrobatPathRegKey) & "AcroRd32.exe"
    strAppName = strAcrobatLocation & " /A ""search=" & pstrObjectTitle & """ """ & strFileName & """"
    Debug.Print strAppName
    Shell strAppName, vbNormalFocus

Open in new window

Interesting, I copied your code into access, and it worked fine (with the spaces).  

You are correct in not needing to use any references.  The search feature was introduced in Adobe 6.0 (a long time ago), so people should not have any problem running the script.

Author

Commented:
Went beyond the call of duty on this one.

Author

Commented:
LAU

Thanks very much. Really useful stuff.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial