How can I code defensively against potential unorthodox hard drive letters? - c#

I can set a SaveFileDialog's InitialDirectory property to where my app will usually be installed like so:
saveFileDialog1.InitialDirectory = #"C:\Program Files\Waltons\Mountains";
...but as "there is one in every crowd," some may use a drive letter other than C for their hard drive? How can I set the InitialDirectory to whichever drive letter the user has specified?
UPDATE
I tried Alexei's code (had to change "Concat" to "Combine" and remove a superfluous ")":
saveFileDialog1.InitialDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Programs), #"Waltons\Mountains");
DialogResult result = saveFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
// TODO: Finish
}
...but it does not open C:\Program Files\Waltons\Mountains
UPDATE 2
Saeb's suggestion seems to work, as the save file dialog opens in C:\Waltons\Mountains\bin\Debug
...which I hope/reckon would correspond to C:\Waltons on the user's machine (or D:\Waltons or Z:\Waltons or whatever).
I would have to append the "\Maps" I guess for the user - check that it's not running in Visual Studio or something and append that in that event.

Location that is writable by normal user would be better default location for save dialog. I.e. "my documents" via Environment.GetFolderPath passing one of Environment.SpecialFolder values:
var pathToMyDocuments = Environment.GetFolderPath(Environment.SpecialFolder.Personal));
If you need location where your program installed by default like program files
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "MyFolder");
or if you need path relative to program check How can I get the application's path in a .NET console application?.
Note that locations above are not writable by normal users and even admin unless you turn off UAC or explicitly "run as administrator" or change default permissions on these folders (either of approaches to bypass default permission have its drawbacks and one should perform serious security review if allowing regular users to write in programs/system folders).

Don't use hardcoded driver letters. Find the path in runtime. e.g.:
saveFileDialog1.InitialDirectory = AppDomain.CurrentDomain.BaseDirectory;

You can use the environment variable systemroot to get the drive. Try opening a cmd prompt and entering set to see a list of all the environment variables avaliable and then use System.Envrionment.GetEnvironmentVariable ("systemdrive") and combine that with the rest of your path.

Related

Search for config file upon login

