process can not open pdf file c# - c#

In a Windows application I need to run another one application that's tetpdflib. That tetpdflib runs in command prompt only. When I drag and drop exe to the command prompt it will execute. Here is my code:
Process tetmlProcess = new Process();
tetmlProcess.StartInfo.CreateNoWindow = true;
tetmlProcess.StartInfo.UseShellExecute = false;
tetmlProcess.StartInfo.RedirectStandardError = true;
tetmlProcess.StartInfo.RedirectStandardInput = true;
tetmlProcess.StartInfo.WorkingDirectory = #"C:\Users\sw_chn\Documents\PDFlib\TET 5.0 32-bit\bin";
tetmlProcess.StartInfo.FileName = #"C:\Users\sw_chn\Documents\PDFlib\TET 5.0 32-bit\bin\tet.exe";
string args1 = #"tet -m wordplus D:\DailyWork\March\JOURNAL-ISSUE_6_3924-3930.pdf";
tetmlProcess.StartInfo.Arguments = args1;
tetmlProcess.Start();
StreamReader news = tetmlProcess.StandardError;
string err = news.ReadToEnd();
Console.WriteLine(err);
Console.ReadLine();
I had following error:
could not open PDF file 'tet' for reading
How to recover from this?

Your Start Arguments contains the Program Name again which leads to this error.
Simply change your code
Process tetmlProcess = new Process();
// ...
tetmlProcess.StartInfo.WorkingDirectory = #"C:\Users\sw_chn\Documents\PDFlib\TET 5.0 32-bit\bin";
tetmlProcess.StartInfo.FileName = #"C:\Users\sw_chn\Documents\PDFlib\TET 5.0 32-bit\bin\tet.exe";
// removing "tet" in Arguments
string args1 = #"-m wordplus D:\DailyWork\March\JOURNAL-ISSUE_6_3924-3930.pdf";
tetmlProcess.StartInfo.Arguments = args1;
tetmlProcess.Start();
// ...
Conclusion
The manual contains example like this
tet --format utf16 --outfile file.utf16 file.pdf
Here is tet mapped as environment variable in the system and stands for the full path of the application.

Related

Execute DTExec file via Command Line

I've got a dotnet core 6 project where I need to execute SSIS packages via dtexec.
So far I have the following code:
private void ExecutePackage()
{
var processOutput = string.Empty;
var processErrorOutput = string.Empty;
var command = #"/C dtexec /file ""C:\git\star\tests\Star.Shared.UnitTests\test-artifacts\TestPackage.dtsx""";
var process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = command;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
processOutput = process.StandardOutput.ReadToEndAsync().Result;
processErrorOutput = process.StandardError.ReadToEndAsync().Result;
if (processOutput != string.Empty)
{
_logger.LogInformation("{output}", processOutput);
}
if (processErrorOutput != string.Empty)
_logger.LogError("{errors}", processErrorOutput);
}
When running this via my unit test, it just seems to hang and I'm unsure as to why.
On one of my previous attempts to get this file to run I got the following message:
An error occurred trying to start process 'dtexec /file "C:\git\star\tests\Star.Shared.UnitTests\test-artifacts\Test_Package.dtsx' with working directory 'C:\git\star\tests\Star.Shared.UnitTests\bin\Debug\net6.0'. The system cannot find the file specified.
Which is telling me that the last time I ran this, it was looking in my tests bin folder for the package instead of where the package is stored.
Is there a setting that I'm missing / set wrong?

Get folder path from local machine to execute process of other application on button click of windows application

