Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Print PDFs with Acro/Reader 8.x ActiveX Error 429 1

Status
Not open for further replies.

zollo9999

Programmer
May 12, 2002
95
0
0
AU
Hi
I need to print on demand 7 external PDF documents.

I've already successfully implemented the legacy methods of using the shell command and passing the /t print command line, as shown here: thread707-860631

I now have Adobe Acrobat & Reader 8.0 where this method no longer works.
There is a OLE interface / object model but I can't get it running.

I get
Error Number: 429
Error Description : ActiveX component can't create object

This error occurs at any of the lines of code after the Dim statements. (First attempts have been commented out).

Here are some attempts at the code:

Code:
Public Sub AcrobotPrintDoc(DocPath As String)
On Error GoTo ErrorHandler

Dim AcApp As Acrobat.AcroApp
Dim AcAvDoc As Acrobat.AcroAVDoc

'Set AcApp = CreateObject("AcroExch.App")
'Set AcAvDoc = CreateObject("AcroExch.AVDoc")

Set AcApp = New Acrobat.AcroApp
Set AcAvDoc = New Acrobat.AcroAVDoc

If AcAvDoc.Open(DocPath, Null) Then
    MsgBox "Error Opening Document"
    GoTo ExitHere
End If

AcApp.GetActiveDoc
If Not AcAvDoc.PrintPagesSilent(1, 1, 2, 1, 1) Then
    MsgBox "Error Printing Document"
    GoTo ExitHere
End If

ExitHere:
  On Error Resume Next
  AcAvDoc.Close (1) 'Close without saving param must be >0
  AcApp.CloseAllDocs
  AcApp.Exit
  AcApp = Nothing
  AcAvDoc = Nothing
  Exit Sub

ErrorHandler:
  MsgBox "Error Number: " & Err.Number & vbCrLf & _
  " Error Description : " & Err.Description
  Resume ExitHere:
End Sub

Perhaps it is related to this similar error,
faq705-2882 indicating the DLL needs to be re-registered?

Thanks in advance for any help.
Cheers everyone


Zollo VBA Developer
[thumbsup]
 
Hi Herman
Thanks for your reply.
That info will be useful and I will look into it further.

Unfortunately, it is not an answer to my problem as I'm not creating pdf reports from access, but needing to print existing PDF documents.

Is there anyone else with any help?
I will attempt to run the code on another box to see if it is a dll install problem.

You might wonder why I am trying to do this as the user can just print the docs themselves.

The purpose is to spoon feed users that have to manage lots of multistep tasks and each task at various stages of completion. By printing the PDF docs from the database application at exactly the time they are required it saves having the user needing to find the documents.

One simpler solution is to shell out to a windows explorer folder and let the user print the docs from there. That is what they are doing now, but it is a less eligant solution.

Thanks in advance


Zollo VBA Developer
[thumbsup]
 
Ahh... sorry for overlooking this fact.

I am wondering if this PFD file is to be printed to the screen and then the user can, in turn if he/she wants to, print to a printer OR does it have to be printed to a printer directly?

I gather that the database knows where this doc/pfd file is.

Herman
Say no to macros
 
Hi again.

I don't know where you are going with those thoughts about printing to the screen. Perhaps viewing and then printing.
I can get all the docs open using a shell command and the string path to each document.

As there are 7 documents to print at one time, I'd rather be able to just print them all rather than print each one manually.

I have form which allows the user to specify which ones to print if they don't need them all, but they always print them all.

It is really this Adobe OLE object model that I need to get running. I've read the documentation and what I can find on relevant Abobe forums but I can't get it going yet. The Adobe forums are not much help as they say to read the documentation to answer all questions. No one I have found so far has posted any example code showing how to get it running.

Note. I've set a reference to the Adobe Acrobat Type Library and the code helpers work and the code compiles but wont run.

As i said, I need to try this on anther machine to see if it is just mine that causes the problem.

Will post results later.
:)

Zollo VBA Developer
[thumbsup]
 
