4

I need to print multiple PDF-files from the hard-drive. I have found this beautiful solution of how to send a file to the printer. The problem with this solution is that if you want to print multiple files you have to wait for each file for the process to finish.

in the command shell it is possible to use the same command with multiple filenames: print /D:printerName file1.pdf file2.pdf and one call would print them all.

unfortunately simply just to put all the filenames into the ProcessStartInfo doesn't work

string filenames = @"file1.pdf file2.pdf file3.pdf"
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "print";
info.FileName = filenames;

neither does it to put the filenames as Arguments of the Process

info.Arguments = filename;

I always get the error: Cannot find the file!

How can I print a multitude of files with one process call?

Here is an example of how I use it now:

public void printWithPrinter(string filename, string printerName)
{

    var procInfo = new ProcessStartInfo();    
    // the file name is a string of multiple filenames separated by space
    procInfo.FileName = filename;
    procInfo.Verb = "printto";
    procInfo.WindowStyle = ProcessWindowStyle.Hidden;
    procInfo.CreateNoWindow = true;

    // select the printer
    procInfo.Arguments = "\"" + printerName + "\""; 
    // doesn't work
    //procInfo.Arguments = "\"" + printerName + "\"" + " " + filename; 

    Process p = new Process();
    p.StartInfo = procInfo;

    p.Start();

    p.WaitForInputIdle();
    //Thread.Sleep(3000;)
    if (!p.CloseMainWindow()) p.Kill();
}
Community
  • 1
  • 1
Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
  • Make a method to print one file (given as parameter). Call this method N times. `Arguments` should work, maybe you are passing too many files, it has maximum [32699](https://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.arguments(v=vs.110).aspx) chars in Win7+ (2080 in earlier versions). – Sinatr May 30 '16 at 12:53
  • I did this already, but I have to wait each time until the process finishes and it takes 2-3 seconds. I need to print 200 files. it would be nice to break it at least into steps of 10 or 20. I try it only with 2 files up to now. It should not be too much. – Mong Zhu May 30 '16 at 13:29
  • the `ProcessStartInfo` always demands a filename. It gives me an error if I don't assign a filename and use it only in the `Arguments` property – Mong Zhu May 30 '16 at 13:31

2 Answers2

4

Following should work:

public void PrintFiles(string printerName, params string[] fileNames)
{
    var files = String.Join(" ", fileNames);
    var command = String.Format("/C print /D:{0} {1}", printerName, files);
    var process = new Process();
    var startInfo = new ProcessStartInfo
    {
        WindowStyle = ProcessWindowStyle.Hidden,
        FileName = "cmd.exe",
        Arguments = command
    };

    process.StartInfo = startInfo;
    process.Start();
}

//CALL
PrintFiles("YourPrinterName", "file1.pdf", "file2.pdf", "file3.pdf");
Abbas
  • 14,186
  • 6
  • 41
  • 72
  • for the call to work you need to change the method head to `PrintFiles(string printerName, params string[] fileNames)`and remove the `;` after `new ProcessStartInfo();` It doesn't give me the File not found error, but it also doesn't print. – Mong Zhu May 30 '16 at 14:36
  • 1
    @MongZhu : See if maybe there's a quoting problem also http://stackoverflow.com/questions/12891383/correct-quoting-for-cmd-exe-for-multiple-arguments – Tewr May 30 '16 at 15:51
  • @Abbas ok your solution actually works. If the file is not empty and has no spaces in the filename. I tried to save ink by test-printing empty pages, but the printer is smarter, it doesn't print empty pages. ( My fault) @ Tewr seems also to be the case. I am trying to get this under control. – Mong Zhu May 31 '16 at 06:55
  • last addition thx2 @Tewr: got the spaces under control by encapsulating every filename in quotes `\"filename\"`. – Mong Zhu May 31 '16 at 07:14
0

It's not necessarily a simple solution, but you could merge the pdfs first and then send then to acrobat.

For example, use PdfMerge

Example overload to your initial method:

    public void printWithPrinter(string[] fileNames, string printerName)
    {
        var fileStreams = fileNames
            .Select(fileName => (Stream)File.OpenRead(fileName)).ToList();
        var bundleFileName = Path.GetTempPath();
        try
        {

            try
            {
                var bundleBytes = new PdfMerge.PdfMerge().MergeFiles(fileStreams);
                using (var bundleStream = File.OpenWrite(bundleFileName))
                {
                    bundleStream.Write(bundleBytes, 0, bundleBytes.Length);
                }
            }
            finally 
            {
                    fileStreams.ForEach(s => s.Dispose());
            }

            printWithPrinter(bundleFileName, printerName);
        }
        finally 
        {
            if (File.Exists(bundleFileName))
                File.Delete(bundleFileName);
        }
    }
Tewr
  • 3,713
  • 1
  • 29
  • 43
  • that is indeed a little overhead. Might work though. But my main question is still how to pass multiple filenames to the process call. May be I should rephrase my question... – Mong Zhu May 30 '16 at 13:53