print pdf with selected printer from dropdown - c#

Hi all i am trying to print a pdf file. For this i have created a windows form application. My application print the pdf if i use the default printer of the system. But problem is that when i try to print the PDF file with selected printer from dropdown my code does not works.
private bool SendToPrinter(string filePath, string filename)
{
bool Status = false;
string PrinterName;
string PaperName;
PrinterName = "";
try
{
PrinterName = Convert.ToString(cmbPrinterList.SelectedItem);
// Set the printer.
AddPrinterConnection(PrinterName);
SetDefaultPrinter(PrinterName);
//Print the file with number of copies sent.
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "print";
info.Arguments = "\"" + PrinterName + "\"";
info.FileName = #filePath + #"\" + filename;
info.CreateNoWindow = false;
info.WindowStyle = ProcessWindowStyle.Hidden;
info.UseShellExecute = true;
Process p = new Process();
p.StartInfo = info;
p.Start();
p.WaitForInputIdle();
System.Threading.Thread.Sleep(2);
if (false == p.CloseMainWindow())
p.Kill();
Status = true;
}
catch (Exception ex)
{
}
return Status;
}
//Set the added printer as default printer.
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SetDefaultPrinter(string Name);
//Add the printer connection for specified pName.
[DllImport("winspool.drv")]
public static extern bool AddPrinterConnection(string pName);
public bool viewTabOrder = true;

Try the below code
This is working with different printers for me. Hope it will help you too :)
public void SendToPrinter(string filePath, string Printer)
{
try
{
Process proc = new Process();
proc.Refresh();
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.StartInfo.Verb = "printto";
proc.StartInfo.FileName = ConfigurationManager.AppSettings["ReaderPath"].ToString();
proc.StartInfo.Arguments = String.Format("/t \"{0}\" \"{1}\"", filePath, Printer);
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
if (proc.HasExited == false)
{
proc.WaitForExit(20000);
}
proc.EnableRaisingEvents = true;
proc.Close();
}
catch (Exception e)
{
}
}
Code to bind the Printers into dropdownlist.
cmbPrinter.Items.Insert(0, "--Select Printer--");
for (int i = 0; i < PrinterSettings.InstalledPrinters.Count; i++)
{
var pkInstalledPrinters = PrinterSettings.InstalledPrinters[i];
cmbPrinter.Items.Insert(i + 1, pkInstalledPrinters);
}
And Pass the parameter as below
SendToPrinter(FilePath,cmbPrinter.SelectedItem.ToString());

Related

C# - Print a PDF Error (System.ComponentModel.Win32Exception:...)

I am trying to write an application to print PDFs.
Now I get an error message where I can't get any further after a long search.
The goal would be to print a PDF file without opening the PDF-Reader.
My Code:
using System.Diagnostics;
private void button1_Click(object sender, EventArgs e)
{
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "print";
info.FileName = #"C:\testFile.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();
}
The error condition occurs at p.Start(); line.
Error message:
System.ComponentModel.Win32Exception: "The system cannot find the
specified file".
New experience: 20.01.2021
If I comment out info.Verb = "print";. Then the PDF is opened.
Is this a sign that it finds the PDF but has no access to printer?
use this code it works for me :
public static void PrintToASpecificPirnter()
{
using (PrintDialog printDialog = new PrintDialog())
{
if (printDialog.ShowDialog() == DialogResult.OK)
{
var StartInfo = new ProcessStartInfo();
StartInfo.CreateNoWindow = true;
StartInfo.UseShellExecute = true;
StartInfo.Verb = "printTo";
StartInfo.Arguments = "\"" + printDialog.PrinterSettings.PrinterName + "\"";
StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
StartInfo.FileName = fileName;
Process.Start(StartInfo);
}
}
}

How to print only 1 copy of document when using "Process" in c#

I am trying to print a pdf in a c# console application, by starting a process.
Instead of printing only 1 copy of the document it prints multiple copies (3, 4, 5 or 6 unpredictable). This is my code...
var p = new Process
{
StartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
Verb = "PrintTo",
Arguments = printerName,
FileName = filePath
}
};
p.Start();
Please can you tell me what I'm doing wrong?
You can do that with this code.
private void SendToPrinter(string prepDok)
{
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "print";
info.FileName = prepDok;
info.CreateNoWindow = false;
info.WindowStyle = ProcessWindowStyle.Hidden;
System.Windows.Forms.PrintDialog pd = new System.Windows.Forms.PrintDialog();
pd.PrinterSettings.Copies = 1;
Process p = new Process();
p.StartInfo = info;
p.StartInfo.Arguments = pd.PrinterSettings.PrinterName;
p.Start();
p.CloseMainWindow();
Thread.Sleep(4000);
if (!p.WaitForExit(5000))
{
if (!p.HasExited)
{
p.Kill();
}
}
}
This will set the number of copies to one and print dialog won't be shown.

Netsh Commands Cannot Display Correct the result in TextBox

