c# start console programm (lame) and execute it - c#

I have written a c# program. Now I would like to convert .avi files in .mp3 files with lame. I've installed the command-line application. Manually it works fine. Now I would like to automate the process:
C# Application => starts Console and run "lame.exe" with the parameters.
I would like to convert more than one file. How can I do this?
Thanks

I don't know how lame works but can't you get a list of all the files you want to convert, iterate through the list with a foreach loop and run the "lame.exe" for every file?

If you can call Lame manually using CMD you should be available to do the same with this:
public void ConvertFileWithLame(string pathToLame, string fileToConvert){
// Use ProcessStartInfo class.
ProcessStartInfo startInfo = new ProcessStartInfo(pathToLame, fileToConvert);
try{
// Start the process with the info we specified.
// Call WaitForExit and then the using-statement will close.
using (Process exeProcess = Process.Start(startInfo)){
exeProcess.WaitForExit();
}
}
catch{
// Log error.
}
}
P.D: Remember that your command must be in your PATH, or indicates the path on the "/path/commandName.exe"

all you have to do is implement a foreach loop for a Directory.GetFiles, then within the foreach loop use a Process.Start to run your command. Please see below for example code:
foreach(var t in Directory.GetFiles("path"))
{
System.Diagnostics.Process.Start("cmd.exe", $"lame command here with interpolated values (t will point to full path of file)");
}

What you could try to do is see if lame.exe accepts multiple arguments for filenames, so then instead of iterating over the filenames, you can just add them in like below
Process.Start("lame.exe", "file1 file2 file3 etc");

Related

Is there a way to distinguish which batch file ran an executable?

