6

I'm getting reports from a WPF application that is deployed in the field that the following ArgumentException is being thrown when attempting to display an Open File Dialog.

Exception Message:   Value does not fall within the expected range.
Method Information:  MS.Internal.AppModel.IShellItem2 GetShellItemForPath(System.String)
Exception Source:    PresentationFramework
Stack Trace
  at MS.Internal.AppModel.ShellUtil.GetShellItemForPath(String path)
  at Microsoft.Win32.FileDialog.PrepareVistaDialog(IFileDialog dialog)
  at Microsoft.Win32.FileDialog.RunVistaDialog(IntPtr hwndOwner)
  at Microsoft.Win32.FileDialog.RunDialog(IntPtr hwndOwner)
  at Microsoft.Win32.CommonDialog.ShowDialog(Window owner)
  ...

The problem is that so far I haven't been able to replicate this in my development environment but I have received several reports from the field that this exception is occurring.

Has anyone seen this before? And most importantly do you know the cause and/or a fix for it other than just simply putting a try/catch around it and instructing the user to try again whatever it is they were trying to do?

In response to a comment, this is the code that opens the dialog (and no, it was not a problem of checking the return type). The exception is thrown from within ShowDialog (see stack trace):

Nullable<bool> result = null;

var dlg = new Microsoft.Win32.OpenFileDialog();
dlg.DefaultExt = ".txt";
dlg.Filter = "Text Files (.txt)|*.txt|All Files|*.*";
dlg.Title = "Open File";
dlg.Multiselect = false;
dlg.InitialDirectory = GetFolderFromConfig("folders.templates");
result = dlg.ShowDialog(Window.GetWindow(this));

if (result == true)
{
    // Invokes another method here..
}
Mike Dinescu
  • 54,171
  • 16
  • 118
  • 151
  • can you post the code that opens the dialog, as if the user cancels the dialog it may be returning a null or incorrect value. – sa_ddam213 Jan 07 '13 at 22:00
  • 2
    Yes, replicating that is going to be difficult. A workaround is to catch the exception (once) and set the InitialDirectory to a known-good directory. – Hans Passant Jan 07 '13 at 22:25
  • Catch the exception. Also test as a user with low privilege. – paparazzo Jan 07 '13 at 22:35
  • @HansPassant - you may be on to something. If it is a Shell32 internal problem with a specific folder maybe upon catching the exception I could attempt to set the initial folder to MyComputer of something along those lines.. Thanks for the suggestion. – Mike Dinescu Jan 07 '13 at 23:00
  • @sa_ddam213 - unfortunately it's not as easy as that (code posted); please see the full description of the problem. In particular, the stack trace. – Mike Dinescu Jan 07 '13 at 23:01
  • What does GetFolderFromConfig return? – Peter Hansen Jan 07 '13 at 23:01
  • @PeterHansen - it returns a path which is supposed to point to a user-selected location on the user's hard-drive. Technically it should always provide a valid path but apparently it must be returning garbage. Will have to investigate further.. – Mike Dinescu Jan 07 '13 at 23:19
  • There is a very similar question at http://stackoverflow.com/questions/9875456/savefiledialog-exception-in-my-wpf-app. Be aware that the WPF OpenFileDialog & SaveFileDialog appear to be horribly intolerant of things like relative paths (which could easily occur if the folders.templates property is user editable as many power users are familiar with, and enjoy the convenience offered by, relative paths). – Richard J Foster Aug 22 '14 at 15:13
  • Possible duplicate of [OpenFileDialog.ShowDialog() throws an exception?](http://stackoverflow.com/questions/6433373/openfiledialog-showdialog-throws-an-exception) – Ian Kemp Jan 18 '17 at 12:14
  • @IanKemp It's not a duplicate. In this case the Problem was the File dialog implementation not handling the InitialDialog property correctly in certain cases. – Mike Dinescu Jan 18 '17 at 16:28
  • @MikeDinescu The comments on that question indicate that its accepted answer has nothing to do with the actual problem, which was, as in your case, the fact that the `OpenFileDialog`'s `InitialDirectory` property was incorrectly set. – Ian Kemp Jan 19 '17 at 06:43

3 Answers3

7

This issue can also occur with non-special directories, such as mapped network drives. In my case, our %HOME% environment variable points to a mapped network drive (Z:). Thus the following code generates the same exception:

Nullable<bool> result = null;

var dlg = new Microsoft.Win32.OpenFileDialog();
dlg.DefaultExt = ".txt";
dlg.Filter = "Text Files (.txt)|*.txt|All Files|*.*";
dlg.Title = "Open File";
dlg.Multiselect = false;
dlg.InitialDirectory = Environment.GetEnvironmentVariable("Home")+@"\.ssh"; // boom
result = dlg.ShowDialog(Window.GetWindow(this));

Solution:

var dlg = new Microsoft.Win32.OpenFileDialog();
dlg.DefaultExt = ".txt";
dlg.Filter = "Text Files (.txt)|*.txt|All Files|*.*";
dlg.Title = "Open File";
dlg.Multiselect = false;
dlg.InitialDirectory = System.IO.Path.GetFullPath(Environment.GetEnvironmentVariable("Home")+@"\.ssh"); // no boom
result = dlg.ShowDialog(Window.GetWindow(this));
Nathan Strong
  • 2,360
  • 13
  • 17
  • Based on what I'm seeing elsewhere, calling System.IO.Path.GetFullPath on the directory is a good practice as it eliminates oddities that may occur (such as relative paths, or the presence of a double \) which the WPF OpenFileDialog & SaveFileDialog appear to be unable to handle. – Richard J Foster Aug 22 '14 at 15:17
3

This should really go to @Hans Passant as he pointed me in the right direction.

It turns out the problem was trivial to replicate (and fix) on my development computer once I figured out what the problem really was. It turns out that the issue was indeed the InitialDirectory property being set to some odd value. in my case I was able to replicate the issue by setting InitialDirectory to "\";

Here's the modified code to address the issue:

 try
 {
     result = dlg.ShowDialog(Window.GetWindow(this));
 }
 catch{
     dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyComputer);
     result = dlg.ShowDialog(Window.GetWindow(this));
 }
