I need to print a pdf-file with ProcessStartInfo.
string docInvoicePath = #"[Path]";
string printername = "\"PRN-OFFICE\"";
string driver = "\"Xerox Global Print Driver PS\"";
string port = "\"[IP]\"";
ProcessStartInfo psInfo = new ProcessStartInfo
{
FileName = #"""C:\Program Files (x86)\Adobe\Reader 9.0\Reader\AcroRd32""",
Arguments = String.Format("/s /o /h /t " + docInvoicePath + " " + printername + " " + driver + " " + port),
Verb = "print",
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
UseShellExecute = false
};
Process process = Process.Start(psInfo);
process.WaitForExit(6000);
if (process.HasExited == false)
{
process.Kill();
}
process.Close();
The filename and arguments are correct they work when pasted in cmd.
The code works properly but after Process.Start when it comes to WaitForExit the programm doesn`t finish. I get the timeout error:
System.Threading.ThreadAbortException: Thread was being aborted.
at System.Threading.WaitHandle.WaitOneNative(SafeHandle waitableSafeHandle, UInt32 millisecondsTimeout, Boolean
hasThreadAffinity, Boolean exitContext)
at System.Threading.WaitHandle.InternalWaitOne(SafeHandle waitableSafeHandle, Int64 millisecondsTimeout, Boolean
hasThreadAffinity, Boolean exitContext)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)...
I searched and try a few things like setting <httpRuntime executionTimeout="300"/> and run into a 500 or like in the code with process.WaitForExit(6000); and higher ther where no exeption but nothing got printed.
Is there an error or am i missing something?
EDIT:
I changed my codeblock above. Now the code works in debug mode but it still won´t print my document when published. I also tried to use a different User.
In debug mode the code prints the document but runs in the kill query.
The ProcessStartInfo.Verbs returns a Argument Exception but i don´t know why.
After a lot of trying, testing and searching i am sure my code works.
So i still don´t really know why my code stoped working.
But changing from Adobe Reader 9.0 on the server to 7.0 it now works.
When i was debuging locally with Adobe Reader 9.0 it also worked, so i think maybe there was an update on the webserver. I diden`t verifyed that yet.
Related
Plan
The plan is to disable and subsequently enable a device from inside a windows forms application. To test the first building block of my plan, I open cmd with admin privileges and the following works perfectly:
> devcon hwids =ports
> devcon hwids *VID_10C4*
> devcon disable *VID_10C4*
> devcon enable *VID_10C4*
I can see the device being disabled and enabled again in device manager.
I can also achieve all of this by putting the commands into a batch file and running it from cmd with admin privileges. The above tells me that my plan is essentially good.
Application
However, what I actually want to do is achieve the same thing from inside a windows forms application:
I've set the following in the app manifest:
requestedExecutionLevel level="requireAdministrator" uiAccess="false"
For the sake of baby steps, I have checked this, just to ensure that there are no stupid mistakes in paths and whatnot. And it works just fine. The log file shows me the expected output from the dir command.
// Build String
string strCmdText =
"'/c cd " + prodPath +
" && dir " +
" > logs\\logFileEnablePrt.txt \"'";
// Run command
var p = new System.Diagnostics.Process();
var psi = new ProcessStartInfo("CMD.exe", strCmdText);
psi.Verb = "runas"; // admin rights
p.StartInfo = psi;
p.Start();
p.WaitForExit();
However, this does not work. It always returns an empty log file and does not change the device as expected:
// Build String
string strCmdText =
"'/c cd " + prodPath +
" && devcon hwids =ports " +
" > logs\\logFileEnablePrt.txt \"'";
// Run command
var p = new System.Diagnostics.Process();
var psi = new ProcessStartInfo("CMD.exe", strCmdText);
psi.Verb = "runas"; // admin rights
p.StartInfo = psi;
p.Start();
p.WaitForExit();
Error from cmd window is :
'devcon' is not recognized as an internal or external command,
operable program or batch file.
What's going on?
The above has me stumped. I've proved the commands work. I've proved my C# code works. But when I join the 2 together, it doesn't work...
NB: My C# program is running on my D: drive, if that makes any difference...
Updates Based on Comments
#Compo
Using your code, it does exactly the same as with mine. I see an empty log file & no changes made to the device. I've altered the /c to /k so I can see what going on the cmd terminal and I see this:
I've even tried your code C:\\Windows\\System32\\devcon hwids =usb pointing directly at devcon. Also tried \devcon.exe for completeness. The inexplicable error is :
I can see the flipping devcon.exe file sitting right there in the folder! Is there any reason it would not recognise it?
Also, with the command as you wrote it, the log file name is actually named logFileEnablePrt.txt'. I agree that your command looks right, so don't ask me why this happens!
#Panagiotis Kanavos
using your code, I get the following error:
This is at the line p.Start();. I tried putting in devcon.exe, and even the whole path (I checked the folder was in my PATH, and it is). Can't get past this. I actually stumbled on that answer you shared and arrived at this brick wall already.
Here is the code works for me, I don't have ports devices so I change it to usb.
public static void Main()
{
string prodPath = #"c:\devcon\x64";
// Build String
string strCmdText =
"/c \"cd /d " + prodPath +
" && devcon hwids =usb " +
" > log.txt \"";
// Run command
var p = new Process();
var psi = new ProcessStartInfo("CMD.exe", strCmdText);
psi.Verb = "runas"; // admin rights
p.StartInfo = psi;
p.Start();
p.WaitForExit();
}
Worked through a few steps and think I may have an answer...
Just specifying devcon fails as expected...windows cant find the exe as the folder it is in is not in the %PATH% variable in windows..
IF I specify the full path however it works...
It wasnt clear from your original code but if your copy of devcon is sitting in either System32 or Syswow directories you may be hitting an emulation issue as well...see here....
EDIT1:: A way to prove this would be to do Direcory.GetFiles(directory containing devcon) and see if the results line up with what you expect
As for passing arguments through to devcon I'd try something like this as opposed to trying to concatenate one giant cmd line..
A similar example but with netstat:
EDIT 2::Another example but with devcon:
The target platform here for the build was x64
EDIT3::
With my application build set to x86:
After working through the answers and comments above, I seem to have something that reliably works, which obviously I'd like to share back for scrutiny and future use.
So, my function ended up looking like this:
private int enablePort(string action)
{
while (true)
{
// Command Arg
string devconPath = #"c:\Windows\SysNative";
string strCmdText =
"'/c \"cd /d \"" +
devconPath +
"\" && c:\\Windows\\SysNative\\devcon " + action + " *VID_10C4* " +
"> \"" + prodPath + "\\logs\\logFileEnablePrt.txt\"\"";
// Process
var p = new Process();
var psi = new ProcessStartInfo()
{
Arguments = strCmdText,
Verb = "runas",
FileName = "CMD.exe",
UseShellExecute = true
};
p.StartInfo = psi;
p.Start();
p.WaitForExit();
// Grab log output
string logPath = prodPath + "\\logs\\logFileEnablePrt.txt";
Console.WriteLine("logPath = " + logPath);
string tempFile = System.IO.File.ReadAllText(logPath);
System.Console.WriteLine("Contents of WriteText.txt = \n{0}", tempFile);
// Check if it worked
var success = false;
if (tempFile.Contains(action))
{
success = true;
return 0;
}
// Error -> Allow user to try again!
if (MessageBox.Show("Was unable to " + action + " Test Jig COM port. Unlug & Replug USB. Check COM port is enabled if not working.", "COM Port Problem", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
{
return -1;
}
}
}
And the calling code was:
this.enablePort("disable");
int milliseconds = 3000;
await Task.Delay(milliseconds);
this.enablePort("enable");
As you can see in the code above, I've logged everything to see what was going on... Stepping through with the debugger, I can now see after the disable:
USB\VID_10C4&PID_EA60\0001 : Disabled
1 device(s) disabled.
And then after the enable:
USB\VID_10C4&PID_EA60\0001 : Enabled
1 device(s) are enabled.
The one extra thing I need to stress is that during testing, I thought I could hook a serial peripheral onto the port and determine whether it could disable and enable successfully by checking the connection. THIS DOES NOT WORK. The above code only works when the port is idle. Perhaps someone who understands the underlying software could hazard an explanation of why this is.
I am executing .exe file in C# using the code below.
If I want to run executable in a silent mode I usually uncomment UseShellExecute and RedirectStandardOutput properties, but this gives me an error:
Unhandled Exception: System.ComponentModel.Win32Exception: The system cannot find the file specified
If I keep a code like this it runs, but the additional command line screen is popping up and closing.
I am running Poisson Surface Reconstruction .exe and wondering if the silent mode is possible or not? Or it must be implemented by author who did this executable?
var proc = new System.Diagnostics.Process {
StartInfo = new System.Diagnostics.ProcessStartInfo {
FileName = "PoissonRecon",
Arguments = "--in " + fileNameIn + " --out " + fileName + " --depth "+depth.ToString()+" --pointWeight 0 --colors",
//UseShellExecute = false,
//RedirectStandardOutput = true,
CreateNoWindow = true,
WorkingDirectory = filePath
}
};
proc.Start();
proc.WaitForExit();
Try adding to arguments line this:
"--mode unattended"
if I'm not mistaken it should make installation silent
How to print pdf document from code on Windows 8-10 ?
I get next exception: Additional information: The specified executable is not a valid application for this OS platform.
when I make proc.Start(). It's becuase I try to call not exe, but pdf file.
This approach was working on Windows 7. On newer versions it doesn't work.
private void SendToPrinter()
{
var proc = new Process
{
string fileName = "c:\output.pdf"
StartInfo = new ProcessStartInfo
{
Verb = "printto",
FileName = fileName,
Arguments = "\"" + printerName + "\"",
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
RedirectStandardOutput = true,
UseShellExecute = false
}
};
proc.Start();
proc.WaitForInputIdle();
Thread.Sleep(3000);
if (!proc.HasExited && !proc.CloseMainWindow())
{
proc.Kill();
}
}
I tried to do it from console, typeing like :
"c:\output.pdf" printto "PDFCreator"
or like this:
"c:\output.pdf" -verb printto "PDFCreator"
printto verb is not working at all, just opens Foxit Reader,
and print verb says "is currently been printed" if I type like this
print "c:\output.pdf" "PDFCreator"
but nothing heppens
I tried not only with printing to file, but with normal printer too. JPG prints from code very well, but not pdf.
I've been trying to make a program to automate the process of running different processes on my computer. So far I've got the following program running a console version of BleachBit(It's like CCleaner), the process appears in task manager, it hits around 25kb process RAM then CPU usage goes to 0% and just sits there doing nothing for ages and never quits.
Is there something wrong I'm doing in my code that could cause this to happen?
I've tried editing the app.manifest to make sure the program has to be run as admin in case it needed more privileges
Also when running similar code in a bat file to run the program, it's opens its own windows and runs fine, so I'm not sure. Any help in the right direction would be fantastic.
The code I'm running is below.
static void Main(string[] args)
{
string Log = "";
if (File.Exists(Environment.CurrentDirectory + "\\BleachBit\\bleachbit_console.exe"))
{
Log += "File exists";
Log += RunProgramCapturingOutput("\\BleachBit\\bleachbit_console.exe", "--preset --clean");
}
else
Log += "Program not found. Please place at \\BleachBit\\bleachbit_console.exe";
File.WriteAllText("log.txt", Log);
Console.ReadLine();
}
public static string RunProgramCapturingOutput(string filename, string arguments)
{
ProcessStartInfo processInfo = new ProcessStartInfo()
{
FileName = Environment.CurrentDirectory + filename,
Arguments = arguments,
CreateNoWindow = false,
UseShellExecute = false,
WorkingDirectory = Path.GetDirectoryName(Environment.CurrentDirectory + filename),
RedirectStandardError = false,
RedirectStandardOutput = true
};
Process process = Process.Start(processInfo);
process.WaitForExit();
string output = output = process.StandardOutput.ReadToEnd();
Console.WriteLine("Output: " + output);
process.Close();
return output;
}
Switching these lines to this:
string output = output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
allows to avoid deadlocks. The program seems to be a relatively slow running program due to hard-drive I/O, just give it time and you'll see it complete.
I found this deadlock issue from https://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput(v=vs.110).aspx
Where it states in a code block: "// To avoid deadlocks, always read the output stream first and then wait."
I am trying to use the GFIX tool that gets shipped with Firebird Database inside my C#/WPF Application to execute certain commands on the database.
Firebird http://www.firebirdsql.org/en/firebird-2-5-3-upd1/
Gfix http://www.firebirdsql.org/manual/gfix.html
To do this I use the following code:
public string RunExternalExe(string filename, string arguments = null)
{
var process = new Process();
process.StartInfo.FileName = filename;
if (!string.IsNullOrEmpty(arguments))
{
process.StartInfo.Arguments = arguments;
}
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
var stdOutput = new StringBuilder();
process.OutputDataReceived += (sender, args) => stdOutput.Append(args.Data);
string stdError = null;
try
{
process.Start();
process.BeginOutputReadLine();
stdError = process.StandardError.ReadToEnd();
process.WaitForExit();
}
catch (Exception e)
{
throw new Exception("OS error while executing " + Format(filename, arguments) + ": " + e.Message, e);
}
if (process.ExitCode == 0)
{
return stdOutput.ToString();
}
else
{
var message = new StringBuilder();
if (!string.IsNullOrEmpty(stdError))
{
message.AppendLine(stdError);
}
if (stdOutput.Length != 0)
{
message.AppendLine("Std output:");
message.AppendLine(stdOutput.ToString());
}
throw new Exception(Format(filename, arguments) + " finished with exit code = " + process.ExitCode + ": " + message);
}
}
private string Format(string filename, string arguments)
{
return "'" + filename +
((string.IsNullOrEmpty(arguments)) ? string.Empty : " " + arguments) +
"'";
}
Found there
How To: Execute command line in C#, get STD OUT results
also I tried every other approach that gets explained in that question, but it still doesn't get me any output.
I try to execute the following command
gfix.exe -user foo -pa foo -shut single -force 0 app1:\bar.fdb
What I see if I execute it in CMD is the following output
"Your user name and password are not defined. Ask your database administrator to set up a Firebird login."
That's an obvious error because user foo with password foo doesn't exist.
So my problem isn't the error itself, its just the fact that I do NOT get this output inside my C# application not matter what I tried so far.
Since I am seeing the error output in my CMD screen it should get output in my C# application or is there any possibility that the tool itself is blocking the output and I don't have a chance to get it?
What I tried so far:
Calling the gfix.exe itself with the arguments.
Calling a bat that contains the call to gfix.exe with its arguments.
Calling CMD with /c or /k that calls the gfix.exe with arguments.
Calling CMD with /c or /k that calls a bat that calls the gfix.exe.
I believe I tried all possible combinations of calling this tool but still I don't get an output.
Also I have tried both RedirectStandardError and RedirectStandardOutput, with async/sync approaches (Begin.. and ReadToEnd), also I tried to input the arguments with the help of RedirectStandardInput and wrote the lines exactly as I would type it with CMD, first a cd "C:\Test" and than the call to gfix.exe all in vain...
Further info the tool works fine if I input everything correctly its runs through and does exactly what it should do, but I would also like to catch when the tool fails and want to output the corresponding error.
Edit:
Notice that I tried the following now, without my C# app involved only doubleclick the bat or executing it in CMD.
I have modified my test bat file to this:
gfix.exe -user foo -pa foo -shut single -force 0 app1:/bar.fdb > Test.txt 2> error.txt
Which creates 2 Text files - both empty.
If I run this .bat in CMD no error is displayed, if I remove the 2> error.txt the error message again gets displayed in the CMD screen. So the redirect seems to "work" only that my txt files are empty... could the gfix tool block this?!?
This works for me:
using (var process = Process.Start(
new ProcessStartInfo
{
FileName = fileName,
Arguments = args,
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
RedirectStandardError = true,
UseShellExecute = false,
}))
{
process.WaitForExit();
if (process.ExitCode != 0)
{
var errorMessage = process.StandardError.ReadToEnd();
Assert.Fail(errorMessage);
}
}
Note the RedirectStandardError = true.
When error happens gfix outputs it not to stdout, but to stderr. This is obvious and std behavior.