VBA - Macro - To Print Multiple digital signed PDF file and save it in subfolder by using "Microsoft Print to PDF" Printer - vba

I am printing multiple digital signed PDF file into PDF via "Microsoft print to PDF" ( To Edit document) . Below mention VBA code is working perfectly. But when run this code each time, it is asking Filename & Destination folder for printed file.
My Expection:
It has to capture file name from existing saved documents file name and destination folder path we have include in VBA Code.
Please help me, How to solve this
Public Sub Print_All_PDF_Files_in_Folder()
Dim folder As String
Dim PDFfilename As String
folder = "C:\Users\Desktop\VBA\" 'CHANGE AS REQUIRED
If Right(folder, 1) <> "\" Then folder = folder & "\"
PDFfilename = Dir(folder & "*.pdf", vbNormal)
While Len(PDFfilename) <> 0
Print_PDF folder & PDFfilename
PDFfilename = Dir() ' Get next matching file
Wend
End Sub
Private Sub Print_PDF(sPDFfile As String)
Shell "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe /p /h " & Chr(34) & sPDFfile & Chr(34), vbNormalFocus
End Sub

Path with spaces must be in quotes, because it is has spaces. Keys /p and /h must be separate from Program name. I check it this way:
i make this command in cmd.exe and when i see what it correct - I revrite it into macro.
Private Sub Print_PDF(sPDFfile As String)
Shell "" & Chr(34) & "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" & Chr(34) & " /p /h " & Chr(34) & sPDFfile & Chr(34)
End Sub

You seem to have multiple conflicts
Your command includes the command to open the Printer Dialog
/P <filename> - Open and go straight to the Printer Prompt dialog
And for "Microsoft Print to PDF" that will allow you to make the manual changes you require to the PDF then manually save to a folder or filename of your choosing.
However you say you want Acrobat to save to a known filename without that prompting. Which in turn makes me question WHY are you using Acrobat to open a PDF and re-save it as a file name without interaction ?
You could do that simply by renaming the PDF without opening it in Acrobat.
One advantage of programmatically opening a "Complex" PDF in Acrobat and Re-Printing as a "Dumber" PDF using "Microsoft Print to PDF" is it can pseudo-manically emulate much more efficient ways of flattening by using a very inefficient reprinting and for that you need to use:-
/T <filename> <printername> <drivername> <portname> - Print the file on the specified printer.
Where printername and drivername are "Microsoft Print to PDF" and portname is where you want it printed.
There are much lighter ways to process a PDF from the command line, but if you already have installed heavyweight Adobe Reader then this is the defacto standard.
[EDIT] in the comments you imply you still need to use acrobat for processing before printing to a fixed name. Then in that case, you need to run those actions first. Before saving as new PDF, prior to printing, thus you need to
get filename
make changes
save changes as new filename
send new filename to printer using:-
"C:\Full path\to\AcroRd32.exe" /T "C:\path to\Input.pdf" "Microsoft Print to PDF" "Microsoft Print to PDF" "C:\path to\Output.pdf"
The problem with batch printing, using /T = TSR (Terminate and Stay Resident), is that the window stays open waiting for the next print in the batch, and most users then add /H to hide it, then afterwards complain its not accessible so as to close at the end of the batch (which simply requires sendkeys %FX or Alt+F4 to close the open window)!
One way round that is, on the last print invoke /T without H, and then a VB focused command (object.AppActivate title) and at simplest sendkeys %FX will close the window.
If using the command line or a .cmd it is simple to use Wscript with a single line .VBS command, however in this case you are already using VBA.

Related

Using AppleScript to programmatically create an AppleScript file in plain text format

