How to get icon of default browser in C#? - c#

I have a button that says "Open in browser". I would like to rename it to "Open" and show default browser's icon next to it.
If default browser is firefox, then I want firefox icon in my button.
If default browser is chrome, then I want chrome icon.
How can I get the default browsers icon?
If it's different for every version of windows, then I need window 7 version.

Embed a blank htm or html file with your application (or create it)
Then call the Icon.ExtractAssociatedIcon method on this file.
It will return default browser icon .

I have changed the code a bit and here is my version.
using System;
using Microsoft.Win32;
using System.Drawing;
namespace Namespace
{
public static class DefaultSystemBrowser
{
private static bool initialized = false;
private static string path = null;
public static string Path
{
get
{
CheckForErrors();
return path;
}
}
public static Icon Icon
{
get {
CheckForErrors();
return Icon.ExtractAssociatedIcon( path );
}
}
public static Bitmap Bitmap
{
get
{
CheckForErrors();
return Icon.ExtractAssociatedIcon( path ).ToBitmap();
}
}
private static void CheckForErrors()
{
if ( !initialized )
throw new InvalidOperationException( "You can't use DefaultSystemBrowser class before you call Determine()." );
if ( ErrorMessage != null )
throw new InvalidOperationException( "You can't use DefaultSystemBrowser class if call to Determine() resulted in error." );
}
/// <summary>
/// Null if no error occured, error description otherwise.
/// </summary>
public static string ErrorMessage
{
get;
private set;
}
/// <summary>
/// Finds out all information about current default browser. You can call this method every time you want to find out default browser.
/// </summary>
public static void Determine()
{
path = String.Empty;
initialized = true;
RegistryKey regKey = null;
ErrorMessage = null;
try
{
//set the registry key we want to open
regKey = Registry.ClassesRoot.OpenSubKey( "HTTP\\shell\\open\\command", false );
//get rid of the enclosing quotes
path = regKey.GetValue( null ).ToString().ToLower().Replace( "" + (char) 34, "" );
//check to see if the value ends with .exe (this way we can remove any command line arguments)
if ( !path.EndsWith( "exe" ) )
//get rid of all command line arguments (anything after the .exe must go)
path = path.Substring( 0, path.LastIndexOf( ".exe" ) + 4 );
initialized = true;
}
catch ( Exception ex )
{
ErrorMessage = string.Format( "ERROR: An exception of type: {0} occurred in method: {1} in the following module: {2}", ex.GetType(), ex.TargetSite, typeof( DefaultSystemBrowser ) );
}
finally
{
//check and see if the key is still open, if so
//then close it
if ( regKey != null )
regKey.Close();
}
}
}
}
Here is how I am using the code:
DefaultSystemBrowser.Determine();
if ( DefaultSystemBrowser.ErrorMessage == null )
{
btnOpenInBrowser.Image = DefaultSystemBrowser.Bitmap;
}
else
{
btnOpenInBrowser.Image = Properties.Resources.firefox_24_noshadow;
}

Related

C# How to get current Powerpoint Presentation File Name?

As you see I have some object in my hand but I couldn't figure out how to get current file name. I am getting _currentSlideName from an xml file and compare to open new slide.
Do you have any suggestion to get current power point presentation file name?
ppt.Application _pptApplication = new ppt.Application();
private void Open(string fileName)
{
_presentation = _pptApplication.Presentations.Open(fileName, MsoTriState.msoTrue, MsoTriState.msoTrue, MsoTriState.msoFalse);
}
private void CheckSlide()
{
if (_oSlideShowView == null)
{
try
{
Open( _settingObj.Path + _currentSlideName);
}
catch (Exception)
{
Open(_settingObj.Path+ "Test.pptx" );
}
}
else if (_currentSlideName != _presentation.Path)
{
try
{
Open( _settingObj.Path + _currentSlideName);
}
catch (Exception)
{
Open(_settingObj.Path+ "Test.pptx" );
}
}
}
Getting the full filename of the open presentation is simply Presentation.FullName. In your case, this would be:
_pptApplication.ActivePresentation.FullName
Note that this only returns the presentation's name if the file is not currently saved. If it is not saved, the presentation's Path is an empty string.
EDIT: The example above returns the full filename. If you want only the name, use the following. Just to clarify that this only makes sense with saved presentations, I've added a check on Path.
if(!_pptApplication.ActivePresentation.Path.Equals("")) {
var name = _pptApplication.ActivePresentation.Name
... do processing...
}
else {
... error ...
}

Watin Internet Explorer how to start in-private mode?

