Link to home
Start Free TrialLog in
Avatar of TommySzalapski
TommySzalapskiFlag for United States of America

asked on

VBA or VBS enumerate all open Acrobat Reader documents

I want to (in some type of code) find all the pdf files that are open in Acrobat Reader (I only have Reader)
Since I don't have Acrobat Pro, I can't get any API calls to work (e.g. GetObject(, "AcroExch.App"))
The solution to the related link (searching running tasks) doesn't work since it only finds the first one, and that only if the pdf was double clicked (since it parses the shell command that started the process).

I need the entire path of the files. I had the idea to try to capture it from the open windows, but don't know how well that would work since only the file name shows and it's formatted differently in XP and 7.

Any ideas?
Avatar of SiddharthRout
Flag of India image

I can give you the code to display the names of all the PDF Files that are open using APIs.

I know how to get the path from the running EXE but not from File names. I am working on that at the moment.

There is one way I can think of...

If I close all the pdf one by one then I can get you the path of all the pdf's. I can then reopen them at the end. Would that help?

Avatar of TommySzalapski


Closing is fine. Don't bother reopening, I can do that. The version for Word and Excel closes them too (since that's the best way to iterate through Excel instances). Closing them doesn't change the command line for the process though.

Interested to see what you can up with.
came* up with
Avatar of SiddharthRout
Flag of India image

Link to home
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Sorry you need to run the last Sub Sample. Also press Ctl G to see immediate window where the output will be generated.

Did you ever find a way to get the path?
No Tommy. Even when I close the 1st pdf file, the Acro Exe still refers to the first file!!! I could get the name of all the pdf's though...

Still trying to figure out other way...

That's because you are looking at the command that started Acrobat.
If you start Acrobat by itself and then open pdfs, the command shell string won't give you any file at all.
Exactly but the API that I know can get the path of the Exe and that is not that we are looking at. So I am still thinking of an alternative to get the paths from the window name.


Ok I have been experimenting and I got stuck. But I am close...

Here is an example that I am trying to incorporate for just one pdf file. If this works then I will be able to get the path for all the PDF in the loop.

Under the file menu of Adobe is the submenu "properties" I am able to click that. I am just stuck as to how to retrieve the value of "Location". See snapshot.


Code Used

Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long

Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long


Private Sub Command_Click()
    Dim parenthwnd As Long
    '~~> Testing with 1.pdf
    parenthwnd = FindWindow(vbNullString, "1.pdf - Adobe Reader")
    '~~> Bringing the window to the foreground
    SetForegroundWindow parenthwnd
    '~~> Stimulating Alt F + R
    SendKeys "%F", True
    SendKeys "R", True
    '~~> Getting the handle of the "Document Properties"
    parenthwnd = FindWindow(vbNullString, "Document Properties")
    '~~> The code works till here
End Sub

Open in new window

Link to home
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of nffvrxqgrcfqvvc

You mean something like this?
I don't really feel like waiting for an 11MB video to download so I can watch it full screen but if it's getting the path and filename of all pdfs open in Acrobat Reader, then yes. I'm not really looking for a video though, I'm looking for code that I can run. Can you post the code you used?
Yes. That looks like what I want. Can you post the code, please?
Even I am curious to see that code.

How do I contact Southmod?

Much appreciated modus_in_rebus :)

Did you get a solution for this yet?
No. I've found programs that find all the open file handles and list them (Process Hacker etc), but none of them have an API that let me get the list programmatically. This may be my best option so far.
I've also been pointed to some Windows API calls beginning with NtQuerySystemInformation but I haven't had the time to try to get them working in VBScript yet.
Do you want me to create library that you can use from script?
Here play with this version until I finish the library. Let me know if you find bugs... If you need more explanation of how to use the library let me know example script version in code section.

'	AdobePDFX32.DLL
'	Version 1.0 Beta
'	egl1044
'        acroPDF.VBS

Dim AcrobatCore			'// AdobePDFX32
Dim AcroProcess			'// IAcrobatProcess
Dim AcroProcessCol		'// IAcrobatProcessCollection
Dim AcroPDFFile			'// IAcrobatPDFFile
Dim AcroPDFFileCol		'// IAcrobatPDFFileCollection
Dim AcroProcessRef		'// IAcrobatProcess (user referenced)

Sub SetObjectInitialStates
	Set AcrobatCore		= Nothing
	Set AcroProcess		= Nothing
	Set AcroProcessCol	= Nothing
	Set AcroPDFFile		= Nothing
	Set AcroPDFFileCol	= Nothing
	Set AcroProcessRef 	= Nothing
End Sub

'// 	Set all object variables to Nothing
Call SetObjectInitialStates

'//	Create Core object
Set AcrobatCore = CreateObject("AdobePDFX32.Core")