How to give specific folder path to start process using C#.Net code?
I have written following code to start the my another application exe(i.e. "ConsoleApplication1.exe") which is stored at (D:) drive of PC.
for (int i = 0; i < chkListBox.CheckedItems.Count; i++)
{
if ((string)chkListBox.Items[i] == "ConsoleApplication1")
{
string path = #"D:\TAS\Development\Latest\ConsoleApplication1\ConsoleApplication1\bin\Debug";
string files = Directory.GetDirectoryRoot(path);
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = path+chkListBox.Items[i].ToString()+".exe"
}
};
process.Start();
}
}
When Clicked on Button then I got following exception:
Exception:
There are quite a few potential problems with the code you posted. It's hard to know what your current problem is without seeing the exception, but I think this is the most likely issue:
On the line FileName = path+chkListBox.Items[i].ToString()+".exe", you appear to be missing a path separator.
Use Path.Combine instead of manual string concatenation to combine paths. By using Path.Combine, you eliminate a whole category of mistakes that can be made when combining two strings to make a new path.
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = Path.Combine(path, chkListBox.Items[i].ToString()+".exe");
}
};

How to redirect command prompt output to a file using asp.net C#?

I have tried to redirect the command prompt output to a file using Asp.Net C#.
System.Diagnostics.Process si = new System.Diagnostics.Process();
si.StartInfo.WorkingDirectory = "c:\\";
si.StartInfo.UseShellExecute = false;
si.StartInfo.FileName = "cmd.exe";
si.StartInfo.Arguments = #"/c dir" +">" + #"Myval.txt";
si.StartInfo.CreateNoWindow = true;
si.StartInfo.RedirectStandardInput = true;
si.StartInfo.RedirectStandardOutput = true;
si.StartInfo.RedirectStandardError = true;
si.Start();
string output = si.StandardOutput.ReadToEnd();
Response.Write(output);
si.Close();
The file is getting created successfully but no content present in it.
Even the variable Output returns nothing.
Help me to resolve this issue.
EDIT after being corrected:
I just tested on my machine and the code works perfectly. I apologize for not reading and testing carefully myself. Myval.txt is created and the DIR output is written into it.
The output variable is empty because you are rerouting any output by the DIR command into the txt file, so that's by design.
Please see if there are any locks on the txt file preventing it from being overwritten. Further than that, I can only guess that there is a security issue preventing the DIR command from running.
IIS7 - I tested this various ways including using a Batch file but the application isn't available on desktop. I can see the worker process and the exe running under my user name but with session id value of zero.
The following has worked for me through command prompt:
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "YOURBATCHFILE.bat";
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
// p.WaitForExit();
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();

Execute multiple commands in same environment from C#