I am writing a few automated web tests using C# Watin framework.
I was hoping anyone can help me out,
How do i open new IE instance in "in private" browse mode? (i.e incognito mode)
The need for "in private" browsing, is because some of the tests, require log in. (and i run a few in parallel)
I could not find any resources on the matter. (other than half patch i found in some forum)
Thanks for your help!
The only solution i was able to find, is to open IE instance via command in incognito mode, then attach Watin to it.
//gen random url so we can find the window later
Random rnd = new Random();
int id = rnd.Next(1000, 10000);
string url = "id" + id+".com";
//opening explorer
Process.Start("IExplore.exe", "-private -nomerge " + url);
browser = Browser.AttachTo<IE>(Find.ByUrl(new Regex(url)));
browser.GoTo("http://www.google.com");
I downloaded WatiN source codes, opened IE.cs and edited the method CreateIExploreInNewProcess
private static Process CreateIExploreInNewProcess()
{
var arguments = "about:blank";
if (GetMajorIEVersion() >= 8 && Settings.MakeNewIe8InstanceNoMerge)
arguments = "-nomerge " + arguments;
if (Settings.OpenInIncognitoMode == true)
{
arguments = "-private " + arguments;
}
var m_Proc = Process.Start("IExplore.exe", arguments);
if (m_Proc == null) throw new WatiNException("Could not start IExplore.exe process");
return m_Proc;
}
Then, added this to Settings.cs:
/// <summary>
/// Gets or sets a value indicating whether the browser will be opened in incognito mode.
/// </summary>
/// <value>
/// <c>true</c> if IE instance needs to be opened in incognito mode, otherwise <c>false</c>.
/// </value>
public static bool OpenInIncognitoMode
{
get { return Instance.OpenInIncognitoMode; }
set { Instance.OpenInIncognitoMode = value; }
}
After that, added this to ISettings.cs
/// <summary>
/// Gets or sets a value indicating whether the browser will be opened in incognito mode.
/// </summary>
/// <value>
/// <c>true</c> if IE instance needs to be opened in incognito mode, otherwise <c>false</c>.
/// </value>
bool OpenInIncognitoMode { get; set; }
Finally, edited DefaultSettings.cs like this:
private struct settingsStruct
{
...
...
public bool makeNewIe8InstanceNoMerge;
public bool closeExistingFireFoxInstances;
public bool incognitoMode;
}
public bool OpenInIncognitoMode
{
get { return settings.incognitoMode; }
set { settings.incognitoMode = value; }
}
private void SetDefaults()
{
settings = new settingsStruct
{
...
...
makeNewIe8InstanceNoMerge = true,
closeExistingFireFoxInstances = true,
incognitoMode = false
};
}
Compile it and add the new DLL to your project. After this, all you need to do in your project is this:
Settings.OpenInIncognitoMode = true;
var browser = new IE(url, true);
The trick is to pass the argument -private to the call of IExplore.exe like here:
string argument = "-private -nomerge about:blank";
process = Process.Start("IExplore.exe", argument);
if (process == null)
throw new InvalidOperationException("The IExplore.exe process can't be started");
Thread.Sleep(3000);
handle = process.MainWindowHandle.ToInt32();
var allBrowsers = new SHDocVw.ShellWindows();
if (handle != 0)
{
foreach (InternetExplorer browser in allBrowsers)
if (browser.HWND == handle)
{
ie = browser;
iehandle = (IntPtr)ie.HWND;
break;
}
}

Pass Parameters to ClickOnce Using ShellExecute

