Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I launch DotNet's OpenFileDialog in C:\Users\Public\Documents?

Is there a way to launch the OpenFileDialog in the C:\Users\Public\Documents folder?

I am writing a C# application, using the DotNet framework. I am trying to launch an OpenFileDialog, with an InitialDirectory of "C:\\Users\\Public\\Documents\\" and a FileName of "world.txt". Unfortunately, the OpenFileDialog is putting me in the Documents shortcut instead of into C:\Users\Public\Documents .

Expected results
I expect to see the OpenFileDialog open, with the top textbox showing > This PC > Windows7_OS (C:) > Users > Public > Documents and the bottom textbox showing world.txt . I expect that if I click in the top textbox, it will show C:\Users\Public\Documents .

Actual results
The OpenFileDialog opens. The top textbox shows > This PC > Documents and the bottom textbox shows world.txt . If I click in the top textbox, it shows Documents . The displayed folder contents are not the same as the contents of C:\Users\Public\Documents .

Things I have tried
I have stopped the code in the Visual Studio debugger after the following line of code:
OpenFileDialog dlg = new OpenFileDialog();

In the Immediate Window, I have executed code such as the following:

dlg.FileName = "world.txt"  
? dlg.FileName  
dlg.InitialDirectory = "C:\\NonExistentDirectory\\";  
dlg.ShowDialog();  
dlg.InitialDirectory = "C:\\";  
dlg.ShowDialog();  
dlg.InitialDirectory = "C:\\Users\\";  
dlg.ShowDialog(); 
dlg.InitialDirectory = "C:\\Users\\Public\\";  
dlg.ShowDialog(); 
dlg.InitialDirectory = "C:\\Users\\Public\\Documents\\";  
dlg.ShowDialog();  

I cancel out of each dialog.

I used C:\WINDOWS\System32\cmd.exe to cd between C:\ and C:\Users\ and C:\Users\Public and C:\Users\Public\Documents\ .

Results of things I have tried

  • When dlg.InitialDirectory = "C:\\NonExistentDirectory\\" , the dialog's folder initially displays as This PC > Documents > Visual Studio 2015 > Projects > SimpleGame > Controller > bin > Debug" . Clicking in the textbox causes it to display C:\Users\Owner\Documents\Visual Studio 2015\Projects\SimpleGame\Controller\bin\Debug . I therefore assume that OpenFileDialog silently handles an invalid InitialDirectory by not changing directories. In this case, it is defaulting to my project's assembly's bin's Debug folder.

  • When dlg.InitialDirectory is "C:\\" or "C:\\Users\\" or "C:\\Users\\Public\\" the dialog behaves as expected. Clicking in the top textbox produces C:\ or C:\Users or C:\Users\Public respectively.

  • When dlg.InitialDirectory = "C:\\Users\\Public\\Documents\\" the dialog behaves incorrectly. The top textbox shows > This PC > Documents and the bottom textbox shows world.txt . If I click in the top textbox, it shows Documents . The displayed folder contents are not the same as the contents of C:\Users\Public\Documents .

  • Using cmd.exe lets me cd between the folders as expected, including into C:\Users\Public\Documents .

My environment
I am running Microsoft Visual Studio Community 2015 Version 14.0.23107.0 D14REL, using Microsoft Visual C# 2015. My operating system is Windows 10 Pro.

like image 448
Jasper Avatar asked Nov 13 '16 06:11

Jasper


People also ask

How do I open an OpenFileDialog file?

Windows. Forms. OpenFileDialog component opens the Windows dialog box for browsing and selecting files. To open and read the selected files, you can use the OpenFileDialog.

How do I get OpenFileDialog in C#?

To create an OpenFileDialog control at design-time, you simply drag and drop an OpenFileDialog control from Toolbox to a Form in Visual Studio. After you drag and drop an OpenFileDialog on a Form, the OpenFileDialog looks like Figure 2. Adding an OpenFileDialog to a Form adds following two lines of code.

How do I open a file using OpenFileDialog in VB net?

Step 1: Drag the OpenFileDialog control from the toolbox and drop it to the Windows form, as shown below. Step 2: Once the OpenFileDialog is added to the form, we can set various properties of the OpenFileDialog by clicking on the OpenFileDialog. Video Player is loading.