Shell "C:\Program Files\Adobe\Acrobat 7.0\Reader\AcroRd32.exe /P /h" & "YourFile.PDF"

This will print one pdf file to the def. printer, so a loop should do the rest for you.


Herman
Say no to macros
 
Hi again

I don't think your code will work with Acrobat / Reader 8.0 We had Reader 7.x previously but now we have 8.0.
I can't wind back to 7.x as I'm part of a big government Department.

Here is the code I used previously with the /t command parameter which does not work for Adobe 8.0

Code:
  mstrFullShellCommand = PathToAdobeAcroReader & _  
       " /t " & DocPath & mstrPrinterParams
    
  mdblShellTaskId = Shell(mstrFullShellCommand, _
       vbNormalFocus)

I'm sure the /p /h parameters don't work as well. I should try them to be sure.

By the way. I tried my new code on another box, but it gave the same error, on the same line.

I will have to do some further online research this afternoon.

I'll post anything that works


Zollo VBA Developer
[thumbsup]
 
Ok, so I installed the version 8.1.2 US-english version....

Shell "C:\Program Files\Adobe\Reader 8.0\Reader\AcroRd32.exe /P /h" & & "YourFile.PDF"

Works like version 7.0 ... at least in this respect.
It does leave the reader window open however, so my guess is that we have a 3/4 success.

I did not try your code but the shell-code does the trick, if the "open reader window" bothers you, you could try to down size your acrobat to var 7.x or you could fiddle with the /-parameters

Herman
Say no to macros
 
Thanks Herman.
I appreciate the efforts you have made.
Sorry I didn't get back to you sooner, perhaps to save you some trouble.

I did try the /p /h commands last night and they did work as you described. (I've got some other problems with my app that are also taking lots of my time to resolve. (I built the app with file/server bound controls, but now I seem to need to convert it to a weblike client/server with unbound controls... but back to this problem.)

I previously used the shell command to return the windows Task Id for the first instance of the reader that opens and then when everything was finished I send a command to kill the task. This isn't working now either but I hope to get it going.

Here is a fragment of the code that does the printing and closes the instance of the reader.
This is the core part of a small public sub in a class module so it is used as a method 8 times to print the 8 docs.
Code:
'    mstrFullShellCommand = PathToAdobeAcroReader & " /t " & DocPath & mstrPrinterParams
    mstrFullShellCommand = PathToAdobeAcroReader & " /p /h " & DocPath
    
    mdblShellTaskId = Shell(mstrFullShellCommand, vbNormalFocus)
    PauseFor (2)
    
    If mdblShellTaskId >= 0 And mdblShellTaskId <= 32 Then
      MsgBox "Could not open PDF document    ", vbOKOnly, "Error Opening PDF    "
      mblnAbort = True
      AppActivate mdblShellTaskId       'Close the launched app
      PauseFor (1)
      SendKeys "%{F4}", True      'send Alt-F4, & wait for processing before continuing
    End If

At the end there was always one instance of the reader still open so I would call the following method to kill the last open reader window:

Code:
Public Sub PdfDocClose(TaskId As Double)
On Error GoTo ExitHere
    'Close the launched app
    PauseFor (3)
    AppActivate TaskId, False 
    SendKeys "%{F4}", True      'send Alt-F4, & wait for processing before continuing

ExitHere:
  Exit Sub
ErrorHandler:
  Resume ExitHere:
End Sub

This is now working with the /p /h command as you described, it is about 80% of what I was attempting.

One other problem has arisen in that at random one of the 8 documents does not print. I think it is due to delays in the network and the timing between printing and closing the documents. I'll need to adjust the code timing, or relocate the documents locally to avoid network traffic.

Thanks

Still curious about the OLE API calls.
I have now done a bit of research on these company boxes that I should have done earlier. We have Reader 8.0 and Adobe Elements 7.0. We don't have Acrobat, but parts of the adobe documentation have lead me to believe I don't need acrobat to be able to control the reader. I'm currently looking at the ActiveX Plug-in related code in the adobe documentations.

Cheers
Paul (real name)

Zollo VBA Developer
[thumbsup]
 
Hi again
As I don't have any version of the full acrobat product, it appears my prefered solution (direct control of adobe reader to print documents) is not possible,
unless I can find a free reader plug-in that enables control of printing. No Luck yet but will keep looking.

The following extracts may be of interest to others

This document: Acrobat Developer FAQ (Adobe Acrobat 7.0.5)
can be found here:

This appears to also be relevant for more recent versions of acrobat and reader.

Page 20
Acrobat and Adobe Reader Comparison
What Are the API Differences Between Acrobat and Adobe Reader?

The APIs that may be used for Adobe Reader are limited technically and legally. Technical limitations are documented in the Acrobat and PDF Library API Overview and the Acrobat Interapplication Communication Overview.
Both Acrobat and Adobe Reader accept plug-ins. The primary difference between the two is that Adobe Reader can neither make changes to a file nor save a file. API methods that change a file in such a way that a save would be required are not available in Adobe Reader.

Developing for Adobe Reader
Adobe Reader only accepts “Reader-enabled” plug-ins, which can only access a limited set of APIs. ..


Page 21
Visual Basic .NET and Visual C# .NET
How Can I Use Visual Basic .NET or Visual C# .NET With the Acrobat SDK?
The Microsoft Windows version of Acrobat is an OLE Automation server. In order to use the OLE objects made available by Acrobat, you must have the full Acrobat product installed on your system and the Acrobat.tlb file included in the project references for your Visual Basic project. This allows you to use the Visual Studio .NET 2003 object browser to browse the OLE objects.

If I find a free plug-in I will post it here.
:)