I have a quiz that has a login feature but, when you change pc you must also change the drive the file is located e.g D drive, E drive etc...
Currently its set to F. Is there something i can add that will make it automatically search each drive for the file?
Here is my code
if (File.Exists(#"F:\C# Completed quiz\adam new\Mario quiz\bin/PlayerDetails.txt"))
{
string[] lines = File.ReadAllLines(#"F:\C# Completed quiz\adam new\Mario quiz\bin/PlayerDetails.txt");
I'd recommend you just put it in the AppData or MyDocuments folder:
string filename = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "C# Completed quiz","adam new","Mario quiz","bin","PlayerDetails.txt");
//or Environment.SpecialFolder.MyDocuments
if (File.Exists(filename))
{
string[] lines = File.ReadAllLines(filename);
}
you need to enumerate the hard drives on the system and inspect them one at a time
https://msdn.microsoft.com/en-us/library/system.io.directory.getlogicaldrives(v=vs.110).aspx
shows how to enumerate the hard drives on the system
This answer uses what looks like a better way
How can I determine if a given drive letter is a local/mapped/usb drive?
Once you know a drive is a mounted drive the you should look at <drive>:/<your path>
Use Resource file to store your txt inside the application or just distribute it with your executable. To add resource file:
Right click on your project and select Properties
Go to Resources tab and create new file
Click Add resource -> Add Existing File...
Choose your text file and click Open
The file can now be accessed like string:
var lines = Properties.Resources.PlayerDetails;
If the file is in the same folder as your exe then you can access it in this way:
var lines = File.ReadAllLines("PlayerDetails.txt");
Edit: Note the comment below if you prefer to use this method.

How do I Use OpenFileDialog to select files or paths

I am writing a WPF / C# application, and would like to enable a user to select one (or multiple) files, or one (or multiple) folders, without having to select which option they use initially, but intentionally. In my opinion, the best way to acchieve this goal would be to have a standard FolderBrowserDialog, and as long as the user does not seelct a file, but browses to a path, clicking the open button should select that path.
Practically, this solution does not work, because OpenFileDialog does not allow empty selections, you can hit "open", but nothing will happen. There is one workaround descriped here which allows to enter a fake name like "Selected Folder." as filename. which can afterwards be filtered out, which is a workaround, but not a nice one:
http://www.codeproject.com/Articles/44914/Select-file-or-folder-from-the-same-dialog
This solution has two important weaknesses:
1.) you will have to filter for the fake name
2.) if you paste a filename manually, or select a file first, and then switch the selection to a folder instead, the fake name is not inserted automatically.
of course I am aware there is something like FolderBrowserDialog, which I omit using even if I only wanted to select folders and not files. The reason: this dialog has no possibility to paste paths from clipboard, and I find it annoying to navigate all the way, I rather copy paths from somewhere and paste them, which works perfectly fine in OpenFileDialog, but not in FolderBrowserDialog. Besides, FolderBrowserDialog does not allow to select files and folders.
I have googled a lot, but do not find satisfying solutions, although I am sure many people must obviously face this problem.
As mentioned, the most elegant way for me would be to make the OpenFileDialog simply allow empty Filename boxes when clicking Open - any way to acchieve this?
Thanks alot.
Letting a user select a directory OR a file using the same dialog is not practical nor intuitively possible.
However, if you want a solution for selecting a Folder, here it is :
If you don't want to create a custom dialog but still prefer a 100% WPF way and don't want to use separate DDLs, additional dependencies or outdated APIs, I came up with a very simple hack using WPF's Save As dialog for actually selecting a directory.
No using directive needed, you may simply copy-paste the code below !
It should still be very user-friendly and most people will never notice.
The idea comes from the fact that we can change the title of that dialog, hide files, and work around the resulting filename quite easily.
It is a big hack for sure, but maybe it will do the job just fine for your usage...
In this example I have a textbox object to contain the resulting path, but you may remove the related lines and use a return value if you wish...
// Create a "Save As" dialog for selecting a directory (HACK)
var dialog = new Microsoft.Win32.SaveFileDialog();
dialog.InitialDirectory = textbox.Text; // Use current value for initial dir
dialog.Title = "Select a Directory"; // instead of default "Save As"
dialog.Filter = "Directory|*.this.directory"; // Prevents displaying files
dialog.FileName = "select"; // Filename will then be "select.this.directory"
if (dialog.ShowDialog() == true) {
string path = dialog.FileName;
// Remove fake filename from resulting path
path = path.Replace("\\select.this.directory", "");
path = path.Replace(".this.directory", "");
// If user has changed the filename, create the new directory
if (!System.IO.Directory.Exists(path)) {
System.IO.Directory.CreateDirectory(path);
}
// Our final value is in path
textbox.Text = path;
}
The only issues with this hack are :
Acknowledge button still says "Save" instead of something like "Select directory", but in a case like mines I "Save" the directory selection so it still works...
Input field still says "File name" instead of "Directory name", but we can say that a directory is a type of file...
There is still a "Save as type" dropdown, but its value says "Directory (*.this.directory)", and the user cannot change it for something else, works for me...
Most people won't notice these, although I would definitely prefer using an official WPF way if microsoft would get their heads out of their asses, but until they do, that's my temporary fix.

Write a text file to a sub-folder

I am trying to write out a text file to: C:\Test folder\output\, but without putting C:\ in.
i.e.
This is what I have at the moment, which currently works, but has the C:\ in the beginning.
StreamWriter sw = new StreamWriter(#"C:\Test folder\output\test.txt");
I really want to write the file to the output folder, but with out having to have C:\ in the front.
I have tried the following, but my program just hangs (doesn't write the file out):
(#"\\Test folder\output\test.txt");
(#".\Test folder\output\test.txt");
("//Test folder//output//test.txt");
("./Test folder//output//test.txt");
Is there anyway I could do this?
Thanks.
Thanks for helping guys.
A colleague of mine chipped in and helped as well, but #Kami helped a lot too.
It is now working when I have:
string path = string.Concat(Environment.CurrentDirectory, #"\Output\test.txt");
As he said: "The CurrentDirectory is where the program is run from.
I understand that you would want to write data to a specified folder. The first method is to specify the folder in code or through configuration.
If you need to write to specific drive or current drive you can do the following
string driveLetter = Path.GetPathRoot(Environment.CurrentDirectory);
string path = diveLetter + #"Test folder\output\test.txt";
StreamWriter sw = new StreamWriter(path);
If the directory needs to be relative to the current application directory, then user AppDomain.CurrentDomain.BaseDirectory to get the current directory and use ../ combination to navigate to the required folder.
You can use System.IO.Path.GetDirectoryName to get the directory of your running application and then you can add to this the rest of the path..
I don't get clearly what you want from this question , hope this get it..
A common technique is to make the directory relative to your exe's runtime directory, e.g., a sub-directory, like this:
string exeRuntimeDirectory =
System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().Location);
string subDirectory =
System.IO.Path.Combine(exeRuntimeDirectory, "Output");
if (!System.IO.Directory.Exists(subDirectory))
{
// Output directory does not exist, so create it.
System.IO.Directory.CreateDirectory(subDirectory);
}
This means wherever the exe is installed to, it will create an "Output" sub-directory, which it can then write files to.
It also has the advantage of keeping the exe and its output files together in one location, and not scattered all over the place.

Getting the last opened file in fileopen dialog box

In FileOpen or FileSave dialogbox when I call them, they automatically go to the last opened path. This happens even if I close my application and open it. But how to get that path/file name to a textbox or variable?
it seems a bit weired but under Windows 7 it works with the folling:
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.InitialDirectory = System.Environment.GetFolderPath(Environment.SpecialFolder.MyComputer);
Try it and tell me if you need further help.
Presumably the information is stored somewhere in the depths of the registry (it's done by the unmanaged control to which OpenFileDialog is only a wrapper). The easiest would probably be to persist the path the last time the dialog was closed in your application somewhere where you can access it.
As mentioned here: What does the FileDialog.RestoreDirectory Property actually do?
They use the path from Environment.CurrentDirectory.
I am having a similar problem to Vicky, which goes as follows. I am developing in Visual Basic 2008 Express Edition under Vista Business SP2.
I have an application with an OpenFileDialog and a SaveFileDialog. When I call the OpenFileDialog on first running the application, it defaults to the directory from which the Application last opened/saved a file. However, this directory IS NOT "Environment.CurrentDirectory" which is set to "C:\Users\Brian\Documents\Visual Studio 2008\Projects\IFPM Analysis\IFPM Analysis\bin\Debug" and is not changed by either the OpenFileDialog or SaveFileDialog.
Later on in the Application, I call the SaveFileDialog, with the initial directory property (.InitialDirectory) set in the code to a default directory. When I subsequently call the OpenFileDialog, it defaults to the directory used by the SaveFileDialog. All the time, the value of "Environment.CurrentDirectory" is unchanged.
So, my question is, where is the directory that is being used by the OpenFileDialog and SaveFileDialog being stored? I assume it is something to do with the underlying FileDialog class, and I know persists even after the Application has been closed and restarted.
Ideally I want to be able to store the directory selected by the user from the OpenFileDialog and reset it after I have used the SaveFileDialog. While I can use the InitialDirectory property of the OpenFileDialog within the Application, this doesn't help me when I close the Application and restart it. Sadly, the typical user actions are:
start Application
open file with OpenFileDialog
save file with SaveFileDialog
leave Application
This means that when the user comes back to the Application, the default directory is the "wrong" one. I know that I can save the last used directory from the OpenFileDialog in my own configuration file so that it will persist outside of the Application, but that seems a little silly when Windows provides me with the same functionality, if only I knew where to look!
Any help gratefully received!
Thanks,
Brian.
The recent opened files list is stored in 2 places:
Recent Folder: The recent folder is usually located under C:\Documents and Settings[Your Profile]\Recent (The path is different under Windows Vista), and it contains shortcuts to the recently opened files.
Registry: Each time that a file is selected in save/open dialog-box, the filename is added to the files list under HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\OpenSaveMRU
This method can help you to get the list:
public static string GetLastOpenSaveFile(string extention)
{
RegistryKey regKey = Registry.CurrentUser;
string lastUsedFolder = string.Empty;
regKey = regKey.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\OpenSaveMRU");
if (string.IsNullOrEmpty(extention))
extention = "html";
RegistryKey myKey = regKey.OpenSubKey(extention);
if (myKey == null && regKey.GetSubKeyNames().Length > 0)
myKey = regKey.OpenSubKey(regKey.GetSubKeyNames()[regKey.GetSubKeyNames().Length - 2]);
if (myKey != null)
{
string[] names = myKey.GetValueNames();
if (names != null && names.Length > 0)
{
lastUsedFolder = (string)myKey.GetValue(names[names.Length - 2]);
}
}
return lastUsedFolder;
}
Success!
Iordan

How can i get the path of the current user's "Application Data" folder?

1)how can i find out the Windows Installation drive in which the user is working.? I need this to navigate to the ApplicationData in DocumentsandSettings.
2)Also how can i get the user name too so that i can goto ApplicaitionData.? Eg: "D:\Documents and Settings\user\Application Data".
Look at combining Environment.GetFolderPath and Environment.SpecialFolder to do this.
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
Depending on what you are doing you might also want to look at
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
If the user is on a domain it will only be stored in their local AppData folder and not synced with their roaming profile.
Have a look at the Environment.SpecialFolders
Environment.SpecialFolder.ApplicationData;
Environment.SpecialFolder.System
that should get you round the username requirement as well.
Have a look at the System.Environment class and its properties and methods, e.g:
string systemDir = System.Environment.SystemDirectory;
string docs = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.MyDocuments));
string systemDrive = System.IO.Path.GetPathRoot(systemDir);
The first one returns "C:\Windows\system32" for example and the second one "C:\Documents and Settings\USERNAME\My Documents".
Try this:
string filePath = Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData);
1)how can i find out the Windows Installation drive in which the user
is working.?
var systemDrive = Environment.ExpandEnvironmentVariables("%systemdrive%");
I need this to navigate to the ApplicationData in
DocumentsandSettings.
You don't really require to fetch the value of either system drive or currently logged in user name to achieve this. There are predefined environment variables %localAppData% and %appData% which give you fully qualified path of these directories as shown in the code below:
var localApplicationData = Environment.ExpandEnvironmentVariables("%localappdata%");
//this gives C:\Users\<userName>\AppData\Local
var roamingApplicationData = Environment.ExpandEnvironmentVariables("%appdata%");
//this gives C:\Users\<userName>\AppData\Roaming
2)Also how can i get the user name too so that i can goto
ApplicaitionData.? Eg: "D:\Documents and Settings\user\Application
Data".
Again, you don't need user name to get the application data path as I've discussed above. Still, for the sake of knowledge you can fetch it from %username% environment variable as shown below:
var currentUserName = Environment.ExpandEnvironmentVariables("%username%");

Categories

Resources