'//	Get a collection of Acrobat processes
Set AcroProcessCol = AcrobatCore.GetAcrobatProcesses

'//	Enumerate the IAcrobatProcessCollection collection
'//	There can be atleast two available, the IAcrobatProcess interface
'//		that you should reference should have a valid MainWindowHandle
'//		property not equal to zero.

Msgbox "Acrobat Reader Process Count: " & AcroProcessCol.Count
For Each AcroProcess In AcroProcessCol

	'// Reference the interface on condition.

	If AcroProcess.MainWindowHandle <> 0 Then

		Set AcroProcessRef = AcroProcess
		Exit For
	End If


'// Display the IAcrobatProcess Interface referenced above.
If Not AcroProcessRef Is Nothing Then

	Msgbox ( AcroProcessRef.Name & vbCrlf & AcroProcessRef.ProcessId & vbCrlf & AcroProcessRef.MainWindowHandle)

End If

'// Obtain the list of open PDF files 
If Not AcroProcessRef Is Nothing Then

	'// Get a collection of IAcrobatPDFFile
	Set AcroPDFFileCol = AcrobatCore.GetAcrobatPDFFiles(AcroProcessRef)

	'// Enumerate the IAcrobatPDFFileCollection collection
	Msgbox "Acrobat Reader Open PDF Count: " & AcroPDFFileCol.Count
	For Each AcroPDFFile In AcroPDFFileCol
		'// Display the FullName of each opened PDF document.

		Msgbox ( AcroPDFFile.FullName )
End If

Open in new window

Pleased to announce Acroof Release Enjoy Tom

Acroof Revision History

Acroof 4/5/2011      - Stable: XP,Vista,Windows 7
- New: Added new detection scheme
- New: Added Win32 file path support for Vista or later operating systems.
- New: Added Win32 file path support for Window XP operating system.
- New: Added Win32 file path support for network paths.
- New: Added MUP and LanmanRedirector support in Windows XP operating system.
- New: Added runtime functionality verification
- Fix: Removed various class/interfaces no longer required with the new detection scheme.
- Some minor changes and improvements
Dim oCore       '//	Acroof.Core
  Dim oFile       '//	IPDFFile
  Dim oFileCol    '//	IPDFFileCollection
  Set oCore = CreateObject("Acroof.Core")

  If oCore.IsCoreSupported Then
    Set oFileCol = oCore.GetOpenPDFFiles
      If oFileCol.Count <> 0 Then
        For Each oFile In oFileCol
          MsgBox oFile.FullName
        MsgBox "No files opened"
      End If
  End If

Open in new window
I really appreciate all the time you put into this, but I think you missed the part where I said I only have Acrobat Reader and so I can't call the Acrobat API at all.

I set a reference to your dll and it lets me declare
Dim oCore As Acroof.Core
So the library is running and connected but when it gets to the line
Set oCore = CreateObject("Acroof.Core")
It says it cannot create the object (which is what I expected to see)

If I set references to every Acro* thing in there it still won't let this line work (which I tried from your other post just to prove the point). It gives the same error.
Set AcrobatCore = CreateObject("AdobePDFX32.Core")

I'm sorry you spent so much time on this, but I still can't call any Acrobat ATIs.
It doesn't use the acrobat type library only internal windows API... You have to run RegSvr32 on acroof.dll before you can use it
I see. Yes that works nicely. Thanks a lot. The only problem is that it requires Admin privaleges to run, but since that wasn't specified in the original question, I won't count it against you. Post the code that you are using in the current dll, please, and then I'll close this out.
Admin privaleges to set up I mean, not run. Once set up, I know it will run for anybody.
<< The only problem is that it requires Admin privaleges to run, but since that wasn't specified in the original question, I won't count it against you. >>

1) Yes and No. You can use per user registration without admin rights and still use the library
2) Count it against me? If you mean points they don't really concern me, I come here to help others
3) The source code not going to happen because it's not a couple lines of code
You can use per user registration without admin rights and still use the library
I had to elevate to admin to register the dll at all.

The source code not going to happen because it's not a couple lines of code
Then why did you bother writing it? This site is supposed to be for experts to freely exchange knowledge. If I wanted a third party app, then you could have read that I had one already. Your library is very inflexible. What if I want it to do something slightly different later? The original question specifically asked for a code solution.
< Do you want me to create library that you can use from script?  >
TommySzalapski: Sure.

You can delete this question if it's not up to your standards
I am a very active member on this site. I would prefer if you ask me if I did something on purpose before assuming I messed something up. I needed a code solution (as a library or not, but code nonetheless) and Sid got the closest to providing one. I accepted all the most useful posts and spent some time choosing them. Now I have to do it all again.
I see. His post wasn't asking for a response, but I understand the notion of the system flagging it. In the future, I will make sure mine is the last post when I close.