Monitor printing of pdf files - c#

So I have to create a console application that prints PDF files. Since I cannot use non-free libraries to print PDF, and I found out that most of free libraries for printing PDF files in .NET use a code similar to this
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "Print";
info.FileName = fileName;
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Hidden;
Process process = new Process();
process.StartInfo = info;
process.Start();
I use this code to start the printing process.
My problem is that I need to monitor the printing in case of an error occuring.
I've been searching for many days but I didn't find anything that works for me, since I can't use WMI (printer driver does not report its status to the spooler), I can't use PrintSystemJobInfo and PrintJobInfoCollection (I found out that it works with files natively handled by .NET but not PDF files), so the only thing that seems to work for now is to manage the printing with PrintQueue.
Now I'm looking for the proper way to use it, what I'm doing now is entering a while loop when the PrintQueueStatus is going from "None" to "Printing", and leaving the loop when the status goes to "Printing to "None", like this :
bool isCompleted = false;
bool isPrinting = false;
while (!isCompleted)
{
_printQueue.Refresh();
switch (_printQueue.QueueStatus)
{
[...]
case PrintQueueStatus.None:
Console.WriteLine("L'état n'est pas spécifié");
if (isPrinting)
{
isPrinting = false;
isCompleted = true;
}
break;
[...]
case PrintQueueStatus.Printing:
Console.WriteLine("Le périphérique imprime");
isPrinting = true;
break;
[...]
}
}
This doesn't allow me to check easily every case of the PrintQueueStatus...
I thought of using events, but since I'm a beginner in .NET and I'm not familiar with events, and can't find how to do it.
So the question is mainly, is it possible to use events to monitor a change in the PrintQueueStatus and how to do it. If it's not possible, how can I do to monitor the printing.
Thanks.

Related

c# printing 2 pages per sheet how programmatically?

