我遇到了一个问题,对话框中可以打开的文件数量限制为大约 600 个。当选择超过此数量时,对话框底部的编辑框会变为空,并且不会打开任何文件。
需要使用应用程序打开的文件具有相对较长的名称(70+个字符),这无疑是一个因素,但无法更改。该应用程序需要能够打开超过 5000 个文件。
问题是,限制在哪里/如何定义,是否可以增加?如果是的话,怎么办?
据我所知,这不是其他人为 C++Builder 报告的问题。我确实找到了一篇与 Delphi 相关的帖子,也有同样的问题,但建议的解决方案(增加全局变量
OpenDialogMaxMultiSelFiles
)不适用于 C++Builder,因为我在任何地方都找不到对它的任何引用。
旧版
TOpenDialog
VCL 组件是 Win32 GetOpenFileName()
和 IFileOpenDialog
API 的包装器。它内部使用哪个 API 取决于各种标准。
如果满足以下条件全部,则会使用
IFileOpenDialog
:
Vcl.Dialogs.UseLatestCommonDialogs
是 True
(默认情况下)。shDialogs
中未启用 TStyleManager.SystemHooks
标志。Comctl32.dll
v6,并且 IsAppThemed()
返回 true
)。Template
属性是nil
OnIncludeItem
、OnClose
和 OnShow
事件没有分配给它们的处理程序。如果不满足其中任何一个条件,
TOpenDialog
将使用 GetOpenFileName()
代替。
当
TOpenDialog
使用GetOpenFileName()
时,它使用固定大小的字符缓冲区从API接收选定的文件名。当启用 ofAllowMultiSelect
标志时,该缓冲区的大小最多为 65519 个字符,并且 API 将使用父目录的完整路径填充它,后跟该目录中所选文件名的列表。当选择的文件超过 600 个时,该缓冲区很容易耗尽。并且没有选项可以根据选择的文件数量动态分配该缓冲区,必须在调用 API 时预先提供该缓冲区。因此,增加此限制的唯一方法(无需修改 VCL 的源代码)就是简单地自己调用 GetOpenFileName()
,为其提供更大的缓冲区来使用,即 1.5-2MB 就足够了。
当
TOpenDialog
使用 IFileOpenDialog
时,它会从 API 接收单个 IShellItemArray
,该 API 提供对 IShellItem
数组的枚举,每个选定文件对应一个。每个完整的文件路径+名称都是从每个IShellItem
动态检索的。因此,这种方法应该仅受可用内存的限制。
如果您想强制执行
IFileOpenDialog
行为,则可以使用 TFileOpenDialog
组件。只要知道它不适用于 Vista 之前的 Windows 版本(如果您需要的话)。