For instance, let's say I have a folder with the following in it:
log.bat
clear.bat
new.bat
init.exe
Each .bat file calls init once or more times. I do not have access to any of the .bat files, so there is not way that I can pass a variable to init.exe. One thing to know about init is a C# application and can accept arguments.
Possibilities:
DOSKEYS - Turns out that they don't work for .bat files.
Environment Variables - I thought I could name an environment variable called init that would do something like init %~n0 to get the batch file name. Sadly, this doesn't work either.
Hacky Alias - Make a batch file named init.bat (as the .bat files call init, not init.exe). Then, in the init.bat file, I would simply put init.exe %~n0. Two things went wrong with this. First, the .bat files for some reason took init.exe priority over init.bat, and so the batch file alias wasn't even called. Secondly, the %~n0 part expanded to init, as it was called from init.bat, not the other batch files.
Am I out of luck? Or is there a hacky method that could work for this?
C:\Windows\system32>wmic process where "commandline like 'notepad'" get parentprocessid
ParentProcessId
5908
C:\Windows\system32>wmic process where "processid=5908" get commandline
CommandLine
C:\Windows\system32\cmd.exe /c ""C:\Users\User\Desktop\New Text Document (2.bat" "
Or to see all info on that batch process
wmic process where "processid=5908" get /format:list
This is not the most elegant solution, but if there's only one of those batch file running at a given time, you could try to list all the cmd.exe processes with Process.GetProcessesByName("cmd"), then find the one running one of the batch file by extracting its command line argument using this approach: https://stackoverflow.com/a/2633674/6621790
The ideas of both Remi and Noodles helped me come to this answer. In C#, I used the following to get the PID of the terminal calling the executable:
//Get PID of current terminal
//Reference: https://github.com/npocmaka/batch.scripts/blob/master/hybrids/.net/getCmdPID.bat
var myId = Process.GetCurrentProcess().Id;
var query = String.Format("SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = {0}", myId);
var search = new ManagementObjectSearcher("root\\CIMV2", query);
var results = search.Get().GetEnumerator();
if (!results.MoveNext())
{
Console.WriteLine("Error");
Environment.Exit(-1);
}
var queryObj = results.Current;
var parentId = queryObj["ParentProcessId"];
int myPid = Convert.ToInt32(parentId);

.net cmd Proces.Start() Can't Change Directory

I think my question title is already crystal clear.
I am invoking Process.Start() method by passing, "cmd.exe" as parameter. But somehow when I execute the program the command prompt that appeared has my .../bin/debug/ in my project folder as its directory. I wanted it to change to C: instead.
Can someone advise me on this?
This is the proper way to set a specified working directory for any kind of process:
var processStartInfo = new ProcessStartInfo();
processStartInfo.WorkingDirectory = #"c:\";
processStartInfo.FileName = "cmd.exe";
// set additional properties
Process proc = Process.Start(processStartInfo);
In addition to the solutions described here, cmd.exe's arguments can accept a command that will be executed immediately after the command line is opened. Also, there's the /k switch that will keep the command line running after executing the command. You can use these two things to achieve your goal:
Process.Start("cmd.exe", #"/k ""cd /d C:\""");
More info: Cmd parameters.
Edit:
Others have posted more eloquent solutions, a la Yuriy-Guts's...
Process.Start("cmd.exe", #"/k ""cd /d C:\""");
(How it works:
http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/cmd.mspx?mfr=true
... the '/k' is part of a post execution command, which keeps your cmd prompt open after the directory change.)
...if your only goal is to launch the command prompt, but I suggest wrapping them in error handling, e.g....
try
{
Process.Start("cmd.exe", #"/k ""cd /d C:\""");
}
catch(Exception e)
{
//Just in case...
Console.WriteLine(e.ToString());
string[] str=Directory.GetLogicalDrives();
Console.WriteLine( "Using C# Directory Class ,Available drives are:");
for(int i=0;i< str.Length;i++)
Console.WriteLine(str[i]);
//If fatal
//Environment.Exit(1)
}
Further, if you're doing other stuff in C:/ I believe the below solution is the most transparent.
Short Answer:
Your IDE is automatically dumping you in the debug directory, because that is the path it's programmed to place your executable. Your executable's point of reference to System objects is the folder it lives in. You'll have to use absolute indexing to get to the root location C: you want to go to.
Long Answer with Code, Self Help Advice
Try Google first, for basics:
https://www.google.com/search?q=change+directory+c%23
First result:
http://www.c-sharpcorner.com/UploadFile/chandrahundigam/WorkingWithDirectory07022005012852AM/WorkingWithDirectory.aspx
(It's poorly formatted, but contains good content.)
To paraphrase:
Add to your code:
using System;
using System.IO;
using System.MarshalByRefObject;
class DoStuff
{
char driveLetter;
...
void Initialize()
{
try
{
Directory.SetCurrentDirectory( string(driveLetter)+string(#":\");
}
catch(FileNotFoundException e)
{
//Just in case...
Console.WriteLine(e.ToString());
string[] str=Directory.GetLogicalDrives();
Console.WriteLine( "Using C# Directory Class ,Available drives are:");
for(int i=0;i< str.Length;i++)
Console.WriteLine(str[i]);
//If fatal
//Environment.Exit(1)
}
Process.Start("cmd.exe");
//Do whatever else you need to do in C:/ ...
}
Note I am new to C# and did not explicitly know how to do this, but it was relatively trivial to figure out. C# experts feel free to correct me if there's any flaws in my approach.
var process = Process.Start(new ProcessStartInfo
{
WorkingDirectory = "C:\\",
FileName="cmd.exe"
});

How to send series of commands to a command window process?

We have a few commands(batch files/executables) on our network path which we have to call to initialize our 'development environment' for that command window. It sets some environmental variables, adds stuff to the Path etc. (Then only whatever working commands we type will be recognized & I don't know what goes inside those initializing commands)
Now my problem is, I want to call a series of those 'working commands' using a C# program, and certainly, they will work only if the initial setup is done. How can I do that? Currently, I'm creating a batch file by scratch from the program like this for example:
file.Writeline("InitializationStep1.bat")
file.Writeline("InitializeStep2.exe")
file.Writeline("InitializeStep3.exe")
Then the actual commands
file.Writeline("Dowork -arguments -flags -blah -blah")
file.Writeline("DoMoreWork -arguments -flags -blah -blah")
Then finally close the file writer, and run this batch file.
Now if I directly execute this using Process.<strike>Run</strike>Start("cmd.exe","Dowork -arguments"); it won't run.
How can I achieve this in a cleaner way, so that I have to run the initialization commands only once? (I could run cmd.exe each time with all three initializers, but they take a lot of time so I want to do it only once)
As #Hakeem has pointed out, System.Diagnostic.Process does not have a static Run method. I think you are referring to the method Start.
Once you have completed building the batch file, then simply execute it using the following code,
Process p = new Process();
p.StartInfo.FileName = batchFilePath;
p.StartInfo.Arguments = #"-a arg1 -b arg2";
p.Start();
Note that the # symbol is required to be prefixed to the argument string so that escape sequence characters like \ are treated as literals.
Alternative code
Process.Start(batchFilePath, #"-a arg1 -b arg2");
or
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.FileName = batchFilePath;
processStartInfo.Arguments = #"-a arg1 -b arg2";
Process.Start(processStartInfo);
More information
Process.Start method
Example of multi command batch file
dir /O
pause
dir
pause
Save this file as .bat and then execute using the Start method. In this case you can specify the argument with the command in the batch file itself (in the above example, the /O option is specified for the dir command.
I suppose you already have done the batch file creation part, now just append the arguments to the commands in the batch file.
Redirecting Input to a process
Since you want to send multiple commands to the same cmd process, you can redirect the standard input of the process to the take the input from your program rather than the keyboard.
Code is inspired from a similar question at: Execute multiple command lines with the same process using C#
private string ProcessRunner()
{
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe");
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.UseShellExecute = false;
Process process = Process.Start(processStartInfo);
if (process != null)
{
process.StandardInput.WriteLine("dir");
process.StandardInput.WriteLine("mkdir testDir");
process.StandardInput.WriteLine("echo hello");
//process.StandardInput.WriteLine("yourCommand.exe arg1 arg2");
process.StandardInput.Close(); // line added to stop process from hanging on ReadToEnd()
string outputString = process.StandardOutput.ReadToEnd();
return outputString;
}
return string.Empty;
}
The method returns the output of the command execution. In a similar fashion, you could also redirect and read the StandardOuput stream of the process.
The Process.Run method that you mentioned, is that from the Process class in System.Diagnostics namespace? AFAIK, the Process type doesn't have either a static or instance method named Run. If you haven't already I'd try with the Start method on Process, either instance or static

Issues about files or folders in use: get the name of another Process that use file or folder

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.

system() to c# without calling cmd.exe

how to translate system("") to C# without calling cmd.exe?
edit: i need to throw something like "dir"
If I correctly understood your question, you're looking for Process.Start.
See this example (from the docs):
// Opens urls and .html documents using Internet Explorer.
void OpenWithArguments()
{
// url's are not considered documents. They can only be opened
// by passing them as arguments.
Process.Start("IExplore.exe", "www.northwindtraders.com");
// Start a Web page using a browser associated with .html and .asp files.
Process.Start("IExplore.exe", "C:\\myPath\\myFile.htm");
Process.Start("IExplore.exe", "C:\\myPath\\myFile.asp");
}
Edit
As you said you needed something like the "dir" command, I would suggest you to take a look at DirectoryInfo. You can use it to create your own directory listing. For example (also from the docs):
// Create a DirectoryInfo of the directory of the files to enumerate.
DirectoryInfo DirInfo = new DirectoryInfo(#"\\archives1\library");
DateTime StartOf2009 = new DateTime(2009, 01, 01);
// LINQ query for all files created before 2009.
var files = from f in DirInfo.EnumerateFiles()
where DirInfo.CreationTimeUtc < StartOf2009
select f;
// Show results.
foreach (var f in files)
{
Console.WriteLine("{0}", f.Name);
}
As other folks noted, it's Process.Start. Example:
using System.Diagnostics;
// ...
Process.Start(#"C:\myapp\foo.exe");
I need to throw something like "dir"
If you need to run DIR, then you need to call cmd.exe as dir is internal to cmd.exe
Not sure if I understand your question. Are you looking for Process.Start?
Do you actually want the equivalent? You may not depending on what exactly you're trying to do.
For example calling copy from the command line has a C# equivalent itself, File.Copy, for dir there's a whole Directory class for getting info (these are a quick 2 out of thousands of examples). Depending on what you're after, C# most likely has a library/function for the specific command you're trying to run, usually a more robust method as well, instead of a global handler.
If the global "invoke this" is what you're after, then as the other answers suggest, using the System.Diagnostics.Process class is your best bet.
If you want to execute a command-line (cmd.exe) command, such as "dir" or "time" or "mkdir", pass the command as an argument to cmd.exe with the flag /C.
For example,
cmd.exe /C dir
or
cmd.exe /C mkdir "New Dir"

Categories