I was attempting to use this Blog to pass an argument to an offline click-once application. Near the bottom of the blog there are example programs to download. I downloaded and published the program "TestRunningWithArgs" the C# version.
Now I am trying to pass an argument to the application which is not working. It keeps saying no "No arguments passed in".
I am trying to use the following code to pass an argument:
shellexecute("File Path\My Applicaiton.application","MyArgument")
This code runs the application but the sample application states it did not receive an argument. The language is visual basic (maybe 4 or 6?).
The code below works and allows internet explorer to run and a specific file be opened from sharepoint and I was wondering if there is a difference that I am missing.
shellexecute("C:\Program Files\Internet Explorer\iexplore.exe",FileLocation)
The only one I see is that the click once is a .application file vs a .exe and is there a way to get this to work?
Below is the code for the click once application, just copied from the supplied example program on the blog
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
GetArgsToShow();
}
/// Get the arguments and show them on the screen.
private void GetArgsToShow()
{
// Get the ActivationArguments from the SetupInformation property of the domain.
string[] activationData =
AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData;
if (activationData != null && activationData.Length > 0)
{
//querystring starts with ?; file association starts with "file:"
if (activationData.Length == 1 && activationData[0].Substring(0, 1) == "?")
{
ProcessQueryString(activationData);
}
else if (activationData.Length == 1 && activationData[0].Length >= 5 && activationData[0].Substring(0,5).ToLower() == #"file:")
{
ProcessFileAssociation(activationData);
}
else
{
ProcessCSVParameters(activationData);
}
}
else
{
if (activationData == null)
{
lstArgs.Items.Add("No arguments passed in.");
}
else
{
lstArgs.Items.Add(String.Format("Number of args = {0}", activationData.Length));
}
}
}
/// Convert a query string into Name/Value pairs and process it.
private void ProcessQueryString(string[] activationData)
{
NameValueCollection nvc =
System.Web.HttpUtility.ParseQueryString(activationData[0]);
//Get all the keys in the collection, then pull the values for each of them.
//I'm only passing each key once, with one value.
string[] theKeys = nvc.AllKeys;
foreach (string theKey in theKeys)
{
string[] theValue = nvc.GetValues(theKey);
lstArgs.Items.Add(string.Format("Key = {0}, Value = {1}", theKey, theValue[0]));
}
}
/// Process what you would get if you set up a file association,
/// and the user double-clicked on one of the associated file.
private void ProcessFileAssociation(string[] activationData)
{
//This is what you get when you set up a file association and the user double-clicks
// on an associated file.
Uri uri = new Uri(activationData[0]);
lstArgs.Items.Add(uri.LocalPath.ToString());
}
/// Process a comma-delimited string of values. Not: can't have spaces or double-quotes in the string,
/// it will only read the first argument.
private void ProcessCSVParameters(string[] activationData)
{
//I have to say here that I've only ever seen 1 entry passed in activationData,
// but I'm checking for multiples just in case.
//This takes each entry and splits it by comma and separates them into separate entries.
char[] myComma = { ',' };
foreach (string arg in activationData)
{
string[] myList = activationData[0].Split(myComma, StringSplitOptions.RemoveEmptyEntries);
foreach (string oneItem in myList)
lstArgs.Items.Add(oneItem);
}
}
}
EDIT
Well I tried accessing the .exe located in "C:\Users\userName\AppData\Local\Apps\2.0\5G9CGPWV.6O3\X7YPB07N.2Q2\test..tion_0000000000000000_0001.0000_03232931d88a66c9\" which did not work.
Found the file you have to call to send an argument.
shellexecute("C:\Users\%USERNAME%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\(Publisher Name)\My Application.appref-ms", Arguement)
The publisher name is specified in visual studio Publish Tab, options and then Publisher Name. This is also the Start Menu Folder where your program can be launched from.

open file with a running process