Which property of OpenFileDialog is set to add extension to file name if the user does not supply any extension?

From FileDialog. AddExtension Property: "Gets or sets a value indicating whether the dialog box automatically adds an extension to a file name if the user omits the extension."


2 Answers

although as stated by Silver, this is a bug but can be roughly bypassed using SendMessage API with WM_SETTEXT on a different thread although hackish to say the least, it will most likely work.

i've put together some dirty code snippet using NSGaga's post to show a proof of concept, this raw example should not be used as is.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace WindowsFormsApplication13
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();

            //start a thread to change the dialog path just before displaying it to the user
            Thread posThread = new Thread(setDialogPath);
            posThread.Start();

            //display dialog to the user
            DialogResult dr = dlg.ShowDialog();
        }

        [DllImport("user32.dll")]
        static extern IntPtr FindWindow(IntPtr lpClassName, string lpWindowName);
        [DllImport("user32.dll")]
        static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, string lParam);
        [DllImport("user32.dll")]
        static extern IntPtr PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
        [DllImport("user32.Dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr GetClassName(IntPtr hWnd, System.Text.StringBuilder lpClassName, int nMaxCount);

        private void setDialogPath()
        {
            const string FULL_PATH = "C:\\Users\\Public\\Documents";

            //messages
            const int WM_SETTEXT = 0xC;
            const int WM_KEYDOWN = 0x100;
            const int WM_KEYUP = 0x101;
            //enter key code
            const int VK_RETURN = 0x0D;

            //dialog box window handle
            IntPtr _window_hwnd;

            //how many attempts to detect the window
            int _attempts_count = 0;

            //get the dialog window handle
            while ((_window_hwnd = FindWindow(IntPtr.Zero, "Open")) == IntPtr.Zero)
                if (++_attempts_count > 100)
                    return;
                else
                    Thread.Sleep(500); //try again

            //in it - find the path textbox's handle.
            var hwndChild = EnumAllWindows(_window_hwnd, "Edit").FirstOrDefault();

            //set the path
            SendMessage(hwndChild, WM_SETTEXT, 0, FULL_PATH);

            //apply the path (send 'enter' to the textbox)
            PostMessage(hwndChild, WM_KEYDOWN, VK_RETURN, 0);
            PostMessage(hwndChild, WM_KEYUP, VK_RETURN, 0);
        }


        public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);

        private static bool EnumWindow(IntPtr handle, IntPtr pointer)
        {
            GCHandle gch = GCHandle.FromIntPtr(pointer);
            List<IntPtr> list = gch.Target as List<IntPtr>;
            if (list == null)
                throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
            list.Add(handle);
            return true;
        }

        public static List<IntPtr> GetChildWindows(IntPtr parent)
        {
            List<IntPtr> result = new List<IntPtr>();
            GCHandle listHandle = GCHandle.Alloc(result);
            try
            {
                Win32Callback childProc = new Win32Callback(EnumWindow);
                EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
            }
            finally
            {
                if (listHandle.IsAllocated)
                    listHandle.Free();
            }
            return result;
        }

        public static string GetWinClass(IntPtr hwnd)
        {
            if (hwnd == IntPtr.Zero)
                return null;
            StringBuilder classname = new StringBuilder(100);
            IntPtr result = GetClassName(hwnd, classname, classname.Capacity);
            if (result != IntPtr.Zero)
                return classname.ToString();
            return null;
        }

        public static IEnumerable<IntPtr> EnumAllWindows(IntPtr hwnd, string childClassName)
        {
            List<IntPtr> children = GetChildWindows(hwnd);
            if (children == null)
                yield break;
            foreach (IntPtr child in children)
            {
                if (GetWinClass(child) == childClassName)
                    yield return child;
                foreach (var childchild in EnumAllWindows(child, childClassName))
                    yield return childchild;
            }
        }

    }
}

Hackish, but doable

like image 76
Stavm Avatar answered Oct 02 '22 09:10

Stavm


If you are using System.Windows.Forms.OpenFileDialog you can set:

dialog.AutoUpgradeEnabled = false;

The dialog will look a little dated/flat/"old school" but it does at least display the correct contents!

like image 28
David Hollinshead Avatar answered Oct 02 '22 09:10

David Hollinshead