Mike Dinescu
  • 54,171
  • 16
  • 118
  • 151
0
      ///<summary>
      /// Tries to handle inability of user to access file dialog folder
      /// by using other folder. Shows meaningful message to 
      /// user for action on failure.
      ///</summary>
      private bool? ShowDialogSafe()
      {
        try
        {
            return dlg.ShowDialog(Window.GetWindow(this));
        }
        // reacts on rare case of bad default folder, filter only folder related excepions
        catch (Exception handledEx) when (IsInitialDirectoryAccessError(handledEx))
        {
            var original = dlg.InitialDirectory;
            var possible = Environment.GetFolderPath(Environment.SpecialFolder.Personal);// hope user has access to his own, may try Desktop
            try
            {
                dlg.InitialDirectory = possible;
                return FileDialog.ShowDialog(Window.GetWindow(this));
            }
            catch (Exception ex) when (IsInitialDirectoryAccessError(ex))
            {
                var message = string.Format("Failed to access directories '{0}' and '{1}'. Please contact system administrator.", original, possible);
                throw new IOException(message, ex);
            }
        }
    }

    /// <summary>
    /// see GetShellItemForPath(string path) http://referencesource.microsoft.com/#PresentationFramework/src/Framework/MS/Internal/AppModel/ShellProvider.cs,f0a8bc5f6e7b1503,references
    /// System.IO.FileNotFoundException: 'The network name cannot be found. (Exception from HRESULT: 0x80070043)' - no such share exsits
    /// "Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))"}  System.UnauthorizedAccessException - folder is forbidden
    /// System.ArgumentException: 'Value does not fall within the expected range.' - badly formatted path
    /// </summary>
    /// <param name="handledEx"></param>
    /// <returns></returns>
    private static bool IsInitialDirectoryAccessError(Exception handledEx)
        => handledEx is IOException || handledEx is UnauthorizedAccessException || handledEx is ArgumentException;
Dzmitry Lahoda
  • 939
  • 1
  • 13
  • 34