Can I run DotNet OpenFileDialog in C: \ Users \ Public \ Documents?

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

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

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

Actual Results
OpenFileDialog opens. The top text box shows > This PC > Documents , and the bottom text box shows world.txt . If I click in the upper text box, it shows Documents . The displayed contents of the folder do not match the contents of C:\Users\Public\Documents .

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

In the Immediate window, I executed the following code:

 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 every dialogue.

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

The results of what I tried

  • When dlg.InitialDirectory = "C:\\NonExistentDirectory\\" , the dialog folder initially appears as This PC > Documents > Visual Studio 2015 > Projects > SimpleGame > Controller > bin > Debug" . Clicking in the text box displays C:\Users\Owner\Documents\Visual Studio 2015\Projects\SimpleGame\Controller\bin\Debug , so I assume that OpenFileDialog silently processes an invalid InitialDirectory without changing directories, in which case it defaults to my Debug project Debug .

  • If dlg.InitialDirectory is "C:\\" or "C:\\Users\\" or "C:\\Users\\Public\\" , the dialog behaves as expected. A click in the upper text box creates C:\ or C:\Users or C:\Users\Public respectively.

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

  • Using cmd.exe allows me to cd between folders as expected, including C:\Users\Public\Documents .

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

+6
source share
4 answers

If you use System.Windows.Forms.OpenFileDialog, you can set:

 dialog.AutoUpgradeEnabled = false; 

The dialog will look a bit dated / flat / "old school", but at least it displays the correct content!

+1
source

although, as pointed out by Silver, this is an error, but can be roughly bypassed using the SendMessage API with WM_SETTEXT in another thread, although at least the hacks will most likely work.

I put together some dirty code snippet using an NSGaga post to show 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 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

+2
source

It seems impossible!

You can see in the following link that this is an error in the .net framework :( you can find the msdn link in the last comment:

It's hard to believe, but:

This is a mistake, and nothing more.

+1
source

You might think that the obvious answer would be to use Environment.SpecialFolder.CommonDo‌​‌​cuments , but it looks like it is doing the same thing as Environment.SpecialFolder.MyDo‌​‌​cuments in Windows 10. This should be a bug in .NET!

Today I ran into this problem and found a solution that worked for me and might work for someone else. Just add the subfolder to the public documents, and then use it as the source directory. It is probably best to store your materials in a subfolder depending on the application, and not just the root anyway. Like this:

 Path.Combine(Environment.SpecialFolder.CommonDocuments, "SomeSubfolder"). 
+1
source

Source: https://habr.com/ru/post/1012275/


All Articles