After 2-3 weeks of trying to programmatically get this to work without trying to use 3rd party vendors, I'm still struggling to try to accomplish the task of outputting 2 pdf pages on the same page, landscape on a standard sheet of paper. What I'm at least able to do is merge 2 different pdf outputs into one file stream for printing purposes, but when I try to print, the pages appear separately. In essence, I'm trying to replicate the following print dialog automatically but without the print dialog:
Here's the c# code I've done so far in attempting this with my final output:
PrinterSettings settings = new PrinterSettings();
string printerName = settings.PrinterName;
printDlg.PrintTicket.PagesPerSheet = 2;
string rwPrinter = printerName;
Process process = new Process();
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.FileName = printFile;
if (rwPrinter.Length > 0)
{
process.StartInfo.Verb = "printto";
process.StartInfo.Arguments = "\"" + rwPrinter + "\"";
}
else
{
process.StartInfo.Verb = "print";
}
try
{
process.Start();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
process.WaitForInputIdle();
I'm seeking any possible solutions without necessarily invoking 3rd party software may with the exception of an Adobe SDK in order to get this idea done, Please advise, thanks.

Trigger Apache Nutch Crawl Programmatically

I'm trying to create a ASP.NET web api to trigger a crawl event to happen. I can't seem to get cygwin to process any of the commands I give it. The only thing I can really do is get it to open a terminal. Once the terminal is open I'd have to redirect the pwd to another location and then trigger my command I want.
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.CreateNoWindow = false;
info.RedirectStandardInput = true;
info.UseShellExecute = false;
info.FileName = "C:\\cygwin64\\bin\\mintty.exe";
p.StartInfo = info;
p.Start();
StreamWriter sw = p.StandardInput;
if (sw.BaseStream.CanWrite)
{
sw.WriteLine(#"cd C:\Users\UName\Desktop\apache-nutch-2.3-mongodb\runtime\local\");
sw.WriteLine("bin/autoCrawl");
}
sw.Close();
p.WaitForExit();
I've tried many approaches, this is the last one I've tried but it just does nothing. Is there a way to launch this crawl from my .NET application? I've looked into the NutchApi about creating a new job with a type of crawl but I'm not sure if that applies here or not.
I ended up figuring out how to use the NutchApi to answer my question.

Printing PDF on OSX

i am working in unity and i have a task of creating and then printing pdf from some of the snapshots taken through cameras in unity.
On windows after creating the pdf that can easily be done by calling the ShellExecute function and passing print as the parameter or using a function posted on stackoverflow i.e:
private void SendToPrinter()
{
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "print";
info.FileName = #"c:\output.pdf";
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Hidden;
Process p = new Process();
p.StartInfo = info;
p.Start();
p.WaitForInputIdle();
System.Threading.Thread.Sleep(3000);
if (false == p.CloseMainWindow())
p.Kill();
}
, but i have no clue at all how would i be able to achieve the same for the OSX build?
Any help will be really appreciated.
You need to look at Apple's "Printing Programming Guide for Mac". (https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Printing/osxp_aboutprinting/osxp_aboutprt.html)
To print a PDF page, you need a CGContextRef. In your views drawRect: method, you can get the the correct graphics context like this:
CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort];
The method you use to draw a PDF page into a context is CGContextDrawPDFPage(context,page);
The easiest way to open a PDF document is to use CGPDFDocumentCreateWithURL
You get the pages using CGPDFDocumentGetPage.

Is there a C# way to read exceptions from cmd processes?

The specific problem I am seeing when executing a cmd process with something like "del *.txt" where one of the 'txt' files is open and cannot be deleted, the cmd process will output a line of text (saying something like 'file in use, cannot delete file') to the console, but not to the StandardOutput or the StandardError. According to this question [ https://stackoverflow.com/a/320779/832705 ] from 2008, the answer is no, but I am wondering if that might have changed in the past 4 years, or if someone has since found a workaround way. Also, I might be misinterpreting that answer, it might mean CLR exceptions and not cmd exceptions.
here is my process setup/start code:
ProcessStartInfo psi = new ProcessStartInfo("cmd", string.Empty);
psi.CreateNoWindow = true;
psi.ErrorDialog = false;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = true;
psi.UseShellExecute = false;
Process p = new Process();
p.StartInfo = psi;
p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
p.ErrorDataReceived += new DataReceivedEventHandler(p_ErrorDataReceived);
outputfilesw = new StreamWriter(outputfile, true);
try
{
p.Start();
p.BeginOutputReadLine();
//work code
}
You just have to call p.BeginErrorReadLine() to start the asynchronous read of StandardError. Answer added at suggestion of OP.
You can read the output, and you can process the text returned. So, you should be able to find the text that indicates an error, even if it doesn't land in the error output.
Also, it is important to note that only the process being run can determine which output stream gets a message. So, if the command you're using decides to send errors to the standard stream, no amount of OS or C# work will change that.

How to get the output of a System.Diagnostics.Process?

I run ffmpeg like this:
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo = new System.Diagnostics.ProcessStartInfo(ffmpegPath, myParams);
p.Start();
p.WaitForExit();
... but the problem is that the console with ffmpeg pops up and disappears right away, so I can't get any feedback. I don't even know if the process ran correctly.
So how can I either:
Tell the console to stay opened
Retrieve in the C# what the console
displayed
What you need to do is capture the Standard Output stream:
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
// instead of p.WaitForExit(), do
string q = "";
while ( ! p.HasExited ) {
q += p.StandardOutput.ReadToEnd();
}
You may also need to do something similar with StandardError. You can then do what you wish with q.
It is a bit finicky, as I discovered in one of my questions
As Jon Skeet has pointed out, it is not smart performance-wise to use string concatenation like this; you should instead use a StringBuilder:
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
// instead of p.WaitForExit(), do
StringBuilder q = new StringBuilder();
while ( ! p.HasExited ) {
q.Append(p.StandardOutput.ReadToEnd());
}
string r = q.ToString();
Lucas' answer has a race condition: If the process finishes quickly the while loop is left (or never entered) even if there is some output left, that is you might miss out on some data. To prevent that, another ReadToEnd should be done after the process exited.
(Note that in comparison to the old version of my answer, I can no longer see a need for WaitForExit once the process.HasExited flag is true, so this boils down to:)
using (var process = Process.Start(startInfo))
{
var standardOutput = new StringBuilder();
// read chunk-wise while process is running.
while (!process.HasExited)
{
standardOutput.Append(process.StandardOutput.ReadToEnd());
}
// make sure not to miss out on any remaindings.
standardOutput.Append(process.StandardOutput.ReadToEnd());
// ...
}
I know this question is old, but I'll add to it anyway.
If all you wish to do is display the output of a command line process, and you're spawning the process from a console window, you need only redirect the standard input (yes, I know it sounds wrong, but it works).
So:
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo = new System.Diagnostics.ProcessStartInfo(ffmpegPath, myParams);
p.UseShellExecute = false;
p.RedirectStandardInput = true;
p.Start();
p.WaitForExit();
Would do just fine.
For a more specific answer directly related to ffmpeg, passing the "-report" command into ffmpeg will make it dump a log into the current directory with what was said in the display of the process.
‘-report’
Dump full command line and console output to a file named
program-YYYYMMDD-HHMMSS.log in the current directory. This file can be
useful for bug reports. It also implies -loglevel verbose.
Note: setting the environment variable FFREPORT to any value has the
same effect.
From FFMpeg Documentation.

Categories

Resources