Executing python script from C# code mysteriously halts - c#

I currently have a set up in which I am using C# to execute a Python script. It also gets whatever the script would normally output in a command line returned back to be used in my application. (Except for error messages for some reason) The problem is that the script execution mysteriously comes to a halt when it reaches a line to open a .json file. I won't paste the script as it is fairly large, but I pinpointed the line it stops at by adding logs. This is the line:
featuresBody = open("features.json")
I have verified that the Python script makes it passed this point when I execute it in a regular command line, but halts here when executed from C#. Here is my C# code that runs the script:
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = #"C:\Python27\python.exe";
start.Arguments = ltrDirectory + "/train_and_upload_demo_model.py -c " + ltrDirectory + "/config.json";
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
string result = reader.ReadToEnd();
System.Diagnostics.Debug.WriteLine(result);
}
}
This logic is picking up the script and running it in the beginning just fine, but just fails at that one line I noted above. I cannot get details as to what is wrong as error messages don't get returned to C# for whatever reason and I cannot replicate the issue in a command line because the same command works there.
Any ideas why opening a .json file works fine normally, but not when executed from C#...?

Related

c# process that running a batch file for blender exporting gets paused

I hope someone can help me with this problem.
Situation:
I need to export an animation from blender as a sequence it has to be tigger inside of an c# app. I'm using blenders obj exporter with a python script that's pretty much the same as the example in this blender wiki:
https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Import-Export/Wavefront_OBJ
This is the python script i wrote:
import bpy
import sys
argv = sys.argv
argv = argv[argv.index("--") + 1:] # get all args after "--"
obj_out = argv[0]
bpy.ops.export_scene.obj(filepath=obj_out, axis_forward='-Z', axis_up='Y', use_animation=1, keep_vertex_order=1, use_normals=1, use_materials=0)
in addition to that i wrote the following batch file:
"C:\Program Files\Blender Foundation\Blender\blender.exe" "C:\Users\holgk\Documents\Some Folders\Test.blend" --background --python "C:\Program Files\Blender Foundation\Blender\convert_blend_to_obj.py" -- "C:\Users\holgk\Documents\Some Folders\Test.obj"
My c# code looks like this:
using System;
using System.Diagnostics;
namespace BlenderToObjs
{
class Program
{
static void Main(string[] args)
{
ProcessStartInfo processInfo;
Process process;
processInfo = new ProcessStartInfo("cmd.exe", "/c \"" + #"C:\blender_export_to_obj.bat" + "\"");
processInfo.CreateNoWindow = false;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
process = Process.Start(processInfo);
process.WaitForExit();
}
}
}
When i'm using the window cmd shell everything works as it should. For every frame an obj file is created. But when i'm using my c# app the cmd line is open, blender starts to execute and for the first frames about 12 of 250 everything works as it should and then nothing happens and the app is still waiting for the exit but no new obj files are created.
Before i wrote the batch file i tried to run blender with that python script directly as a process and i had the same problem it started but was "pausing"/"stalling" after a few frames of exporting.
I'm guessing that it has to do with my c# process code (because running in the cmd shell does work) but i don't know what i'm doing wrong.
could it be, that your blender is freezing in the process or that the obj export fails?
it seems like you don't catch the error and blender never gets terminated so it just keeps going.
first, you should wrap your python code into a try, except block:
import bpy
import sys
def main():
try:
# Do stuff
argv = sys.argv
argv = argv[argv.index("--") + 1:] # get all args after "--"
obj_out = argv[0]
bpy.ops.export_scene.obj(filepath=obj_out, axis_forward='-Z', axis_up='Y', use_animation=1, keep_vertex_order=1, use_normals=1, use_materials=0)
O.wm.quit_blender()
except:
# you could write your error file here
# exit blender
sys.exit(1)
O.wm.quit_blender()
main()
the problem here is that you can't exit blender (yet, or I never figured it out) with an exit code that would indicate the success of the python script, because even with sys.exit(1) blender will terminate with a success message.
add something like this to write your error messages to a file that you later can read (or that your c# code can read)
log.error('Failed to bake light map textures', exc_info=True)
if 'ERROR_FILE' in os.environ:
with open(os.environ['ERROR_FILE'], 'w') as file:
file.write(traceback.format_exc())
let me know if that helped you any further in solving the mystery

MVC executing a LibreOffice conversion

Hi I'm trying to convert either a doc or docx to a pdf in a c# MVC application. I know I can do this using libreOffice. So I created a simple batch file to take 2 variables and then run them into the libreoffice 'soffice' headless to convert to pdf.
So that gave me this code.
echo on
SET var1=%2
IF "%var1:~-1%"=="\" SET var1=%var1:~0,-1%
cd "C:\Program Files\LibreOffice 5\program\"
soffice --headless --convert-to pdf %1 --outdir %var1%
Originally I thought the problem was within my MVC application and the way I called this batch script. But I commented (REM) the soffice and outputted out the command in the bash using the standard output.
var psi = new ProcessStartInfo("cmd.exe", "/k " + command);
//psi.CreateNoWindow = true;
psi.FileName = command;
psi.UseShellExecute = false;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.Arguments = string.Format("{0} {1}", fullPath2, tempPath);
var process = Process.Start(psi);
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
Trace.WriteLine(output);
Trace.WriteLine(error);
process.WaitForExit();
When I commented the soffice line - it hit the WaitForExit and worked no problems (ok with no pdf conversions, but the script exited).
If I don't do that it seems to execute the cmd and even the soffice commands because I can see them in the task manager - but obvisouly nothing happens.
Additionally the code above works when I did a c# command line program (I've hard coded the file/command lines in both instances). The executable also works when I run as the user that is running the app pool in my MVC application.
The bash file also works file 'standalone' no matter if me or my appPool user run it.
So what gives - why won't this run.
This is the code that comes out of that trace - so what the bash script does.
c:\windows\system32\inetsrv>echo on
c:\windows\system32\inetsrv>SET var1=C:\inetpub\xxxxxxxxx\Temp\
c:\windows\system32\inetsrv>IF "\" == "\" SET var1=C:\inetpub\xxxxxxxxx\Temp
c:\windows\system32\inetsrv>cd "C:\Program Files\LibreOffice 5\program\"
C:\Program Files\LibreOffice 5\program>soffice --headless --convert-to pdf C:\inetpub\xxxxxxxxx\Temp\636295920370843147.doc --outdir C:\inetpub\xxxxxxxxx\Temp
I've got a feeling that this has something to do with the amount of characters or something because the soffice does fireup (can see it in the task manager).
FYI there are no spaces or special characters anywhere.
Any ideas?
Update
This looks to be an issue with the wait command. So any help with that helpful, I'm starting to think perhaps this is an issue with c# and libreoffice 5 - I've seen examples that supposedly work with libreoffice 4.
I guess my challenge continues....

Compile in C using a Windows Forms Application

I'm creating a compiler App in C#, using Visual Studio 2010.
The goal of this program is to compile a code written in either C# or C at runtime and return the results of the compilation.
I have done the C# part, but the C part is the one I have problems. For this one, I've tried to use the Visual Studio Command Prompt. The way I'm coding this part is like this:
Create a .c file in C:\ using File.Create.
Using a Process, open the Visual Studio Command Prompt and execute the compilation.
Capture the output to return it as the compilation results.
However, it doesn't work. It throws and Win32 exception, but I don't really know why.
I've heard something about using gcc. But I thought about using the Visual Studio Command Prompt as a possible solution.
EDIT: I figured out the steps to do it (I think). But the Win32 exception appears when the program tries to do the process.Start() line. I guess this might be a permissions problem, but I don't really know.
A friend of mine worked on something similar, and helped me to solve this problem.
On steps 2 and 3, I was trying to write the input and read the output using simply the process standard input and output, and also, I was trying to use an .lnk to run the Command Prompt. All those things caused the error.
The solution was:
Create two batch files, one to start up the Command Prompt and the other to compile the .c file (those were created outside the program's code).
(On runtime) Create the .c file, using the code written. If file exists, delete it and create a new one.
Start the process with cmd.exe.
Run the batch files, using a Stream Writer to write them in the cmd.exe.
Retrieve the output using a Stream Reader.
Fortunately, this worked! Code ended like this:
string CompileC (string code)
{
string path = #"C:\sample.c";
string results = "";
try
{
if (File.Exists(path))
File.Delete(path);
using (FileStream fs = File.Create(path))
{
byte[] codeText = new UTF8Encoding(true).GetBytes(code);
fs.Write(codeText, 0, codeText.Length);
}
Process process = new Process();
process.StartInfo.FileName = #"C:\Windows\system32\cmd.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
using (StreamWriter sw = process.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
//This batch starts up the Visual Studio Command Prompt.
sw.WriteLine(#"C:\Startup.bat");
//This batch does the compilation, once the Command Prompt
//is running, using the 'cl' command.
sw.WriteLine(#"C:\Compile.bat");
}
}
using (StreamReader sr = process.StandardOutput)
{
if (sr.BaseStream.CanRead)
results = sr.ReadToEnd();
}
}
catch (Exception ex) { MessageBox.Show(ex.ToString()); }
return results;
}

Getting output from one executable in an other one

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

Perl Script Output Capture Problem using C#

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.

Categories