class TcpIpCommands
{
public string Check()
{
Process p = new Process();
p.StartInfo.FileName = #"C:\Windows\syswow64\netsh.exe";
p.StartInfo.Arguments = "int tcp show global";
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.StandardOutputEncoding = Encoding.GetEncoding(737);
p.Start();
p.WaitForExit();
return p.StandardOutput.ReadToEnd();
}
public string Command(string FileName, string Arguments)
{
ProcessStartInfo p = new ProcessStartInfo();
p.FileName = FileName;
p.Arguments = Arguments;
p.UseShellExecute = false;
p.CreateNoWindow = true;
p.RedirectStandardOutput = true;
p.StandardOutputEncoding = Encoding.GetEncoding(737);
using (Process process = Process.Start(p))
{
using (StreamReader reader = process.StandardOutput)
{
string result = reader.ReadToEnd();
return result;
}
}
}
public string Reseting()
{
Process p = new Process();
p.StartInfo.FileName = #"C:\Windows\syswow64\netsh.exe";
p.StartInfo.Arguments = #"interface tcp reset";
p.StartInfo.Verb = "runas";
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.StandardOutputEncoding = Encoding.GetEncoding(737);
p.Start();
p.WaitForExit();
return p.StandardOutput.ReadToEnd();
}
}
I have an problem with Command Method and Reseting Method. If i try to execute them I receive in RichTextBox the message
set global command failed on ipv4 the parameter is incorrect
But If i run netsh interface tcp show global or hit the Check Method they info me that the status are change.
here are the buttons
private void BtnCheck_Click(object sender, EventArgs e)
{
TcpIpCommands tic = new TcpIpCommands();
richTextBox1.Text = tic.Check();
}
private void btnChimney_Click(object sender, EventArgs e)
{
TcpIpCommands tic = new TcpIpCommands();
richTextBox1.Text = tic.Command(#"C:\Windows\system32\netsh.exe", "interface tcp set global chimney=enabled");
}
private void BtnReset_Click(object sender, EventArgs e)
{
TcpIpCommands tic = new TcpIpCommands();
richTextBox1.Text = tic.Reseting();
}
I cant understand why RichTextBox shows that message but the process execute succefully.
A note. I have try to run the commands with
StartInfo.Verb = "runas";
and both from
C:\Windows\System32\netsh.exe
and
C:\Windows\syswow64\netsh.exe
and i get the same error "set global command failed on ipv4 the parameter is incorrect" but the code execute and the parameter change.

Xcopy in C# - how to call it?

Here I should copy file from nearby local ip address to my local system i have used the following code for copying using the Xcopy command and then launching the process but copying through Argumentsetting in code mentioned if I execute in command prompt it is copying but through code is not copying please tell what is the issue. Any ideas? what through code not copying.
string Porocess = String.Format("\"{0}\\xcopy.exe\"", Environment.SystemDirectory.ToString());
string SolutionSettings = string.Format("\"\\\\{0}\\C$\\Documents and Settings\\All Users\\Application Data\\Symantec\\Common Client\\settings.bak\"", IPaddress);
string TargetSettings = string.Format("\"C:\\Documents and Settings\\All Users\\Application Data\\Symantec\\settings.bak\"");
string Argumentsetting = /*"\"" +*/ SolutionSettings + " " + TargetSettings + " /Y";// parameters to launch process
int iret1 = LauncProcess(Porocess, Argumentsetting, Environment.SystemDirectory.ToString());
public static int LauncProcess(string sProcess, string sParams, string sWorkingDir)
{
int iRet = 0;
Process process = null;
try
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = sProcess;
startInfo.Arguments = sParams;
startInfo.WorkingDirectory = sWorkingDir;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
process = Process.Start(startInfo);
process.WaitForExit();
Console.WriteLine("Copy has finished.");
if (process.HasExited)
{
Console.WriteLine("Process has exited.");
if (process.ExitCode != 0)
{
iRet = 1;
}
else
{
iRet = 0;
}
}
else
{
iRet = 1;
}
}
catch (Exception ex)
{
iRet = 1;
}
finally
{
process.Dispose();
}
return iRet;
}
check whether source address and destination address are correctly given
Process process = new Process();
process.StartInfo.Arguments= #"D:\sourcePath F:\DestinationPath /e /y /I";
process.Start();

Execute multiple command lines with the same process using .NET