Zollo VBA Developer
[thumbsup]
 
Re. your random no-print-problem could a simple DoEvents line solve this problem ?

Herman
Say no to macros
 
Perhaps
I'm already using the following pausefor sub

Code:
Public Sub PauseFor(intSeconds As Integer)
Dim dtEndTime As Date

dtEndTime = DateAdd("s", intSeconds, Now())
Do Until Now() >= dtEndTime
  DoEvents
Loop

End Sub

Zollo VBA Developer
[thumbsup]
 
Well it looks like that angle is covered then, increase the sec's?....
The only thing I can suggest then, is some sort of check that the last print has indeed been delivered to the print queue....

This problem indicated that some jobs are closed too soon, this could suggest that the prints (pdf-files) are of different sizes, whitch would be normal, but perhaps some sec's/file size relation is indicated here.

Just a thourght


Herman
Say no to macros
 
Yes I agree. I will have to spend some time tweaking it and testing it.

One thing that may help in my case is installing the PDFs on the users desktop or a local server.

"What the... ?" I here you say! Our IT systems are mildly schizophrenic. My work section has been added two other large government departments that are still merging and the result is my server is in a building about 1 km away.

I am persuing getting my system moved to a local server 6 months ahead of schedule. (I also moved other template documents to the users desktop, but this did not work and I have not had time to investigate why before having to roll the app back to a workable state).

This would further reduce network traffic and increase response time for printing although printing now is not noticably slower than before.

Signing off
Paul

Zollo VBA Developer
[thumbsup]
 
Guys i was wondering if you's could help me here

I have the following working for acrobat reader 5.0 but not with adobe reader 7.0. I want to do the exact same of open, print and close files without visually showing to my user.

This is what happens and works with acrobat reader 5. I can't get it woring with adobe reader 7. It keeps opening the files.

Please see

Code:
Private Declare Function ShellExecute 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


Private Sub UserForm_Initialize()
     
    Me.Caption = StrConv(strFileType, vbUpperCase) & " file listing within the " & StrConv(strDirectory, vbUpperCase) & " directory"
     
     
    With Application.FileSearch
         
        .NewSearch
        .LookIn = strDirectory
        .SearchSubFolders = False
        .Filename = "*." & strFileType
        .MatchTextExactly = False
         
        If .Execute() > 0 Then
            For i = 1 To .FoundFiles.Count
                Dim strFileName As String
                If Right(.FoundFiles(i), 3) = strFileType Then
                    strFileName = Mid(.FoundFiles(i), Len(strDirectory) + 1, Len(.FoundFiles(i)) - (Len(strDirectory) + Len(strFileType) + 1))
                    Me.lstDirectoryFiles.AddItem strFileName
                End If
            Next i
             
        End If
         
    End With
     
     
     
