One of the methods i used :
PrintDocument doc = new PrintDocument();
doc.PrinterSettings.PrinterName = "printername";
string[] files = Directory.GetFiles("D:\\Invoice");
foreach (string file in files)
{
string fname = Path.GetFileName(file);
doc.DocumentName = fname;
doc.Print();
Console.WriteLine(file);
}
This gives an exception on the doc.Print() line.
"Settings to access printer 'printername' are not valid."
The other method i used :
Process printJob = new Process();
printJob.StartInfo.FileName = #"C:\Program Files (x86)\Adobe\Reader 10.0\Reader\AcroRD32.exe";
printJob.StartInfo.UseShellExecute = false;
printJob.StartInfo.Verb = "Print";
printJob.StartInfo.CreateNoWindow = true;
printJob.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
printJob.StartInfo.Arguments = "\"" + printerAddress + "\"";
string[] files = Directory.GetFiles("D:\\Invoice");
foreach (string file in files)
{
string fname = Path.GetFileName(file);
printJob.StartInfo.WorkingDirectory = Path.GetDirectoryName(fname);
printJob.Start();
//Console.WriteLine(fname);
}
This gives an error after printJob.Start(). As it is pdf file, it opens the Adobe reader and displays the error message there. Hopw it explains.
"There was an error opening the document. The file could not be found."
Can anyone help me on these issues?
In 2nd snippet, this seems wrong:
string fname = Path.GetFileName(file);
printJob.StartInfo.WorkingDirectory = Path.GetDirectoryName(fname);
printJob.Start();
You just set WorkingDirectory. How does printJob get the actual file name?
In 1st snippet, you are probably not setting everything. Have you checked the MSDN documentation? It's generally a good idea to try to find, then read and try to understand the docs, before asking at SO...
Related
Problem: I am using C# .net platform to SFTP a file to remote host with a key file/.pem file and no password.
C#.net source code:
ProcessStartInfo p = new ProcessStartInfo
{
FileName = "sh",
Arguments = "upload.sh " + file
};
p.RedirectStandardOutput = true;
p.UseShellExecute = false;
p.CreateNoWindow = true;
Process proc1 = new Process();
proc1.StartInfo = p;
proc1.Start();
string result = proc1.StandardOutput.ReadToEnd();
log.InfoFormat(result);
upload.sh:
sftp -i testsftp-key testsftp#sftp.xxx-xxx.com
put filename
here
testsftp-key :.pem filename(key file),
testsftp :username,
sftp.xxx-xxx.com :host address.
filename :file to be uploaded
File is not getting uploaded when exe is executed by rrot user/cronjob. Executing using non-root user like pi uploads the file.
Permissions are 777 for all.
Error:
permission denied
How to solve this permission issue?
I found an answer to this:
ProcessStartInfo p = new ProcessStartInfo
{
FileName = "sh",
Arguments = "/home/pi/../upload.sh " + file
};
p.RedirectStandardOutput = true;
p.RedirectStandardError = true;
p.UseShellExecute = false;
p.CreateNoWindow = false;
Process proc1 = new Process();
proc1.StartInfo = p;
proc1.Start();
string result = "";
using (System.IO.StreamReader output = proc1.StandardOutput)
{
result = output.ReadToEnd();
}
string error = "";
using (System.IO.StreamReader output = proc1.StandardError)
{
error = output.ReadToEnd();
}
log.InfoFormat("SFTP result: {0}", result);
log.InfoFormat("{0}", error);
I am capturing the redirected stdout and stderr using streamreader. Now i can see the script upload.sh being run successfully and uploading the file to the remote server as well.
I took help from here:
How to capture Shell command output in C#?
i'm trying to write some file names in the "fileList.txt".the file has been created but when i try to write in it , it shows me the error above. what should i do?
string strFilePath;
//the current path is : "R:\mft classes\c# fundamental\c#.net apps\employeeinfo\WindowsFormsApplication2\bin\Debug"
strFilePath = Directory.GetCurrentDirectory();
strFilePath = Directory.GetParent(strFilePath).ToString();
strFilePath = Directory.GetParent(strFilePath).ToString();
strFilePath = Directory.GetParent(strFilePath).ToString();
strFilePath = strFilePath + "\\fileList.txt";
File.Create(strFilePath);
foreach (string saveMe in listBox1.Items)
{
File.WriteAllText(strFilePath, saveMe);
}
Use stream writer instead.
string strFilePath;
//the current path is : "R:\mft classes\c# fundamental\c#.net apps\employeeinfo\WindowsFormsApplication2\bin\Debug"
strFilePath = Directory.GetCurrentDirectory();
strFilePath = strFilePath + "\\fileList.txt";
using (StreamWriter sw = new StreamWriter(strFilePath, true))
{
foreach (string saveMe in listBox1.Items)
{
sw.Write(saveMe);
}
}
Problem is exactly what the error says. If you have the file opened in any other program, for example text editor, like Notepad or Word, close it before running your code.
The process cannot access the file because it is being used by another process
private void DeleteReport()
{
int invid = Convert.ToInt32(Session["InvId"]);
string FileName = invid + "_Report" + ".pdf";
string path1 = Server.MapPath("~/Report/" + FileName);
if (File.Exists(path1))
{
File.Delete(path1);
}
}
The error tells you, that the file is used and can't be deleted. So nothing wrong. As you did not formulate a
real question, lets try to help you in following way.
I guess that only your program is using the report, so good possible, you block the report
somewhere else.
E.g., the following code
string path = "C:\\Temp\\test.txt";
FileStream file = File.Open(path, FileMode.OpenOrCreate);
if (File.Exists(path))
File.Delete(path);
raises the same error. It does not necessarily mean that the process is another process.
What you can do is for example, for testing purpose, install SysInternal
http://technet.microsoft.com/en-us/sysinternals/bb896655.aspx and add following code around your
File.Delete statement. Then you will see, what process uses the file:
try
{
File.Delete(path);
}
catch (Exception)
{
using (Process tool = new Process())
{
tool.StartInfo.FileName = #"C:\Program Files (x86)\SysinternalsSuite\handle.exe"; //Your path
tool.StartInfo.Arguments = path + " /accepteula";
tool.StartInfo.UseShellExecute = false;
tool.StartInfo.RedirectStandardOutput = true;
tool.Start();
tool.WaitForExit();
string outputTool = tool.StandardOutput.ReadToEnd();
string matchPattern = #"(?<=\s+pid:\s+)\b(\d+)\b(?=\s+)";
foreach (Match match in Regex.Matches(outputTool, matchPattern))
{
Process p = Process.GetProcessById(int.Parse(match.Value));
MessageBox.Show(p.ProcessName); // OR LOG IT
}
}
throw;
}
Credit for handle.exe call to https://stackoverflow.com/a/1263609/2707156
In the code below, the console prompts the user for 2 files (currently in a networked location). It then copies those files to the local drive for quicker reading of the PDF, but I'm running into a problem. If I reference the last line of code as PdfDocument pdf = new PdfDocument("C:\somepdf.pdf"); the file is accessed extremely quickly.
However, with the current copy processes, for some reason, this line of code alone is taking upwards of 18-20 minutes to process. I'm assuming that this is because the file, having recently been copied, is still locked under a process, even though the actual copy process takes less than 10 seconds.
In my research, I have seen various ways of identifying the process that's locking the file and killing it, but this doesn't seem to apply to what I'm trying to do.
Unfortunately, I'm to the point where I have to ask for help. Am I overlooking something here? I don't see why it would take 15 less minutes to process a pdf referenced locally, than one processed by a copy process, then locally.
Thoughts?
string selectFileNameO;
string selectFileNameF;
string FileNameO;
string FileNameF;
using (OpenFileDialog dialog = new OpenFileDialog())
{
dialog.Title = "Choose File";
dialog.FileName = "";
dialog.ShowDialog();
selectFileNameO = dialog.FileName;
}
string ext = System.IO.Path.GetExtension(selectFileNameO);
selectFileNameF = Path.GetFileName(selectFileNameO);
selectFileNameF = selectFileNameF.Substring(0, selectFileNameF.Length - ext.Length);
selectFileNameF = "C:\\" + selectFileNameF + ".ext";
Console.WriteLine(selectFileNameF);
using (OpenFileDialog dialog2 = new OpenFileDialog())
{
dialog2.Title = "Choose 2 File";
dialog2.FileName = "";
dialog2.ShowDialog();
FileNameO = dialog2.FileName;
}
string ext1 = System.IO.Path.GetExtension(FileNameO);
FileNameF = Path.GetFileName(FileNameO);
FileNameF = FileNameF.Substring(0, FileNameF.Length - ext1.Length);
FileNameF = "C:\\" + FileNameF + ".ext";
File.Copy(FileNameO, FileNameF, true);
int distanceToString = 535;
int lengthOfString = 6;
string myDataSet;
using (StreamReader sr = new StreamReader(selectFileNameF))
{
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
myDataSet = line.Substring(distanceToString, lengthOfString);
selectFileUIDs.Add(myDataSet);
Console.WriteLine(myDataSet);
}
sr.Dispose();
}
Console.WriteLine(FileNameF);
PdfDocument pdf = new PdfDocument(FileNameF);
I know its a known topic in many forums and blogs. I read many articles. And many of them are quiet informative. But for me it seems like it demands new approach to achieve this task.
Am looking for a solution to print a html on server side. But after working with many options i realised that we
cant give printer name or
its printing html raw content like a txt file
Later came to know about ghostscript (https://stackoverflow.com/a/2600189/1238159) can be used to print a PDF on server side silently.
Also tried with crystal report (but how to pass HTML content to it dynamically eventhough it wont support many tags), itextsharp, ssrs, pdfsharp etc etc but none of them were supporting many of the HTMl tags & W3C standards. So i ended at one point to generate PDF. Only wkhtmltopdf is perfect for converting html to pdf. it supports every html tag unlike anyother as of my experience. but printing PDf is the question for me from many years.
But now am facing a problem even with GhostScript (am using ver 9.05). With localhost i can use it perfectly. i can print on server side to what ever printer name coming from UI silently. but with the IP address or machine name its not working. i even implemented Impersonation. Even though the process gets hanged while calling GhostScript.
Now what i want to get clear is
Is it possible to print a html or pdf (actual content) on server side?
Any open source tools are there to achieve this
printer name I would like to pass dynamically
Any clue or workaround might help many hours of people around the globe. :)
Many thanks in advance.
Regards,
Pavan N
After using the suggestion by Lau. am able to do it in command prompt (means cmd.exe runs under my account). but my application will run under network service.
Now am getting a problem just a kind of this ACCESS Denied
Yeah. Finally i was able to start the process. and am able to see my gswin32c.exe process under task manager with my domain credentials. code is as follows:
public bool PrintVSPDF(string ghostScriptPath, int numberOfCopies, string printerName, string pdfFileName)
{
Logger.AddToLog("printerName", printerName);
string impersonationUsername = "";
string impersonationDomain = "";
string impersonationPWD = "";
if (ConfigurationManager.AppSettings["UName"] != null)
{
impersonationUsername = Encryption.Decrypt(ConfigurationManager.AppSettings["UName"].ToString(), Encryption.DEFAULT_KEY, Encryption.DEFAULT_SEED);
impersonationDomain = impersonationUsername.Split('\\').Count() > 1 ? impersonationUsername.Split('\\')[0] : "";
impersonationUsername = impersonationUsername.Split('\\').Count() > 1 ? impersonationUsername.Split('\\')[1] : impersonationUsername.Split('\\')[0];
}
if (ConfigurationManager.AppSettings["PD"] != null)
{
impersonationPWD = Encryption.Decrypt(ConfigurationManager.AppSettings["PD"].ToString(), Encryption.DEFAULT_KEY, Encryption.DEFAULT_SEED);
}
using (Impersonation imp = new Impersonation(impersonationUsername, impersonationDomain, impersonationPWD))
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.Arguments = "-dPrinted -dNoCancel -dNOPAUSE -dBATCH -dNumCopies=" + Convert.ToString(numberOfCopies) + " -sDEVICE=mswinpr2 -sOutputFile=%printer%\"" + printerName + "\" \"" + pdfFileName + "\" ";
startInfo.FileName = ghostScriptPath;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
//startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.UserName = impersonationUsername;
startInfo.Domain = impersonationDomain;
SecureString ss = new SecureString();
for (int i = 0; i < impersonationPWD.Length; i++)
{
ss.AppendChar(impersonationPWD[i]);
}
startInfo.Password = ss;
Process process = null;
try
{
process = Process.Start(startInfo);
//Logger.AddToLog("Error VS", process.StandardError.ReadToEnd());
//Logger.AddToLog("Output VS", process.StandardOutput.ReadToEnd());
//Logger.AddToLog(process.StartInfo.Arguments.ToString(), "VS Print Arguments");
//Console.WriteLine(process.StandardError.ReadToEnd() + process.StandardOutput.ReadToEnd());
//Logger.AddToLog(process.StartInfo.FileName.ToString(), "VS Print file name");
process.WaitForExit(30000);
if (process.HasExited == false)
process.Kill();
int exitcode = process.ExitCode;
process.Close();
return exitcode == 0;
}
catch (Exception ex)
{
Logger.AddToLog(ex);
return false;
}
}
}
But the process is working perfectly in localhost:5030 ie., while running from my visual studio. but with IP address or machine name. it just hangs and throws this error
Same thing is happening for adobe reader, foxit, etc etc.
( Process must exit before requested information can be determined. : at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.get_ExitCode() )
I have been working on a project that is doing just this. It has been a very frustrating experience. The most reliable method I have found is to export my reports to PDF and then use Foxit Reader (NOT Adobe Reader due to security problems) via Diagnostics.Process to print the document.
The printer name can be supplied to the Foxit Reader command line args.
The environment I am working with is ASP.net 3.5 on IIS 7 on Windows Server 2008 R2 x64.
I am also using Sql Server Reporting Services.
Maybe this code will help you out:
public FileContentResult GetPOReport(DataTable reportData, int poNumber, string copies, out string fileName, out string downloadPath)
{
fileName = "PO_" + poNumber.ToString().Trim() + "_" + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".pdf";
downloadPath = "/Generated/" + fileName;
var outputFiles = new Dictionary<string, string>
{
{"", Server.MapPath("~" + downloadPath)}
};
if (!string.IsNullOrWhiteSpace(copies))
{
var copyList = copies.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var temp in copyList)
outputFiles.Add(temp, Server.MapPath("~" + "/Generated/" + temp.Trim() + ".pdf"));
}
FileContentResult returnFile = null;
foreach (var outputFile in outputFiles)
{
var file = WriteReportToDisk(reportData, outputFile.Value, outputFile.Key);
if (file == null)
continue;
if (string.IsNullOrWhiteSpace(outputFile.Key))
returnFile = file;
else
PrintReport(outputFile.Value);
}
return returnFile;
}
public void PrintReport(string filePath)
{
try
{
if (!ConfigurationManager.AppSettings.AllKeys.Contains("AdobeReaderPath") ||
!ConfigurationManager.AppSettings.AllKeys.Contains("AdobePrintParameters") ||
!ConfigurationManager.AppSettings.AllKeys.Contains("PrinterName"))
return;
var adobeReaderPath = ConfigurationManager.AppSettings["AdobeReaderPath"].Trim();
var adobePrintParameters = ConfigurationManager.AppSettings["AdobePrintParameters"].Trim();
var printerName = ConfigurationManager.AppSettings["PrinterName"].Trim();
var printProcessDomain = ConfigurationManager.AppSettings["PrintProcessDomain"].Trim();
var printProcessUserName = ConfigurationManager.AppSettings["PrintProcessUserName"].Trim();
var printProcessPassword = ConfigurationManager.AppSettings["PrintProcessPassword"].Trim();
var userPrinter = Entities.UserPrinters.FirstOrDefault(p => p.UserName == User.Identity.Name);
if (userPrinter != null)
printerName = userPrinter.PrinterName.Trim();
using (var process = new Process
{
StartInfo =
new ProcessStartInfo(
adobeReaderPath,
string.Format(adobePrintParameters, filePath, printerName)
)
})
{
if (!string.IsNullOrWhiteSpace(printProcessUserName))
{
if (!string.IsNullOrWhiteSpace(printProcessDomain))
process.StartInfo.Domain = printProcessDomain;
process.StartInfo.UserName = printProcessUserName;
var securePassword = new SecureString();
foreach (var passwordCharacter in printProcessPassword)
securePassword.AppendChar(passwordCharacter);
process.StartInfo.Password = securePassword;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.LoadUserProfile = true;
}
process.Start();
process.WaitForExit(30000);
}
}
catch (Exception exception)
{
EventLog.WriteEntry("PO Suggestion Viewer", string.Format("PO Suggestion Viewer Error:\n{0}", exception.Message));
throw;
}
}
public FileContentResult WriteReportToDisk(DataTable reportData, string filePath, string copy)
{
var webReport = new WebReport()
{
ExportFileName = "PO Report",
ReportPath = Server.MapPath("~/Reports/PurchaseOrderReport.rdlc")
};
if (!string.IsNullOrWhiteSpace(copy))
webReport.ReportParameters.Add(new ReportParameter("Copy", copy));
if ((User != null) && (User.Identity != null) && (User.Identity.Name != null))
webReport.ReportParameters.Add(new ReportParameter("User", User.Identity.Name));
webReport.ReportDataSources.Add(new ReportDataSource("ReportData", reportData));
var report = webReport.GetReport();
Response.AddHeader("content-disposition", string.Format("attachment; filename={0}.{1}", webReport.ExportFileName, webReport.FileNameExtension));
Response.ContentType = "application/pdf";
var file = File(report, webReport.MimeType, "POReport");
System.IO.File.WriteAllBytes(filePath, file.FileContents);
return file;
}
My web.config contains:
<appSettings>
<add key="webpages:Version" value="1.0.0.0" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="AdobeReaderPath" value="C:\Program Files (x86)\Foxit Software\Foxit Reader\Foxit Re-ader.exe" />
<add key="AdobePrintParameters" value="-t "{0}" "{1}"" />
<add key="PrinterName" value="HP_Office" />
<add key="PrintProcessDomain" value="DOMAIN_NAME" />
<add key="PrintProcessUserName" value="DOMAIN_USER" />
<add key="PrintProcessPassword" value="DOMAIN_PASSWORD" />
</appSettings>
sorry for the late posting. i taught i already answered this Q.
I found a work around to convert html to pdf.
am using WKHTMLTOPDF API to convert the html to pdf. and it looks awesome compared to many commercial products out there. am able to get coloured/greyscale, margins, indexing. and many more.
here is the link i followed
http://code.google.com/p/wkhtmltopdf/
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + #"\bin\wkhtmltopdf.exe";
pdfFile = localReportPath + "\\Reports\\Savedfiles\\" + filename + ".pdf";
//Ref: http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf-0.9.9-doc.html
startInfo.Arguments = " --minimum-font-size 16 --margin-left 10mm --margin-right 10mm --zoom 3 " + htmlFile + " " + pdfFile;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process p = Process.Start(startInfo);
p.WaitForExit();
p.Dispose();
p.Close();
and the same i sent for ghostscript to get an beautiful TIFF file for faxing. performance is good with huge data also.
Regards,
Pavan N