I have an AppleScript that is used to programmatically create a test script file in one of these Office 2016 app folders:
~/Library/Application Scripts/com.microsoft.Excel
~/Library/Application Scripts/com.microsoft.Word
~/Library/Application Scripts/com.microsoft.Powerpoint
This is the test.scpt file content which is programmatically generated:
on handlerTest(thisPhrase)
say thisPhrase
end handlerTest
This test.scpt file contains a single handler which speaks the phrase passed to it.
When the script is created in one of these folders, I cannot see the content of the script file in Finder and calling the handler from a Microsoft Office app using the new VBA AppleScriptTask causes the Office app to crash. I think the script is being created as a byte-compiled file because it cannot be viewed in Finder as plain text.
If I then copy the script file generated programmatically by my script creator script to the Documents folder, the plain-text content of the script is viewable in Finder.
Now, if I copy the script file from the Documents folder back to the corresponding com.microsoft folder (without modifying it), I can now see the plain-text content in Finder and calling the handler using the VBA AppleScriptTask function works as expected. I don't understand how the format is apparently changing due to copy/paste actions?
How can I programmatically create the script file in the com.microsoft.xyz folder in plain text format?
Here is my VBA procedure:
Sub TestScript()
AppleScriptTask "test.scpt", "handlerTest", "hello world"
End Sub
Here is my example script creator script which programmatically creates a test.scpt file in the com.microsoft.Powerpoint scripting folder: (kudos to eliteproxy for the original source script)
property theFolders : {"~/Library/'Application Scripts'/com.microsoft.Powerpoint"}
try
tell application "Finder" to set targetFolder to (target of the front window) as alias
on error -- no window
set targetFolder to (choose folder)
end try
# build a parameter string from the folder list
set {tempTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, space}
set {theFolders, AppleScript's text item delimiters} to {theFolders as text, tempTID}
do shell script "cd " & quoted form of POSIX path of targetFolder & "; mkdir -p " & theFolders
--Write the Script file if it does not exist
if ExistsFile("~/Library/'Application Scripts'/com.microsoft.Powerpoint/test.scpt") is false then
tell application "Finder"
--GET THE WORKING DIRECTORY FOR FILE COPY OF SCRIPT
get folder of (path to me) as Unicode text
set workingDir to POSIX path of result
--Write the new script in the current working directory
set textFile to workingDir & "test.scpt"
--Delete script if it exists
set posixPath to POSIX path of textFile as string
do shell script "rm -rf \"" & posixPath & "\""
--Create Script Interface file for Microsoft PowerPoint VBA Applications
set fd to open for access textFile with write permission
-- Create test handler which speaks the passed phrase parameter
write "on handlerTest(thisPhrase)" & linefeed to fd as «class utf8» starting at eof
write "say thisPhrase" & linefeed to fd as «class utf8» starting at eof
write "end handlerTest" & linefeed to fd as «class utf8» starting at eof
close access fd
--Copy the script file into the MACOS-Specific 'safe' folder
set fromPath to quoted form of POSIX path of (workingDir) & "test.scpt"
set toPath to quoted form of "~/Library/'Application Scripts'/com.microsoft.Powerpoint"
do shell script "cp -R " & fromPath & space & "~/Library/'Application Scripts'/com.microsoft.Powerpoint" with administrator privileges
end tell
end if
--Delete the temp script file from the working directory
set posixPath to POSIX path of textFile as string
do shell script "rm -rf \"" & posixPath & "\""
--Provide confirmation
set theAlertTitle to "TEST"
set theAlertMsg to "The script has been successfully installed."
display alert theAlertTitle message theAlertMsg as informational buttons {"OK"} default button "OK" cancel button "OK"
--For use when checking if a file exists
on ExistsFile(filePath)
tell application "System Events" to return (exists disk item filePath) and class of disk item filePath = file
end ExistsFile
I could be wrong in my interpretation of your question, but it appears as if you are looking to create file “Test.scpt” with your handler “handlerTest” as the code, in a folder named “com.microsoft.Excel” (for example). If that is all you are looking to achieve, I believe this solution should work for you...
script theHandler
on handlerTest(thisPhrase)
say thisPhrase
end handlerTest
end script
storeScript()
on storeScript()
set thisScript to store script theHandler in (path to home folder as text) ¬
& "Library:Application Scripts:com.microsoft.Excel:Test.scpt" replacing yes
end storeScript

merge files with macro from server

I have macros to merge .csv files.
It is working when I am merging files from folder witch placed at desktop,
But when I am trying to merge files that are placed on a server then macro does not work.
Any ides Why?
I can show that part of selecting folder with .csv files:
Dim fileCount As Long
' Open the file dialog
With Application.FileDialog(msoFileDialogOpen)
.AllowMultiSelect = True
.Filters.Add "CSV files", "*.csv"
.Show
For fileCount = 1 To .SelectedItems.Count
Debug.Print .SelectedItems(fileCount)
Next fileCount
End With
And I am creating the .txt file to collect all data
'Create the bat file
Open BatFileName For Output As #1
Print #1, "Copy " & Chr(34) & foldername & "*.csv" _
& Chr(34) & " " & TXTFileName
Close #1
'Run the Bat file to collect all data from the CSV files into a TXT file
ShellAndWait BatFileName, 0
If Dir(TXTFileName) = "" Then
MsgBox "There are no csv files in this folder"
Kill BatFileName
Exit Sub
End If
What is the diference between file on desktop and file on server?
I get message when i am merging files from server: there are no csv files in this folder
But i am sure that there are .csv files.
Thanks
It's hard to tell what 'does not work' actually means. I'm guessing you don't have Excel installed, but you should know whether that's true or not before posting here, so we can probably rule out that option. More likely, it's not working in a web-based environment. VBA doesn't work in any web environment, like a Web Server, Website, SharePoint, etc. In addition, Make sure you are granting System Access to your macros in the server through QEMC (System, Setup, QlikView Servers, expand and click, Seucrity tab in the right pane "Allow unsafe macro execution on server" and "Allow macro execution on server" ticked) and in the Macro editor, (Ctrl + M, bottom left drop downs). Finally, if they are creating some filesystem object (such an excel file) make sure you are using the IE Plugin.

excel vba won't execute .bat but manually executing bat works fine

Hi I have a perfectly working bat named: start.bat
containing:
start C:\Users\*user*\Documents\*path*\hidebat.vbs
and once it is manually opened it works perfectly, meaning it opens hidebat.vbs, which opens a .bat minimized which uploads files to my cloud. Hence it's verified.
I've added
pause
to the start.bat to see what it does and when I tell excel to open the start.bat it will open cmd and display the exact command as required, but it will not execute the hidebat.vbs.
I expect that there is somehow some path constraint or environment constraint when it is run from excel that prevents it to actually reach out of that limited environment.
Within excel I have tried calling the .bat in 3 different ways with:
Dim path As String
path = Application.ActiveWorkbook.path
path = path & "\"
Dim MY_FILENAME3 As String
MY_FILENAME3 = path & "start.bat"
1.
retVal = Shell(MY_FILENAME3, vbNormalFocus)
' NOTE THE BATCH FILE WILL RUN, BUT THE CODE WILL CONTINUE TO RUN.
If retVal = 0 Then
MsgBox "An Error Occured"
Close #FileNumber
End
End If
2.
PathCrnt = ActiveWorkbook.path
Call Shell(PathCrnt & "start.bat")
3.
Dim batPath As String: batPath = path
Call Shell(Environ$("COMSPEC") & " /c " & batPath & "start.bat", vbNormalFocus)
Does anybody have any clue on why it will not execute the .bat file, or what I could do to ensure it will run correctly?
Note. I think it is because it opens the default path, so I'm gonna tell it to "cd" to the actual path where the excel is saved and where the .bat files are.
Yes that was it, the path was set to some random/standard/working/current path by command, so I had to add:
Print #FileNumber, "cd " & path
to the excel macro
so that start.bat looked like:
cd *path*
start *path*\hidebat.vbs
Hope this helps future me's.

Extract data from PDF file with VB.Net

I'm trying to pull some data from a large PDF file in VB.Net I found the following code online, but it's not helping:
Sub PrintPDF (strPDFFileName as string)
Dim sAdobeReader as String
'This is the full path to the Adobe Reader or Acrobat application on your computer
sAdobeReader = "C:\Program Files\Adobe\Acrobat 6.0\Reader\AcroRd32.exe"
RetVal = Shell(sAdobeReader & "/P" & Chr(34) & sStrPDFFileName & Chr(34), 0)
End Sub
I'm really lost. Any ideas?
/P will just display load the file and display the Print dialog - dead end.
You will probably need a library of some sort to get to the contents of the PDF.
If the file has a very simple structure you maybe able to extract the data just by reading the bytes. See if you can open it with a file like Notepad++ and see the contents.
BTW VS2010 has several editors for looking at/editing files:
File, Open File... pick the file then use the dropdown on the Open button.

Printing to a pdf printer programmatically

I am trying to print an existing file to PDF programmatically in Visual Basic 2008.
Our current relevant assets are:
Visual Studio 2008 Professional
Adobe Acrobat Professional 8.0
I thought about getting a sdk like ITextSharp, but it seem like overkill for what I am trying to do especially since we have the full version of Adobe.
Is there a relatively simple bit of code to print to a PDF printer (and of course assign it to print to a specific location) or will it require a the use of another library to print to pdf?
I want to print a previosly created document to a pdf file. In this case it a .snp file that I want to make into a .pdf file, but I think the logic would be the same for any file type.
I just tried the above shell execute, and it will not perform the way I want it to. as it prompts me as to where I want to print and still does not print where I want it to (multiple locations), which is crucial as we create a lot of the same named PDF files (with different data within the PDF and placed in corresponding client folders)
The current process is:
Go to \\report server\client1
create pdf files of all the snp documents in the folder by hand
copy the pdf to \\website reports\client1
then repeat for all 100+ clients takes roughly two hours to complete and verify
I know this can be done better but I have only been here three months and there were other pressing concerns that were a lot more immediate. I also was not expecting something that looks this trivial to be that hard to code.
The big takeaway point here is that PDF IS HARD. If there is anything you can do to avoid creating or editing PDF documents directly, I strongly advise that you do so. It sounds like what you actually want is a batch SNP to PDF converter. You can probably do this with an off-the-shelf product, without even opening Visual Studio at all. Somebody mentioned Adobe Distiller Server -- check your docs for Acrobat, I know it comes with basic Distiller, and you may be able to set up Distiller to run in a similar mode, where it watches Directory A and spits out PDF versions of any files that show up in Directory B.
An alternative: since you're working with Access snapshots, you might be better off writing a VBA script that iterates through all the SNPs in a directory and prints them to the installed PDF printer.
ETA: if you need to specify the output of the PDF printer, that might be harder. I'd suggest having the PDF distiller configured to output to a temp directory, so you can print one, move the result, then print another, and so on.
This is how I do it in VBScript. Might not be very useful for you but might get you started. You need to have a PDF maker (adobe acrobat) as a printer named "Adobe PDF".
'PDF_WILDCARD = "*.pdf"
'PrnName = "Adobe PDF"
Sub PrintToPDF(ReportName As String, TempPath As String, _
OutputName As String, OutputDir As String, _
Optional RPTOrientation As Integer = 1)
Dim rpt As Report
Dim NewFileName As String, TempFileName As String
'--- Printer Set Up ---
DoCmd.OpenReport ReportName, View:=acViewPreview, WindowMode:=acHidden
Set rpt = Reports(ReportName)
Set rpt.Printer = Application.Printers(PrnName)
'Set up orientation
If RPTOrientation = 1 Then
rpt.Printer.Orientation = acPRORPortrait
Else
rpt.Printer.Orientation = acPRORLandscape
End If
'--- Print ---
'Print (open) and close the actual report without saving changes
DoCmd.OpenReport ReportName, View:=acViewNormal, WindowMode:=acHidden
' Wait until file is fully created
Call waitForFile(TempPath, ReportName & PDF_EXT)
'DoCmd.Close acReport, ReportName, acSaveNo
DoCmd.Close acReport, ReportName
TempFileName = TempPath & ReportName & PDF_EXT 'default pdf file name
NewFileName = OutputDir & OutputName & PDF_EXT 'new file name
'Trap errors caused by COM interface
On Error GoTo Err_File
FileCopy TempFileName, NewFileName
'Delete all PDFs in the TempPath
'(which is why you should assign it to a pdf directory)
On Error GoTo Err_File
Kill TempPath & PDF_WILDCARD
Exit_pdfTest:
Set rpt = Nothing
Exit Sub
Err_File: ' Error-handling routine while copying file
Select Case Err.Number ' Evaluate error number.
Case 53, 70 ' "Permission denied" and "File Not Found" msgs
' Wait 3 seconds.
Debug.Print "Error " & Err.Number & ": " & Err.Description & vbCr & "Please wait a few seconds and click OK", vbInformation, "Copy File Command"
Call sleep(2, False)
Resume
Case Else
MsgBox Err.Number & ": " & Err.Description
Resume Exit_pdfTest
End Select
Resume
End Sub
Sub waitForFile(ByVal pathName As String, ByVal tempfile As String)
With Application.FileSearch
.NewSearch
.LookIn = pathName
.SearchSubFolders = True
.filename = tempfile
.MatchTextExactly = True
'.FileType = msoFileTypeAllFiles
End With
Do While True
With Application.FileSearch
If .Execute() > 0 Then
Exit Do
End If
End With
Loop
End Sub
Public Sub sleep(seconds As Single, EventEnable As Boolean)
On Error GoTo errSleep
Dim oldTimer As Single
oldTimer = Timer
Do While (Timer - oldTimer) < seconds
If EventEnable Then DoEvents
Loop
errSleep:
Err.Clear
End Sub
PDFforge offers PDFCreator. It will create PDFs from any program that is able to print, even existing programs. Note that it's based on GhostScript, so maybe not a good fit to your Acrobat license.
Have you looked into Adobe Distiller Server ? You can generate PostScript files using any printer driver and have it translated into PDF. (Actually, PDFCreator does a similar thing.)
What you want to do is find a good free PDF Printer driver. These are installed as printers, but instead of printing to a physical device, render the printer commands as a PDF. Then, you can either ShellExecute as stated above, or use the built in .net PrintDocument, referring the the PDF "printer" by name. I found a couple free ones, including products from Primo and BullZip (freedom limited to 10 users) pretty quickly.
It looks like SNP files are Microsoft Access Snapshots. You will have to look for a command line interface to either Access or the Snapshot Viewer that will let you specify the printer destination.
I also saw that there is an ActiveX control included in the SnapshotViewer download. You could try using that in your program to load the snp file, and then tell it where to print it to, if it supports that functionality.
I had the same challenge. The solution I've made was buying a component called PDFTron. It has an API to send pdf documents to a printer from an unattended service.
I posted some information in my blog about that. Take a look!
How to print a PDF file programmatically???
Try using ShellExecute with the Print Verb.
Here is a blog I found with Google.
http://www.vbforums.com/showthread.php?t=508684
If you are trying to hand generated the PDF (with and SDK or a PDF printer driver) it's not very easy. The PDF format reference is available from Adobe.
The problem is that the file is a mix of ASCII and tables that have binary offsets within the file to reference objects. It is an interesting format, and very extensible, but it is difficult to write a simple file.
It's doable if you need to. I looked at the examples in the Adobe PDF reference, hand typed them in and worked them over till I could get them to work as I needed. If you will be doing this a lot it might be worth it, otherwise look at an SDK.
I encountered a similar problem in a C# ASP.NET app. My solution was to fire a LaTeX compiler at the command line with some generated code. It's not exactly a simple solution but it generates some really beautiful .pdfs.
Imports System.Drawing.Printing
Imports System.Reflection
Imports System.Runtime.InteropServices
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim pkInstalledPrinters As String
' Find all printers installed
For Each pkInstalledPrinters In _
PrinterSettings.InstalledPrinters
printList.Items.Add(pkInstalledPrinters)
Next pkInstalledPrinters
' Set the combo to the first printer in the list
If printList.Items.Count > 0 Then
printList.SelectedItem = 0
End If
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
Dim pathToExecutable As String = "AcroRd32.exe"
Dim sReport = " " 'pdf file that you want to print
'Dim SPrinter = "HP9F77AW (HP Officejet 7610 series)" 'Name Of printer
Dim SPrinter As String
SPrinter = printList.SelectedItem
'MessageBox.Show(SPrinter)
Dim starter As New ProcessStartInfo(pathToExecutable, "/t """ + sReport + """ """ + SPrinter + """")
Dim Process As New Process()
Process.StartInfo = starter
Process.Start()
Process.WaitForExit(10000)
Process.Kill()
Process.Close()
Catch ex As Exception
MessageBox.Show(ex.Message) 'just in case if something goes wrong then we can suppress the programm and investigate
End Try
End Sub
End Class
Similar to other answers, but much simpler. I finally got it down to 4 lines of code, no external libraries (although you must have Adobe Acrobat installed and configured as Default for PDF).
Dim psi As New ProcessStartInfo
psi.FileName = "C:\Users\User\file_to_print.pdf"
psi.Verb = "print"
Process.Start(psi)
This will open the file, print it with default settings and then close.
Adapted from this C# answer