OFN_ALLOWMULTISELECT 时 Windows API 函数 GetOpenFileName() 的字符限制是不是有解决方法?

Posted

技术标签:

【中文标题】OFN_ALLOWMULTISELECT 时 Windows API 函数 GetOpenFileName() 的字符限制是不是有解决方法?【英文标题】:Is there a workaround for the character limit on the Windows API function GetOpenFileName() when OFN_ALLOWMULTISELECT?OFN_ALLOWMULTISELECT 时 Windows API 函数 GetOpenFileName() 的字符限制是否有解决方法? 【发布时间】:2010-11-05 16:06:45 【问题描述】:

根据 MSDN 文档,函数 GetOpenFileName() 在使用 Windows 2000 和更高版本为 Unicode 编译时,使用选项 OFN_ALLOWMULTISELECT 没有字符限制。但是,在 Windows XP x64 SP2 上,我发现 32k ANSI 限制仍然有效,尽管使用了 Unicode。我在网上看到过其他关于这个问题的投诉,但没有解决方案。有谁知道一个简单的解决方法?

为了完整起见,我使用的是 Visual Studio 2010,并使用 C++ 进行编码。

【问题讨论】:

也许“无限制”的定义不同。 32K 正在进入“此缓冲区的大小无效”的长期区域。单个文件的 Ansi 限制为 MAX_PATH 或 260 个字符 iirc。 AFAIK,单个文件路径的 Unicode 和 ANSI 限制为 MAX_PATH(XP+ 上为 260)。但我不确定你在“这个缓冲区的大小无效”领域得到了什么。传递给 GetOpenFileName 的 OPENFILENAME 结构(参见 msdn.microsoft.com/en-us/library/ms646839%28VS.85%29.aspx)中的缓冲区大小是一个 DWORD(无符号长整数),因此限制应该远大于 32k。 奇怪的问题。当然有一个解决方法,使用 GetOpenFileNameW()。 奇怪的答案。 GetOpenFileNameW() 是使用 GetOpenFileName() 并为 Unicode 编译时调用的函数。所以这提出了同样的问题。 我的意思是 32K 足够大,它可能会超过缓冲区过于偏执的健全性检查限制。 【参考方案1】:

文档可能有误。 GetOpenFileName() 有点过时了,它不再支持最新的 Vista/Windows 7 功能。更糟糕的是,GetOpenFileName() 会弹出一个类似于 Windows 95 中的打开对话框,至少当您尝试在 Vista 或 Windows 7 上使用 LPOFNHOOKPROC 功能自定义对话框时。

从 Vista 和 Windows Server 2008 开始,推荐的新 API 是 IFileDialog 接口:http://www.codeproject.com/KB/vista/VGFileDialogs.aspx?msg=2368264。不幸的是,这在 XP 上不可用,因此您需要根据操作系统版本实现这两个 API。如果您需要在“打开”对话框中添加一些自定义控件,则别无选择,只能使用 IFileDialogCustomize。

我知道您的问题是关于 Windows XP,我建议的解决方法对您没有帮助,但不幸的是 IFileDialog 是 GetOpenFileName() 的唯一替代方法。

【讨论】:

+1 在 XP 上运行时只是降低了限制,但只要它可用就切换到 IFileDialog【参考方案2】:

可能是一个迟到的答案,但我也必须处理这个问题,并想提出我的解决方案,以防其他人将来遇到这种情况(如果你这样做,我表示哀悼)。对于那些想知道为什么要使用旧版 GetOpenFileName() 的人,如果您受困于旧版 .NET 1.1 并且由于限制(在现实世界中,有时付钱给您的个人或组织需要它),我们除了受其约束别无选择,所以请把批评放在一边,坚持OP的问题。此外,一个不错的功能(我相信人们可以纠正我)是,当设置了 ALLOWMULTISELECT 时,此方法实际上不会打开文件,因此您可以将其用作选择多个文件的界面,而不会占用每个文件的资源作为流打开的文件(即想象多选 1000 多个文件,每个文件都有一个为它打开的流! - 注意:.NET 的 OpenFileDialog 也可以这样做,因为您必须显式调用 OpenFile() 方法来打开资源,因此迭代Filenames 属性是可能的,但如果您超出我不知道的神秘限制,它可能会给出“InvalidOperationException: Too many files selected”)。

首先,尽管https://msdn.microsoft.com/en-us/library/windows/desktop/ms646927%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 在评论中说的是

Note, when selecting multiple files, the total character limit for the file names depends on the version of the function.
    • ANSI: 32k limit
    • Unicode: no restriction 

无论您是明确调用“GetOpenFileNameW()”还是让它在内部切换到它,Windows XP 都有 32KB 的限制(正如 OP 所提到的)。虽然我没有时间调查,但在 Win7 和 Server 2012(64 位)上,相同的 API 调用将正确(显然)切换到 Unicode 模式并绕过 32KB 限制。

我发现,在阅读了 https://msdn.microsoft.com/en-us/library/ms996463.aspx?f=255&MSPPError=-2147217396 上的 MSDN 文章后,如果我为 CDN_SELCHANGE 捕获 WM_NOTIFY,然后用一个非常大的缓冲区(即大于 32KB)查询 CDM_GETSPEC,你实际上可以捕获文件列表/collections 大于 32KB 限制。很抱歉MSDN文章中描述的解决方案是C#而不是C++,但最终结果应该是一样的。

【讨论】:

以上是关于OFN_ALLOWMULTISELECT 时 Windows API 函数 GetOpenFileName() 的字符限制是不是有解决方法?的主要内容,如果未能解决你的问题,请参考以下文章

CFileDialog 多文件选择

markdown Raspbian - 首次启动时的Wi-Fi和SSH

如何调用通用对话框

当 Wi-Fi Direct 范围内的对等点不再可用时,如何通知?

XCUITest - 如何在应用程序运行时禁用 Wi Fi?

如何通过 Wi-Fi 调试 Android 6.0? (netcfg 问题)