Jump to content

ShellExecute / Acrobat Reader / Print verb / SW_HIDE


Recommended Posts

Hey Guys,

I have noticed something really interesting.
All though actually every single application works perfectly fine with all possible show flags, acrobat reader does not really care about them.
The thing is I am trying to run printing multiple documents in background, but reader is always showing the window, instead of keeping it hidden or minimized as I would wish.

ShellExecute($sFile, '', '', 'print', @SW_HIDE)

Has anyone else experienced same problem on windows 10?
If not, do you have any suggestions, how to solve the problem to run printing pdf files completely in background?

Thanks

Edited by DesireDenied
Link to comment
Share on other sites

I feel your pain. Tried to print pdfs via acrobat from python - the god-damn window always opens.

Only idea I have is to wait for the window and then minimize it :(

Any of my own codes posted on the forum are free for use by others without any restriction of any kind. (WTFPL)

Link to comment
Share on other sites

You can try this.

it is unfinished but works well.

It has some elements i will insert in the next weeks if i need them.

#include <Constants.au3>
#include <GuiConstants.au3>
#include <FileConstants.au3>
#include <EditConstants.au3>
#include <file.au3>

Opt("MustDeclareVars", 1)
Opt("TrayIconHide", 1)

Local $dropFile_1, $dropFile_2, $label, $msg, $dropFile_txt, $szDrive, $szDir, $szFName, $szExt, $print_pid, $default, $Printer,$Printer_setback

;Abfrage Standard Drucker
$default = RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows", "Device") ;default Printer auslesen
$Printer_setback = $default

If Not StringInStr($default, "FinePrint") Then
    If Not IsDeclared("iMsgBoxAnswer") Then Local $iMsgBoxAnswer
    $iMsgBoxAnswer = MsgBox(52, "Fineprint", "Ich benötige Fineprint als Standard Drucker." & @CRLF & "Jetzt setzen?", 15)
    Select
        Case $iMsgBoxAnswer = 6 ;Yes
            RunWait('RUNDLL32 PRINTUI.DLL,PrintUIEntry /y /n "FinePrint"') ;default printer setzen
            $default = RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows", "Device") ;default Printer auslesen

        Case $iMsgBoxAnswer = 7 ;No

        Case $iMsgBoxAnswer = -1 ;Timeout

    EndSelect
EndIf
;Ende - Abfrage Standard Drucker

; Gui erstellen
GUICreate('Drag and Drop', 150, 170, @DesktopWidth / 2 - 192, _
        @DesktopHeight / 2 - 235, -1, $DS_MODALFRAME + $WS_EX_ACCEPTFILES + $WS_EX_TOPMOST)

GUICtrlCreateGroup("", 5, 5, 140, 90)

$dropFile_1 = GUICtrlCreateLabel($dropFile_1, 10, 20, 130, 70, -1)
GUICtrlSetData($dropFile_1, @LF & @LF & "Datei hier ablegen")
GUICtrlSetState($dropFile_1, $GUI_DROPACCEPTED)
GUICtrlSetTip($dropFile_1, 'Zu druckende Datei in dieses Feld ziehen')
$Printer = GUICtrlCreateLabel($default, 10, 150, 140, 60, -1)

Local $idStart = GUICtrlCreateButton("Start", 15, 110, 100, 25)
GUICtrlSetState($idStart, 128)
Local $idset = GUICtrlCreateButton("", 130, 120, 15, 15)
GUICtrlSetTip($idset, 'Drucker auf FinePrint umstellen')
Local $sFile1

GUISetState()
;Ende - Gui erstellen

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            GUIDelete()
            ExitLoop
        Case $GUI_EVENT_DROPPED
            If @GUI_DropId = $dropFile_1 Then
                Dim $Path = @GUI_DragFile
                _PathSplit(@GUI_DragFile, $szDrive, $szDir, $szFName, $szExt)
                GUICtrlSetData($dropFile_1, $szFName & $szExt)
                GUICtrlSetState($idStart, 64)
            EndIf
        Case $idStart
            $sFile1 = GUICtrlRead($dropFile_1)
            If $sFile1 Then
                GUICtrlSetState($idStart, 128)
                GUICtrlSetData($dropFile_1, "In Arbeit...")
                ShellExecute(@GUI_DragFile, "", "", "Print")
                If @error Then Exit
                Sleep(5000)
                GUICtrlSetState($idStart, 64)
                GUICtrlSetData($dropFile_1, "Datei hier ablegen")
            Else
                MsgBox($MB_SYSTEMMODAL, "Error", "Keine Datei zum Drucken eingefügt")
            EndIf
        Case $idset
            RunWait('RUNDLL32 PRINTUI.DLL,PrintUIEntry /y /n "FinePrint"');default printer setzen
            $default = RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows", "Device") ;default Printer auslesen
            GUICtrlSetData($Printer, $default)
            MsgBox(262192, "", "Der Drucker wurde auf FinePrint umgestellt.")           ;MsgBox features: Title=No, Text=Yes, Buttons=OK, Icon=Warning, Miscellaneous=Top-most attribute

    EndSwitch
WEnd
Link to comment
Share on other sites

You could also try to use COM object to print.  I have been using it successfully like this :

#include <Constants.au3>
#include <GUIConstants.au3>

Global $oMyError = ObjEvent("AutoIt.Error", "_ComErrFunc")

_Print_PDF()

Func _Print_PDF()
  Local $hGUI = GUICreate("Example")
  Local $idPrint = GUICtrlCreateButton("&Print", 310, 370, 85, 25)
  GUISetState()

  Local $sFile

  While 1
    Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE
        ExitLoop
      Case $idPrint
        $sFile = FileOpenDialog("Choose a PDF File", @ScriptDir, "PDF Files(*.pdf)", $FD_FILEMUSTEXIST+$FD_PATHMUSTEXIST)
        If Not @error Then _AcroPrint ($sFile)
    EndSwitch
  WEnd
EndFunc   ;==>_Print_PDF

Func _AcroPrint($sFile)
  If Not FileExists($sFile) Then Return SetError(1)
  Local $oPDF = ObjCreate("AcroPDF.PDF.1")
  If Not IsObj($oPDF) Then Return SetError(2)
  ConsoleWrite($oPDF.GetVersions & @CRLF)

  $oPDF.src = $sFile

  GUICreate("")
  GUICtrlCreateObj($oPDF, 0, 0)
  $oPDF.PrintAll()
EndFunc   ;==>_AcroPrint

Func _ComErrFunc()
  MsgBox($MB_SYSTEMMODAL, "AutoItCOM Error", _
      "We intercepted a COM Error !" & @CRLF & @CRLF & _
      "Description is: " & @TAB & $oMyError.description & @CRLF & _
      "Win Description:" & @TAB & $oMyError.windescription & @CRLF & _
      "Number is: " & @TAB & Hex($oMyError.number, 8) & @CRLF & _
      "Last Dll Error is: " & @TAB & $oMyError.lastdllerror & @CRLF & _
      "Script Line is: " & @TAB & $oMyError.scriptline & @CRLF & _
      "Source is: " & @TAB & $oMyError.source)
  SetError(100)
EndFunc   ;==>_ComErrFunc

 

Link to comment
Share on other sites

Thank you, Nine! (I know, not my topic, but I haven't been able to find the Acrobat Reader object before.)

The documentation for AcroPDF.PDF.1 appears to be here (page 106) under AxAcroPDFLib.AxAcroPDF

This might be helpful because there are a few more methods for printing without using a dialog box: PrintAllFit, PrintPages, and PrintPagesFit

All my code provided is Public Domain... but it may not work. ;) Use it, change it, break it, whatever you want.

Spoiler

My Humble Contributions:
Personal Function Documentation - A personal HelpFile for your functions
Acro.au3 UDF - Automating Acrobat Pro
ToDo Finder - Find #ToDo: lines in your scripts
UI-SimpleWrappers UDF - Use UI Automation more Simply-er
KeePass UDF - Automate KeePass, a password manager
InputBoxes - Simple Input boxes for various variable types

Link to comment
Share on other sites

Link to comment
Share on other sites

@Nine The only thing is, I can't use PrintAllFit method at work, and its really hard to tell what is going wrong.

getVersions() output
Accessibility=20.12,AcroForm=20.12,Annots=20.12,Checkers=20.12,DigSig=20.12,DropboxStorage=20.12,DVA=20.12,eBook=20.12,EScript=20.12,IA32=20.12,MakeAccessible=20.12,Multimedia=20.12,PDDom=20.12,PPKLite=20.12,ReadOutLoud=20.12,reflow=20.12,SaveAsRTF=20.12,Search=20.12,SendMail=20.12,Spelling=20.12,StorageConnectors=20.12,Updater=20.12,weblink=20.12,

error
Testing.au3" (59) : ==> The requested action with this object has failed.:
$oPDF.PrintAllFit()
$oPDF^ ERROR

Any suggestions what is going on?

Link to comment
Share on other sites

@Nine All works perfectly fine but after some number of printed documents I am getting an error that too many documents are currently opened, and I have to close some of them to be able to print another one, and I am not sure how to properly close the document through acrobat pdf object.

If I try to clear $oPDF object just right away after $oPDF.PrintAllFit(True) most of the documents wont print or blank pages are printed.

Func _AcroPrint($sFile)
  If Not FileExists($sFile) Then Return SetError(1)
  Local $oPDF = ObjCreate("AcroPDF.PDF.1")
  If Not IsObj($oPDF) Then Return SetError(2)
  ConsoleWrite($oPDF.GetVersions & @CRLF)

  $oPDF.src = $sFile

  $hGUI = GUICreate("")
  $hObj = GUICtrlCreateObj($oPDF, 0, 0)
  $oPDF.PrintAllFit(True)
  Sleep(500)
  GuiCtrlDelete($hObj)
  GuiDelete($hGUI)
  $oPDF = 0
EndFunc   ;==>_AcroPrint


So I came up with the idea to make an array of $oPDF objects, activeX handles (gui, ctrl) and timestamps, and to clear them all in a single function:

Func flushPrintQueue()
    Local $aItemsToRemove[0]
    For $i=0 To UBound($aPrintQueue)-1
        If TimerDiff($aPrintQueue[$i][3]) > 10000 Then ; object creation timestamp
            _ArrayAdd($aItemsToRemove, $i)
            $aPrintQueue[$i][0] = 0             ; activeX object
            GUICtrlDelete($aPrintQueue[$i][2])  ; activeX control handle
            GUIDelete($aPrintQueue[$i][1])      ; activeX gui handle
        EndIf
    Next

    _ArrayInsert($aItemsToRemove, 0, UBound($aItemsToRemove))
    _ArrayDelete($aPrintQueue, $aItemsToRemove)
EndFunc

But it does not work. Am I even passing to array my $oPDF by refference, or is this just some copy of an object?

Edited by DesireDenied
misspellings, code errors
Link to comment
Share on other sites

  • 2 weeks later...

Not exactly sure what seems to be the problem, but maybe using a persistent object ?

#include <Constants.au3>
#include <GUIConstants.au3>

Global $oPDF = ObjCreate("AcroPDF.PDF.1")
GUICreate("")
GUICtrlCreateObj($oPDF, 0, 0)

_Print_PDF()

Func _Print_PDF()
  Local $hGUI = GUICreate("Example")
  Local $idPrint = GUICtrlCreateButton("&Print", 310, 370, 85, 25)
  GUISetState()

  Local $sFile

  While 1
    Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE
        ExitLoop
      Case $idPrint
        $sFile = FileOpenDialog("Choose a PDF File", @ScriptDir, "PDF Files(*.pdf)", $FD_FILEMUSTEXIST+$FD_PATHMUSTEXIST)
        If Not @error Then _AcroPrint ($sFile)
    EndSwitch
  WEnd
EndFunc   ;==>_Print_PDF

Func _AcroPrint($sFile)
  If Not FileExists($sFile) Then Return SetError(1)
  If Not IsObj($oPDF) Then Return SetError(2)
  ConsoleWrite($oPDF.GetVersions & @CRLF)

  $oPDF.src = $sFile

  $oPDF.PrintAll()
EndFunc   ;==>_AcroPrint

I tested on a few files and it works for me...

Link to comment
Share on other sites

Additional information (after tests) :  There is some memory usage increases using the first approach (one creating object at each print).  That's corroborate your issue about too many opened documents after awhile. With the last approach (creating a persistant object), there is no more increase in memory usage.  I would assume that this should solve your problem.

Link to comment
Share on other sites

  • 3 weeks later...

@Nine
Once again, many thanks for your reply.

We are using my script to print artworks in pdf files. Size of each file can vary from 1-600MB or even more, but for most of the time its around couple of megabytes.
In most cases its not just one or two documents but, lets say, number of printed documents per order goes like this: 4, 11, 8, 3, 27, 13 and we want to queue them all for print in one minute. 

I have also already tried to use persistent object but it did not worked as expected. Same message appeared after short while.
It does not really matters if its single global object or an array of objects. Single Acrobat Reader process handle all of them.

Another problem with single PDF object is that, it does not really wait to be done or return anything if its done, and if you try to use fixed sleep time between documents, you can slow down entire process or whats worst, you can overwrite buffering / rastering current document ending up with blank pages printed out in case of complex artworks. 

So I came up with another idea: don't let my script to have opened more than 15 activex pdf objects, and if there is still something to print, wait in a loop until at some of the objects will be cleared out by flushPrintQueue function running in the background. And finally, after 60 seconds from last printed document, close entire AcrRdr32 process (the one which have no own window handles) and it works.

Edited by DesireDenied
my english is really bad
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...