Is there anyway to specify a PrintTo printer when spawning a process? - c#

What I Have
I am currently writing a program which takes a specified file and the performs some action with it. Currently it opens it, and/or attaches it to an email and mails it to specified addresses.
The file can either be of the formats: Excel, Excel Report, Word, or PDF.
What I am currently doing is spawning a process with the path of the file and then starting the process; however I also am trying to fix a bug feature that I added which adds the verb 'PrintTo' to the startup information, depending on a specified setting.
What I Need
The task I am trying to accomplish is that I would like to have the document open and then print itself to a specified printer named within the program itself. Following that up, the file should then close itself automatically.
If there is no way to do this generically, we might be able to come up with a way to do it for each separate file type.
What you Need
Here is the code I'm using:
ProcessStartInfo pStartInfo = new ProcessStartInfo();
pStartInfo.FileName = FilePath;
// Determine wether to just open or print
if (Print)
{
if (PrinterName != null)
{
// TODO: Add default printer.
}
pStartInfo.Verb = "PrintTo";
}
// Open the report file unless only set to be emailed.
if ((!Email && !Print) || Print)
{
Process p = Process.Start(pStartInfo);
}
How I'm doing...
Still stumped... might call it like Microsoft does,'That was by design'.

The following works for me (tested with *.doc and *.docx files)
the windows printto dialog appears by using the "System.Windows.Forms.PrintDialog" and for the "System.Diagnostics.ProcessStartInfo" I just take the selected printer :)
just replace the FILENAME with the FullName (Path+Name) of your Office file. I think this will also work with other files...
// Send it to the selected printer
using (PrintDialog printDialog1 = new PrintDialog())
{
if (printDialog1.ShowDialog() == DialogResult.OK)
{
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo(**FILENAME**);
info.Arguments = "\"" + printDialog1.PrinterSettings.PrinterName + "\"";
info.CreateNoWindow = true;
info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
info.UseShellExecute = true;
info.Verb = "PrintTo";
System.Diagnostics.Process.Start(info);
}
}

Theoretically, according to an article on MSDN you should be able to change it to be along the lines of (untested):
// Determine wether to just open or print
if (Print)
{
if (PrinterName != null)
{
pStartInfo.Arguments = "\"" + PrinterName + "\"";
}
pStartInfo.CreateNoWindow = true;
pStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
pStartInfo.UseShellExecute = true;
pStartInfo.WorkingDirectory = sDocPath;
pStartInfo.Verb = "PrintTo";
}

get from Rowland Shaw:
ProcessStartInfo startInfo = new ProcessStartInfo(Url)
{
Verb = "PrintTo",
FileName = FilePath,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = true,
Arguments = "\"" + PrinterName+ "\"",
};
Process.Start(startInfo);
FilePath look like 'D:\EECSystem\AttachedFilesUS\53976793.pdf'
PrinterName is your printer name
copy the code,it will work.

Related

Using command prompt to delete specific files within downloads folder

