Output the result of a process - c#

I wanted to make an online c# compiler and also run the compiled program and output it to my website.
How can I do this? I have understood the implementation of the c# compiler but have not been able to display the output of the compiled program on to my website. The process.Start function will just initiate the .exe but how do I display the results from that .exe file?

You need to start the process using a ProcessStartInfo object specifying RedirectStandardOutput to true.
http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput.aspx

You need to redirect standard ouput of your process.
Please note that you need to make sure users aren't running arbitrary code on your server. How do you protect against C# code that tries to format your disc?

Related

Run an External Program or Batch File From a C# Xamarin Program

I want to have my C# (Xamarin) program run an EXE or batch (BAT) file. The user will be running my program, and will click on one of several buttons, some of which open Web pages and others of which run external programs. These files will be on the same computer as the one running the main program and don't need greater permissions. The overall program will be in Windows, UWP.
I already have code to pull info from the database saying "the button the user clicked references a program and it's (eg) C:\Tools\MyTool.exe". (Real path more like (C:\Users\Me\source\repos\ProductNameV2\ProductName\ProductName.UWP\Assets\EXE\whatever.exe".) I used a "demo.bat" file containing nothing but echo and pause statements, or references to a built-in Windows program like Notepad or Calc that an ordinary command prompt can recognize without an explicit path (ie. that's part of the recognized system Path). Yes, the real path to the dummy file does exist; I checked. I've also explicitly added files demo.bat and dummy.txt to my C# project.
Here's roughly what I've tried so far to actually run a batch file, or an EXE, or just to try opening a text file. Nothing works.
1)
bool check = await Launcher.CanOpenAsync(#"file:///C:\Tools\demo.bat"); // Returns false.
bool check = await Launcher.CanOpenAsync(#"file:///C:\Tools\dummy.txt"); // Returns true.
await Launcher.OpenAsync(#"file:///C:\Tools\demo.bat") // Seems to do nothing; silently fails.
await Launcher.OpenAsync(#"file:///C:\Tools\dummy.txt") // Same.
2)
Process batchProcess = new Process();
batchProcess.StartInfo.FileName = #"file:///C:\Tools\demo.bat"; // Same result with notepad.exe
batchProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
batchProcess.Start();
batchProcess.WaitForExit();
// Result: "Access is denied" error during Start().
3)
var otherProcessInfo = new ProcessStartInfo(#"file:///C:\Tools\demo.bat")
var otherProcess = Process.Start(otherProcessInfo);
otherProcess.WaitForExit();
otherProcess.Close();
// Result: "The system cannot find the file specified" despite it being the same path as in previous examples.
// Also tried literally using the path C:\Tools\demo.bat, without adding that to the C# project.
// One thing that slightly works is to use:
var otherProcessInfo = new ProcessStartInfo("cmd.exe", "/c echo Hello world!");
// This version opens a window and instantly closes it again. With "/c pause" instead, it opens, saying "press any key to continue".
// Chaining multiple commands with newline or semicolon characters doesn't work as a form of batch file.
So: the only tiny success I've had here is to run cmd.exe, to run a one-line command. I suppose that depending on what the batch file must do, there's some possibility of receiving a string, breaking it into lines, then running cmd.exe using method 3 to call them one at a time. Which is ugly at best.
Is there some better way to do this -- to run a batch file or an EXE from within my program?
EDIT: Yes, I did in fact look at documentation before asking. Why did I use URIs? Because of multiple errors telling me that the simple path strings ("C:\this\that") I was using were in an "Invalid URI format". Using Process.Start("notepad.exe") silently fails, doing nothing. Using a method involving System.Diagnostics.Process (found at How to run external program via a C# program? and yes I saw that before) fails with an error of "Access denied" when using my batch file reference, or silently failing (no window opens) using plain old notepad.exe. I avoided setting Process options that say hide the window.
So to rephrase: Is there a way to make my program run some EXE somewhere on the computer, or to run a batch file that has more than one command in it? What is that way?
Using the data you collected, I was able to run a batch file by doing the following:
var strPathToExeOrBat = System.IO.Path.Combine("C:\\Tools", "demo.bat");
var otherProcessInfo = new ProcessStartInfo("cmd.exe", $"/c call \"{strPathToExeOrBat\"");
var otherProcess = Process.Start(otherProcessInfo);
otherProcess.WaitForExit();
otherProcess.Close();
I also think it would be helpful to review the capabilities of the cmd.exe application.
I found this post to be helpful:
https://stackoverflow.com/questions/515309/what-does-cmd-c-mean#:~:text=%2FC%20Carries%20out%20the%20command%20specified%20by%20the%20string%20and,switches%20by%20typing%20cmd%20%2F%3F%20.
In particular the /k option will leave the window open, if you don't want it to close after running a script.
Thank you very much for your question! It really helped me find the answer to this! (at least for my situation of a .NET MAUI windows app, but MAUI is built off of Xamarin.Forms, so you shouldn't have a problem doing the same thing)
EDIT: Updated to use file path from question and string interpolation with System.IO.Path.Combine for slightly greater cross platform capability

How to expand the search environment variable %ProgramData% and use the start up info

I got PythonApplication1.py into the Sources of the C# Windows Form Application. On specific condition I write it into the Program Data folder this way:
File.WriteAllBytes(#"%ProgramData%\\Folder\\PythonApplication1.py", Resources.PythonApplication1);
and then with specific condition C# runs Python Application from program data folder, this way:
Process.Start(#"%ProgramData%\\Folder\\PythonApplication1.py");
On the side of Python code I got second thing, it writes some data into the text document, which is located by the same path, but creation of it happens in Python itself, but it can be done from C# code, no matter, here:
path = (#"%ProgramData%\Folder\doc.txt")
but python code must write in this file by same program data path:
data = open (r'doc.txt', 'w')
and to write, just by same location, as both are there:
with open(r'doc.txt') as my_file:
The problem is, when I run this python code as it shown above, this way:
Process.Start(#"%ProgramData%\\Folder\\PythonApplication1.py");
It does two wrong things, which does not happens, if it is not %ProgramData% directory and located with C# .exe in debug folder, just by Process.Start("PythonApplication1.py");, or if I run Python Code inside %ProgramData%\Folder path with doc.txt, just by hand. It creates and writes directly into the file, all is correct.
Otherwise if Process.Start(#"%ProgramData%\\Folder\\PythonApplication1.py"); I got second result, it does not writes data into the doc.txt by %ProgramData%\Folder and python code creates it out of program data folder in debug folder with C# .exe.
So question is how to create and write from python code into the doc.txt located by C# Application "%ProgramData%\Folder" path.
Seems like, if PythonApplication1.py is exist inside ProgramData:
File.WriteAllBytes(#"%ProgramData%\\TAOZ\\PythonApplication1.py", Resources.PythonApplication1);
And if executed by hand it creates text document and writes to it, it must do the with Process.Start, but not.
also I tried to use star info, but not sure if this is correct, anyway I got same result:
ProcessStartInfo startInfo = new ProcessStartInfo(#"%ProgramData%\\folder\\PythonApplication1.py");
startInfo.WindowStyle = ProcessWindowStyle.Minimized;
Process.Start(startInfo);
So seems like I need two things here. To expand the search environment variable %ProgramData%. and also need to use the start up info to tell the process to start on that particular folder. Otherwise, the current working folder will be the same folder as application I guess, but not sure how to do it, and if it is reason of problem, need your help.
Since it's a python program, you'll have to point to the python EXE. Assuming you have the pythonpath environment variable, this ought to work:
ProcessStartInfo startInfo = new ProcessStartInfo(Environment.ExpandEnvironmentVariables(#"%PYTHONPATH%\python.exe"), Environment.ExpandEnvironmentVariables(#"%ProgramData%\folder\PythonApplication1.py"));
startInfo.WorkingDirectory = Environment.ExpandEnvironmentVariables(#"%ProgramData%\folder\");
startInfo.WindowStyle = ProcessWindowStyle.Minimized;
Process.Start(startInfo);

Run an executable present in Windows Path using C#

I'm trying to run some commands, like rails test, using a C# command line. I tried using How To: Execute command line in C#, get STD OUT results but I'll need full path to the rails executable for that to work. Is there any alternative that will find work just like the windows command line does?
If you can P/Invoke, you could locate the executable with PathFindOnPath. A quick google doesn't show a C# equivalent.
without P/Invoke, Environment.GetEnvironmentVariable("Path").Split(";") should give you a list of paths to probe.
However, this is not the entire resolution used by ShellExecute or even the console.
I believe if you have UseShellExecute set to true in the ProcessStartInfo used to start the process, it'll use the path. Haven't checked it yet - will do so when I get a chance.

PHP class to C# class?

I work for a company that makes application's in C#.
recently we got a customer asking us to look in to rebuilding an application written in PHP.
This application receives GPS data from car mounted boxes and processes that into workable information.
The manufacturer for the GPS device has a PHP class that parses the received information and extracts coordinates. We were looking in to rewriting the PHP class to a C# class so we can use it and adapt it. And here it comes, on the manufacturers website there is a singel line of text that got my skin krawling:
"The encoding format and contents of the transmitted data are subject to constant changes.
This is caused by implementations of additional features by new module firmware versions which makes it virtually impossible to document it and for you to properly decode it yourself."
So i am now looking for a option to use the "constantly changing" PHP class and access it in C#. Some thing link a shell only exposing some function's i need. Except i have no idea how i can do this. Can any one help me find a solution for this.
I know it's a really hacky solution, but if you need a bit of PHP code that you don't want to have to repeatedly port to C# each time, you could try the following approach, although it means that you would need the php command line tool on the target machine.
First step is to have a php script that continously reads data off stdin, decodes it using this special class from the vendor, and writes the result out to stdout. Really simple example:
<?php
include("VendorDecodingClass.php");
while(true)
{
$input = fgets(STDIN); //read off of the stdin stream
//can't remember if this is valid, but somehow check that there is some data
if($input)
{
//pass it off to the vendor decoding class
$output = VendorDecoding::decode($input);
fwrite(STDOUT, $output); //write the results back out
}
//sleep here so you don't suck up CPU like crazy
//(1 second may be a bit long tho, may want usleep)
//Edit: From Tom Haigh, fgets will block, so the sleep isn't necessary
//sleep(1);
}
?>
Anyway, once you have that in place, in your C# application, right at the start, create a new Process to run that script and then save the Process instance somewhere, so you can reference the STDIN and STDOUT at a later point. Example:
ProcessStartInfo procStartInfo = new ProcessStartInfo("php", "yourscript.php");
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
Process proc = new Process(); //store this variable somewhere
proc.StartInfo = procStartInfo;
proc.Start();
Then, when you want to decode your data, you just write to the stdin of the php process you created, and wait for a response on the stdout. Using the stdin/stdout approach is a lot more efficient than creating a new process each time you want to decode some data, because the overhead of creating that process can be noticeable.
proc.StandardInput.WriteLine(somedata); //somedata is whatever you want to decode
//may need to wait here, or perhaps catch an exception on the next line?
String result = proc.StandardOutput.ReadLine();
//now result should contain the result of the decoding process
Disclaimer here, I haven't tested any of this code, but that is the general gist of how I might do it.
Something else I just thought of, you will want some mechanism for terminating that PHP process. It may be OK to use Process.Kill, but if the decoding does any file IO, or anything critical you may want to send an interrupt signal to the php script somehow.
I assume the php script is on your machine and returns usefull data. The first -not very elegant solution- that pops into my mind is the following:
Make sure your machine has the php commandline installed, so that you are able to run the php script from commandline. To execute a commandlinetool from C# see code for that here. The returned data now probably needs to get processed my your C# program.
I have never tried this and do not know anyone that has, but I remember comming across this sometime ago and thought I would throw it out there as a possible option for you.
Phalanger is a compiler project that compiles PHP code to IL, so you can use that then have a managed assembly that you reference from your code directly.
If the format is a regex you can try to put it in an application setting file (not resources, these are compiled WITH the application, you can't change them without recompiling the app).
Application settings are not changeable by the user but you can do that by editing the XML.
Or you can set the settings to user mode and then you can change the format from inside your application code.
Why don't you just launch the PHP script from C#, have it output its results to a file and then use that file as input for your C# program?
Personally, I would setup a PHP web service with a proper and stable API that the C# project can access, implement the manufacturers supplied PHP class in the web service and let it be.

Launching a .pl file using Process.Start

I have been using Process.Start to launch executables (.exe) files. Now I need to execute a .pl file with some arguments. can I still use Process.Start or I need a different approach?
EDIT :- I am having to mark this question unanswered as I am getting the following error when I try to call the perl file from the CSharp code:- (When I call the same from the commandline with the same path and parameters, It works fine)
System.ApplicationException: StartProcess Failed
System.ComponentModel.Win32Exception: The specified executable is not a valid application for this OS platform)
Please note that when I try to call an .exe file from my C# code, I dont see the above error.
EDIT:-
Checking the following link now:- How do I call Perl script in C# application?
It seems that the ProcessStartInfo constructor has two parameters - fileName and the arguments. You should set Perl.exe as the fileName and the "argument" would be your perl file (.pl) with other arguments It accepts. Checking now....
You certainly can :) you can also pass it arguments by adding them after the file name in
Process.Start(file.pl args1 args 2);
It will load the file with your default application for .pl files, the other option is to specify the software then pass your file as a parameter providing you have the right software to handle the file it should be fine
Process.Start() can be pointed at any file and it will be opened using the default software or that which you specify, it need not be an executable.
Yes you can, Process.Start() takes a string parameter, what you pass for this parameter does exactly the same thing it would do if you entered the same string in the windows start -> run dialog.

Categories