Get directory where executed code is located - c#

I know that in the same directory where my code is being executed some files are located. I need to find them and pass to another method:
MyLib.dll
Target1.dll
Target2.dll
Foo(new[] { "..\\..\\Target1.dll", "..\\..\\Target2.dll" });
So I call System.IO.Directory.GetFiles(path, "*.dll"). But now I need to get know the path:
string path = new FileInfo((Assembly.GetExecutingAssembly().Location)).Directory.FullName)
but is there more short way?

You may try the Environment.CurrentDirectory property. Note that depending on the type of application (Console, WinForms, ASP.NET, Windows Service, ...) and the way it is run this might behave differently.

Environment.CurrentDirectory returns the current directory, not the directory where the executed code is located. If you use Directory.SetCurrentDirectory, or if you start the program using a shortcut where the directory is set this won't be the directory you are looking for.
Stick to your original solution. Hide the implementation (and make it shorter) using a property:
private DirectoryInfo ExecutingFolder
{
get
{
return new DirectoryInfo (
System.IO.Path.GetDirectoryName (
System.Reflection.Assembly.GetExecutingAssembly().Location));
}
}

Related

Search and return path of given folder name (Windows and Linux)

I want to get the path of an existing folder SeleniumTestData inside the solution.
Why? My selenium tests should create at start of the test, temporary folder which are being ignored in Git, so each of my colleagues has their own TestData folders for their own TestExecutions on their machine (Like Save/Load Cookies) and dont pull TestData from other colleagues.
The folder where i want to create other folder by code is named SeleniumTestData folder and is inside:
..\source\repos\CoffeeTalk\src\Tests
I cant hardcore the path, as i'm facing here 2 problems:
Tests are being ran in Windows and Docker (Linux)
Co-Workers are saving the solution in different windows directories
Now i need a general solution which will work in any of these cases.
I already tried: var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());
which returned: D:\source\repos\CoffeeTalk\src\Tests\Web\CoffeeTalk.Client.Selenium.Tests\bin\Debug\net6.0
and then tried to navigate back by executing the codeline currentDirectory?.Parent about 5-6 times. But its then again different in Linux.
Now im looking for a clean way. I suppose the first way i did it was not wrong by getting the CurrentDirectory and navigate back.
I already searched for solutions using stackoverflow, google. Either the solutions are outdated or im not getting the result im expecting.
Here i have the method which creates the folder, but im struggling with the GetFolderPath method.
public static void CreateFolder(string folderName, string newFolderName)
{
var folderPath = GetFolderPath(folderName);
var pathCombined = Path.Combine(folderPath, newFolderName);
var folderExists = Directory.Exists(pathCombined);
if (folderExists) return;
Directory.CreateDirectory(pathCombined);
}
Directory.GetCurrentDirectory isn't the directory with your executable file. It's something else (I don't know) that by the way depends on the OS. You should use this instead:
using System.Reflection;
// ...
string exeDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase);
And then go up the folders hierarchy as you want:
string neededFolder = new DirectoryInfo(exeDirectory).Parent.Parent.Parent.ToString(); // Or more "Parent" calls
As far as I know, it works on different OSs.

Create a folder without read-only using c# [duplicate]