I'm trying to use the following code to delete specific files from my downloads folder -
var process = new Process();
var startInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Normal,
FileName = "cmd.exe",
RedirectStandardInput = true,
UseShellExecute = false
};
process.StartInfo = startInfo;
process.Start();
process.StandardInput.WriteLine("cd C://users/%username%/downloads");
process.StandardInput.WriteLine("del /f Secci*");
When debugging the code - the command prompt window flashes open but then instantly closes (even though it didn't specify for it to be hidden in the code) so I'm struggling to see if it's even managing to CD into the correct directory. Currently the file(s) are not being deleted from the downloads folder either. This is part of a 'Before Test' class within our test automation project. Would be great if someone could give some suggestions on why this might not be working?
For deleting in cmd prompt. Try this
string file = "Secci*";
Process process = new Process();
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.UseShellExecute = false;
process.Start();
process.StandardInput.WriteLine("cd C://users/%username%/downloads");
process.StandardInput.WriteLine(string.Format("del \"{0}\"", file));
If you are trying to use System.IO, Try this.
using System.IO;
string file = "Secci*";
//Because "SpecialFolder" doesn't have Downloads in it, this is my workaround. There may be better ones out there.
string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
path = path.Replace("Documents", "Downloads");
string[] List = Directory.GetFiles(path, file);
foreach (string f in List)
{
File.Delete(f);
}
You can get all the files by enumerating the directory.
Once you have the files that match your criteria, you can iterate over them and perform actions on them.
var dir = new DirectoryInfo("C://users/%username%/downloads");
foreach (var file in dir.EnumerateFiles("Secci*")) {
file.Delete();
}
https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.enumeratefiles?view=netframework-4.7.2

C# Print PDF and move file fails. File is being used by another process

I have this process to print a pdf to a printer. My intention is that after the process completes, the file should be moved to a done folder.
However, right now I am getting a file is being used by another process error.
I have tried setting a longer waitforexit timer and checking if the file is being used but it still fails.
This is the process and move function
public string Process(string FilePath, string PrinterName)
{
Process p = new Process();
p.StartInfo = new ProcessStartInfo()
{
CreateNoWindow = true,
Verb = "printTo",
FileName = FilePath,
Arguments = PrinterName
};
p.Start();
if (!p.WaitForExit(5000))
{
p.Close();
p.Dispose();
p.Kill();
}
return FilePath;
}
Print process in the main program
print.Process(pol[i].FilePath, pol[i].PrinterDriver);
System.IO.File.Move(pol[i].FilePath, Input + "\\Done");

How to provide page range in process print request

I have a document which I am sending to print using below c# code
p.StartInfo = new ProcessStartInfo()
{
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
Verb = "print",
FileName = FileToPrintPath//put the correct path here
};
p.Start();
Now, I have a condition where instead of printing whole document I want to print juts from page number 2 to 5. How can I do this?
I don't know the direct answer to your question but you can easily figure this out with using the code below. Show a dialog and choose page number, number of copies etc. and see how it appears in printDialog1.PrinterSettings. once you know the format, remove the dialog code and hardcode it into Arguments:
using (PrintDialog printDialog1 = new PrintDialog())
{
if (printDialog1.ShowDialog() == DialogResult.OK)
{
var info = new ProcessStartInfo(**FILENAME**);
info.Arguments = "\"" + printDialog1.PrinterSettings.PrinterName + "\"";
// Use the debugger a message dialog to see
// contents of printDialog1.PrinterSettings
}
}
I wrote a quick test and here is what was stored in PrinterSettings:
[PrinterSettings Microsoft XPS Document Writer Copies=1 Collate=False Duplex=Simplex FromPage=0 LandscapeAngle=270 MaximumCopies=1 OutputPort=PORTPROMPT: ToPage=0]
So you need to pass FromPage and ToPage:
info.Arguments = "\"" + printDialog1.PrinterSettings.PrinterName + "\"" + "FromPage=2 ToPage=5";
In your code:
p.StartInfo = new ProcessStartInfo()
{
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
Verb = "print",
FileName = FileToPrintPath,//put the correct path here,
Arguments = "\"Printer Name Goes Here\" FromPage=2 ToPage=5";
};
Please not they are space separated arguments and if your printer name has spaces, you need to put the printer name within quotations.

Activating conda environment from c# code (or what is the differences between manually opening cmd and opening it from c#?)

I want to run a gpu accelerated python script on windows using conda environment (dlwin36).
I’m trying to activate dlwin36 and execute a script:
1) activate dlwin36
2) set KERAS_BACKEND=tensorflow
3) python myscript.py
If I manually open cmd on my machine and write:"activate dlwin36"
it works.
But when I try opening a cmd from c# I get:
“activate is not recognized as an internal or external command, operable program or batch file.”
I tried using the following methods:
Command chaining:
var start = new ProcessStartInfo();
start.FileName = "cmd.exe";
start.Arguments = "/c activate dlwin36&&set KERAS_BACKEND=tensorflow&&python myscript.py";
Process.Start(start).WaitForExit();
(I’ve tested several variations of UseShellExecute, LoadUserProfile and WorkingDirectory)
Redirect standard input:
var commandsList = new List<string>();
commandsList.Add("activate dlwin36");
commandsList.Add("set KERAS_BACKEND=tensorflow");
commandsList.Add("python myscript.py");
var start = new ProcessStartInfo();
start.FileName = "cmd.exe";
start.UseShellExecute = false;
start.RedirectStandardInput = true;
var proc = Process.Start(start);
commandsList.ForEach(command => proc.StandardInput.WriteLine(command));
(I’ve tested several variations of LoadUserProfile and WorkingDirectory)
In both cases, I got the same error.
It seems that there is a difference between manually opening cmd and opening it from c#.
The key is to run activate.bat in your cmd.exe before doing anything else.
// Set working directory and create process
var workingDirectory = Path.GetFullPath("Scripts");
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
RedirectStandardInput = true,
UseShellExecute = false,
RedirectStandardOutput = true,
WorkingDirectory = workingDirectory
}
};
process.Start();
// Pass multiple commands to cmd.exe
using (var sw = process.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
// Vital to activate Anaconda
sw.WriteLine("C:\\PathToAnaconda\\anaconda3\\Scripts\\activate.bat");
// Activate your environment
sw.WriteLine("activate your-environment");
// Any other commands you want to run
sw.WriteLine("set KERAS_BACKEND=tensorflow");
// run your script. You can also pass in arguments
sw.WriteLine("python YourScript.py");
}
}
// read multiple output lines
while (!process.StandardOutput.EndOfStream)
{
var line = process.StandardOutput.ReadLine();
Console.WriteLine(line);
}
You need to use the python.exe from your environment. For example:
Process proc = new Process();
proc.StartInfo.FileName = #"C:\path-to-Anaconda3\envs\tensorflow-gpu\python.exe";
or in your case:
start.Arguments = "/c activate dlwin36&&set KERAS_BACKEND=tensorflow&&\"path-to-Anaconda3\envs\tensorflow-gpu\python.exe\" myscript.py";
I spent a bit of time working on this and here's the only thing that works for me: run a batch file that will activate the conda environment and then issue the commands in python, like so. Let's call this run_script.bat:
call C:\Path-to-Anaconda\Scripts\activate.bat myenv
set KERAS_BACKEND=tensorflow
python YourScript.py
exit
(Note the use of the call keyword before we invoke the activate batch file.)
After that you can run it from C# more or less as shown above.
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = "cmd.exe";
start.Arguments = "/K c:\\path_to_batch\\run_script.bat";
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
start.RedirectStandardError = true;
start.WorkingDirectory = "c:\\path_to_batch";
string stdout, stderr;
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
stdout = reader.ReadToEnd();
}
using (StreamReader reader = process.StandardError)
{
stderr = reader.ReadToEnd();
}
process.WaitForExit();
}
I am generating the batch file on the fly in C# to set the necessary parameters.
If this is gonna help anyone in the future. I found that you must run the activation from C:\ drive.