I'm trying to execute multiple commands without create a new process each time. Basically, I want to start the DOS command shell, switch to the MySQL command shell, and execute a command. Here's how I am calling the procedure (also below). Also, how do I handle the "\"'s in the command?
ExecuteCommand("mysql --user=root --password=sa casemanager", 100, false);
ExecuteCommand(#"\. " + Environment.CurrentDirectory + #"\MySQL\CaseManager.sql", 100, true);
private void ExecuteCommand(string Command, int Timeout, Boolean closeProcess)
{
ProcessStartInfo ProcessInfo;
Process Process;
ProcessInfo = new ProcessStartInfo("cmd.exe", "/C " + Command);
ProcessInfo.CreateNoWindow = false;
ProcessInfo.UseShellExecute = false;
Process = Process.Start(ProcessInfo);
Process.WaitForExit(Timeout);
if (closeProcess == true) { Process.Close(); }
}
You can redirect standard input and use a StreamWriter to write to it:
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.RedirectStandardInput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
using (StreamWriter sw = p.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
sw.WriteLine("mysql -u root -p");
sw.WriteLine("mypassword");
sw.WriteLine("use mydb;");
}
}
const string strCmdText = "/C command1&command2";
Process.Start("CMD.exe", strCmdText);
Couldn't you just write all the commands into a .cmd file in the temp folder and then execute that file?
As another answer alludes to under newer versions of Windows it seems to be necessary to read the standard output and/or standard error streams otherwise it will stall between commands. A neater way to do that instead of using delays is to use an async callback to consume output from the stream:
static void RunCommands(List<string> cmds, string workingDirectory = "")
{
var process = new Process();
var psi = new ProcessStartInfo();
psi.FileName = "cmd.exe";
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.UseShellExecute = false;
psi.WorkingDirectory = workingDirectory;
process.StartInfo = psi;
process.Start();
process.OutputDataReceived += (sender, e) => { Console.WriteLine(e.Data); };
process.ErrorDataReceived += (sender, e) => { Console.WriteLine(e.Data); };
process.BeginOutputReadLine();
process.BeginErrorReadLine();
using (StreamWriter sw = process.StandardInput)
{
foreach (var cmd in cmds)
{
sw.WriteLine (cmd);
}
}
process.WaitForExit();
}
I prefer to do it by using a BAT file.
With BAT file you have more control and can do whatever you want.
string batFileName = path + #"\" + Guid.NewGuid() + ".bat";
using (StreamWriter batFile = new StreamWriter(batFileName))
{
batFile.WriteLine($"YOUR COMMAND");
batFile.WriteLine($"YOUR COMMAND");
batFile.WriteLine($"YOUR COMMAND");
}
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe", "/c " + batFileName);
processStartInfo.UseShellExecute = true;
processStartInfo.CreateNoWindow = true;
processStartInfo.WindowStyle = ProcessWindowStyle.Normal;
Process p = new Process();
p.StartInfo = processStartInfo;
p.Start();
p.WaitForExit();
File.Delete(batFileName);
ProcessStartInfo pStartInfo = new ProcessStartInfo();
pStartInfo.FileName = "CMD";
pStartInfo.Arguments = #"/C mysql --user=root --password=sa casemanager && \. " + Environment.CurrentDirectory + #"\MySQL\CaseManager.sql"
pStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(pStartInfo);
The && is the way to tell the command shell that there is another command to execute.
A command-line process such cmd.exe or mysql.exe will usually read (and execute) whatever you (the user) type in (at the keyboard).
To mimic that, I think you want to use the RedirectStandardInput property: http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardinput.aspx
You could also tell MySQL to execute the commands in the given file, like so:
mysql --user=root --password=sa casemanager < CaseManager.sql
You need to READ ALL data from input, before send another command!
And you can't ask to READ if no data is avaliable... little bit suck isn't?
My solutions... when ask to read... ask to read a big buffer... like 1 MEGA...
And you will need wait a min 100 milliseconds... sample code...
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim oProcess As New Process()
Dim oStartInfo As New ProcessStartInfo("cmd.exe", "")
oStartInfo.UseShellExecute = False
oStartInfo.RedirectStandardOutput = True
oStartInfo.RedirectStandardInput = True
oStartInfo.CreateNoWindow = True
oProcess.StartInfo = oStartInfo
oProcess.Start()
Dim Response As String = String.Empty
Dim BuffSize As Integer = 1024 * 1024
Dim x As Char() = New Char(BuffSize - 1) {}
Dim bytesRead As Integer = 0
oProcess.StandardInput.WriteLine("dir")
Threading.Thread.Sleep(100)
bytesRead = oProcess.StandardOutput.Read(x, 0, BuffSize)
Response = String.Concat(Response, String.Join("", x).Substring(0, bytesRead))
MsgBox(Response)
Response = String.Empty
oProcess.StandardInput.WriteLine("dir c:\")
Threading.Thread.Sleep(100)
bytesRead = 0
bytesRead = oProcess.StandardOutput.Read(x, 0, BuffSize)
Response = String.Concat(Response, String.Join("", x).Substring(0, bytesRead))
MsgBox(Response)
End Sub
End Class
I'm using these methods:
public static Process StartCommand(params string[] commands) => StartCommand(commands, false);
public static Process StartCommand(IEnumerable<string> commands, bool inBackground, bool runAsAdministrator = true)
{
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
if(commands.Any()) p.StartInfo.Arguments = #"/C " + string.Join("&&", commands);
if (runAsAdministrator)
p.StartInfo.Verb = "runas";
if (inBackground)
{
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
}
p.Start();
return p;
}
Enjoy...

Categories