C# Subcommands within console application - c#

I would like to have commands within the executable itself for example:
shorten http://stackoverflow.com/
and the url will be parsed as an argument, if I set it to return the argument, it should return me http://stackoverflow.com/
Another example is
foo bar
and it will check what is the main command which is foo and subcommands under it, which is bar and will execute the command.
This should be done within the executable and not calling the executable in the directory. I would like to have multiple custom commands within the executable and not create one for each command.
I understand how to have arguments if each command was an executable, but I would like a few commands and subcommands within 1 executable. Is this possible?
EDIT:
This is what I want:
static void Main(string[] args)
{
for (int i = 0; i < args.Length; i++)
{
if (args[i] == "short")
{
Console.WriteLine(args[i + 1]);
}
}
Console.Read();
}
which will return me the arguments of short. So if I type short link it will return me link.
However this will only work if I call the executable through the command line like C:\Path\ConsoleApplication1.exe not if I open up the application and type short link, which will not return me anything and close.
How do I make it work when I open up the application and type it in?

You can use Console.ReadLine:
var input = Console.ReadLine();
To get command and argument(s) use String.Split :
var command = input.Split()[0];
var argument1 = input.Split()[1];
etc.

Related

Can't input data with Console.ReadLine

I'm trainning in C# alone for this moment, and encounter my first problem.
I use VSCode as IDE.
What I Am Try To Do
Create two functions, the first, data like name and return it. the second return full name. All in one in a class.
What I Do From Here
using System
namespace Helloworld
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
Console.WriteLine(p.getFullName())
}
public string getName(string message)
{
string? name;
do
{
Console.WriteLine(message);
name = Console.ReadLine();
}
while (string.IsNullOrEmpty(firstName)); // For avoid null or empty string, I'm not found another solution.
return name;
}
public string getFullName()
{
const string firstNameMessage = "Enter your first name: ";
const string lastNameMessage = "Enter yout last name: ";
string result = $"{getName(firstNameMessage)} {getName(lastNameMessage)}"
return result;
}
}
}
I Have Encountered Any Problems
1 - When I launch the command dotnet run, my program follow instructions while the first Console.WriteLine. When I type an random name in VSCode's Debug Console. Nothing happens...
My questions: Does this problem come my code ? Am I using an unsuitable IDE ? Or Am I not working with the good VSCode's Tools ?
2 - When I want restart or build I have a message like The process cannot access the file C:\Users\Username\ Documents\Work\learningCSharp\bin\Debug\net6.0\learningCSharp.dll' because it is being used by another process.
My question: How I kill process which use my DLL file ?
I solve all my problem finally alone. I read here the solution.
I'm posting the solution anyway.
in your launch.json replace "console": "internalConsole" by "console": "integratedTerminal.
If you are senior in C#, Can you tell us if is it same for all IDEs ?