Printing a PDF Silently with Adobe Acrobat

I'm having 2 issues when trying to print a pdf silently in C# using adobe acrobat. I'm printing the pdfs using Process.Start().
The first issue is that I cannot launch Adobe Acrobat without specifying the full path to the executable. I assume it doesn't add it to your path when you install it. Is there an easy way to launch the newest version of acrobat on a machine without specifying full path names? I'm worried that the client is going to do an update and break my code that launches this. I'm also concerned with them installing this on machines with different versions of windows (install paths are different in 64 bit environment vs. 32 bit).
My second problem is the fact that whenever I launch acrobat and print it still leaves the acrobat window open. I thought that the command line parameters I was using would suppress all of this but apparently not.
I'm trying to launch adobe acrobat from the command line with the following syntax:
C:\Program Files (x86)\Adobe\Reader 10.0\Reader>AcroRd32.exe /t "Label.pdf" "HP4000" "HP LaserJet 4100 Series PCL6" "out.pdf"
It prints out fine but it still leaves the acrobat window up. Is there any other solution besides going out and killing the process programmatically?
I ended up bailing on Adobe Acrobat here and going with FoxIt Reader (Free pdf reader) to do my pdf printing. This is the code I'm using to print via FoxIt in C#:
Process pdfProcess = new Process();
pdfProcess.StartInfo.FileName = #"C:\Program Files (x86)\Foxit Software\Foxit Reader\Foxit Reader.exe";
pdfProcess.StartInfo.Arguments = string.Format(#"-p {0}", fileNameToSave);
pdfProcess.Start();
The above code prints to the default printer but there are command line parameters you can use to specify file and printer. You can use the following syntax:
Foxit Reader.exe -t "pdf filename" "printer name"
Update:
Apparently earlier versions of acrobat do not have the problem outlined above either. If you use a much older version (4.x or something similar) it does not exhibit this problem.
Some printers do support native pdf printing as well so it's possible to send the raw pdf data to the printer and it might print it. See https://support.microsoft.com/en-us/kb/322091 for sending raw data to the printer.
Update 2
In later versions of our software we ended up using a paid product:
http://www.pdfprinting.net/
Nick's answer looked good to me, so I translated it to c#. It works!
using System.Diagnostics;
namespace Whatever
{
static class pdfPrint
{
public static void pdfTest(string pdfFileName)
{
string processFilename = Microsoft.Win32.Registry.LocalMachine
.OpenSubKey("Software")
.OpenSubKey("Microsoft")
.OpenSubKey("Windows")
.OpenSubKey("CurrentVersion")
.OpenSubKey("App Paths")
.OpenSubKey("AcroRd32.exe")
.GetValue(String.Empty).ToString();
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "print";
info.FileName = processFilename;
info.Arguments = String.Format("/p /h {0}", pdfFileName);
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Hidden;
//(It won't be hidden anyway... thanks Adobe!)
info.UseShellExecute = false;
Process p = Process.Start(info);
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
int counter = 0;
while (!p.HasExited)
{
System.Threading.Thread.Sleep(1000);
counter += 1;
if (counter == 5) break;
}
if (!p.HasExited)
{
p.CloseMainWindow();
p.Kill();
}
}
}
}
I've tried both Adobe Reader and Foxit without luck. The current versions of both are very fond of popping up windows and leaving processes running. Ended up using Sumatra PDF which is very unobtrusive. Here's the code I use. Not a trace of any windows and process exits nicely when it's done printing.
public static void SumatraPrint(string pdfFile, string printer)
{
var exePath = Registry.LocalMachine.OpenSubKey(
#"SOFTWARE\Microsoft\Windows\CurrentVersion" +
#"\App Paths\SumatraPDF.exe").GetValue("").ToString();
var args = $"-print-to \"{printer}\" {pdfFile}";
var process = Process.Start(exePath, args);
process.WaitForExit();
}
The following is tested in both Acrobat Reader 8.1.3 and Acrobat Pro 11.0.06, and the following functionality is confirmed:
Locates the default Acrobat executable on the system
Sends the file to the local printer
Closes Acrobat, regardless of version
string applicationPath;
var printApplicationRegistryPaths = new[]
{
#"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Acrobat.exe",
#"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRD32.exe"
};
foreach (var printApplicationRegistryPath in printApplicationRegistryPaths)
{
using (var regKeyAppRoot = Registry.LocalMachine.OpenSubKey(printApplicationRegistryPath))
{
if (regKeyAppRoot == null)
{
continue;
}
applicationPath = (string)regKeyAppRoot.GetValue(null);
if (!string.IsNullOrEmpty(applicationPath))
{
return applicationPath;
}
}
}
// Print to Acrobat
const string flagNoSplashScreen = "/s";
const string flagOpenMinimized = "/h";
var flagPrintFileToPrinter = string.Format("/t \"{0}\" \"{1}\"", printFileName, printerName);
var args = string.Format("{0} {1} {2}", flagNoSplashScreen, flagOpenMinimized, flagPrintFileToPrinter);
var startInfo = new ProcessStartInfo
{
FileName = printApplicationPath,
Arguments = args,
CreateNoWindow = true,
ErrorDialog = false,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden
};
var process = Process.Start(startInfo);
// Close Acrobat regardless of version
if (process != null)
{
process.WaitForInputIdle();
process.CloseMainWindow();
}
got another solution .. its combination of other snippets from stackOverflow. When I call CloseMainWindow, and then call Kill .. adobe closes down
Dim info As New ProcessStartInfo()
info.Verb = "print"
info.FileName = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Microsoft").OpenSubKey("Windows").OpenSubKey("CurrentVersion").OpenSubKey("App Paths").OpenSubKey("AcroRd32.exe").GetValue(String.Empty).ToString()
info.Arguments = String.Format("/p /h {0}", "c:\log\test.pdf")
info.CreateNoWindow = True
info.WindowStyle = ProcessWindowStyle.Hidden
info.UseShellExecute = False
Dim p As Process = Process.Start(info)
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
Dim counter As Integer = 0
Do Until p.HasExited
System.Threading.Thread.Sleep(1000)
counter += 1
If counter = 5 Then
Exit Do
End If
Loop
If p.HasExited = False Then
p.CloseMainWindow()
p.Kill()
End If
Problem 1
You may be able to work your way around the registry. In HKEY_CLASSES_ROOT\.pdf\PersistentHandler\(Default) you should find a CLSID that points to a value found in one of two places. Either the CLSID folder of the same key, or (for 64 bit systems) one step down in Wow6432Node\CLSID then in that CLSID's key.
Within that key you can look for LocalServer32 and find the default string value pointing to the current exe path.
I'm not 100% on any of this, but seems plausible (though you're going to have to verify on multiple environments to confirm that in-fact locates the process you're looking for).
(Here are the docs on registry keys involved regarding PersistentHandlers)
Problem 2
Probably using the CreateNoWindow of the Process StartInfo.
Process p = new Process();
p.StartInfo.FileName = #"C:\Program Files (x86)\Adobe\Reader 10.0\Reader\AcroRd32.exe";
p.StartInfo.Arguments = "/t \"Label.pdf\" \"HP4000\" \"HP LaserJet 4100 Series PCL6\" \"out.pdf\"";
p.CreateNoWindow = true;
p.Start();
p.WaitForExit();
(only a guess however, but I'm sure a little testing will prove it to work/not work)
If you use Acrobat reader 4.0 you can do things like this:
"C:\Program Files\Adobe\Acrobat 4.0\Reader\Acrord32.exe" /t /s "U:\PDF_MS\SM003067K08.pdf" Planning_H2
BUT if the PDF file has been created in a newer version of Acrobat an invisible window opens
For Problem 2
Using /h param will open the Acrobat or Adobe Reader in minimized window.
Example:
C:\Program Files (x86)\Adobe\Reader 10.0\Reader>AcroRd32.exe **/h** /t "Label.pdf" "HP4000" "HP LaserJet 4100 Series PCL6" "out.pdf"
Related Documentation: https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/Acrobat_SDK_developer_faq.pdf#page=24
You have already tried something different than Acrobat Reader, so my advice is forget about GUI apps and use 3rd party command line tool like RawFilePrinter.exe
private static void ExecuteRawFilePrinter() {
Process process = new Process();
process.StartInfo.FileName = "c:\\Program Files (x86)\\RawFilePrinter\\RawFilePrinter.exe";
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.Arguments = string.Format("-p \"c:\\Users\\Me\\Desktop\\mypdffile.pdf\" \"Canon Printer\"");
process.Start();
process.WaitForExit();
if (process.ExitCode == 0) {
//ok
} else {
//error
}
}
Latest version to download: https://bigdotsoftware.pl/rawfileprinter

Categories