Search for a specific ".exe" and open programatically [duplicate] - c#

This question already has answers here:
When running a program using Process.Start, it can't find it's resource files
(2 answers)
Closed 6 years ago.
I want my program to search a users computer for a file called "xonotic.exe" and open it. Xonotic is a video game if that helps. Inside it's parent folder it contains many other contents that .exe uses on launch.
// Prepare the process to run
ProcessStartInfo start = new ProcessStartInfo();
// Enter the executable to run, including the complete path
start.FileName = #"C:\Users\Landon\Desktop\Xonotic\xonotic.exe";
start.WindowStyle = ProcessWindowStyle.Hidden;
start.CreateNoWindow = false;
Process.Start(start);
When I run my program in vs with this code it launches "xonotic.exe" but (here's what it looks like). That is a print of the screen on launch and if it looks like the text is going off the edge of my screen its because it is; what you see is what I see.
When I exit vs and just open "xonotic.exe" as I would normally it launches perfectly. My question is why would the programmatic way and the manual way open the same .exe in two different ways? Also when I get out of the buggy xonotic and hover over the icon to see the full view it says that you have reached this menu due to missing or unlocatable content/data. (You can see what I'm talking about here). Also if this part can be resolved easily is there a way to search for the .exe without having to know the filepath? I figured something like this would be super easy, all I want to do is launch program but it has been giving me a lot of grief.

Set the WorkingDirectory property first, then you may also try to set UseShellExecute property as well if needed:
string pathToExecutable = #"C:\Users\Landon\Desktop\Xonotic\xonotic.exe";
var startInfo = new ProcessStartInfo()
{
FileName = pathToExecutable,
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = false,
WorkingDirectory = System.IO.Path.GetDirectoryName(pathToExecutable),
UseShellExecute = true
};
UPDATE:
You can search on all drive in all folders, but this would be very time consuming. Here is the code for that:
string[] drives = Directory.GetLogicalDrives();
string pathToExecutable = String.Empty;
foreach (string drive in drives)
{
pathToExecutable =
Directory
.EnumerateFiles(drive, "xonotic.exe", SearchOption.AllDirectories)
.FirstOrDefault();
if (!String.IsNullOrEmpty(pathToExecutable))
{
break;
}
}
if (String.IsNullOrEmpty(pathToExecutable))
{
// We did not find the executable.
}
else
{
// We found the executable. Now we can start it.
}

You have here 3 different question, maybe give them numbers for each question.
And about your third question-
you must have a path of the root and then you can search for all the exe files in the subfolders
string PathOfEXE = #"C:\"; //or d:\ or whatever you want to be the root
List<string> fileEntries = Directory.GetFiles(PathOfEXE , "*.exe",
System.IO.SearchOption.AllDirectories).ToList();
Directory.GetFiles(PathPractice, "*.exe", System.IO.SearchOption.AllDirectories).ToList();
System.IO.SearchOption.AllDirectories).ToList();
foreach (string fullPathfileName in fileEntries)
{
string fileName =System.IO.Path.GetFileName(fullPathfileName )
if (fileName=="xonotic.exe"){ //your code goes here
string pathToExecutable = fullPathfileName ;
}
}

Related

Process.start with application & filename as variables

Have been searching, but surprisingly could not find this specific question:
With C# I want (by clicking a button in a form) to run a certain file, with an certain application.
When using "Process.start(variable)" I can only pick one of the two.
And by using "Process.startinfo.filename" (like: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.filename?view=net-5.0) this also seems to be the case.
Isn't is possible to just combine both in some "easy" way?
Thanks.
Typically you would run a file with an application using a command argument (i.e. 'notepad.exe file.txt').
If that is possible with the application(s) you are attempting to launch, then you would simply need to set the Filename property of StartInfo to the name, if in the PATH, or the full path of the application and the Arguments property to the path of the file.
var process = new Process();
process.StartInfo.FileName = "notepad.exe";
process.StartInfo.Arguments = "C:\\{pathToFile}\\file.txt";
process.Start();
The above code would launch notepad opening file.txt. You can simply replace the FileName and Arguments with variables containing the paths to the application and file.

How to specify username when referencing directory in C# [duplicate]

This question already has answers here:
C# getting the path of %AppData%
(11 answers)
Closed 3 years ago.
Essentially I am trying to create a C# program that goes into a local directory and performs some tasks by executing a batch file. The batch file itself is located in the AppData Roaming table and requires the C# program to know the username of the computer, whatever it may be.
This is what I currently have:
static void Main()
{
ProcessStartInfo processInfo = new ProcessStartInfo("C:\\Users\\%username%\\AppData\\Roaming");
processInfo.WindowStyle = ProcessWindowStyle.Hidden;
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = true;
Process batchProcess = new Process();
batchProcess.StartInfo = processInfo;
batchProcess.Start();
}
Notice how I've added %username% but it doesn't seem to understand environmental variables.
What can I add to my code?
My code is not exactly a duplicate as the use case is entirely different, I am referencing the app data roaming directory and opening a batch located in it.
You can get the user folder for the current user like this:
string userfolder = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
And so the path you want would be like:
string path = Path.Combine(userfolder, "AppData\\Roaming");
ProcessStartInfo processInfo = new ProcessStartInfo(path);

Executing directory

I have a C# program that is running and I want to launch another executable in different directory.
I have this code on event:
string path = "Y:\Program\test.exe";
Process.Start(path);
Problem is that in order for program to work right it need to take information from settings.ini where the exe file is located but it takes settings.ini from program folder with which I am trying to launch second program. test.exe is working fine when I am opening it from its folder by double click. What could be the problem?
You need to tell the process what the working directory is via ProcessStartInfo.WorkingDirectory:
var processStartInfo = new ProcessStartInfo
{
WorkingDirectory = #"Y:\Program",
FileName = #"Y:\Program\test.exe",
};
Process.Start(processStartInfo);
Edit:
In order to get the directory from the user, you can use DirectoryInfo.FullName:
var userFileInfo = new FileInfo(userInsertedVariableHere);
var parentDirectory = userFileInfo.Directory.FullName;

Can Process.Start() take the system PATH into account?

I've been searching and experimenting for a while with this, but I have had no luck.
I am trying to make a console program to automate some tasks that I couldn't quite do with a BAT file. I want to call "signcode.exe" from the Windows SDK, the bin folder with all the tools in my system PATH, and I can call "signcode" from anywhere, but Process.Start is ignoring the path.
Current code:
System.Diagnostics.Process sign = new System.Diagnostics.Process();
sign.StartInfo.FileName = signCommand.Substring(0, signCommand.IndexOf(' ')); // signtool.exe
sign.StartInfo.Arguments = signCommand.Substring(signCommand.IndexOf(' ') + 1); // /sign /a file1 file2
// sign.StartInfo.EnvironmentVariables["Path"] = Environment.GetEnvironmentVariable("PATH"); // This doesn't work either
sign.StartInfo.UseShellExecute = false;
sign.StartInfo.RedirectStandardOutput = true;
sign.StartInfo.RedirectStandardError = true;
sign.Start(); // Throws Win32Exception - The system cannot find the file specified
I've confirmed that StartInfo.EnvironmentVariables["Path"] matches my system path, and contains the Windows SDK folder. Setting it manually doesn't work either.
I've even tried setting TempPath as shown on the MSDN page for EnvironmentVariables Property, but that didn't work either. I wonder why you would be able to set this if it has no effect.
If System.Diagnostics.Process cannot use the path, are there any other functions I could use? I'd like to see the output of the command in my console application as well.
Here is some additional debug values:
Console.WriteLine("Sign Filename = '{0}'", sign.StartInfo.FileName);
Sign Filename = 'signtool.exe'
Console.WriteLine("Sign Arguments = '{0}'", sign.StartInfo.Arguments);
Sign Arguments = '/sign /f C:\Visual Studio\Projects\MGInsight\MGInsight\APPARENTINC.pfx /t http://timestamp.comodoca.com/authenticode "C:\Visual Studio\Projects\MGInsight\MGInsight\Publish\Application Files\\MGInsight_0_9_1_85\MGInsight.exe" "C:\Visual Studio\Projects\MGInsight\MGInsight\Publish\Application Files\\MGInsight_0_9_1_85\XPXScanner.dll" "C:\Visual Studio\Projects\MGInsight\MGInsight\Publish\Application Files\\MGInsight_0_9_1_85\NetworkCalculations.dll"'
Console.WriteLine("Sign Path = '{0}'", sign.StartInfo.EnvironmentVariables["Path"]);
Sign Path = 'C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;"C:\Program Files\Intel\WiFi\bin\";"C:\Program Files\Common Files\Intel\WirelessCommon\";"C:\Program Files (x86)\cwRsync\bin";"C:\Program Files (x86)\Git\cmd";"C:\Program Files (x86)\Git\bin";"C:\Program Files (x86)\Zend\ZendServer\bin";"C:\Program Files (x86)\Zend\ZendServer\share\ZendFramework\bin";"C:\Program Files\Java\jre6\bin";"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\";"C:\Program Files\Microsoft Windows Performance Toolkit\";C:\MinGW\bin;"C:\Program Files (x86)\Microsoft\ILMerge";"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin";C:\Program Files (x86)\Nmap'
The path "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin" is where signtool.exe is, and I can run it from a command prompt by simply typing signtool, but if I run this application from the same prompt, it doesn't register that path.
Adding to mhutch's answer: It does indeed take PATH into consideration, but I have noticed you actually need to restart Visual Studio to pick up any path changes. It is kind of sneaky.
I'm pretty sure Process.Start does respect PATH.
Are you sure your signCommand value is correct?
Is the directory value in PATH specified using quotes? The docs mention that such values will not be respected.
Note that FileName can also be a full path to the executable.
If you updated PATH recently, be sure to restart Visual Studio. Environment variables are loaded at the launch of Visual Studio. Note that this applies to DEBUG mode execution.
Well, I guess the problem was related to what mhutch said, from the MSDN docs:
If you have a path variable declared in your system using quotes,
you must fully qualify that path when starting any process found
in that location. Otherwise, the system will not find the path. For
example, if c:\mypath is not in your path, and you add it using
quotation marks: path = %path%;"c:\mypath", you must fully qualify
any process in c:\mypath when starting it.
I saw that initially, but it seemed strange so I disregard it. Not sure why that's the case but it seems to be.
I tried copying signtool.exe to C:\sign\tool\bin and added that to my path, and then my code worked, so I guess because I have quotes in that path due to the spaces, I am SOL and will have to manually search the path for the windows SDK path unless there is some way to add something with spaces to the path without using quotes.
I believe you're looking for the ProcessStartInfo.WorkingDirectory property.
The StartInfo filename is actually the full path to the executable
For example, on a wrapper I have for x264, it looks like this:
x264Start.FileName = Directory.GetCurrentDirectory() + #"\Tools\x264\x264x86-r1995.exe";
I'd sense-check the code by adding a try {}, catch {} in there and writing the actual filename you are trying to call into the debug if you have an error.
Otherwise add something like the below:
if (File.exists(sign.FileName))
{
sign.Start();
}
else
{
Console.WriteLine("Can't find {0}", sign.FileName);
throw new Exception("File doesn't exist");
}
EDIT: Added a full example - this searches for CCleaner and then runs it with the "/AUTO" switch. Just tested and works fine.
// detect if 64-bit system
string programFiles = "";
if (Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE").Contains("64"))
{
Console.WriteLine("#info# x64 detected");
programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
}
else
{
Console.WriteLine("#info# x86 detected");
programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
}
// search
string[] dirs = Directory.GetDirectories(programFiles, "CCleaner", SearchOption.AllDirectories);
string[] exes = Directory.GetFiles(programFiles, "CCleaner64.exe", SearchOption.AllDirectories);
//debug only
foreach (string s in dirs)
{
Console.WriteLine(s);
}
foreach (string s in exes)
{
Console.WriteLine(s);
}
// access directly
ProcessStartInfo CCleaner = new ProcessStartInfo(exes[0], "/AUTO");
Process.Start(CCleaner);
Your code does seem to take the path into account for me.
It's hard to say what might be wrong in your case, but you might try running your command through cmd.exe:
sign.StartInfo.FileName = "cmd";
sign.StartInfo.Arguments = "/c signtool.exe ...";

Use relative Path in Microsoft Surface application?

I convert my wave file into a mp3 file by the following code:
internal bool convertToMp3()
{
string lameEXE = #"C:\Users\Roflcoptr\Documents\Visual Studio 2008\Projects\Prototype_Concept_2\Prototype_Concept_2\lame\lame.exe";
string lameArgs = "-V2";
string wavFile = fileName;
string mp3File = fileName.Replace("wav", "mp3");
Process process = new Process();
process.StartInfo = new ProcessStartInfo();
process.StartInfo.FileName = lameEXE;
process.StartInfo.Arguments = string.Format("{0} {1} {2}", lameArgs, wavFile, mp3File);
process.Start();
process.WaitForExit();
int exitCode = process.ExitCode;
if (exitCode == 0)
{
return true;
}
else
{
return false;
}
}
This works, but now I'd like to not use the absolut path to the lame.exe but a relative path. I included a lame.exe in the folder /lame/ on the root of the project. How can I reference it?
If you have rights to distribute the file with your application, then one way of doing it would be to include the .exe file as an item in your C# project, with
Build Action = None
Copy to Output Directory = Copy if newer
You can then just use
string lameEXE = #"lame.exe"
Assuming your binary app is in Debug folder and the lame folder is in the main project directory:
string lameEXE = #"..\..\lame\lame.exe
Hovewer, folders structure will be probably different in your release version.
Directly using a path relative to the application directory is a bad idea since the working directory might not be identical to the application directory. This can lead to bugs and security holes. For example you might execute files in untrusted directories.
Some cases where the working directory isn't identical to the application directory:
The user opens a file from the explorer. Then the working directory is the directory where the file is in
Depending on the settings Common Dialogs(OpenFileDialog, SaveFileDialog) change the working directory.
So you should expand it relative to the project directory. Unfortunately I know of no clean library function which does that for you. In simple cases this can be done by concatenating the relative path to the application directory:
string appDir = Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) + "\\";
const string relativePath=#"..\..\lame.exe";//Whatever relative path you want
string absolutePath=appDir+relativePath;
...
process.StartInfo.FileName =absolutePath;
...

Categories

Resources