c# printing 2 pages per sheet how programmatically? - c#

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.

Related

How to get the text from a pop-up box generated from cmd?

I'm trying to get the activation status of Windows. I've got this code:
Process proc = new Process();
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.StartInfo.FileName = "cmd.exe";
proc.StartInfo.Arguments = "/C slmgr /xpr";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardInput = true;
proc.Start();
string x = "";
while (!proc.HasExited)
{
x += proc.StandardOutput.ReadToEnd();
}
return x;
As some of you may know, the command "slmgr /xpr" will make a pop-up appear informing you of your Windows activation status.
Executing this code, I get the pop-up box (and "x" is empty).
What I want is to get the text that's in it (so it appears on a label in my form). I wonder if there's any way to extract just the text from inside the pop-up that appears, in this case it would be something like "the machine is permanently activated".
Is there any simple way to achieve this?
slmgr is actually a VBScript file not an executable, when you run it it will default to using the WScript runtime which is for windowed scripts and uses Message Boxes for default output. If you change to CScript you will get console output:
proc.StartInfo.FileName = "cscript.exe";
proc.StartInfo.Arguments = "/nologo \"" + Path.Combine(Environment.SystemDirectory, "slmgr.vbs") + "\" /xpr";
You can then capture this: Capturing console output from a .NET application (C#)
You could also look inside the script file, see whats its doing & reimplement it in your code (ymmv).

how to catch command prompt process finish in C# and do something after that?

I am working with voice records. I need to use an .exe file for convert Wav to .mp3 file. Everything is fine I can execute this exe but I need to do something after when process end with my output .mp3 file. I know my output directory but i cant handle MP3 file before its not created yet. I know maybe I need to use Thread.sleep(); or something like that because I cant catch a file before its not exist.
Here is my code:
string mp3GuidName = Guid.NewGuid().ToString();
var mp3FilePath = WavFilePath.Replace("finalWavFile", mp3GuidName).Replace("wav", "mp3");
var extrasFilePath = HttpContext.Current.Server.MapPath("/").Replace("DevApp.Web", "Extras");
string strArguments = "/c start " + extrasFilePath + "lame.exe --abr 80 -V5 " + WavFilePath + " " + mp3FilePath;
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = strArguments ;
process.StartInfo = startInfo;
process.Start();
var attactment = new Attachment
{
CreatedOn = DateTime.Now,
UpdatedOn = DateTime.Now,
Title = mp3GuidName +".mp3",
Size = _storageProvider.GetFile(mp3FilePath).GetSize(), // here I am trying to get mp3 file but i cant catch it. Because if this wav files size is huge, then convert process is taking time and my mp3 file is not created yet.
FileExtension = _storageProvider.GetFile(mp3FilePath).GetFileType()
};
attactment.MimeType = _storageProvider.GetMimeType(attactment.FileExtension);
attactment.FileUrl = mp3GuidName+".mp3";// file.GetName();
attactment.AttachmentFolderId = folder.Id;
_attachmentRepository.Add(attactment);
I was try to use process.WaitForExit();but I cant solve this problem. I still cant acces to mp3 file.
so how can I catch when the process finish?
Best Regards.
Remove the start command argument from your argument string and you should be able to use process.WaitForExit(); to wait for Lame to finish with encoding:
string strArguments = "/c " + extrasFilePath + "lame.exe --abr 80 -V5 " + WavFilePath + " " + mp3FilePath;
However, you can simplify your code and avoid this dance with cmd.exe altogether by starting lame.exe directly:
string strArguments = "--abr 80 -V5 " + WavFilePath + " " + mp3FilePath;
...
startInfo.FileName = extrasFilePath + "lame.exe";
startInfo.Arguments = strArguments;
...
Below some information about why using the start command argument in your scenario is counterproductive.
Executing console applications such as lame.exe using cmd.exe (or from a console or batch file) normally block cmd.exe (or console/batch file) until the console application exits.
However, using the start command turns this normally blocking execution of a console application into a non-blocking execution. With this argument, the cmd.exe (or console/batch file) will continue execution while the console application is still running. In your particular case it means cmd.exe will exit right after it has started lame.exe (since it has nothing else to execute), effectively sabotaging your attempt to wait for lame.exe to finish.
Edited:
Base on the comments below I have to make it clear that the oroginal solution I recommended does not check if the file is free but it checks only if the file exists!
So I rather recommend the following:
private bool IsBusy(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None);
}
catch ()
{
return true;
}
finally
{
if (stream != null)
stream.Close();
}
return false;
}
the usage will be:
while(IsBusy(fileinfo))
{
//just wait
}
ORIGINAL:
You can use a while loop to find out when the file is ready:
while(!File.Exists(mp3FileName))
{
//just wait
}
// add the attachment here