End Sub

Private Sub cmdPrint_Click()

    Dim strURL As String
    strURL = strDirectory & lstDirectoryFiles & "." & strFileType
    
        If strURL = strDirectory & "." & strFileType Then
        MsgBox "You haven't selected a file to print.", vbExclamation, StrConv(strFileType, vbUpperCase) & " Open Editor"
        End If
        
    Application.ScreenUpdating = False
         
    Call ShellExecute(0&, vbNullString, strURL, vbNullString, vbNullString, 0) 'Change 0 to vbNormalFocus to view.
    PrintURL = ShellExecute(0&, "print", strURL, vbNullString, vbNullString, 0) 'Change 0 to vbNormalFocus to view.
    Application.Run "CloseDefinedApp"
    
    Application.ScreenUpdating = False
           
End Sub


Code:
Public strClassNameToClose As String
'************** Code Start ***************
' This code was originally written by Dev Ashish.
' It is not to be altered or distributed,
' except as part of an application.
' You are free to use it in any application,
' provided the copyright notice is left unchanged.
' provided the copyright notice is left unchanged.
'
' Code Courtesy of
' Dev Ashish
'
'Gets the ClassNames of running applications

Private Declare Function apiGetClassName Lib "user32" Alias _
                "GetClassNameA" (ByVal hWnd As Long, _
                ByVal lpClassName As String, _
                ByVal nMaxCount As Long) As Long
Private Declare Function apiGetDesktopWindow Lib "user32" Alias _
                "GetDesktopWindow" () As Long
Private Declare Function apiGetWindow Lib "user32" Alias _
                "GetWindow" (ByVal hWnd As Long, _
                ByVal wCmd As Long) As Long
Private Declare Function apiGetWindowLong Lib "user32" Alias _
                "GetWindowLongA" (ByVal hWnd As Long, ByVal _
                nIndex As Long) As Long
Private Declare Function apiGetWindowText Lib "user32" Alias _
                "GetWindowTextA" (ByVal hWnd As Long, ByVal _
                lpString As String, ByVal aint As Long) As Long
Private Const mcGWCHILD = 5
Private Const mcGWHWNDNEXT = 2
Private Const mcGWLSTYLE = (-16)
Private Const mcWSVISIBLE = &H10000000
Private Const mconMAXLEN = 255
Function fEnumWindows(filter As String) As String

Dim lngx As Long, lngLen As Long
Dim lngStyle As Long, strCaption As String

    lngx = apiGetDesktopWindow()

    'Return the first child to Desktop

    lngx = apiGetWindow(lngx, mcGWCHILD)

    Do While Not lngx = 0

        strCaption = fGetCaption(lngx)

            If Len(strCaption) > 0 Then

                'Debug.Print strCaption

                'enum visible windows only

                'If lngStyle And mcWSVISIBLE Then

                '    fEnumWindows = fGetClassName(lngx)

                '    Exit Function

                If InStr(fGetCaption(lngx), filter) > 0 Then

                    'fEnumWindows = apiGetWindowLong(lngx, mcGWLSTYLE)
                    fEnumWindows = fGetClassName(lngx)

                    Exit Function

                End If

            End If

        lngx = apiGetWindow(lngx, mcGWHWNDNEXT)

    Loop

End Function
Private Function fGetClassName(hWnd As Long) As String
    Dim strBuffer As String
    Dim intCount As Integer
   
    strBuffer = String$(mconMAXLEN - 1, 0)
    intCount = apiGetClassName(hWnd, strBuffer, mconMAXLEN)
    If intCount > 0 Then
        fGetClassName = Left$(strBuffer, intCount)
            strClassNameToClose = Left$(strBuffer, intCount)
    End If