I am making an application that can open a custom document. I connected the document extension to the application (using registry), but when I open the document, it is always opened with a new instance of the application.
I want some logic that can open a document running the current process if it exists. I dont mean a single instance. It should be able to run by multiple instances. Like IE or chrome, it should be able to open an HTML file with tab when the process is running, but it can also run a new instance.
How can I do it?
This article contains a good description (images taken from there as well).
The approach uses ThreadPool object with EventWaitHandle object to pass messages (objects) between processes (.Net Remoting).
When the application starts, it uses CreateSingleInstance() to call the existing instance OR register itself as single instance application.
public static bool CreateSingleInstance( string name, EventHandler<InstanceCallbackEventArgs> callback )
{
EventWaitHandle eventWaitHandle = null;
int curSessionId = System.Diagnostics.Process.GetCurrentProcess().SessionId;
name += curSessionId;
string eventName = string.Format( "{0}-{1}", Environment.MachineName, name );
// If there is another instance
InstanceProxy.IsFirstInstance = false;
InstanceProxy.CommandLineArgs = Environment.GetCommandLineArgs();
try
{
//try to open a handle with the eventName
eventWaitHandle = EventWaitHandle.OpenExisting( eventName );
}
catch
{
InstanceProxy.IsFirstInstance = true;
}
if( InstanceProxy.IsFirstInstance )
{
eventWaitHandle = new EventWaitHandle( false, EventResetMode.AutoReset, eventName );
// register wait handle for this instance (process)
ThreadPool.RegisterWaitForSingleObject( eventWaitHandle, WaitOrTimerCallback, callback, Timeout.Infinite, false );
eventWaitHandle.Close();
// register shared type (used to pass data between processes)
RegisterRemoteType( name );
}
else
{
// here will be the code for the second instance/
}
return InstanceProxy.IsFirstInstance;
}
private static void RegisterRemoteType( string uri )
{
// register remote channel (net-pipes)
var serverChannel = new IpcServerChannel( Environment.MachineName + uri );
ChannelServices.RegisterChannel( serverChannel, true );
// register shared type
RemotingConfiguration.RegisterWellKnownServiceType(
typeof( InstanceProxy ), uri, WellKnownObjectMode.Singleton );
// close channel, on process exit
Process process = Process.GetCurrentProcess();
process.Exited += delegate
{
ChannelServices.UnregisterChannel( serverChannel );
};
}
[Serializable]
[System.Security.Permissions.PermissionSet( System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust" )]
internal class InstanceProxy : MarshalByRefObject
{
private static bool firstInstance;
private static string[] arrCommandLineArgs;
public static bool IsFirstInstance
{
get
{
return firstInstance;
}
set
{
firstInstance = value;
}
}
public static string[] CommandLineArgs
{
get
{
return arrCommandLineArgs;
}
set
{
arrCommandLineArgs = value;
}
}
public void SetCommandLineArgs( bool isFirstInstance, string[] commandLineArgs )
{
firstInstance = isFirstInstance;
arrCommandLineArgs = commandLineArgs;
}
}
public class InstanceCallbackEventArgs : EventArgs
{
private bool firstInstance;
private string[] arrCommandLineArgs;
internal InstanceCallbackEventArgs( bool isFirstInstance, string[] commandLineArgs )
{
firstInstance = isFirstInstance;
arrCommandLineArgs = commandLineArgs;
}
public bool IsFirstInstance
{
get
{
return firstInstance;
}
set
{
firstInstance = value;
}
}
public string[] CommandLineArgs
{
get
{
return arrCommandLineArgs;
}
set
{
arrCommandLineArgs = value;
}
}
}
There are many options here, a few them are:
Try use DDE which is ancient history but it is still used by many applications like MS Office. DDE commands are registered on open command for file extension (look HKEY_CLASSES_ROOT\Excel.Sheet.8\shell\Open for example). If application hasn't already been started, it is launched by OS, and DDE command is submitted. If launched, DDE command is submitted to running instance which is registered as a DDE server.
When your process starts try to create an IpcChannel with a predefined name. If your process is launched with file argument, pass file name to running process via IpcChannel. Problem is only one process can create IpcChannel with same name. If that process quits, other processes are left without an open channel.
Every process creates an IpcChannel using process id. When your process starts with a file argument, you enumerate processes where process' path is same as yours, then connect to that process using IpcChannel (where name can be obtained by looking at process id), and then pass filename to it.
Enumerate processes where process' path is same as yours, and send a WM_COPYDATA message containing your filename.

Better way to check if a Path is a File or a Directory?

I am processing a TreeView of directories and files. A user can select either a file or a directory and then do something with it. This requires me to have a method which performs different actions based on the user's selection.
At the moment I am doing something like this to determine whether the path is a file or a directory:
bool bIsFile = false;
bool bIsDirectory = false;
try
{
string[] subfolders = Directory.GetDirectories(strFilePath);
bIsDirectory = true;
bIsFile = false;
}
catch(System.IO.IOException)
{
bIsFolder = false;
bIsFile = true;
}
I cannot help to feel that there is a better way to do this! I was hoping to find a standard .NET method to handle this, but I haven't been able to do so. Does such a method exist, and if not, what is the most straightforward means to determine whether a path is a file or directory?
From How to tell if path is file or directory:
// get the file attributes for file or directory
FileAttributes attr = File.GetAttributes(#"c:\Temp");
//detect whether its a directory or file
if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
MessageBox.Show("Its a directory");
else
MessageBox.Show("Its a file");
Update for .NET 4.0+
Per the comments below, if you are on .NET 4.0 or later (and maximum performance is not critical) you can write the code in a cleaner way:
// get the file attributes for file or directory
FileAttributes attr = File.GetAttributes(#"c:\Temp");
if (attr.HasFlag(FileAttributes.Directory))
MessageBox.Show("Its a directory");
else
MessageBox.Show("Its a file");
How about using this?
if(File.Exists(data.path))
{
// is file
}
else if(Directory.Exists(data.path))
{
// is Folder
}
else
{
// invalid path
}
File.Exists() will return false if it's not a file even if the directory does exist, so if it returns true, we know we got a file, if it returns false, we either have a directory or an invalid path so next we test if it's a valid directory with Directory.Exists() if that returns true, we have a directory if not it's an invalid path.
With only this line you can get if a path is a directory or a file:
File.GetAttributes(data.Path).HasFlag(FileAttributes.Directory)
Here's mine:
bool IsPathDirectory(string path)
{
if (path == null) throw new ArgumentNullException("path");
path = path.Trim();
if (Directory.Exists(path))
return true;
if (File.Exists(path))
return false;
// neither file nor directory exists. guess intention
// if has trailing slash then it's a directory
if (new[] {"\\", "/"}.Any(x => path.EndsWith(x)))
return true; // ends with slash
// if has extension then its a file; directory otherwise
return string.IsNullOrWhiteSpace(Path.GetExtension(path));
}
It's similar to others' answers but not exactly the same.
As an alternative to Directory.Exists(), you can use the File.GetAttributes() method to get the attributes of a file or a directory, so you could create a helper method like this:
private static bool IsDirectory(string path)
{
System.IO.FileAttributes fa = System.IO.File.GetAttributes(path);
return (fa & FileAttributes.Directory) != 0;
}
You could also consider adding an object to the tag property of the TreeView control when populating the control that contains additional metadata for the item. For instance, you could add a FileInfo object for files and a DirectoryInfo object for directories and then test for the item type in the tag property to save making additional system calls to get that data when clicking on the item.
After combining the suggestions from the other answers, I realized I came up with about the same thing as Ronnie Overby's answer. Here are some tests to point out some things to think about:
folders can have "extensions": C:\Temp\folder_with.dot
files cannot end with a directory separator (slash)
There are technically two directory separators which are platform specific -- i.e. may or may not be slashes (Path.DirectorySeparatorChar and Path.AltDirectorySeparatorChar)
Tests (Linqpad)
var paths = new[] {
// exists
#"C:\Temp\dir_test\folder_is_a_dir",
#"C:\Temp\dir_test\is_a_dir_trailing_slash\",
#"C:\Temp\dir_test\existing_folder_with.ext",
#"C:\Temp\dir_test\file_thats_not_a_dir",
#"C:\Temp\dir_test\notadir.txt",
// doesn't exist
#"C:\Temp\dir_test\dne_folder_is_a_dir",
#"C:\Temp\dir_test\dne_folder_trailing_slash\",
#"C:\Temp\dir_test\non_existing_folder_with.ext",
#"C:\Temp\dir_test\dne_file_thats_not_a_dir",
#"C:\Temp\dir_test\dne_notadir.txt",
};
foreach(var path in paths) {
IsFolder(path/*, false*/).Dump(path);
}
Results
C:\Temp\dir_test\folder_is_a_dir
True
C:\Temp\dir_test\is_a_dir_trailing_slash\
True
C:\Temp\dir_test\existing_folder_with.ext
True
C:\Temp\dir_test\file_thats_not_a_dir
False
C:\Temp\dir_test\notadir.txt
False
C:\Temp\dir_test\dne_folder_is_a_dir
True
C:\Temp\dir_test\dne_folder_trailing_slash\
True
C:\Temp\dir_test\non_existing_folder_with.ext
False (this is the weird one)
C:\Temp\dir_test\dne_file_thats_not_a_dir
True
C:\Temp\dir_test\dne_notadir.txt
False
Method
/// <summary>
/// Whether the <paramref name="path"/> is a folder (existing or not);
/// optionally assume that if it doesn't "look like" a file then it's a directory.
/// </summary>
/// <param name="path">Path to check</param>
/// <param name="assumeDneLookAlike">If the <paramref name="path"/> doesn't exist, does it at least look like a directory name? As in, it doesn't look like a file.</param>
/// <returns><c>True</c> if a folder/directory, <c>false</c> if not.</returns>
public static bool IsFolder(string path, bool assumeDneLookAlike = true)
{
// https://stackoverflow.com/questions/1395205/better-way-to-check-if-path-is-a-file-or-a-directory
// turns out to be about the same as https://stackoverflow.com/a/19596821/1037948
// check in order of verisimilitude
// exists or ends with a directory separator -- files cannot end with directory separator, right?
if (Directory.Exists(path)
// use system values rather than assume slashes
|| path.EndsWith("" + Path.DirectorySeparatorChar)
|| path.EndsWith("" + Path.AltDirectorySeparatorChar))
return true;
// if we know for sure that it's an actual file...
if (File.Exists(path))
return false;
// if it has an extension it should be a file, so vice versa
// although technically directories can have extensions...
if (!Path.HasExtension(path) && assumeDneLookAlike)
return true;
// only works for existing files, kinda redundant with `.Exists` above
//if( File.GetAttributes(path).HasFlag(FileAttributes.Directory) ) ...;
// no idea -- could return an 'indeterminate' value (nullable bool)
// or assume that if we don't know then it's not a folder
return false;
}
This was the best I could come up with given the behavior of the Exists and Attributes properties:
using System.IO;
public static class FileSystemInfoExtensions
{
/// <summary>
/// Checks whether a FileInfo or DirectoryInfo object is a directory, or intended to be a directory.
/// </summary>
/// <param name="fileSystemInfo"></param>
/// <returns></returns>
public static bool IsDirectory(this FileSystemInfo fileSystemInfo)
{
if (fileSystemInfo == null)
{
return false;
}
if ((int)fileSystemInfo.Attributes != -1)
{
// if attributes are initialized check the directory flag
return fileSystemInfo.Attributes.HasFlag(FileAttributes.Directory);
}
// If we get here the file probably doesn't exist yet. The best we can do is
// try to judge intent. Because directories can have extensions and files
// can lack them, we can't rely on filename.
//
// We can reasonably assume that if the path doesn't exist yet and
// FileSystemInfo is a DirectoryInfo, a directory is intended. FileInfo can
// make a directory, but it would be a bizarre code path.
return fileSystemInfo is DirectoryInfo;
}
}
Here's how it tests out:
[TestMethod]
public void IsDirectoryTest()
{
// non-existing file, FileAttributes not conclusive, rely on type of FileSystemInfo
const string nonExistentFile = #"C:\TotallyFakeFile.exe";
var nonExistentFileDirectoryInfo = new DirectoryInfo(nonExistentFile);
Assert.IsTrue(nonExistentFileDirectoryInfo.IsDirectory());
var nonExistentFileFileInfo = new FileInfo(nonExistentFile);
Assert.IsFalse(nonExistentFileFileInfo.IsDirectory());
// non-existing directory, FileAttributes not conclusive, rely on type of FileSystemInfo
const string nonExistentDirectory = #"C:\FakeDirectory";
var nonExistentDirectoryInfo = new DirectoryInfo(nonExistentDirectory);
Assert.IsTrue(nonExistentDirectoryInfo.IsDirectory());
var nonExistentFileInfo = new FileInfo(nonExistentDirectory);
Assert.IsFalse(nonExistentFileInfo.IsDirectory());
// Existing, rely on FileAttributes
const string existingDirectory = #"C:\Windows";
var existingDirectoryInfo = new DirectoryInfo(existingDirectory);
Assert.IsTrue(existingDirectoryInfo.IsDirectory());
var existingDirectoryFileInfo = new FileInfo(existingDirectory);
Assert.IsTrue(existingDirectoryFileInfo.IsDirectory());
// Existing, rely on FileAttributes
const string existingFile = #"C:\Windows\notepad.exe";
var existingFileDirectoryInfo = new DirectoryInfo(existingFile);
Assert.IsFalse(existingFileDirectoryInfo.IsDirectory());
var existingFileFileInfo = new FileInfo(existingFile);
Assert.IsFalse(existingFileFileInfo.IsDirectory());
}
public bool IsDirectory(string path) {
return string.IsNullOrEmpty(Path.GetFileName(path)) || Directory.Exists(path);
}
Checks if the path file name is an empty string, or if the directory exists. This way you won't have the file attributes error while still providing redundancies for a possible exists failure.
Here's what we use:
using System;
using System.IO;
namespace crmachine.CommonClasses
{
public static class CRMPath
{
public static bool IsDirectory(string path)
{
if (path == null)
{
throw new ArgumentNullException("path");
}
string reason;
if (!IsValidPathString(path, out reason))
{
throw new ArgumentException(reason);
}
if (!(Directory.Exists(path) || File.Exists(path)))
{
throw new InvalidOperationException(string.Format("Could not find a part of the path '{0}'",path));
}
return (new System.IO.FileInfo(path).Attributes & FileAttributes.Directory) == FileAttributes.Directory;
}
public static bool IsValidPathString(string pathStringToTest, out string reasonForError)
{
reasonForError = "";
if (string.IsNullOrWhiteSpace(pathStringToTest))
{
reasonForError = "Path is Null or Whitespace.";
return false;
}
if (pathStringToTest.Length > CRMConst.MAXPATH) // MAXPATH == 260
{
reasonForError = "Length of path exceeds MAXPATH.";
return false;
}
if (PathContainsInvalidCharacters(pathStringToTest))
{
reasonForError = "Path contains invalid path characters.";
return false;
}
if (pathStringToTest == ":")
{
reasonForError = "Path consists of only a volume designator.";
return false;
}
if (pathStringToTest[0] == ':')
{
reasonForError = "Path begins with a volume designator.";
return false;
}
if (pathStringToTest.Contains(":") && pathStringToTest.IndexOf(':') != 1)
{
reasonForError = "Path contains a volume designator that is not part of a drive label.";
return false;
}
return true;
}
public static bool PathContainsInvalidCharacters(string path)
{
if (path == null)
{
throw new ArgumentNullException("path");
}
bool containedInvalidCharacters = false;
for (int i = 0; i < path.Length; i++)
{
int n = path[i];
if (
(n == 0x22) || // "
(n == 0x3c) || // <
(n == 0x3e) || // >
(n == 0x7c) || // |
(n < 0x20) // the control characters
)
{
containedInvalidCharacters = true;
}
}
return containedInvalidCharacters;
}
public static bool FilenameContainsInvalidCharacters(string filename)
{
if (filename == null)
{
throw new ArgumentNullException("filename");
}
bool containedInvalidCharacters = false;
for (int i = 0; i < filename.Length; i++)
{
int n = filename[i];
if (
(n == 0x22) || // "
(n == 0x3c) || // <
(n == 0x3e) || // >
(n == 0x7c) || // |
(n == 0x3a) || // :
(n == 0x2a) || // *
(n == 0x3f) || // ?
(n == 0x5c) || // \
(n == 0x2f) || // /
(n < 0x20) // the control characters
)
{
containedInvalidCharacters = true;
}
}
return containedInvalidCharacters;
}
}
}
The most accurate approach is going to be using some interop code from the shlwapi.dll
[DllImport(SHLWAPI, CharSet = CharSet.Unicode)]
[return: MarshalAsAttribute(UnmanagedType.Bool)]
[ResourceExposure(ResourceScope.None)]
internal static extern bool PathIsDirectory([MarshalAsAttribute(UnmanagedType.LPWStr), In] string pszPath);
You would then call it like this:
#region IsDirectory
/// <summary>
/// Verifies that a path is a valid directory.
/// </summary>
/// <param name="path">The path to verify.</param>
/// <returns><see langword="true"/> if the path is a valid directory;
/// otherwise, <see langword="false"/>.</returns>
/// <exception cref="T:System.ArgumentNullException">
/// <para><paramref name="path"/> is <see langword="null"/>.</para>
/// </exception>
/// <exception cref="T:System.ArgumentException">
/// <para><paramref name="path"/> is <see cref="F:System.String.Empty">String.Empty</see>.</para>
/// </exception>
public static bool IsDirectory(string path)
{
return PathIsDirectory(path);
}
I came across this when facing a similar problem, except I needed to check if a path is for a file or folder when that file or folder may not actually exist. There were a few comments on answers above that mentioned they would not work for this scenario. I found a solution (I use VB.NET, but you can convert if you need) that seems to work well for me:
Dim path As String = "myFakeFolder\ThisDoesNotExist\"
Dim bIsFolder As Boolean = (IO.Path.GetExtension(path) = "")
'returns True
Dim path As String = "myFakeFolder\ThisDoesNotExist\File.jpg"
Dim bIsFolder As Boolean = (IO.Path.GetExtension(path) = "")
'returns False
Hopefully this can be helpful to someone!
soooo late in the game i know, but thought i'd share this anyway. If you are solely working with the paths as strings, figuring this out is easy as pie:
private bool IsFolder(string ThePath)
{
string BS = Path.DirectorySeparatorChar.ToString();
return Path.GetDirectoryName(ThePath) == ThePath.TrimEnd(BS.ToCharArray());
}
for example:
ThePath == "C:\SomeFolder\File1.txt" would end up being this:
return "C:\SomeFolder" == "C:\SomeFolder\File1.txt" (FALSE)
Another example:
ThePath == "C:\SomeFolder\" would end up being this:
return "C:\SomeFolder" == "C:\SomeFolder" (TRUE)
And this would also work without the trailing backslash:
ThePath == "C:\SomeFolder" would end up being this:
return "C:\SomeFolder" == "C:\SomeFolder" (TRUE)
Keep in mind here that this only works with the paths themselves, and not the relationship between the path and the "physical disk"... so it can't tell you if the path/file exists or anything like that, but it sure can tell you if the path is a folder or a file...
If you want to find directories, including those that are marked "hidden" and "system", try this (requires .NET V4):
FileAttributes fa = File.GetAttributes(path);
if(fa.HasFlag(FileAttributes.Directory))
I needed this, the posts helped, this gets it down to one line, and if the path isn't a path at all, it just returns and exits the method. It addresses all of the above concerns, doesn't need the trailing slash either.
if (!Directory.Exists(#"C:\folderName")) return;
I see, I'm 10 years too late to the party.
I was facing the situation, where from some property I can receive either a file name or a full file path. If there is no path provided, I have to check the file-existence by attaching a "global" directory-path provided by another property.
In my case
var isFileName = System.IO.Path.GetFileName (str) == str;
did the trick.
Ok, it's not magic, but perhaps this could save someone a few minutes of figuring out.
Since this is merely a string-parsing, so Dir-names with dots may give false positives...
I use the following, it also tests the extension which means it can be used for testing if the path supplied is a file but a file that doesn't exist.
private static bool isDirectory(string path)
{
bool result = true;
System.IO.FileInfo fileTest = new System.IO.FileInfo(path);
if (fileTest.Exists == true)
{
result = false;
}
else
{
if (fileTest.Extension != "")
{
result = false;
}
}
return result;
}
using System;
using System.IO;
namespace FileOrDirectory
{
class Program
{
public static string FileOrDirectory(string path)
{
if (File.Exists(path))
return "File";
if (Directory.Exists(path))
return "Directory";
return "Path Not Exists";
}
static void Main()
{
Console.WriteLine("Enter The Path:");
string path = Console.ReadLine();
Console.WriteLine(FileOrDirectory(path));
}
}
}
Using the selected answer on this post, I looked at the comments and give credence to
#ŞafakGür, #Anthony and #Quinn Wilson for their info bits that lead me to this improved answer which I wrote and tested:
/// <summary>
/// Returns true if the path is a dir, false if it's a file and null if it's neither or doesn't exist.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static bool? IsDirFile(this string path)
{
bool? result = null;
if(Directory.Exists(path) || File.Exists(path))
{
// get the file attributes for file or directory
var fileAttr = File.GetAttributes(path);
if (fileAttr.HasFlag(FileAttributes.Directory))
result = true;
else
result = false;
}
return result;
}
Maybe for UWP C#
public static async Task<IStorageItem> AsIStorageItemAsync(this string iStorageItemPath)
{
if (string.IsNullOrEmpty(iStorageItemPath)) return null;
IStorageItem storageItem = null;
try
{
storageItem = await StorageFolder.GetFolderFromPathAsync(iStorageItemPath);
if (storageItem != null) return storageItem;
} catch { }
try
{
storageItem = await StorageFile.GetFileFromPathAsync(iStorageItemPath);
if (storageItem != null) return storageItem;
} catch { }
return storageItem;
}
Very late to the party here but I've found the Nullable<Boolean> return value to be quite ugly - IsDirectory(string path) returning null doesn't equate to a non-existent path without verbose commenting, so I've come up with the following:
public static class PathHelper
{
/// <summary>
/// Determines whether the given path refers to an existing file or directory on disk.
/// </summary>
/// <param name="path">The path to test.</param>
/// <param name="isDirectory">When this method returns, contains true if the path was found to be an existing directory, false in all other scenarios.</param>
/// <returns>true if the path exists; otherwise, false.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="path"/> is null.</exception>
/// <exception cref="ArgumentException">If <paramref name="path"/> equals <see cref="string.Empty"/></exception>
public static bool PathExists(string path, out bool isDirectory)
{
if (path == null) throw new ArgumentNullException(nameof(path));
if (path == string.Empty) throw new ArgumentException("Value cannot be empty.", nameof(path));
isDirectory = Directory.Exists(path);
return isDirectory || File.Exists(path);
}
}
This helper method is written to be verbose and concise enough to understand the intent the first time you read it.
/// <summary>
/// Example usage of <see cref="PathExists(string, out bool)"/>
/// </summary>
public static void Usage()
{
const string path = #"C:\dev";
if (!PathHelper.PathExists(path, out var isDirectory))
return;
if (isDirectory)
{
// Do something with your directory
}
else
{
// Do something with your file
}
}
Just adding a fringe case - "Folder Selection." in path
In my app I get recently opened paths passed to me, some of which have "Folder Selection." at the end.
Some FileOpenDialogs and WinMerge add "Folder Selection." to paths (it's true).
But under Windows OS "Folder Selection." is not an advised file or folder name (as in don't do it, ever - shakes fist).
As said here: http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx
Do not end a file or directory name with a space or a period. Although the underlying file system may support such names, the Windows shell and user interface does not. However, it is acceptable to specify a period as the first character of a name. For example, ".temp".
So whilst "Folder Selection." shouldn't be used, it can be. (awesome).
Enough explanation - my code (I like enums a lot):
public static class Utility
{
public enum ePathType
{
ePathType_Unknown = 0,
ePathType_ExistingFile = 1,
ePathType_ExistingFolder = 2,
ePathType_ExistingFolder_FolderSelectionAdded = 3,
}
public static ePathType GetPathType(string path)
{
if (File.Exists(path) == true) { return ePathType.ePathType_ExistingFile; }
if (Directory.Exists(path) == true) { return ePathType.ePathType_ExistingFolder; }
if (path.EndsWith("Folder Selection.") == true)
{
// Test the path again without "Folder Selection."
path = path.Replace("\\Folder Selection.", "");
if (Directory.Exists(path) == true)
{
// Could return ePathType_ExistingFolder, but prefer to let the caller known their path has text to remove...
return ePathType.ePathType_ExistingFolder_FolderSelectionAdded;
}
}
return ePathType.ePathType_Unknown;
}
}
This is my solution, beware that i was looking for a function that strictly avoid any unnecessary file system access at all, but only string manipulations are allowed here (paths may not exist):
public static bool IsFolder(string path)
{
if (string.IsNullOrEmpty(path)) return false;
if (path.EndsWith("\\")) return true;
return (path.Contains("\\") && string.IsNullOrEmpty(Path.GetExtension(path)));
}
Wouldn't this work?
var isFile = Regex.IsMatch(path, #"\w{1,}\.\w{1,}$");

Categories

Resources