How to run a program in the same folder? - c#

So I'm learning how to develop software and I'm running into a problem. When I create a form in Visual Studio and have it open a document or open something else when I click a button I have it pointing here:
C:\User\MyName\Documents\TestApp\test.txt
What I want to know is how do I get it to where the program just looks at TestApp folder vs going through the C: Drive? Say all the files are needed for the program to run are located in the TestApp folder.

If you know that your app is going to be run from the same place every time (like a folder) you can call the GetCurrentDirectory() method. This will return a string of the current directory that your app is running from.
String pwd = GetCurrentDirectory(); //Contains something like C:\Users\Daedric\TestApp\
String finalString = Path.Combine(pwd, "test.txt"); //As per Corak

You need start file from your app folder?
Application.StartupPath
for start file
Process.Start(Application.StartupPath + #"\test.txt");

Besides above answer, following example can help you understand how Path works:
class Program
{
static void Main()
{
string[] pages = new string[]
{
"cat.aspx",
"really-long-page.aspx",
"test.aspx",
"invalid-page",
"something-else.aspx",
"Content/Rat.aspx",
"http://dotnetperls.com/Cat/Mouse.aspx",
"C:\\Windows\\File.txt",
"C:\\Word-2007.docx"
};
foreach (string page in pages)
{
string name = Path.GetFileName(page);
string nameKey = Path.GetFileNameWithoutExtension(page);
string directory = Path.GetDirectoryName(page);
//
// Display the Path strings we extracted.
//
Console.WriteLine("{0}, {1}, {2}, {3}",
page, name, nameKey, directory);
}
}
}
Sample output would be like this:
Input C:\Windows\File.txt
GetFileName: File.txt
GetDirectoryName: C:\Windows

GetCurrentDirectory is not the correct method to use as the return value can change while you application is running. You can see this by simply running the following in a console app:
Console.WriteLine(Directory.GetCurrentDirectory());
Directory.SetCurrentDirectory(#"c:\temp\");
Console.WriteLine(Directory.GetCurrentDirectory());
You can use the following to give you the assembly location:
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)

Related

Azure Batch and Determine the Path of the Downloaded EXE on the Compute Node in c#

I am using Azure Batch. I am writing a c# application that uploads files to an Azure storage account. The code then creates a pool and tasks - this is all working fine except for one thing. The task has a commandline which is executed on each node (VM) in the pool to run the c# application on each node. The app has been successfully downloaded to the node but I think my path to the exe is wrong in the code..
const string appPackageId = "ffmpeg";
const string appPackageVersion = "6.0";
...
string taskCommandLine = String.Format("cmd /c {0}\\ffmpeg\\bin\\{1}.exe -i {2} {3}", appPath, appPackageId, inputMediaFile, outputMediaFile);
// Create a cloud task (with the task ID and command line) and add it to the task list
CloudTask task = new CloudTask(taskId, taskCommandLine);
task.ResourceFiles = new List<ResourceFile> { inputFiles[i] };
...
How to I set the taskCommandLine to the correct path of the exe on the VM ?
I know there are folders created on the VM but I am not sure where the exe and support files are downloaded to...? (there must be some kind of file/folder structure)
Regards
Ian
I managed to log on to one node (VM) and see the full file path to my exe.
The code fix was...
const string appPackageId = "ffmpeg";
const string appPackageVersion = "6.0";
...
string taskCommandLine = String.Format("cmd /c {0}\\ffmpeg\\bin\\{1}.exe -i {2} {3}", appPath, appPackageId, inputMediaFile, outputMediaFile);
The above calls the DEFAULT version of the application.
Thanks
Ian

What are relative paths relative to?

Consider the following statement in a C# console application:
Process.Start("3rdParty/SomeTool.exe");
This statement starts SomeTool.exe in the 3rdParty folder relative to... what, exactly? The folder where the application's .exe resides? The current working directory (which can be changed during the application's lifetime)? Something else?
It is relative to the current working directory of your process.
You can determine your current working directory using Directory.GetCurrentDirectory() and change it using Directory.SetCurrentDirectory().
Well, why don't we find out?
Let's create a simple console application and have some fun with it:
namespace ConsoleApplication1
{
class Program
{
public static void Main()
{
Directory.CreateDirectory("Test");
Console.WriteLine($"Absolute path is: { Path.GetFullPath("Test")}");
Console.ReadLine();
}
}
}
Build it in release mode (we are deploying it after all) and put it in some accesible location. Now double click on it and see what output you get.
Absolute path is: {SomeAccesibleLocationPath}\Test
Hmmm, it seems like the relative path is relative to the directory where the executable was launched. Is this always so?
Let's build another app, we'll call it ConsoleApplication2, and play some more:
class Program
{
public static void Main()
{
Console.WriteLine($"TEST #1: {LaunchProcessAndGetAbsolutePath()}");
Console.WriteLine($"TEST #2: {LaunchProcessAndGetAbsolutePath(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments))}");
Console.ReadLine();
}
private static string LaunchProcessAndGetAbsolutePath(string workingDirectory = null)
{
var startInfo = new ProcessStartInfo(#"{SomeAccesibleLocationPath}\ConsoleApplication1.exe");
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardInput = true;
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
if (workingDirectory != null)
{
startInfo.WorkingDirectory = workingDirectory;
}
using (var p = Process.Start(startInfo))
{
var ret = p.StandardOutput.ReadLine();
p.StandardInput.WriteLine();
p.WaitForExit();
return ret;
}
}
}
If we run this, you'll see that the output is the following:
TEST #1: {MyConsoleApplication2ExecutableDirectory}\Test
TEST #2: {MyDocumentsPath}\Test
Important facts to consider:
The relative paths are always relative to the working directory.
When starting a process from another process, the default working directory is the working directory of the "parent" process, its not the directory of the launched "child" process.
When launching a process by double clicking on the executable, the working directory is set to the executable's directory.
In general, the working directory need not be the executable's directory. Your program's correctness should not rely on this condition ever.
As mentioned, it is relative to the current working directory. The value can be changed and determined via Directory.SetCurrentDirectory(), resp. Directory.GetCurrentDirectory()
Some notes:
The current working directory CAN be the folder where the executable resides; this is the default working directory if none is specified. But it can also be set to a different folder when a process is started or while running. On start either by setting the property ProcessStartInfo.WorkingDirectory when launching a process, or also by using the working directory field in the symbolic link dialog in e.g. the start menu. The latter can be done by a user. The current working directory CAN also be changed by any 3rd party library that is being loaded into the process.
Therefore relative paths in an application without checking the working directory are unreliable and usually cause unexpected behavior.

recognize if program was run from Desktop

Is there any way to recognize if the application has been run from a shortcut instead of executable file? I need to make my users to copy exe file to their desktops rather than create shortcuts to it due to personalization issues. Any ideas?
Edit: creating the installer is not an option.
I don't know if this helps, but if you want your exe file to be on the desktop, this could work:
string path = Directory.GetCurrentDirectory();
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
if (!path.Equals(desktopPath))
{
Console.WriteLine("file is not at desktop");
}
If you do have an app in the windows shared folder you can configure it to prevent execution of the applications.
Or you can provide user just with link to .bat file instead of .exe and it would do something like this (using robocopy):
robocopy \\remote\server\exe %AppData%\your\folder app.exe /XO
start %AppData%\your\folder\app.exe
And on the C# side you can just check application path and do something like this:
public class Program
{
public int Main()
{
string original_path = System.IO.Path.GetFullPath(#"\\remote\app.exe");
string current_path = System.IO.Path.GetFullPath(
System.Reflection.Assembly.GetExecutingAssembly().Location);
if(original_path == current_path){
System.IO.File.Copy(original_path, #"C:\foo\bar\app.exe", true);
System.Diagnostics.Process.Start(#"C:\foo\bar\app.exe");
return 0;
}
// Run program normally here
}
}

How to get Directory while running unit test

Hi when running my unit test I'm wanting to get the directory my project is running in to retrieve a file.
Say I have a Test project named MyProject. Test I run:
AppDomain.CurrentDomain.SetupInformation.ApplicationBase
and I receive "C:\\Source\\MyProject.Test\\bin\\Debug".
This is close to what I'm after. I don't want the bin\\Debug part.
Anyone know how instead I could get "C:\\Source\\MyProject.Test\\"?
I would do it differently.
I suggest making that file part of the solution/project. Then right-click -> Properties -> Copy To Output = Copy Always.
That file will then be copied to whatever your output directory is (e.g. C:\Source\MyProject.Test\bin\Debug).
Edit: Copy To Output = Copy if Newer is the better option
Usually you retrieve your solution directory (or project directory, depending on your solution structure) like this:
string solution_dir = Path.GetDirectoryName( Path.GetDirectoryName(
TestContext.CurrentContext.TestDirectory ) );
This will give you the parent directory of the "TestResults" folder created by testing projects.
Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName;
This will give you the directory you need....
as
AppDomain.CurrentDomain.SetupInformation.ApplicationBase
gives nothing but
Directory.GetCurrentDirectory().
Have alook at this link
http://msdn.microsoft.com/en-us/library/system.appdomain.currentdomain.aspx
Further to #abhilash's comment.
This works in my EXE's, DLL's and when tested from a different UnitTest project in both Debug or Release modes:
var dirName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location.Replace("bin\\Debug", string.Empty));
/// <summary>
/// Testing various directory sources in a Unit Test project
/// </summary>
/// <remarks>
/// I want to mimic the web app's App_Data folder in a Unit Test project:
/// A) Using Copy to Output Directory on each data file
/// D) Without having to set Copy to Output Directory on each data file
/// </remarks>
[TestMethod]
public void UT_PathsExist()
{
// Gets bin\Release or bin\Debug depending on mode
string baseA = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
Console.WriteLine(string.Format("Dir A:{0}", baseA));
Assert.IsTrue(System.IO.Directory.Exists(baseA));
// Gets bin\Release or bin\Debug depending on mode
string baseB = AppDomain.CurrentDomain.BaseDirectory;
Console.WriteLine(string.Format("Dir B:{0}", baseB));
Assert.IsTrue(System.IO.Directory.Exists(baseB));
// Returns empty string (or exception if you use .ToString()
string baseC = (string)AppDomain.CurrentDomain.GetData("DataDirectory");
Console.WriteLine(string.Format("Dir C:{0}", baseC));
Assert.IsFalse(System.IO.Directory.Exists(baseC));
// Move up two levels
string baseD = System.IO.Directory.GetParent(baseA).Parent.FullName;
Console.WriteLine(string.Format("Dir D:{0}", baseD));
Assert.IsTrue(System.IO.Directory.Exists(baseD));
// You need to set the Copy to Output Directory on each data file
var appPathA = System.IO.Path.Combine(baseA, "App_Data");
Console.WriteLine(string.Format("Dir A/App_Data:{0}", appPathA));
// C:/solution/UnitTestProject/bin/Debug/App_Data
Assert.IsTrue(System.IO.Directory.Exists(appPathA));
// You can work with data files in the project directory's App_Data folder (or any other test data folder)
var appPathD = System.IO.Path.Combine(baseD, "App_Data");
Console.WriteLine(string.Format("Dir D/App_Data:{0}", appPathD));
// C:/solution/UnitTestProject/App_Data
Assert.IsTrue(System.IO.Directory.Exists(appPathD));
}
I normally do it like that, and then I just add "..\..\" to the path to get up to the directory I want.
So what you could do is this:
var path = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + #"..\..\";
For NUnit this is what I do:
// Get the executing directory of the tests
string dir = NUnit.Framework.TestContext.CurrentContext.TestDirectory;
// Infer the project directory from there...2 levels up (depending on project type - for asp.net omit the latter Parent for a single level up)
dir = System.IO.Directory.GetParent(dir).Parent.FullName;
If required you can from there navigate back down to other directories if required:
dir = Path.Combine(dir, "MySubDir");
According to https://github.com/nunit/nunit/issues/742#issuecomment-121964506
For NUnit3 , System.Environment.CurrentDirector is never changed, so it shall be the path of solution.
Eg:
string szProjectPath = System.Environment.CurrentDirectory + #"\where\your\project\is";
I prefer fixed location rather than GetParent().
One drawback of GetParent is when build is changed from AnyCPU to x86, default path would be changed from bin\Debug to bin\x86\Debug.
Need to get another parent, and it's pain in the neck.
Also, you may still access to you test assemblies at TestContext.CurrentContext.TestDirectory and get output from TestContext.CurrentContext.WorkDirectory
Edit:
Note: There are many changes in NUnit3. I will suggest reading through the documentation about "Breaking changes"
The best solution I found was to put the file as an embedded resource on the test project and get it from my unit test. With this solution I don´t need to care about file paths.
I'm not sure if this helps, but this looks to be briefly touched on in the following question.
Visual Studio Solution Path environment variable
In general you may use this, regardless if running a test or console app or web app:
// returns the absolute path of assembly, file://C:/.../MyAssembly.dll
var codeBase = Assembly.GetExecutingAssembly().CodeBase;
// returns the absolute path of assembly, i.e: C:\...\MyAssembly.dll
var location = Assembly.GetExecutingAssembly().Location;
If you are running NUnit, then:
// return the absolute path of directory, i.e. C:\...\
var testDirectory = TestContext.CurrentContext.TestDirectory;
My approach relies on getting the location of the unit testing assembly and then traversing upwards. In the following snippet the variable folderProjectLevel will give you the path to the Unit test project.
string pathAssembly = System.Reflection.Assembly.GetExecutingAssembly().Location;
string folderAssembly = System.IO.Path.GetDirectoryName(pathAssembly);
if (folderAssembly.EndsWith("\\") == false) {
folderAssembly = folderAssembly + "\\";
}
string folderProjectLevel = System.IO.Path.GetFullPath(folderAssembly + "..\\..\\");
You can do it like this:
using System.IO;
Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, #"..\..\"));
use StackTrace
internal static class Extensions
{
public static string GetSourceDirectoryName(this Type type)
{
StackTrace stackTrace = new StackTrace(true);
foreach (var frame in stackTrace.GetFrames())
{
if (frame.GetMethod() is { } method && method.DeclaringType == type)
{
return Path.GetDirectoryName(frame.GetFileName());
}
}
throw new Exception($"未找到{type.Name}源文件目录");
}
}

Notepad Path in VS2008

In my application, I have defined the following:
public static readonly string NOTEPAD = "%windir%\\notepad.exe";
I can type in the text value of NOTEPAD into the Run command on my Win7 machine, and Notepad will open.
However, from within my Visual Studio C# project, the Write Line routine will fire every time:
if (!File.Exists(NOTEPAD)) {
Console.WriteLine("File Not Found: " + NOTEPAD);
}
Does Visual Studio not understand %windir%?
Instead of expanding the variable manually as suggested by the other answers so far, you can have the Environment class do this for you just like the Run command does:
if (!File.Exists(Environment.ExpandEnvironmentVariables(NOTEPAD))) {
Console.WriteLine("File Not Found: " + NOTEPAD);
}
See http://msdn.microsoft.com/en-us/library/system.environment.expandenvironmentvariables.aspx
When looking on my windows XP box, the location of notepad is:
%SystemRoot%\system32\notepad.exe
Not:
%windir%\notepad.exe
You also need to make sure that these environment variables are resolved correctly - use Environment.GetEnvironmentVariable and Path.Combine to build up the correct path:
string root = Environment.GetEnvironmentVariable("SystemRoot");
string path = Path.Combine(root, "system32", "notepad.exe");
Just have a closer Look at the Class Environment. The Environment Variable is SystemRoot, so you can use
Environment.GetEnvironmentVariable("windir") (or something like that)
http://msdn.microsoft.com/en-us/library/system.environment.getenvironmentvariable.aspx
The console "Resolves" the %windir% environment variable to the correct path. You need to use the above function to do the same within your application.
Use Environment.GetEnvironmentVariable("windir");
So you could declare it like this:
public static readonly string NOTEPAD = Environment.GetEnvironmentVariable("windir") + "\\notepad.exe";

Categories

Resources