This seems trivial, but google only gives me powershell-related stuff and how to implement pipelines within programs.
I'm trying to consume input arguments from the (standard command processor cmd.exe for Windows 7, not powershell) command line pipeline on windows like 'more' does.
I'm trying to get this to work with two self-created .exe files:
randgen (creates a random number and writes it to the console)
wordwrite (the c# program that I want to consume this random number from the pipeline)
And using two common windows executables to test and model the behaviour:
echo (writes input to console)
more (displays output one screen at a time, can consume input from the pipeline)
Here's the current content of my Main function in wordwrite:
static void Main(string[] args)
{
string ouname = args[0];
DocWrite(ouname);
}
and the behaviour trying to naively pipe output from randgen into wordwrite:
D:\code>randgen | wordwrite
Unhandled Exception: System.IndexOutOfRangeException: Index was outside the bounds of the array.
at ADDoc.ADOUDoc.Main(String[] args)
(plus a popup telling me wordwrite.exe has stopped working)
Which is the behaviour of trying to consume a null array of arguments as input:
D:\code>wordwrite
Unhandled Exception: System.IndexOutOfRangeException: Index was outside the bounds of the array.
at ADDoc.ADOUDoc.Main(String[] args)
So the output of randgen isn't being read from the pipeline correctly as an argument to the wordwrite executable's args array (thanks #Peter Duniho for explaining the difference between stdin and how argument assignation works). Contrast that with the behaviour of the 'more' executable:
D:\code>randgen | more
56929227
That said, this 'pipeline-awareness' seems to be inherent to the 'more' executable itself, as another common windows executable, echo.exe, is just as pipeline-blind as wordwrite.exe:
D:\code>randgen | echo
ECHO is on.
D:\code>echo blah
blah
D:\code>echo
ECHO is on.
Here we can see that the attempt to use the pipeline is effectively the same as providing no arguments for echo.exe (contrasted in the middle with behaviour when an argument is provided).
Which suggests there is something I can add the the body of my Main function in wordwrite.exe to enable pipeline-consuming behaviour like the 'more' executable does. Does anyone know how this is done?
You can read data 'from the pipeline' (effectively, the stdin stream*) by using the Console.ReadLine() method, like so:
static void Main()
{
string ouname = Console.ReadLine();
DocWrite(ouname);
}
*The pipeline is a tool to direct the output of one process (stdout) to the input (stdin) of another one. So when you think of 'consuming input from the pipeline', think 'assign stdin to a variable that you then do stuff with'.
Reference:
C# Console receive input with pipe
Related
I'm trying to make a call from one process to start another, supplying starting arguments as separate parameters in a ProcessStartInfo. The starting call uses a URL registered in Windows to find the second program, entered into FileName. I then add a string containing 4 parameters to Arguments. As I have understood it, the spaces in the string indicate the separation of the arguments.
Program 1
//Create starting information
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo() {
FileName = "urlHandle:",
Arguments = "/argA valueA /argB valueB"
};
//Start second program
System.Diagnostics.Process.Start(startInfo);
Program 2
//Print received arguments to a file
Environment.GetCommandLineArgs().ToList().ForEach(a => writer.WriteLine(a + ",\t"));
The second program starts as intended (meaning the URL is working), but the output is incomplete.
[path to .exe of second program],
urlHandle:,
It contains the path to the program, the string set as FileName , but everything put into Arguments is missing.
Does anybody have any ideas why the arguments disappear?
Note 1: If I would add the arguments into the FileName, I would receive them as one string. In order to trigger the behaviour I want in the second program, I must supply it with several parameters instead of one. I know this is possible from testing it manually from the terminal.
Note 2: I'm using .Net Framework, so trying ArgumentList from .Net Core is not an option.
After some more tests I have found the issue. The error does not lie in how I set up and use ProcessStartInfo, but rather in that I am using a custom URL protocol.
In the Windows registry one defines the number of parameters that can be sent via the URL call ("C:\[path to my .exe]" "%1"). The first argument is the Filename, and is as such the only thing sent via the protocol. In order to send more, one is required to add "%2", "%3", etc.
Note: The path itself becomes argument 0 in the receiving program, while the actual sent parameters start at argument 1 and beyond.
I'm trying to create a C# console app to do some proccess. I want to open my demo.exe and send some parameters from a .BAT file to that cosole.
I know the .bat should be something like:
demo.exe -a cclock -cc 1306 -mc 1750
But, I don't have any idea to make my .exe to get the parameters I'm sending.
This is where the arguments to Main method helps.
In an standard C# program entry method is like,
static int Main(string[] args)
Here args[] is the array of arguments passed to your executable via command line.
So in your example,
demo.exe -a cclock -cc 1306 -mc 1750
args is a string array containing following,
{"-a", "cclock", "-cc", "1306", "-mc", "1750"}
You can retrieve these value in this manner,
args[0] = "-a"
args[1] = "cclock"
args[2]= "-cc" ...... and so on
You can use these value for the rest of your code.
Remember that whatever values you pass are broken into separate string values on each occurrence of white-space. Also whatever value you pass will be taken as string. So you have to do your own validation and parsing.
Your application's Main method (typically in Program.cs) can accept a parameter string[] args, which you can access to get the command line parameters used to launch your app. Alternatively, you can also use Environment.GetCommandLineArgs() anywhere in the application to do the same thing.
I have a C# project that takes in arguments that I'm trying to run from a bat file. For an application that doesn't take arguments I just put the following inside a file called run.bat
pathname\helloworld\bin\Debug\helloworld.exe
What if my program takes in parameters, how do I adjust. When is the echo of used? any good tutorial on writing batch files? Thanks
pathname\helloworld\bin\Debug\helloworld.exe "argument 1" "argument 2" 3
using System;
public class Demo {
public static void Main(string[] args) {
foreach(string arg in args)
Console.WriteLine(arg);
}
}
I would try
#rem turn off echo - atsign is line-level way how to do it
#echo off
#rem provided your app takes three params, this is how to pass them to exe file
pathname\helloworld\bin\Debug\helloworld.exe %1 %2 %3
String arguments tend to just follow the EXE after a space. So if you have two parameters "Bob", and "is a jerk" you could write this in the .bat:
helloworld.exe Bob "is a jerk"
Bob becomes the first parameter, since it has whitespace around it. But "is a jerk" is all one because of the quotation marks. So this would be two parameters.
Your tags mention C, but I'm unclear if you actually meant you're calling this from C, the completely seperate language; you seem to be just indicating you use a batch file.
For your bat file, just add parameters after your exe path, like this:
pathname\helloworld\bin\debug\helloworld.exe param1 param2
Then, there's a method in your Program.cs file that looks like this:
[STAThread]
static void Main(string[] args)
{
Application.Run(args.Length > 0 ? new Main(args[0]) : new Main());
}
Here you can tweak the parameters that are processed and send them to your startup form.
As for the echo, that's just like a print statement, anything you want to output to the console window...
Hi I would like to make my self able to maybe define my app into CMD by that I can type program instead of program.exe kind of like how ping works for example.
I also need help with arguments.
The point of my app is to send a get request to a local server evaling PHP fetching a result from it so I can easy quick debug things and calculate things ect from CMD.
So for example I have to do.
W:\Users\example>e.exe
echo "example";
.....
example
W:\Users\example>
Tow things with the above are very annoying. I need to enter e.exe and THAN I need to enter the code to eval :-/
How could I make it so I could just do
W:\Users\example>e echo "example";
.....
example
W:\Users\example
I really would like to get this working to make use faster + more simple ! this is a programmers way to calculating math :P
EDIT:
Below is the code;
static void Main(string[] args)
{
WebClient client = new WebClient();
Console.WriteLine("...");
string input = Console.ReadLine();
string php = client.DownloadString("http://192.168.1.50/test.php?exec="+input);
Console.WriteLine(".....");
Console.WriteLine("");
Console.WriteLine(php);
Console.WriteLine("");
}
I've tried to do "+arg[0] but does nothing at start :?
Don't type ".exe" as you don't need to type it... You may want to put your e.exe some place listed in PATH environment variable (or add path to the executable to the PATH).
Main(string[] args) are arguments passed to your program - use them whatever way you want. Note that they will be split on spaces, so you may need to String.Join them back if you need all arguments as one.
You can also use Environment.CommandLine if you need access to comple not parsed command line.
This one seems trivial but the answer has eluded me for a few days now.
I have a Windows batch file, that calls a C# program to do an extra verification that cannot be done in a batch file. After the verification is complete I need to return a status and a string back to the calling shell.
Now the return value is trivial and my C# console app simply sets a return value (exit code if you will). And I thought the string will also be a piece of cake. I attempted to define a new shell variable using the:
Environment.SetEnvironmentVariable("ERR", "Some text");
This call should (and does) define a shell variable within the current process - that is the very C# process that created the variable. The value is lost as soon as the C# app terminates and the shell that created the C# app knows nothing about the variable. So... A call with no particular use... At all... Unless perhaps if I created a child process from the C3 app, perhaps it would inherit my variables.
The EnvironmentVariableTarget.Machine and EnvironmentVariableTarget.User targets for the SetEnvironmentVariable call don't solve the problem either, as only a newly created process will get these new values from the registry.
So the only working solution I can think of is:
write to stdout
write to a file
encode extra meaning into the return value
The first two are a bit ugly and the last one has its limitations and problems.
Any other ideas (how to set a shell variable in the parent process)? Maybe such shell variable modifications are a security concern (think PATH)...
Thank-you for your time.
I had the same problem as Ryan and the only thing that came to my mind as a work-around was to write a batch in error out to set the variable and to call it from the batch.
ConsoleApplication1.exe:
'put some sensible code here
'put result in variable myResult
Dim myResult As String = Guid.NewGuid().ToString("D").ToUpperInvariant()
Console.WriteLine("Normal output from the consonle app")
Console.Error.WriteLine("#ECHO OFF")
Console.Error.WriteLine("SET zzzResult={0}", myResult)
Test.cmd (the calling batch):
#ECHO OFF
:Jump to folder of batch file
PUSHD %~d0%~p0
:Define a temp file
SET zzzTempFile=%TEMP%\TMP%Random%.CMD
:Call .NET console app
ConsoleApplication1.exe 2>%zzzTempFile%
:Call the generated batch file
CALL %zzzTempFile%
:Clean up temp file
DEL %zzzTempFile%
:Clean up variable
SET zzzTempFile=
:Do something with the result
ECHO Yeah, we finally got it!
ECHO:
ECHO The value is "%zzzResult%".
ECHO:
:Clean up result variable
SET zzzResult=
:Go back to original folder
POPD
That should do the trick. And yes, I do know this is an old post and Ryan is solving other issues by now, but there might be still somebody else out there having the same problem...
What you are asking is to be able to arbitrarily write to the memory space of a running process. For good reason, this is not possible without SeDebugPrivilege.
Any of the three solutions you list will work. Stdout is the standard way to communicate with a batch script.
By the way, you're writing a Windows batch file. I'm pretty sure the ship has already sailed on "a bit ugly".
If you want to put a value of some output into a variable in the batch you can use the following construct:
FOR /F "usebackq tokens=4 delims=\[\] " %i IN (`ver`) DO set VERSION=%i
ECHO %VERSION%
Output on my OS:
6.1.7601
'usebackq' means we are using back quotes which gives the ability to use a fileset in the command quoted with double quotes. You may not need this. 'tokens' means the index in the resulting string array to select (it can be a range M-N). If you need to skip lines use 'skip=X'). 'delims' are the string separators to use (like string-Split() in .Net).
You will put your console app instead of 'ver' and adapt the delimiters and tokens to match your specific output. If you have more variables to fill you will need to make the if a bit more complex but that should make a good start.
My BAT is a bit rusty, but I think it's possible to retrieve the 'exit' code from processes you've run externally, perhaps via %ERRORLEVEL%. If that's the case, make sure to exit your program via
Environment.Exit(123); // where 123 = error code
You can't add any messages, so you'll have to do that in the .bat file.
If this isn't the case, stdout is probably the best way.
After stumbling on this myself as well recently, I came up with this approach. What I did is run the bat file using the Process class, i.e.
// Spawn your process as you normally would... but also have it dump the environment varaibles
Process process = new Process();
process.StartInfo.FileName = mybatfile.bat;
process.StartInfo.Arguments = #"&&set>>envirodump.txt";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = false;
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
// Read the environment variable lines into a string array
string[] envirolines = File.ReadAllLines("envirodump.txt");
File.Delete("envirodump.txt");
// Now simply set the environment variables in the parent process
foreach(string line in a)
{
string var = line.Split('=')[0];
string val = line.Split('=')[1];
Environment.SetEnvironmentVariable(var, val);
}
This seems to have worked for me. It's not the cleanest approach, but will work in a bind. :)