I'm developing a small C# GUI tool which is supposed to fetch some C++ code and compile it after going through some wizard. This works all nice if I run it from a command prompt after running the famous vcvarsall.bat. Now I would like the user not to go to a command prompt first but have the program call vcvars followed by nmake and other tools I need. For that to work the environment variables set by vcvars should obviously be kept.
How can I do that?
The best solution I could find yet was to create a temporary cmd/bat script which will call the other tools, but I wonder if there is a better way.
Update: I meanwhile experimented with batch files and cmd. When using batch files vcvars will terminate the complete batch execution so my second command (i.e. nmake) won't be executed. My current workaround is like this (shortened):
string command = "nmake";
string args = "";
string vcvars = "...vcvarsall.bat";
ProcessStartInfo info = new ProcessStartInfo();
info.WorkingDirectory = workingdir;
info.FileName = "cmd";
info.Arguments = "/c \"" + vcvars + " x86 && " + command + " " + args + "\"";
info.CreateNoWindow = true;
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
Process p = Process.Start(info);
This works, but the output from the cmd call is not captured. Still looking for something better
I have a couple of different suggestions
You may want to research using MSBuild instead of NMake
It's more complex, but it can be controlled directly from .Net, and it is the format of VS project files for all projects starting with VS 2010, and for C#/VB/etc. projects earlier than that
You could capture the environment using a small helper program and inject it into your processes
This is probably a bit overkill, but it would work. vsvarsall.bat doesn't do anything more magical than set a few environment variables, so all you have to do is record the result of running it, and then replay that into the environment of processes you create.
The helper program (envcapture.exe) is trivial. It just lists all the variables in its environment and prints them to standard output. This is the entire program code; stick it in Main():
XElement documentElement = new XElement("Environment");
foreach (DictionaryEntry envVariable in Environment.GetEnvironmentVariables())
{
documentElement.Add(new XElement(
"Variable",
new XAttribute("Name", envVariable.Key),
envVariable.Value
));
}
Console.WriteLine(documentElement);
You might be able to get away with just calling set instead of this program and parsing that output, but that would likely break if any environment variables contained newlines.
In your main program:
First, the environment initialized by vcvarsall.bat must be captured. To do that, we'll use a command line that looks like cmd.exe /s /c " "...\vcvarsall.bat" x86 && "...\envcapture.exe" ". vcvarsall.bat modifies the environment, and then envcapture.exe prints it out. Then, the main program captures that output and parses it into a dictionary. (note: vsVersion here would be something like 90 or 100 or 110)
private static Dictionary<string, string> CaptureBuildEnvironment(
int vsVersion,
string architectureName
)
{
// assume the helper is in the same directory as this exe
string myExeDir = Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location
);
string envCaptureExe = Path.Combine(myExeDir, "envcapture.exe");
string vsToolsVariableName = String.Format("VS{0}COMNTOOLS", vsVersion);
string envSetupScript = Path.Combine(
Environment.GetEnvironmentVariable(vsToolsVariableName),
#"..\..\VC\vcvarsall.bat"
);
using (Process envCaptureProcess = new Process())
{
envCaptureProcess.StartInfo.FileName = "cmd.exe";
// the /s and the extra quotes make sure that paths with
// spaces in the names are handled properly
envCaptureProcess.StartInfo.Arguments = String.Format(
"/s /c \" \"{0}\" {1} && \"{2}\" \"",
envSetupScript,
architectureName,
envCaptureExe
);
envCaptureProcess.StartInfo.RedirectStandardOutput = true;
envCaptureProcess.StartInfo.RedirectStandardError = true;
envCaptureProcess.StartInfo.UseShellExecute = false;
envCaptureProcess.StartInfo.CreateNoWindow = true;
envCaptureProcess.Start();
// read and discard standard error, or else we won't get output from
// envcapture.exe at all
envCaptureProcess.ErrorDataReceived += (sender, e) => { };
envCaptureProcess.BeginErrorReadLine();
string outputString = envCaptureProcess.StandardOutput.ReadToEnd();
// vsVersion < 110 prints out a line in vcvars*.bat. Ignore
// everything before the first '<'.
int xmlStartIndex = outputString.IndexOf('<');
if (xmlStartIndex == -1)
{
throw new Exception("No environment block was captured");
}
XElement documentElement = XElement.Parse(
outputString.Substring(xmlStartIndex)
);
Dictionary<string, string> capturedVars
= new Dictionary<string, string>();
foreach (XElement variable in documentElement.Elements("Variable"))
{
capturedVars.Add(
(string)variable.Attribute("Name"),
(string)variable
);
}
return capturedVars;
}
}
Later, when you want to run a command in the build environment, you just have to replace the environment variables in the new process with the environment variables captured earlier. You should only need to call CaptureBuildEnvironment once per argument combination, each time your program is run. Don't try to save it between runs though or it'll get stale.
static void Main()
{
string command = "nmake";
string args = "";
Dictionary<string, string> buildEnvironment =
CaptureBuildEnvironment(100, "x86");
ProcessStartInfo info = new ProcessStartInfo();
// the search path from the adjusted environment doesn't seem
// to get used in Process.Start, but cmd will use it.
info.FileName = "cmd.exe";
info.Arguments = String.Format(
"/s /c \" \"{0}\" {1} \"",
command,
args
);
info.CreateNoWindow = true;
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
foreach (var i in buildEnvironment)
{
info.EnvironmentVariables[(string)i.Key] = (string)i.Value;
}
using (Process p = Process.Start(info))
{
// do something with your process. If you're capturing standard output,
// you'll also need to capture standard error. Be careful to avoid the
// deadlock bug mentioned in the docs for
// ProcessStartInfo.RedirectStandardOutput.
}
}
If you use this, be aware that it will probably die horribly if vcvarsall.bat is missing or fails, and there may be problems with systems with locales other than en-US.
There is probably no better way than collect all the data you need, generate bat file and run it using Process class.
As you wrote, you are redirecting output, which means you must set UseShellExecute = false; so I think there is no way to set your variables other then calling SET from the bat file.
EDIT: adding a specific use case for nmake calling
I've needed to get various "build path stuff" in the past, and this is what I've used - you may need to tweak things here or there to suit, but basically, the only thing that vcvars does is set up a bunch of paths; these helper methods go fetch those path names, you'd just need to pass them into your start info:
public static string GetFrameworkPath()
{
var frameworkVersion = string.Format("v{0}.{1}.{2}", Environment.Version.Major, Environment.Version.Minor, Environment.Version.Build);
var is64BitProcess = Environment.Is64BitProcess;
var windowsPath = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
return Path.Combine(windowsPath, "Microsoft.NET", is64BitProcess ? "Framework64" : "Framework", frameworkVersion);
}
public static string GetPathToVisualStudio(string version)
{
var is64BitProcess = Environment.Is64BitProcess;
var registryKeyName = string.Format(#"Software\{0}Microsoft\VisualStudio\SxS\VC7", is64BitProcess ? #"Wow6432Node\" : string.Empty);
var vsKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(registryKeyName);
var versionExists = vsKey.GetValueNames().Any(valueName => valueName.Equals(version));
if(versionExists)
{
return vsKey.GetValue(version).ToString();
}
else
{
return null;
}
}
And you'd take advantage of this stuff via something like:
var paths = new[]
{
GetFrameworkPath(),
GetPathToVisualStudio("10.0"),
Path.Combine(GetPathToVisualStudio("10.0"), "bin"),
};
var previousPaths = Environment.GetEnvironmentVariable("PATH").ToString();
var newPaths = string.Join(";", previousPaths.Split(';').Concat(paths));
Environment.SetEnvironmentVariable("PATH", newPaths);
var startInfo = new ProcessStartInfo()
{
FileName = "nmake",
Arguments = "whatever you'd pass in here",
};
var process = Process.Start(startInfo);

error while redirecting process input from file

I'm receiving an output error while trying to redirect a process input from a file - reading the file content and writing it to the process input.
the error: <output file> The volume for a file has been externally altered so that the opened file is no longer valid.
the code:
*before foreach loop:
prc = new Process();
prc.StartInfo.FileName = prcs;
prc.StartInfo.UseShellExecute = false;
*inside foreachloop:
prc = new Process();
prc.StartInfo.FileName = prcs;
prc.StartInfo.UseShellExecute = false;
if (prcs == asProcesses[0])//first process - only redirect output
{
prc.StartInfo.RedirectStandardInput = true;
prc.StartInfo.RedirectStandardOutput = true;
prc.Start();
sw = prc.StandardInput;
StreamReader sr1 = new StreamReader(sInRedirect);
while ((outputLine = sr1.ReadLine()) != null)
{
sw.Write(outputLine);
sw.WriteLine();
}
sr = prc.StandardOutput;
}
* i get the message while writing the command: "text1.txt < sort"
another thing, if i run the program in another computer i get the message:
" the pipe is being closed"
thank you for your help!
It seems that the permission on your output directory are set in a way that prevents Visual Studio from compiling.
Remove any read-only flags from the project's folder and all subdirectories, clear the output folder and, if necessary, take ownership of the folders or give yourself full permissions.
Source: msdn - Visual Studio 2010 fails to build or debug reports error 'Failed to write to output file'.

Categories

Resources