How to setup multiple launch arguments that could be added via batch file launch (C#)

I need to create a console application that can take multiple different launch arguments (which can be added using the batch file). I so far tried this, but it seems like I don't understand it correctly.
Code:
static void Main(string[] args)
{
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.Arguments = LaunchArguments.Operation_AddLocale;
processStartInfo.Arguments = LaunchArguments.Operation_CreateTextFile;
processStartInfo.UseShellExecute = false;
if (processStartInfo.Arguments == LaunchArguments.Operation_CreateTextFile)
{
Console.WriteLine("Creating a text file.");
File.Create("file.txt");
Console.Write("Done!");
}
if (processStartInfo.Arguments == LaunchArguments.Operation_AddLocale)
{
if (Directory.Exists("locale"))
{
try
{
File.Create("locale.txt");
}
catch (Exception ex)
{
Console.WriteLine("An error occured: ");
Console.Write(ex.ToString());
Console.Write(ex.Message.ToString());
Console.ReadLine();
}
}
else
{
Console.WriteLine("Incorrect Input, quitting");
Console.WriteLine("This application only accepts arguments of type '-CreateTextFile; -AddLocale'");
Console.Beep();
Console.ReadLine();
}
}
I made a constant string 'Operation_AddLocale' and 'Operation_CreateTextFile'.
by batch file:
#echo off
start SW_project_generator.exe -AddLocale
This all should do that if I launch the application via this batch file, it will do the operations that are in the 'if (processStartInfo.Arguments == LaunchArguments.Operation_AddLocale)' and if the batch file would add the '-CreateTextFile' argument, it will go to the 'if (processStartInfo.Arguments == LaunchArguments.Operation_CreateTextFile)'.
However, when I launch this app via my batch file, it will always just use the first argument (which is the '-CreateTextFile') and creates a text file and then goes to the else option.
Application's Output:
Creating a text file.
Done!Incorrect Input, quitting
This application only accepts arguments of type '-CreateTextFile; -AddLocale;'
Alright so, my question is, how to make this working, that if I create a batch file give it a argument of type '-AddLocale' it will just go to the 'AddLocale' operations and if I give it something else that is defined in the app, like the 'CreateTextFile', it'll go to it's 'if' statement. And finnaly, if the launch argument will be equal to nothing or wrong one, it'll show the quitting message.
Thanks everyone for help.

How to get the Full Path of a File?

I try to get the Full Path of a File. ie. calc
Input: calc
Expected output: C:\WINDOWS\system32\calc.exe
I could find out how to do it with PowerShell:
(Get-Command calc).Source
Or with CommandLine:
where.exe calc
But unfortunately I can not get it done with C#.
The documentation for Get-Command says:
Get-Command * gets all types of commands, including all of the non-PowerShell files in the Path environment variable ($env:Path), which it lists in the Application command type.
So we will need to get the Path environment variable and iterate over the directories it lists, looking for files with extensions that indicate the file is a program, for example "*.com" and "*.exe".
The problem with the Path environment variable is that it can become polluted with non-existent directories, so we will have to check for those.
The case of the filename and extension don't matter, so case-insensitive comparisons need to be made.
static void ShowPath(string progName)
{
var extensions = new List<string> { ".com", ".exe" };
string envPath = Environment.GetEnvironmentVariable("Path");
var dirs = envPath.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string d in dirs.Where(f => Directory.Exists(f)))
{
foreach (var f in (Directory.EnumerateFiles(d).
Where(thisFile => extensions.Any(h => Path.GetExtension(thisFile).Equals(h, StringComparison.InvariantCultureIgnoreCase)))))
{
if (Path.GetFileNameWithoutExtension(f).Equals(progName, StringComparison.InvariantCultureIgnoreCase))
{
Console.WriteLine(f);
return;
}
}
}
Console.WriteLine("Not found.");
}
static void Main(string[] args)
{
ShowPath("calc");
Console.ReadLine();
}
Output:
C:\WINDOWS\system32\calc.exe
There is always the possibility that the current user does not have permission to list the files from somewhere in the path, so checks should be added for that. Also, you might want to use StringComparison.CurrentCultureIgnoreCase for the comparison.
You can get the Pathenvironment variable, split it with ; as delimiter and loop over that result. Then, check if the file path + #"\" + name + ".exe" exists.
var findMe = "calc";
var pathes = Environment.GetEnvironmentVariable("Path").Split(';');
foreach (var path in pathes)
{
var testMe = $#"{path}\{findMe}.exe";
if (File.Exists(testMe))
{
Console.WriteLine(testMe);
}
}
This outputs :
C:\WINDOWS\system32\calc.exe
I do not know about any way of doing that exact thing from C# either. However the paths are usually well known and can be retreived via the SpecialFolders Enumeration:
using System;
using System.Diagnostics;
using System.IO;
namespace RunAsAdmin
{
class Program
{
static void Main(string[] args)
{
/*Note: Running a batch file (.bat) or similar script file as admin
Requires starting the interpreter as admin and handing it the file as Parameter
See documentation of Interpreting Programm for details */
//Just getting the Absolute Path for Notepad
string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
string FullPath = Path.Combine(windir, #"system32\notepad.exe");
//The real work part
//This is the programm to run
ProcessStartInfo startInfo = new ProcessStartInfo(FullPath);
//This tells it should run Elevated
startInfo.Verb = "runas";
//And that gives the order
//From here on it should be 100% identical to the Run Dialog (Windows+R), except for the part with the Elevation
System.Diagnostics.Process.Start(startInfo);
}
}
}
I did not just use System (37) back then, as I wrote it when x32/x86 Systems were still a thing. You would need to check how it resolves nowadays.
Note that most of those paths are duplicated in the PATH System Variable, so you could look it up: https://www.architectryan.com/2018/03/17/add-to-the-path-on-windows-10/
Path Variables in turn go back to the old DOS days. Basically if you gave the Commandline a command/filename it would try the build-in commands, then Executables in the current working Directory (.bat, .com, .exe), and then go look over the path directories to again look for executeables. And only if all that failed, would it complain.
I finally tried to combine all three answers and came up with this:
I post it here in case someone has the same problem.
public static string[] GetPathOf(string cmd)
{
var list = new List<string>();
list.AddRange(Environment.GetEnvironmentVariable("path", EnvironmentVariableTarget.Machine).Split(';'));
list.AddRange(Environment.GetEnvironmentVariable("path", EnvironmentVariableTarget.Process).Split(';'));
list.AddRange(Environment.GetEnvironmentVariable("path", EnvironmentVariableTarget.User).Split(';'));
list = list.Distinct().Where(e=>Directory.Exists(e)).SelectMany(e=> new DirectoryInfo(e).GetFiles()).Where(e=>Regex.IsMatch(e.Name,"(?i)^"+cmd+"\\.(?:exe|cmd|com)")).Select(e=>e.FullName).ToList();
return list.ToArray();
}

Call Process.Start once and subsequent calls without starting new process

I have a c# method that sets the brightness of all monitors using a third-party executable.I call it using the method below. The problem is that I need to call this executable with different parameters to change the brightness. But my code creates a new process each time I call SetBrightness. How does one use an exiting process that is already running, and pass different parameters to execute it again? I don't see any method inthe Process class that makes this easy.
Edit: When I run this exe using the command line, the process stays open in the Windows System Tray, and I see the process is running in Task Manager. When I run my code, however, I sometimes see two instances of the exe in Task Manager. So I guess what I'm trying to do is always call the same instance but with different parameters. Restarting the exe every time is not an option because it takes too long to start up each time.
public bool SetBrightness(short monitorStartIndex, short monitorEndIndex, short brightness)
{
// Construct the parameter string used by the tool so that it updates all monitors in one call.
// Example "1 b75 2 b75" will set brightness to 75 for monitors 1 and 2.
StringBuilder arguments = new StringBuilder();
for (int i = monitorStartIndex; i <= monitorEndIndex; i++)
{
arguments.Append(i).Append(" ");
arguments.Append(string.Format("b{0}", brightness)).Append(" ");
}
var path = Path.GetDirectoryName(Environment.GetCommandLineArgs()[1]);
var final = Path.Combine(path, "External Assemblies\\ClickMonitorDDC_3_9.exe");
var p = new Process
{
StartInfo =
{
FileName = final,
Arguments = arguments.ToString(),
UseShellExecute = false,
RedirectStandardOutput = true
}
};
try
{
p.Start();
}
catch (Exception e)
{
Trace.TraceError("Error while changing the brightness using ClickMonitorDDC_3_9.exe. Inner Exception : " + e.Message);
return false;
}
return true;
}
You will want to use the WaitForExit method available in the Process class. If you attempt to use the third-party executable from the command line using the same type of parameters as you have in your code, it should return to the prompt as it is setting the parameters and exiting. You would just call your method whenever you want to change the brightness and wait until it's set and exit out.
Change your code as seen below:
try
{
p.Start();
p.WaitForExit()
}

Running EXE file form CMD made with C#

I'm newbie in c# and I'm stuck on this conundrum
I've recently made a Gui Program in c# that include several tabs and some other stuff
Now I want to make one of the tabs as a exe file that i would be able to run via cmd .
the entire code i want to put in file is comprised of one class
something like that
class E2p
{
main program( take 2 arg )
{some Code
make a CSV file in appDirectory
}
I want to turn it to EXE file so I can run it from CMD like that
E2pChck.exe -i 10.0.0.127 -r RandomWord
How can I do it ??
I'm not 100% sure what you're after, but I think you mean that you want to be able to run your exe from the command line with a couple of arguments.
These arguments are passed into your application in the Main method, which you'll find in Program.cs. In a command line application the arguments parameter is provided for you, but you can add it to a Windows Forms application.
class Program
{
static void Main(string[] args)
{
string firstArgument;
string secondArgument;
const int NumberOfArgumentsRequired = 2;
// you can access the arguments using the args array,
// but we need to make sure we have enough arguments,
// otherwise we'll get an index out of range exception
// (as we're trying to access items in an array that aren't there)
if (args.Length >= NumberOfArgumentsRequired)
{
firstArgument = args[0];
secondArgument = args[1];
}
else
{
// this block will be called if there weren't enough arguments
// it's useful for setting defaults, although that could also be done
// at the point where the strings were declared
firstArgument = "This value was set because there weren't enough arguments.";
secondArgument = "So was this one. You could do this at the point of declaration instead, if you wish.";
}
string outputString = string.Format("This is the first: {0}\r\nAnd this is the second: {1}", firstArgument, secondArgument);
Console.WriteLine(outputString);
Console.ReadKey();
}
}
If you typed E2pChck.exe -i 10.0.0.127 -r RandomWord into the command line then:
args[0] would be "-i"
args[1] would be "10.0.0.127"
args[2] would be "-r"
args[3] would be "RandomWord"
I know this doesn't technically answer the question, but the OP asked for an example of starting a process.
You would put this code in your button handler (probably on a separate thread so your UI doesn't hang)
System.Diagnostics.ProcessStartInfo csvGenerationProcInfo = new System.Diagnostics.ProcessStartInfo();
csvGenerationProcInfo.Arguments = "-i 10.0.0.127 -r RandomWord";
csvGenerationProcInfo.FileName = "E2pChck.exe";
System.Diagnostics.Process csvGenerationProc = System.Diagnostics.Process.Start(csvGenerationProcInfo);
csvGenerationProc.WaitForExit();
Or, if you don't need all the features of ProcessStartInfo you can just use:
System.Diagnostics.Process.Start("E2pChck.exe", "-i 10.0.0.127 -r RandomWord");
Hope that helps!

Categories

Resources