I was successfully able to remove read only attribute on a file using the following code snippet:
In main.cs
FileSystemInfo[] sqlParentFileSystemInfo = dirInfo.GetFileSystemInfos();
foreach (var childFolderOrFile in sqlParentFileSystemInfo)
{
RemoveReadOnlyFlag(childFolderOrFile);
}
private static void RemoveReadOnlyFlag(FileSystemInfo fileSystemInfo)
{
fileSystemInfo.Attributes = FileAttributes.Normal;
var di = fileSystemInfo as DirectoryInfo;
if (di != null)
{
foreach (var dirInfo in di.GetFileSystemInfos())
RemoveReadOnlyFlag(dirInfo);
}
}
Unfortunately, this doesn't work on the folders. After running the code, when I go to the folder, right click and do properties, here's what I see:
The read only flag is still checked although it removed it from files underneath it. This causes a process to fail deleting this folder. When I manually remove the flag and rerun the process (a bat file), it's able to delete the file (so I know this is not an issue with the bat file)
How do I remove this flag in C#?
You could also do something like the following to recursively clear readonly (and archive, etc.) for all directories and files within a specified parent directory:
private void ClearReadOnly(DirectoryInfo parentDirectory)
{
if(parentDirectory != null)
{
parentDirectory.Attributes = FileAttributes.Normal;
foreach (FileInfo fi in parentDirectory.GetFiles())
{
fi.Attributes = FileAttributes.Normal;
}
foreach (DirectoryInfo di in parentDirectory.GetDirectories())
{
ClearReadOnly(di);
}
}
}
You can therefore call this like so:
public void Main()
{
DirectoryInfo parentDirectoryInfo = new DirectoryInfo(#"c:\test");
ClearReadOnly(parentDirectoryInfo);
}
Try DirectoryInfo instead of FileInfo
DirectoryInfo di = new DirectoryInfo(#"c:\temp\content");
di.Attributes = FileAttributes.Normal;
To clean up attrbutes on files-
foreach (string fileName in System.IO.Directory.GetFiles(#"c:\temp\content"))
{
System.IO.FileInfo fileInfo = new System.IO.FileInfo(fileName);
fileInfo.Attributes = FileAttributes.Normal;
}
The dialog just works in a fairly bizarre way. It always shows up the way you see it in your screen shot, whatever the state of the ReadOnly attribute. The checkbox is in the 'indetermined' state. You have to click it and either clear or check it to make it perform its action. And in spite of the prompt text (but not the hint next to the checkbox), it only changes the ReadOnly attribute on the files in the directory, not the directory itself.
Use the attrib command line command to see what is really going on. In all likelihood, your code fails because the directory contains files that have their ReadOnly attribute set. You'll have to iterate them.
The read-only flag on directories in Windows is actually a misnomer. The folder does not use the read-only flag. The issue is going to be with the customization. The flag is used by Windows to identify that there are customizations on the folder.
This is an old post, with an issue that is sunsetting, but, figured people might still run into it, as it is pretty annoying when you hit it.
Microsoft's Explanation
IEnumerable / Lambda solution for recursively removing readonly attribute from directories and files:
new DirectoryInfo(#"some\test\path").GetDirectories("*", SearchOption.AllDirectories).ToList().ForEach(
di => {
di.Attributes &= ~FileAttributes.ReadOnly;
di.GetFiles("*", SearchOption.TopDirectoryOnly).ToList().ForEach(fi => fi.IsReadOnly = false);
}
);
Set the Attributes property on the original dirInfo:
dirInfo.Attributes = FileAttributes.Normal;
FileSystemInfo[] sqlParentFileSystemInfo = dirInfo.GetFileSystemInfos();
foreach (var childFolderOrFile in sqlParentFileSystemInfo)
{
RemoveReadOnlyFlag(childFolderOrFile);
}
Just in case any one happens across this later...
ALL of the other answers posted before mine are either wrong or use unnecessary recursion.
First of all the "Read Only" check box in the property dialog of windows always has the tri-state marker for folders. This is because the folder itself is not read only but the files inside can be.
If you want to set/unset read only flag for ALL files. you can do it simply as follows:
void SetReadOnlyFlagForAllFiles(DirectoryInfo directory, bool isReadOnly)
{
// Iterate over ALL files using "*" wildcard and choosing to search all directories.
foreach(FileInfo File in directory.GetFiles("*", SearchOption.All.Directories))
{
// Set flag.
File.IsReadOnly = isReadOnly;
}
}
I see that #DotnetDude said in comments that solutions of guys don't work. To my mind it is happens because guys don't mentioned that need to use File.SetAttributes method to apply new attributes.
This may or may not be directly related, but the root issue in your case may be caused by the underlying files. For example, I ran into this issue trying to delete a directory:
System.IO.Directory.Delete(someDirectory, true)
This results in "Access to the path 'blah' is denied". To resolve this underlying problem, I removed the read-only attribute on sub-files and was then able to remove the parent directory. In my case, I was using powershell, so you can use the .NET equivalent.
dir -r $PrePackageDirectory |% {if ($_.PSIsContainer -ne $true){$_.IsReadOnly = $false}}
Shell("net share sharefolder=c:\sharefolder/GRANT:Everyone,FULL")
Shell("net share sharefolder= c:\sharefolder/G:Everyone:F /SPEC B")
Shell("Icacls C:\sharefolder/grant Everyone:F /inheritance:e /T")
Shell("attrib -r +s C:\\sharefolder\*.* /s /d", AppWinStyle.Hide)
this code is working for me.. to share a folder to every one with read and write permission

Simple how to make a application directory path

Ok I know it is simple but I have forgotten how to do it. I want to create a folder in a directory but if I do "C:\Users\George\AppData\Roaming\myprogram" this only woks for me it will not work with everybody that I send it to
I tried "C:\Users\[User]\AppData\Roaming\Myprogram" but it says access denied so what can I use to make this work for everyone?
Here is the segment of code I am using to do this if it helps :
public Form2()
{
InitializeComponent();
Directory.CreateDirectory(#"C:\Users\[User]\AppData\Roaming\SkypeAdmin");
Directory.CreateDirectory(#"C:\Users\[User]\AppData\Roaming\SkypeAdmin\mem");
}
and I tried :
public Form2()
{
InitializeComponent();
Directory.CreateDirectory(#"C:\Users\User\AppData\Roaming\SkypeAdmin");
Directory.CreateDirectory(#"C:\Users\User\AppData\Roaming\SkypeAdmin\mem");
}
Your approach predefines a path for the folder so the location would only be valid for you and anyone else who has the specified loacation.
You can try this instead:
public Form1()
{
InitializeComponent();
DirectoryInfo di = Directory.CreateDirectory(skypeAdminPath);
DirectoryInfo di2 = Directory.CreateDirectory(skypeMemPath);
}
string skypeAdminPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "SkypeAdmin\\";
string skypeMemPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "SkypeAdmin\\mem\\";
Using Path.Combine:
string skypeAdminPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "SkypeAdmin\\");
string skypeMemPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "SkypeAdmin\\mem\\");
You can use CommonAppDataPath
string path = Application.CommonAppDataPath;//for folder with version
this may change every version of your application, if you dont want this behavior and you want Same Directory for all the version of your App you can use this
string path = Directory.GetParent(Application.CommonAppDataPath);
the directory will be readily available when your code executes above line, this is created on demand.
Note:
I assume that you want to create some directory for all users and use it. instead of doing so you can used shared Directory and access it from any user.
This is how a sample CommonAppData path look like
C:\ProgramData\MyCompany\WindowsFormsApplicationTest\1.0.0.0
Typically CommonAppDataBase\CompanyName\ProductName\Version
You need to use Enviroment.GetFolderPath for that:
Directory.CreateDirectory(Path.Combine(
Enviroment.GetFolderPath(Enviroment.SpecialFolder.ApplicationData),
#"\SkypeAdmin\"));
Directory.CreateDirectory(Path.Combine(
Enviroment.GetFolderPath(Enviroment.SpecialFolder.ApplicationData),
#"\SkypeAdmin\mem\"));
That does exactly what (I think) you mean to do. Your solution doesn't work because there is no folder called [User] or User in the system, so you can't create a folder in there, and Directory.CreateDirectory doesn't replace that for the user path for you.

How to get the exact path of notepad.exe in order to associate a file extension

I need to associate a file extension I have created “.rulog” with notepad.exe as part of a setup project installation for a windows 7 machine (it’s here since we require admin privileges to write to the registry).
Basically I need to obtain programmatically the exact path of the notepad.exe. Now, I understand that it typically lives in C:\Windows\system32. This is part of PATH system environment variable, so I guess I could loop through all the PATH variables and test if “notepad.exe” exists by combining “notepad.exe” with the current path using File.Exists. However this feels very clumsy.
Essentially I need to add an entry to
Computer\HKEY_CLASSES_ROOT\.rulog\shell\open\command\
with the value of the path of notepad.
Incidentally I can see that .txt in:
Computer\HKEY_CLASSES_ROOT\.txt\ShellNew
has a value for ItemName of
“#%SystemRoot%\system32\notepad.exe,-470”
Perhaps I can just copy this value? Or is this dangerous?(e.g. does not exist).
You can use:
Environment.GetEnvironmentVariable("windir") + "\\system32\\notepad.exe";
Or even easier:
Environment.SystemDirectory + "\\notepad.exe";
That way it doesn't matter which drive the os is on.
Copying the value with %systemroot% should be just fine. If it works for the OS, it should work for you!
Fool-proof solution:
string NotepadPath = Environment.SystemDirectory + "\\notepad.exe";
if (System.IO.File.Exists(NotepadPath))
{
Microsoft.Win32.Registry.SetValue("HKEY_CLASSES_ROOT\\.rulog\\shell\\open\\command\\", "", NotepadPath + " %1");
}
else
{
//do something else or throw new ApplicationException("Notepad not found!");
}

How to reference the C:\Users\Public directory programmatically in C#

Is it safe to programmatically reference the public folder through:
Directory = System.Environment.GetEnvironmentVariable("public")+"MyCompanyName" // etc.
or is there a better way?
Again, what if someone deletes the environment variable for public, and is this safe to use for different language OSs?
This follows: How to install to the Public directory in Windows 7 from the VS 2010 deployment Setup Project
This seems a tad questionable, but it should work:
// This should give you something like C:\Users\Public\Documents
string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments);
var directory = new DirectoryInfo(documentsPath);
// Now this should give you something like C:\Users\Public
string commonPath = directory.Parent.FullName;
It depends on what you want to achieve.
There is a enum called SpecialFolder. You can use it to get the Path to some Directories.
For Example:
System.Environment.GetFolderPath(Environment.SpecialFolder.CommonDesktopDirectory)
points to "C:\Users\Public\Desktop".
IMHO, your way isn't wrong, though i would do some Exception Handling in case the EnvVar is really missing.
Also you could use the ENUM with "CommonDesktopDirectory" and get rid of the "\Desktop" part.
Notice that the Environment.SpecialFolder.CommonDesktopDirectory is only available in .NET 4.0. For my .NET 3.5 systems (Windows 7 or XP) I used the registry key for the Shell Folders. My code snippet is in VB.NET.
Private mRegShellPath="Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
Private mCommonDesktop = Nothing
' dgp rev 3/8/2012
Private ReadOnly Property CommonDesktop As String
Get
If mCommonDesktop Is Nothing Then
Dim RegKey As RegistryKey
Try
RegKey = Registry.LocalMachine.OpenSubKey(mRegShellPath, False)
mCommonDesktop = RegKey.GetValue("Common Desktop")
Catch ex As Exception
mCommonDesktop = ""
End Try
End If
Return mCommonDesktop
End Get
End Property
If you want a place to put application-specific data that can accessed by all users, use as a base:
Environment.GetFolderPath(SpecialFolder.CommonApplicationData)
Also, consider using Path.Combine to combine elements to form a new path:
Path.Combine(
Environment.GetFolderPath(SpecialFolder.CommonApplicationData),
"MyCompanyName")
Have you looked at this ?
http://msdn.microsoft.com/en-us/library/system.environment.specialfolder.aspx
Specifies enumerated constants used to retrieve directory paths to system special folders.
Ie
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)
You can get all these %wildcard% literals by looking into
Windows->Start-->regedit-->
Then, you perform
using System;
string path2Downloads = Environment.ExpandEnvironmentVariables(#"%USERPROFILE%\Downloads");
string path2Music = Environment.ExpandEnvironmentVariables(#"%USERPROFILE%\Music");
... and, so on .... and to test:
using System.IO;
string[] files = { "" };
if (Directory.Exists(path2Music)) {
files = Directory.GetFiles(path2Music);
}

Categories