I was following one of the thread to run perl scripts from my c# program.
My c# code is like this:
private void RunScript(ArrayList selectedScriptFileList)
{
foreach (var curScriptFileName in selectedScriptFileList)
{
ProcessStartInfo myProcessStartInfo = new ProcessStartInfo("perl.exe");
myProcessStartInfo.Arguments = (string)(curScriptFileName);
myProcessStartInfo.UseShellExecute = false;
myProcessStartInfo.RedirectStandardOutput = true;
myProcessStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
myProcessStartInfo.CreateNoWindow = true;
myProcess.StartInfo = myProcessStartInfo;
myProcess.Start();
myProcess.WaitForExit();
string output = myProcess.StandardOutput.ReadToEnd();
this.ScriptTestResultTextBox.AppendText(output);
}
}
And my perl script requires XML parsing. I can read the print statement before the XML parsing, but not after the parsing starts. The script runs find on DoS shell.
Here is part of my script:
print("\n");
print("****************** test1.pl ***********************\n");
print("\n");
print("1");
print("2");
my $scriptName = 'test1.pl';
my $file = '../../ScriptParamLib.xml';
my $parser = XML::LibXML->new();
my $tree = $parser->parse_file($file);
my $root = $tree->getDocumentElement;
my #species = $root->getElementsByTagName('test_node');
print("Accessing XML Data Base...\n");
The c# testbox only shows the first three print statement but not the last one.
Does anybody knows why?
Thanks
You could add more debugging print statements (e.g. one between every other line of your code) to see how far the execution gets. However, I'm going to go on a hunch and suggest that adding these three lines to your script will either solve the problem outright or lead you closer to a solution:
use strict;
use warnings;
use XML::LibXML;
Please update your question indicating how far execution gets and what errors you see!
I figured I should roll my comments into an answer since they proved to be helpful:
Since using an absolute path for $file in the Perl script works, the issue most likely has something to do with the working directory of the process that gets spawned from the C# program. You can use the Cwd module in the Perl script to see what the working directory actually is. If it's not what you expect, try setting it via the WorkingDirectory property of ProcessStartInfo in your C# program. Relative paths should work just fine after that.
Related
I have created a script using Python2.7 and compiled it using pyinstaller into an exe of the same name, in this case "GeneralStats.py" turns into "GeneralStats.exe" using --onefile and -w arguments.
When called with C# I use:
var pythonDirectory = (Directory.GetCurrentDirectory());
var filePathExe1 = Path.Combine(pythonDirectory + "\\Python\\GeneralStats.exe");
Process.Start(filePathExe1);
When called outside of C#, so in my local files I can run the .exe and the result is a text file with lots of values in (Running correctly).
However, when ran with C# in this format, I get an error that "GeneralStats returned -1!"
Which I have had issues with before, but it was a simple python error that when I returned to my code and ran it, I would receive an error that I overlooked.
This time my python code returns no errors and works outside of C#.
Any ideas of why this could be? I can provide any code or file directories necessary, please just ask if you feel it would help with debugging.
EDIT:
Solved by removing:
var filePathExe1 = Path.Combine(pythonDirectory + "\\Python\\GeneralStats.exe");
Process.Start(filePathExe1);
And replacing with:
ProcessStartInfo _processStartInfo = new ProcessStartInfo();
_processStartInfo.WorkingDirectory = Path.Combine(pythonDirectory + "\\Python");
_processStartInfo.FileName = #"GeneralStats.exe";
_processStartInfo.CreateNoWindow = true;
Process myProcess = Process.Start(_processStartInfo);
You need to set the working directory for the Process - it is probably trying to load files from its working directory but isn't finding them.
See, e.g. this:
Use the ProcessStartInfo.WorkingDirectory property to set it prior to starting the process. If the property is not set, the default working directory is %SYSTEMROOT%\system32.
Set it to the path where GeneralStats.exe is.
I am trying to run ".sh" file from c# core application.But it doesn't seem to be running properly.Here is my scenario.
I am working on .Net core project which is hosted on Linux environment.We are trying to create "PDF" in our project for which we have used "Apache FOP".
Here i have created one "shell script" file "transform.sh" which internally calls "fop" with required parameters.Since developement is being done on windows machine we tested the same usinf "batch" file i.e. "transform.bat",but since we cannot use the "batch" file on linux enviornment we have created shell script file "transform.sh"
Following is the code from"transform.sh"
./fop -xml $1 -xsl $2 -pdf $3
Following is C# code from which i am calling the "shell script file
var process = new Process
{
StartInfo = new ProcessStartInfo
{
UseShellExecute = false,
RedirectStandardOutput = true,
Arguments = string.Format("{0} {1} {2}", XML_filename, XSL_filename, output)
}
};
process.StartInfo.FileName = "Path to shell script file";
process.Start();
process.WaitForExit();
Above code doesnot give any error but it also does not create the pdf file.If i directly run the shell script file from "Terminal" it works fine and create pdf file.
./transform.sh "/home/ubuntu/psa//PdfGeneration/ApacheFolder/XMLFolder/test.xml" "/home/ubuntu/psa/PdfGeneration/ApacheFolder/XSLTFolder/Certificate.xsl" "/home/ubuntu/psa/PdfGeneration/ApacheFolder/PDFFolder/t444t.pdf"
Please let me know if there is something wrong i am doing?How can i make the sheel script run on linux through C# core application.
Thanks.
I was able to solve the issue,just thought that i should put my solution here so that it may help others in future...
As mentioned in Question i was not able to generate the PDF file through shell script on linux machine.After debugging as suggested by "#JNevill" I came to understand that the shell script file was not getting called from .net process itself.
So my first task was to make the shell script file called through .Net Process.
After lots of searching through Net and trying out different solutions i got solution at How to perform command in terminal using C#(Mono).
So changed my code of calling the process as follow,
var command = "sh";
var myBatchFile = //Path to shell script file
var argss = $"{myBatchFile} {xmlPath} {xsltPath} {pdfPath}"; //this would become "/home/ubuntu/psa/PdfGeneration/ApacheFolder/ApacheFOP/transform.sh /home/ubuntu/psa/PdfGeneration/ApacheFolder/XMLFolder/test.xml /home/ubuntu/psa/PdfGeneration/ApacheFolder/XSLTFolder/Certificate.xsl /home/ubuntu/psa/PdfGeneration/ApacheFolder/PDFFolder/test.pdf"
var processInfo = new ProcessStartInfo();
processInfo.UseShellExecute = false;
processInfo.FileName = command; // 'sh' for bash
processInfo.Arguments = argss; // The Script name
process = Process.Start(processInfo); // Start that process.
var outPut = process.StandardOutput.ReadToEnd();
process.WaitForExit();
After changing the code ,the ".sh" file got executed and i was able to generate the PDF file.
Also script of the ".sh" file i.e. (transform.sh) which was calling Apache FOP file i.e. "FOP.sh" also needed to be changed.
Initially code was
./fop -xml $1 -xsl $2 -pdf $3
Which i changed as follow,(Change was to give full path of the FOP file)
/home/ubuntu/psa/PdfGeneration/ApacheFolder/ApacheFOP/fop -xml $1 -xsl $2 -pdf $3
Late answer, but for me, it worked just by setting the RedirectStandardOutput to true and changing the FileName property like this:
processInfo.FileName = #"C:\Program Files\Git\git-bash.exe";
processInfo.RedirectStandardOutput = true;
I am using grunt (javascript Task runner) for my web development build process. Included are things like tests with jasmine, code checking with plato, documentation (YUIdoc) and so on...
To make things a bit more convenient (and also to include this build process into another build process later) I tried to create a simple .net (C#) application that is able to execute the grunt commands and then outputs the results into a textbox. As I can always execute the grunt commands easily via the cmd-Window I tried utilizing System.Diagnostics.Process with cmd.exe to do that. Here is what I tried (for generating the code documentation):
private void documentationToolStripMenuItem_Click(object sender, EventArgs e)
{
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/C grunt doc";
p.StartInfo.WorkingDirectory = "c:\\myProjectFolder\\";
p.Start();
p.WaitForExit();
rtbOut.Text = p.StandardOutput.ReadToEnd();
}
First thing which is weired: I am getting this output:
>Loading "requirejs.js" tasks...
Yes, I do use require.js inside my project but this has nothing to do with documentation. This is the output I usually get and I would expect:
>Running "doc" task
>
>Running "yuidoc:compile" (yuidoc) task
>Start YUIDoc compile...
>Scanning: ../someFolder/
>Output: ../release/Documentation/
>YUIDoc compile completed in 0.968 seconds
And the documentation is not generated of course. But there is a data.json File which is generated in the correct folder but it is empty. So at least it appears that it started correctly but could not continue(?) I also tried with other tasks but none of them work using a Process in C#.
In case anyone has the same problem I answer my own question as I found a solution now that works for me.
I am simply doing a 'detour' now using PowerShell scripts. There is a nice article about how you can run PowerShell from C# here:
http://www.codeproject.com/Articles/18229/How-to-run-PowerShell-scripts-from-C
Included in the System.Management.Automation there is the class Runspace which can be used to call PowerShell scripts. Now in my case such a 'script' is not more than this:
grunt build
You get back some escape codes for coloring the output which you can remove by calling it like:
grunt --no-color build
I using C# .NET , vs 2008 , .net 3.5
For me, is difficult, but I need sample code in C# for this:
Check if a file or a folder is in use
If file or a folder is in use, the name of Process that use it
For example, in my issue.
I try delete file, and I get "The process cannot access the file 'XYZ' because it is being used by another process." Exception.
File.Delete(infoFichero.Ruta);
I want check if a file is in use, and the name of Process that use it.
I need sample code, source code, please. I dont want use c++, I dont know c, c++, unmanaged code, or WinApi. I want use only C# code (managed code .net).
I have read several references but not get sample code source,
How to check if a file is in use?
Emulate waiting on File.Open in C# when file is locked
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/9dabc172-237a-42db-850e-ada08885a5d5
How to check if a file is in use?
Easiest way to read text file which is locked by another application
Using C# is it possible to test if a lock is held on a file
EDIT:
From Yan Jun - MSFT
string path = "D:\\temp2.xlsx";
foreach (Process c in Process.GetProcesses()) {
if (c.MainWindowTitle.Contains(Path.GetFileName(path))){
MessageBox.Show(c.ProcessName);
return;
}
}
try{
FileInfo f = new FileInfo(path);
f.Delete();
}
catch (Exception ex){
MessageBox.Show(ex.Message);
}
...
But it is difficult get solution for all 100% issues.
Problem if c.MainWindowTitle == null or not contains filename.
Problem for shared folder in another machine, PC, server,... like:
File.Delete(#\desiis\TEmporal\Project\script.targets);
any sample code, I ask for help gurus, MVPs, anyone.
UPDATE: the same issue for a folder
There's not going to be a way to find the process that has the file opened without stepping into the WinApi, I don't think. And as far as checking whether its in use, the only thing you can really do, as the SO questions you linked to state, is to wrap the file access attempts in a try/catch block.
The code to find which file has it opened is likely to be ugly, but there may be an API out there that wraps this up nicely. There are 3rd party utilities that will tell you this (Unlocker being the best known example). You can also use ProcessExplorer to search for open file handles by the filename. Those don't really help you though.
The short answer of what I'm trying to get across here is you have the answer for the first part of your question in the SO questions you already linked, and the second part would probably require WIN32 calls, which you want to avoid, but you're probably going to have to get your hands dirty in Win32... Still want help?
EDIT: You could shell out to sysinternals Handle utility. You would need to get the output of that command and parse it yourself. You can read the executed process's output like this
string result = proc.StandardOutput.ReadToEnd();
The issue with this is you're going to get a license agreement popup the first time you run the Handle utility. Not to mention the whole licensing issues if this is something you hope to deploy...
If you're still interested, I can show you how you'd go about this.
EDIT: Here's a runnable program that will find the exe name and pid of any program that has an open handle to a file. I added comments, but can elaborate further if necessary. I use Regular Expressions here to parse the output as that makes the most sense given the task at hand.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ProcessStartInfo si = new ProcessStartInfo();
si.FileName = "handle.exe"; //name of the handle program from sysinternals
//assumes that its in the exe directory or in your path
//environment variable
//the following three lines are required to be able to read the output (StandardOutput)
//and hide the exe window.
si.RedirectStandardOutput = true;
si.WindowStyle = ProcessWindowStyle.Hidden;
si.UseShellExecute = false;
si.Arguments = "test.xlsx"; //this is the file you're trying to access that is locked
//these 4 lines create a process object, start it, then read the output to
//a new string variable "s"
Process p = new Process();
p.StartInfo = si;
p.Start();
string s = p.StandardOutput.ReadToEnd();
//this will use regular expressions to search the output for process name
//and print it out to the console window
string regex = #"^\w*\.EXE";
MatchCollection matches = Regex.Matches(s, regex, RegexOptions.Multiline);
foreach (var match in matches)
{
Console.WriteLine(match);
}
//this will use regex to search the output for the process id (pid)
//and print it to the console window.
regex = #"pid: (?<pid>[0-9]*)";
matches = Regex.Matches(s, regex, RegexOptions.Multiline);
foreach (var obj in matches)
{
Match match = (Match)obj; //i have to cast to a Match object
//to be able to get the named group out
Console.WriteLine(match.Groups["pid"].Value.ToString());
}
Console.Read();
}
}
}
There is no purely managed way to do this. You have to use some low-level APIs through P/invoke or similar.
There's good information here on a way to do it, but it's C++ code. You'd have to do the porting yourself.
http://www.codeproject.com/KB/shell/OpenedFileFinder.aspx
Note there are some complex issues with this, namely the issues around kernel vs. userspace memory. This is not a simple problem you're trying to solve.
Try the windows Process Explorer:
http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx
Won't let you do it from code, but at least you can figure out what the source of your locks are.
I'm currently trying to get the output of an executable console-app into an other one. To be exact, a little overview of what I'm trying to do:
I have one executable which I cannot edit and neither see it's code. It writes some (quite a bunch to be honest) lines into the console when executed.
Now I want to write another executable that starts the one above and reads the things it writes.
Seems simple to me, so I started coding but ended up with an error message saying that StandardOut has not been redirected or the process hasn't started yet.
I tried it using this kinda structure (C#):
Process MyApp = Process.Start(#"C:\some\dirs\foo.exe", "someargs");
MyApp.Start();
StreamReader _Out = MyApp.StandardOutput;
string _Line = "";
while ((_Line = _Out.ReadLine()) != null)
Console.WriteLine("Read: " + _Line);
MyApp.Close();
I can open the executable and it also does open the one inside, but as soon as it comes to reading the returned values, the app crashes.
What am I doing wrong?!
Take a look at the documentation for the Process.StandardOutput property. You will need to set a boolean indicating that you want the stream redirected as well as disabling shell execute.
Note from the documentation:
To use StandardOutput, you must set ProcessStartInfo..::.UseShellExecute to false, and you must set ProcessStartInfo..::.RedirectStandardOutput to true. Otherwise, reading from the StandardOutput stream throws an exception
You would need to change your code a little bit to adjust for the changes:
Process myApp = new Process(#"C:\some\dirs\foo.exe", "someargs");
myApp.StartInfo.UseShellExecute = false;
myApp.StartInfo.RedirectStandardOutput = false;
myApp.Start();
string output = myApp.StandardOutput.ReadToEnd();
p.WaitForExit();
you could try setting processStartInfo.RedirectStandardOutput = true;
As noted above, you can use RedirectStandardOutput as here.
Another, dirtier way is something like
using (Process child = Process.Start
("cmd", #"/c C:\some\dirs\foo.exe someargs > somefilename"))
{
exeProcess.WaitForExit();
}
And then read its output from somefilename