How to print a PDF file from code? [duplicate] - c#

This question already has answers here:
How can I send a file document to the printer and have it print?
(12 answers)
Windows 8 blows error on c# process for printing pdf file, how?
(1 answer)
Closed 9 years ago.
I've been developing an application in visual c# which needs to print an existing pdf file at the press of a button.
I've been using the System.Diagnostics.Process method to print but it fails to work as desired in a Windows 8 environment as the "Printto" command doesn't seem to work there.
I would like to use an alternative such as possibly the System.Drawing.Printing.PrintDocument which had an example that works with text files but when I tried with a pdf it was printing random characters instead.
My google searches for such seem to come up empty or I'm not entering the right keywords, but I need a solution which not only prints pdf to target printer but can determine if the printer is ready, offline or out of paper as well as an error catch.
Please advise as I'm also willing to look at any SDK or third party routes recommendable.
edit: added code snippet I'm currently using:
string defFile = (Path.Combine(GlobalVars.pdfPath, tkt_no + "_DEF.pdf"));
string rwPrinter = "";
if (GlobalVars.useDefaultPrinter == false)
{
foreach (string strPrinter in System.Drawing.Printing.PrinterSettings.InstalledPrinters)
{
if (strPrinter.StartsWith("ZDesigner"))
{
rwPrinter = strPrinter;
break;
}
}
}
if (jobdo.Equals("print"))
{
Process process = new Process();
//process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.FileName = defFile;
if (rwPrinter.Length > 0)
{
process.StartInfo.Verb = "printto";
//process.StartInfo.Verb = (Path.Combine(System.Windows.Forms.Application.StartupPath, "printto.exe"));
process.StartInfo.Arguments = "\"" + rwPrinter + "\"";
}
else
{
process.StartInfo.Verb = "print";
}
try
{
process.Start();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
process.WaitForInputIdle();
//while (process.MainWindowHandle == IntPtr.Zero)
//{
// Thread.Sleep(20);
// process.Refresh();
//}
Thread.Sleep(7000);
try
{
process.Kill();
}
catch { }
// close any occurrences of Adobe Reader that may not close through a citrix environment regardless
foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses())
{
if (p.ProcessName.Equals("AcroRd32"))
{
ObjectQuery sq = new ObjectQuery
("Select * from Win32_Process where ProcessID = '" + p.Id + "'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(sq);
foreach (ManagementObject oReturn in searcher.Get())
{
string[] o = new string[2];
oReturn.InvokeMethod("GetOwner", (object[])o);
if(o[0] != null)
if(o[0].Equals(System.Environment.UserName))
p.Kill();
}
}
}
if (rwPrinter == "")
{
rwPrinter = "the default printer";
}
else
MessageBox.Show("Ticket " + tkt_no + " was printed to " + rwPrinter + ".");
}

Please see this, using iTextSharp library you can easily create PDF file:
http://sourceforge.net/projects/itextsharp/

Related

C# + 7z.exe doesn't seem to work [duplicate]

This question already has answers here:
Unzip a file in c# using 7z.exe
(6 answers)
Closed 8 years ago.
string path = #"C:\Users\<user>\Documents\Visual Studio\Projects\7ZipFile\RequiredDocs\";
ProcessStartInfo zipper = new ProcessStartInfo(#"C:\Program Files\7-Zip\7z.exe");
zipper.Arguments = string.Format("a -t7z {0}.7z {0} *.txt -mx9", path);
zipper.RedirectStandardInput = true;
zipper.UseShellExecute = false;
zipper.CreateNoWindow = true;
zipper.WindowStyle = ProcessWindowStyle.Hidden;
Process process = Process.Start(zipper);
Goal: Zip all *.txt file(s) within "path" and save that zipped file within "path" and these .txt files should not be present in the "path" after zipping
When I run the code, nothing seems to happen (0 error)...
Please help!
Thank you
UPDATE: I am using 7Zip and have installed 7Zip application on Windows where this code will be used w/ .NET 3.5.
The normal way of using 7Zip from a program is to invoke 7za.exe (not the installed 7z program) and include 7za with your application.
This page has a good tutorial on how to use it. Works great every time I have needed to zip/7zip programmatically.
You could also use the ZipArchive class if you want normal zip functionality in a pure .NET way (requires .NET 4.5)
Also, your path should be in quotes in case there is a space. Note that the quotes are escaped with '\'. "" is also a valid escape sequence for a quote in C#:
string.Format("a -t7z \"{0}.7z\" \"{0}\" *.txt -mx9", path);
Here's an example from my application. This example extracts an archive but it shows you how to set up the process. Just change the command to 7z and the arguments. This example assumes you're shipping 7za.exe with your application. Good luck.
public static bool ExtractArchive(string f) {
string tempDir = Environment.ExpandEnvironmentVariables(Configuration.ConfigParam("TEMP_DIR"));
if (zipToolPath == null) return false;
// Let them know what we're doing.
Console.WriteLine("Unpacking '" + System.IO.Path.GetFileName(f) + "' to temp directory.");
LogFile.LogDebug("Unpacking '" + System.IO.Path.GetFileName(f) + "' to temp directory '" + tempDir + "'.",
System.IO.Path.GetFileName(f));
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
if (pid == PlatformID.Win32NT || pid == PlatformID.Win32S || pid == PlatformID.Win32Windows || pid == PlatformID.WinCE) {
p.StartInfo.FileName = "\"" + Path.Combine(zipToolPath, zipToolName) + "\"";
p.StartInfo.Arguments = " e " + "-y -o" + tempDir + " \"" + f + "\"";
} else {
p.StartInfo.FileName = Path.Combine(zipToolPath, zipToolName);
p.StartInfo.Arguments = " e " + "-y -o" + tempDir + " " + f;
}
try {
p.Start();
} catch (Exception e) {
Console.WriteLine("Failed to extract the archive '" + f + "'.");
LogFile.LogError("Exception occurred while attempting to list files in the archive.");
LogFile.LogExceptionAndExit(e);
}
string o = p.StandardOutput.ReadToEnd();
p.WaitForExit();
string[] ls = o.Split('\n');
for (int i = 0; i < ls.Count(); i++) {
string l = ls[i].TrimEnd('\r');
if (l.StartsWith("Error")) {
LogFile.LogError("7za: Error '" + ls[i + 1] + "'.", f);
Console.WriteLine("Failed to extract the archive '" + f + "'.");
return false;
}
}
return true;
}

Open and print PDF files

I'd like to open and print all PDF files located in a given folder. The files are named according to the following pattern:
NameOfThePrinter_Timestamp.pdf
Now I want to print those files using the corresponding printer:
static void Main(string[] args)
{
string pdf = #"C:\PathToFolder";
if (Directory.GetFiles(pdf).Length > 0)
{
string[] files = Directory.GetFiles(pdf);
var adobe = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Microsoft").OpenSubKey("Windows").OpenSubKey("CurrentVersion").OpenSubKey("App Paths").OpenSubKey("AcroRd32.exe");
var path = adobe.GetValue("");
string acrobat = path.ToString();
for (int i = 0; i < files.Length; i++)
{
Process process = new Process();
process.StartInfo.FileName = acrobat;
process.StartInfo.Verb = "printto";
process.StartInfo.Arguments = "/p /s /h \"" + files[i] + "\"";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.Start();
DateTime start = DateTime.Now;
IntPtr handle = IntPtr.Zero;
while (handle == IntPtr.Zero && DateTime.Now - start <= TimeSpan.FromSeconds(2))
{
try
{
System.Threading.Thread.Sleep(50);
handle = process.MainWindowHandle;
} catch (Exception) { }
}
foreach (String verb in process.StartInfo.Verbs)
{
// Display the possible verbs.
Console.WriteLine(" {0}. {1}", i.ToString(), verb);
i++;
}
System.Threading.Thread.Sleep(10000);
Console.Out.WriteLine("File: " + files[i] + " is printing!");
process.Kill();
}
foreach (string str in files)
{
File.Delete(str);
}
Console.Out.WriteLine("Files are deleted!");
}
}
My question is: How can I pass the printer name as parameter?
Here I've tried something, but it either throws and error or prints to the default printer:
process.StartInfo.Arguments = "/p /s /h \"" + files[i] + "\"";
You can use Ghostscript to send the PDF document to the printer.
Here you can find a sample how to send the PDF document to printer: How to print PDF on default network printer using GhostScript (gswin32c.exe) shell command
And here you can find Ghostscript wrapper for .NET if you want to control Ghostscript directly without calling .exe file: http://ghostscriptnet.codeplex.com
function printDisclosureDocument() {
var doc = document.getElementById('pdfDocument');
if (doc == 'undefined' || doc == null) {
var pdfbox = document.createElement('embed');
pdfbox.type = 'application/pdf';
pdfbox.src = 'ShowPDF.aspx?refid=' + $('#MainContent_hdnRefId').val();
pdfbox.width = '1';
pdfbox.height = '1';
pdfbox.id = 'pdfDocument';
document.body.appendChild(pdfbox);
}
if (doc != null && doc != 'undefined') {
//Wait until PDF is ready to print
if (typeof doc.print === 'undefined') {
setTimeout(function () { printDisclosureDocument(); }, 500);
} else {
doc.print();
}
}
else {
setTimeout(function () { printDisclosureDocument(); }, 500);
}
}

Error upon sending and executing multiple test files

I am writing an application which launches a tester (.cmd), so I am passing in the tests that have been entered into a listbox. This method works perfectly fine if there is one test entered, but if there is 2 or more, it give me the error:
"An unhandled exception of type 'System.ComponentModel.Win32Exception'
occurred in System.dll
Additional information: The system cannot find the file specified"
The StartInfo.Filename and the currentTestFromListbox[i] both look correct in the debugger.
Anyone have any idea where I'm going wrong?
I apologize that my code is confusing--im just a beginner.
public void executeCommandFiles()
{
int i = 0;
int ii = 0;
int numberOfTests = listboxTestsToRun.Items.Count;
executeNextTest:
var CurrentTestFromListbox = listboxTestsToRun.Items.Cast<String>().ToArray();
string filenameMinusCMD = "error reassigning path value";
int fileExtPos = CurrentTestFromListbox[i].LastIndexOf(".");
if (fileExtPos >= 0)
{
filenameMinusCMD = CurrentTestFromListbox[i].Substring(0, fileExtPos);
}
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.Arguments = #"pushd Y:\Tests\" + filenameMinusCMD + #"\" + CurrentTestFromListbox[i];
startInfo.WorkingDirectory = #"pushd Y:\Tests\" + filenameMinusCMD + #"\";
startInfo.FileName = CurrentTestFromListbox[i];
Process.Start(startInfo);
//Wait for program to load before selecting main tab
System.Threading.Thread.Sleep(10000);
//Select MainMenu tab by sending a left arrow keypress
SendKeys.Send("{LEFT}");
i++;
if (i < numberOfTests)
{
checkIfTestIsCurrentlyRunning:
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.Contains("nameOfProgramIAmTesting"))
{
System.Threading.Thread.Sleep(2000);
//if (ii > 150)
if (ii > 6) //test purposes only
{
MessageBox.Show("The current test (" + filenameMinusCMD + ") timed out at 5 minutes. The next test has been started.", "Test timed out",
MessageBoxButtons.OK,
MessageBoxIcon.Error,
MessageBoxDefaultButton.Button1);
}
ii++;
goto checkIfTestIsCurrentlyRunning;
}
goto executeNextTest;
}
}
}
}
Thanks!
-Joel
Here is your code re-factored. The sleeps/gotos were really bothering me. I couldn't really test it, but I think it should work the same. Let me know if it doesn't work or you have any questions.
This assumes your listbox has content like this in it:
testname.cmd
test2.cmd
test3.exe
lasttest.bat
Here is my attempt:
public void executeCommandFiles()
{
foreach (string test in listboxTestsToRun.Items)
{
//gets the directory name from given filename (filename without extension)
//assumes that only the last '.' is for the extension. test.1.cmd => test.1
string testName = test.Substring(0, test.LastIndexOf('.'));
//set up a FileInfo object so we can make sure the test exists gracefully.
FileInfo testFile = new FileInfo(#"Y:\Tests\" + testName + "\\" + test);
//check if it is a valid path
if (testFile.Exists)
{
ProcessStartInfo startInfo = new ProcessStartInfo(testFile.FullName);
//get the Process object so we can wait for it to finish.
Process currentTest = Process.Start(startInfo);
//wait 5 minutes then timeout (5m * 60s * 1000ms)
bool completed = currentTest.WaitForExit(300000);
if (!completed)
MessageBox.Show("test timed out");
//use this if you want to wait for the test to complete (indefinitely)
//currentTest.WaitForExit();
}
else
{
MessageBox.Show("Error: " + testFile.FullName + " was not found.");
}
}
}

How to display list process, when i run sql*loader in c#

How to display list process, when i run sql*loader in c#. I mean when i run sql*loader from cmd windows, i get list process how many row has been inserted. But when i run SQL*Loader from C#, i can't get process SQL*Loader.
This is my code:
string strCmd, strSQLLoader;
string strLoaderFile = "XLLOAD.CTL";
string strLogFile = "XLLOAD_LOG.LOG";
string strCSVPath = #"E:\APT\WorkingFolder\WorkingFolder\sqlloader\sqlloader\bin\Debug\8testskrip_HTTP.csv";
string options = "OPTIONS (SKIP=1, DIRECT=TRUE, ROWS=1000000,BINDSIZE=512000)";
string append = "APPEND INTO TABLE XL_XDR FIELDS TERMINATED BY ','";
string table = "OPTIONALLY ENCLOSED BY '\"' TRAILING NULLCOLS (xdr_id,xdr_type,session_start_time,session_end_time,session_last_update_time,session_flag,version,connection_row_count,error_code,method,host_len,host,url_len,url,connection_start_time,connection_last_update_time,connection_flag,connection_id,total_event_count,tunnel_pair_id,responsiveness_type,client_port,payload_type,virtual_type,vid_client,vid_server,client_addr,server_addr,client_tunnel_addr,server_tunnel_addr,error_code_2,ipid,c2s_pkts,c2s_octets,s2c_pkts,s2c_octets,num_succ_trans,connect_time,total_resp,timeouts,retries,rai,tcp_syns,tcp_syn_acks,tcp_syn_resets,tcp_syn_fins,event_type,flags,time_stamp,event_id,event_code)";
strCmd = "sqlldr xl/secreat#o11g control=" + strLoaderFile + " LOG=" + strLogFile;
System.IO.DirectoryInfo di;
try
{
System.Diagnostics.ProcessStartInfo cmdProcessInfo = new System.Diagnostics.ProcessStartInfo("cmd.exe");
di = new DirectoryInfo(strCSVPath);
strSQLLoader = "";
strSQLLoader += "LOAD DATA INFILE '" + strCSVPath.ToString().Trim() + "' " + append + " " + table;
StreamWriter writer = new StreamWriter(strLoaderFile);
writer.WriteLine(strSQLLoader);
writer.Flush();
writer.Close();
// Redirect both streams so we can write/read them.
cmdProcessInfo.RedirectStandardInput = true;
cmdProcessInfo.RedirectStandardOutput = true;
cmdProcessInfo.UseShellExecute = false;
cmdProcessInfo.LoadUserProfile = true;
//System.Diagnostics.Process.Start("CMD.exe", strCmdLine);
// Start the procses.
System.Diagnostics.Process pro = System.Diagnostics.Process.Start(cmdProcessInfo);
// Issue the dir command.
pro.StandardInput.WriteLine(strCmd);
// Exit the application.
pro.StandardInput.WriteLine("exit");
//Process[] processlist = Process.GetProcesses();
//foreach(Process pro in processlist){
Console.WriteLine("Process: {0} ID: {1}", pro.ProcessName, pro.Id);
Console.WriteLine(pro.StandardOutput.ReadLine());
//}
// Read all the output generated from it.
string strOutput;
strOutput = pro.StandardOutput.ReadToEnd();
pro.Dispose();
}
catch (Exception ex)
{
return;
}
finally
{
}
Thanks
When you send
pro.StandardInput.WriteLine("exit");
to the process, this will close the console and exit the process.
So when you call
Console.WriteLine("Process: {0} ID: {1}", pro.ProcessName, pro.Id);
it raises a
"Process has exited, so the requested
information is not available."
exception. To fix this, move your exit call to after this line.
Never ignore exceptions!!! They tell you useful things that help you to fix your problems!!

How to Print any document in a SELECTED printer

I would like to print any document such as pdf,word,excel or text files in a selected printer using .net .I have got success to do such printing in the default printer .The only issue now is to print in the selected printer.
Here is the code for the printing.
public bool Print(string FilePath)
{
if (File.Exists(FilePath)) {
if (ShellExecute((System.IntPtr )1, "Print", FilePath, "", Directory.GetDirectoryRoot(FilePath), SW_SHOWNORMAL).ToInt32() <= 32) {
return false;
} else {
return true;
}
} else {
return false;
}
}
Process printJob = new Process();
printJob.StartInfo.FileName = path;
printJob.StartInfo.UseShellExecute = true;
printJob.StartInfo.Verb = "printto";
printJob.StartInfo.CreateNoWindow = true;
printJob.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
printJob.StartInfo.Arguments = "\"" + printerAddress + "\"" + " " + printerExtraParameters;
printJob.StartInfo.WorkingDirectory = Path.GetDirectoryName(path);
printJob.Start();
What file format are you testing with success to the default printer?
Its not possible to just send "any" document to a printer, generally the specific file format needs to be interpretted by an application that can read the file format then render it to a printer or a file that can be interpretted by the printer.
In most cases if you can render to a PostScript or PDF you can get its to print using a single interpretter.

Categories