我可以在 C:\Users\Public\Documents 中启动 DotNet 的 OpenFileDialog 吗?
Can I launch DotNet's OpenFileDialog in C:\Users\Public\Documents?
有没有办法启动 C:\Users\Public\Documents
文件夹中的 OpenFileDialog
?
我正在使用 DotNet 框架编写 C# 应用程序。我正在尝试启动 OpenFileDialog
,InitialDirectory
为 "C:\Users\Public\Documents\"
,FileName
为 "world.txt"
。不幸的是,OpenFileDialog
将我置于 Documents
快捷方式中,而不是 C:\Users\Public\Documents
中。
预期结果
我希望看到 OpenFileDialog 打开,顶部文本框显示 > This PC > Windows7_OS (C:) > Users > Public > Documents
,底部文本框显示 world.txt
。我希望如果我点击顶部的文本框,它会显示 C:\Users\Public\Documents
.
实际结果
打开文件对话框打开。顶部文本框显示 > This PC > Documents
,底部文本框显示 world.txt
。如果我点击顶部的文本框,它会显示 Documents
。显示的文件夹内容与C:\Users\Public\Documents
的内容不相同
我尝试过的东西
我已经在以下代码行之后停止了 Visual Studio 调试器中的代码:
OpenFileDialog dlg = new OpenFileDialog();
在即时 Window 中,我执行了如下代码:
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();
我取消了每个对话框。
我在C:\
和C:\Users\
和C:\Users\Public
和C:\Users\Public\Documents\
之间使用了C:\WINDOWS\System32\cmd.exe
到cd
。
我尝试过的结果
当 dlg.InitialDirectory = "C:\NonExistentDirectory\"
时,对话框的文件夹最初显示为 This PC > Documents > Visual Studio 2015 > Projects > SimpleGame > Controller > bin > Debug"
。单击文本框会使其显示 C:\Users\Owner\Documents\Visual Studio 2015\Projects\SimpleGame\Controller\bin\Debug
。因此,我假设 OpenFileDialog
通过不更改目录来静默处理无效的 InitialDirectory
。在这种情况下,它默认为我项目程序集的 bin 文件夹 Debug
。
当 dlg.InitialDirectory
为 "C:\"
或 "C:\Users\"
或 "C:\Users\Public\"
时,对话框按预期运行。单击顶部文本框分别生成 C:\
或 C:\Users
或 C:\Users\Public
。
当 dlg.InitialDirectory = "C:\Users\Public\Documents\"
对话框行为不正确。顶部文本框显示 > This PC > Documents
,底部文本框显示 world.txt
。如果我点击顶部的文本框,它会显示 Documents
。显示的文件夹内容与C:\Users\Public\Documents
.
的内容不相同
使用 cmd.exe
让我可以按预期在文件夹之间 cd
,包括 C:\Users\Public\Documents
.
我的环境
我是 运行 Microsoft Visual Studio Community 2015 Version 14.0.23107.0 D14REL,使用 Microsoft Visual C# 2015。我的操作系统是 Windows 10 Pro。
看来不可能!
您可以在下面link看到它是.net framework 中的一个错误:(
msdn link
您可以在最后一条评论中找到:
It is hard to believe but:
It is a bug and nothing else.
尽管如 Silver 所述,这是一个错误,但可以在不同的线程上使用带有 WM_SETTEXT 的 SendMessage API 粗略绕过,尽管至少可以说 ,它很可能会起作用。
我使用 NSGaga's post 整理了一些脏代码片段来展示概念证明,不应按原样使用此原始示例。
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;
}
}
}
}
有点老套,但可行
如果您正在使用 System.Windows.Forms.OpenFileDialog,您可以设置:
dialog.AutoUpgradeEnabled = false;
对话框看起来有点dated/flat/"old school",但它至少显示了正确的内容!
你会认为明显的答案是使用 Environment.SpecialFolder.CommonDocuments
,但这似乎与 Windows 10 上的 Environment.SpecialFolder.MyDocuments
完全相同。这一定是.NET!
我 运行 今天解决了这个问题,找到了一个对我有用的解决方案,可能对其他人也有用。只需将子文件夹添加到 Public 文档,然后将其用作初始目录即可。将您的东西存储在特定于应用程序的子文件夹中而不是仅仅存储在根目录中可能是更好的做法。像这样:
Path.Combine(Environment.SpecialFolder.CommonDocuments, "SomeSubfolder").
有没有办法启动 C:\Users\Public\Documents
文件夹中的 OpenFileDialog
?
我正在使用 DotNet 框架编写 C# 应用程序。我正在尝试启动 OpenFileDialog
,InitialDirectory
为 "C:\Users\Public\Documents\"
,FileName
为 "world.txt"
。不幸的是,OpenFileDialog
将我置于 Documents
快捷方式中,而不是 C:\Users\Public\Documents
中。
预期结果
我希望看到 OpenFileDialog 打开,顶部文本框显示 > This PC > Windows7_OS (C:) > Users > Public > Documents
,底部文本框显示 world.txt
。我希望如果我点击顶部的文本框,它会显示 C:\Users\Public\Documents
.
实际结果
打开文件对话框打开。顶部文本框显示 > This PC > Documents
,底部文本框显示 world.txt
。如果我点击顶部的文本框,它会显示 Documents
。显示的文件夹内容与C:\Users\Public\Documents
的内容不相同
我尝试过的东西
我已经在以下代码行之后停止了 Visual Studio 调试器中的代码:
OpenFileDialog dlg = new OpenFileDialog();
在即时 Window 中,我执行了如下代码:
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();
我取消了每个对话框。
我在C:\
和C:\Users\
和C:\Users\Public
和C:\Users\Public\Documents\
之间使用了C:\WINDOWS\System32\cmd.exe
到cd
。
我尝试过的结果
当
dlg.InitialDirectory = "C:\NonExistentDirectory\"
时,对话框的文件夹最初显示为This PC > Documents > Visual Studio 2015 > Projects > SimpleGame > Controller > bin > Debug"
。单击文本框会使其显示C:\Users\Owner\Documents\Visual Studio 2015\Projects\SimpleGame\Controller\bin\Debug
。因此,我假设OpenFileDialog
通过不更改目录来静默处理无效的InitialDirectory
。在这种情况下,它默认为我项目程序集的 bin 文件夹Debug
。当
dlg.InitialDirectory
为"C:\"
或"C:\Users\"
或"C:\Users\Public\"
时,对话框按预期运行。单击顶部文本框分别生成C:\
或C:\Users
或C:\Users\Public
。当
dlg.InitialDirectory = "C:\Users\Public\Documents\"
对话框行为不正确。顶部文本框显示> This PC > Documents
,底部文本框显示world.txt
。如果我点击顶部的文本框,它会显示Documents
。显示的文件夹内容与C:\Users\Public\Documents
. 的内容不相同
使用
cmd.exe
让我可以按预期在文件夹之间cd
,包括C:\Users\Public\Documents
.
我的环境
我是 运行 Microsoft Visual Studio Community 2015 Version 14.0.23107.0 D14REL,使用 Microsoft Visual C# 2015。我的操作系统是 Windows 10 Pro。
看来不可能!
您可以在下面link看到它是.net framework 中的一个错误:( msdn link 您可以在最后一条评论中找到:
It is hard to believe but:
It is a bug and nothing else.
尽管如 Silver 所述,这是一个错误,但可以在不同的线程上使用带有 WM_SETTEXT 的 SendMessage API 粗略绕过,尽管至少可以说 ,它很可能会起作用。
我使用 NSGaga's post 整理了一些脏代码片段来展示概念证明,不应按原样使用此原始示例。
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;
}
}
}
}
有点老套,但可行
如果您正在使用 System.Windows.Forms.OpenFileDialog,您可以设置:
dialog.AutoUpgradeEnabled = false;
对话框看起来有点dated/flat/"old school",但它至少显示了正确的内容!
你会认为明显的答案是使用 Environment.SpecialFolder.CommonDocuments
,但这似乎与 Windows 10 上的 Environment.SpecialFolder.MyDocuments
完全相同。这一定是.NET!
我 运行 今天解决了这个问题,找到了一个对我有用的解决方案,可能对其他人也有用。只需将子文件夹添加到 Public 文档,然后将其用作初始目录即可。将您的东西存储在特定于应用程序的子文件夹中而不是仅仅存储在根目录中可能是更好的做法。像这样:
Path.Combine(Environment.SpecialFolder.CommonDocuments, "SomeSubfolder").