Using ffmpeg in C#. Can't get the FFmpeg output

I'm kind of new to C# and I have tried for a week but can't solve this problem...
I'm creating video information and convert apps by running ffmpeg command and display the output in a TextBox. Here is my code:
ProcessStartInfo psi1 = new ProcessStartInfo("Cmd");
psi1.UseShellExecute = false;
psi1.RedirectStandardOutput = true;
psi1.RedirectStandardError = true;
psi1.CreateNoWindow = true;
psi1.RedirectStandardInput = true;
psi1.WindowStyle = ProcessWindowStyle.Hidden;
var proc = Process.Start(psi1);
if (!String.IsNullOrEmpty(txtpath.Text))
{
proc.StandardInput.WriteLine(#"cd" + " " + txtpath.Text);
proc.StandardInput.WriteLine(#"for %a in (*) do ffmpeg -threads 0 -i %a -vf scale=-1:480:force_original_aspect_ratio=increase %~Na.mp4");
proc.StandardInput.WriteLine("exit");
}
string s = proc.StandardError.ReadToEnd();
richTextBox1.Text = s;
txtpath.Text is the input folder select by user. After run, the ffmpeg.exe run as background as my wish, but on the text box there is only one line and that's it. I wanna capture the whole process until the end.
And moreover, can i point out which file is running by ffmpeg ?
(Moreoever, the i haved research and find out that ffmpeg process is not the output but the error, that's why i have used StandardError.ReadToEnd )

Monitor printing of pdf files

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.

C#: get external shell command result line by line

I am writing a C# winform application that starts a second process to execute shell commands like "dir" and "ping". I redirect the second process's output so my app can receive the command result. It roughly works fine.
The only problem is my winform app receives the command line output as a whole instead of line by line. For example, it has to wait for the external "ping" command to finish (which takes many seconds or longer) and then receives the whole output (many lines) at once.
What I want is the app receives the cmdline output in real-time, i.e. by lines not by block. Is this doable?
I am using this code to read the output:
while ((result = proc.StandardOutput.ReadLine()) != null)
But it does not work the way I expected.
Thanks in advance.
EDIT: here is the code I am using:
System.Diagnostics.ProcessStartInfo procStartInfo = new
System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);
procStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
// The following commands are needed to redirect the standard output.
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
// Now we create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
// Get the output into a string
string result;
try {
while ((result = proc.StandardOutput.ReadLine()) != null)
{
AppendRtfText(result+"\n", Brushes.Black);
}
} // here I expect it to update the text box line by line in real time
// but it does not.
Have a look at the example in this msdn article on how to do the reading completly async.
Beyond that I expect your code does to read line by line now but the UI doesn't get any time to repaint (missing Application.DoEvents(); after updating the RTFTextBox
Instead of loop using while ((result = proc.StandardOutput.ReadLine()) != null) you should of using:
...
proc.OutputDataReceived += proc_DataReceived;
proc.Start();
proc.BeginOutputReadLine();
proc.WaitForExit();
This will start asynchronous reading the lines when they arrives, you then handle the lines read by e.Data in proc_DataReceived handler, since you are use BeginOutputReadline the e.Data will be a string lines.
This could be usefull:
http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/8d6cebfc-9b8b-4667-85b5-2b92105cd0b7/
http://www.dotnetperls.com/redirectstandardoutput
I had the same issue and got around it with the following. I found that if I had an error in the external app I was getting no output at all using the ReadToEnd() method, so switched to use the line by line streamreader. Will be switching over to use the answer provided by Saa'd though as that looks like the proper way to handle it.
Also found this solution: c# coding convention public/private contexts which provides for error handling at the same time and giving a fuller explanation to the use of externalApp.OutputDataReceived += (sender, args) => Console.WriteLine(args.Data);
Process externalApp = new Process();
externalApp.StartInfo.FileName = config.ExternalApps + #"\location\DeleteApp.exe";
externalApp.StartInfo.Arguments = Directory.GetCurrentDirectory() + #"\..\..\..\project\argumentsForDeleteApp.xml";
externalApp.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
externalApp.StartInfo.UseShellExecute = false;
externalApp.StartInfo.RedirectStandardOutput = true;
Console.Out.WriteLine(DateTime.UtcNow.ToLocalTime().ToString() +
":###### External app: " + externalApp.StartInfo.FileName + " - START");
externalApp.Start();
using (StreamReader reader = externalApp.StandardOutput)
{
while (!reader.EndOfStream)
{
string result = reader.ReadLine();
Console.Out.WriteLine(result);
}
}
externalApp.WaitForExit();

Categories

Resources