End Function
Private Function fGetCaption(hWnd As Long) As String
    Dim strBuffer As String
    Dim intCount As Integer

    strBuffer = String$(mconMAXLEN - 1, 0)
    intCount = apiGetWindowText(hWnd, strBuffer, mconMAXLEN)
    
    If intCount > 0 Then
        fGetCaption = Left$(strBuffer, intCount)

    End If
    
End Function

Code:
'************** Code Start ***************
' This code was originally written by Dev Ashish.
' It is not to be altered or distributed,
' except as part of an application.
' You are free to use it in any application,
' provided the copyright notice is left unchanged.
'
' Code Courtesy of
' Dev Ashish
'
'Closes an application based on its' ClassName

Private Const WM_CLOSE = &H10
Private Const INFINITE = &HFFFFFFFF

Private Declare Function apiPostMessage _
    Lib "user32" Alias "PostMessageA" _
    (ByVal hWnd As Long, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    lParam As Any) _
    As Long

Private Declare Function apiFindWindow _
    Lib "user32" Alias "FindWindowA" _
    (ByVal lpClassName As String, _
    ByVal lpWindowName As String) _
    As Long
    
Private Declare Function apiWaitForSingleObject _
    Lib "kernel32" Alias "WaitForSingleObject" _
    (ByVal hHandle As Long, _
    ByVal dwMilliseconds As Long) _
    As Long
    
Private Declare Function apiIsWindow _
    Lib "user32" Alias "IsWindow" _
    (ByVal hWnd As Long) _
    As Long
        
Private Declare Function apiGetWindowThreadProcessId _
    Lib "user32" Alias "GetWindowThreadProcessId" _
    (ByVal hWnd As Long, _
    lpdwProcessID As Long) _
    As Long
  
Function fCloseApp(lpClassName As String) As Boolean
'Usage Examples:
'   To close Calculator:
'       ? fCloseApp("SciCalc")
'

'
Dim lngRet As Long, hWnd As Long, pid As Long

    hWnd = apiFindWindow(lpClassName, vbNullString)
    If (hWnd) Then
        lngRet = apiPostMessage(hWnd, WM_CLOSE, 0, ByVal 0&)
        Call apiGetWindowThreadProcessId(hWnd, pid)
        Call apiWaitForSingleObject(pid, INFINITE)
        fCloseApp = Not (apiIsWindow(hWnd) = 0)
    End If
End Function
'************* Code End ***************

Code:
Public strDirectory, strFileType As String
Public intCounter As Integer
Sub OpenDisplayFileNameForm()

'Change to where relevant files are saved
'strDirectory = "C:\Users\owen\trading\"
strDirectory = "C:\"
'Change to the desired file extension to open (case sensitive).
'Must also change the filter argument for the fEnumWindows
'function on the vbaCloseDefinedApplication module to match
strFileType = "pdf"
'Reset the intCounter variable
intCounter = 0

With Application.FileSearch

    .NewSearch
    .LookIn = strDirectory
    .SearchSubFolders = False
    .Filename = "*." & strFileType
    .MatchTextExactly = False
    
        If .Execute() > 0 Then
                For i = 1 To .FoundFiles.Count
                    Dim strFileName As String
                        If Right(.FoundFiles(i), 3) = strFileType Then
                        intCounter = intCounter + 1
                        End If
                Next i
        
        End If

End With
   
    If intCounter = 0 Then
    MsgBox "There are no " & strFileType & " files in the " & StrConv(strDirectory, vbUpperCase) & " directory.", vbExclamation, "File Name Paste Editor"
    Exit Sub
    Else
    Application.ScreenUpdating = False
    'Sheets("FileList").Visible = True
    'Sheets("FileList").Select
    'Range("A1").Select
    'Range(Selection, Selection.End(xlDown)).ClearContents
    frmDirectoryFileSelector.Show
    End If

End Sub
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top