CFileDialog设置多选的问题解决

1sweety小白

1sweety小白

2016-02-19 11:11

下面是个简单易学的CFileDialog设置多选的问题解决教程,图老师小编详细图解介绍包你轻松学会,喜欢的朋友赶紧get起来吧!
他的代码大致如下:
  static TCHAR BASED_CODE szFilter[] = _T(&TXT(*.txt)|*.txt||&);
  CFileDialog dlg(TRUE,_T(&txt&), NULL,OFN_HIDEREADONLY|OFN_ALLOWMULTISELECT,
  szFilter, NULL );
  INT_PTR nResult = dlg.DoModal();
  我测试了一下,选择比较多txt文件时,确实如他所言,会出现返回值是IDCANCEL的情况,但是有时如果少几个文件,就会返回IDOK。这说明多选文件对话框所选择的文件有一个临界值。选择文件的多少里面体现的应该是一个字符串缓冲区。因此我猜想CFileDialog里面应该有一个字符串缓冲区用于存贮用户所选的文件名,这个缓冲区有一个默认长度,假如所选的全部文件长度超出了默认长度,DoModal函数的返回值是IDCANCEL。如果是这样,那么就有以下一些问题:
  1.如果存在这个缓冲区,CFileDialog类中有哪些数据成员负责控制这个缓冲区,这个缓冲区的默认长度又是多少?
  2.如何增加这个缓冲区的长度以增加用户选择更多文件的需要?
  为此我搜索了一些资料。设置CFileDialog类的初始化值主要集中在m_ofn这个数据成员。
  m_ofn
  The Windows OPENFILENAME structure. Provides access to basic file dialog box parameters.
  其中m_ofn有两个成员负责文件名缓冲区:lpstrFile和nMaxFile。
  lpstrFile
  指向包含初始化文件名编辑控件使用的文件名的缓冲。如果不需要初始值,这个缓冲的第一个字符必须是NULL。当GetOpenFileName或GetSaveFileName函数返回成功时,这个缓冲包含驱动器,路径,文件名,及所选择的文件的扩展名。
  如果OFN_ALLOWMULTISELECT标记被设置并且用户选择了多个文件,缓冲包含了当前目录下被选择文件的文件名。对于Explorer 风格对话框,目录和文件名字符串是被NULL分开的,在文件名之后有一个额外的NULL。对于旧风格对话框,字符串是被空格分开的并且函数为带有空格的文件名使用短文件名。你可以使用FindFirstFile函数在长短文件名之间转换。如果用户只选择了一个文件,lpstrFile字符串在路径和文件名之间没有分隔。
  如果缓冲太小,函数返回FALSE并且CommDlgExtendedError函数返回FNERR_BUFFERTOOSMALL.。既然这样,lpstrFile缓冲的首先两个字节包含必需的大小(字节或字符)。
  nMaxFile
  指定lpstrFile缓冲的大小,以TCHARs为单位。对于ANSI版本,是字节的个数;对于 Unicode版本,是字符的个数。这个缓冲必须足够存储路径和文件名字符串,包含结尾的null字符。如果缓冲太小,GetOpenFileName和GetSaveFileName函数返回假(FALSE)缓冲最小应该在256个字符长。
  经过调试观察,我发现nMaxFile的初始值为260。但是我写程序测试这个缓冲区的默认大小时,却和这个初始值有矛盾。
  我的测试办法是这样的。首先在E盘建一个Txt Data的文件夹,然后创建40个空的txt文件。创建代码如下:
for (int i = 0;i40;i++)
  {
  CString strName = _T(&&);
  strName.Format(_T(&E:Txt Data%d.txt&),i);
  CreateFile(strName, // file to open
  GENERIC_READ, // open for reading
  FILE_SHARE_READ, // share for reading
  NULL, // default security
  CREATE_NEW, // existing file only
  FILE_ATTRIBUTE_NORMAL, // normal file
  NULL); // no attr. template
  }
  然后我经过多次尝试,发现在选择0..txt,1.txt,2.xtxt,27.txt(共28个文件)时DoModal函数的返回值是IDOK,但是在选择0..txt,1.txt,2.xtxt,27.txt,28.txt(共29个文件)时DoModal函数的返回值是IDCANCEL。接着我计算了一下所选中的文件的总长度(在unicode字符集下编译):
  CString strAllFiles = _T(&&);
  for (int i = 0;i28;i++)
  {
  CString strName = _T(&&);
  strName.Format(_T(&E:Txt Data%d.txt&),i);
  strAllFiles = strAllFiles + strName;
  }
  int nStrLen = strAllFiles.GetLength();
  nStrLen的返回值是494,如果增加一个28.txt,即:
  CString strAllFiles = _T(&&);
  for (int i = 0;i29;i++)
  {
  CString strName = _T(&&);
  strName.Format(_T(&E:Txt Data%d.txt&),i);
  strAllFiles = strAllFiles + strName;
  }
  int nStrLen = strAllFiles.GetLength();
  nStrLen的返回值是512.在多字节字符集下也是这个数值。这里需要注意的是CString::GetLength() 对于ASCII,返回字符串所占字节的数目,但如果是Unicode则实际上返回的是字符数而不是字节数
  那么我初步断定那个缓冲区的默认大小不是我调试观察到的260,而是512。至于开头如何解决那个问题,只需要定义一个更大的缓冲区,将lpstrFile指向这个缓冲区,重设nMaxFile的值即可,具体是:
  TCHAR szLargeBuf[4096]; // 定义一个临时缓冲区
  memset(szLargeBuf,'0',4096);
  static TCHAR BASED_CODE szFilter[] = _T(&TXT(*.txt)|*.txt||&);
  CFileDialog dlg(TRUE,_T(&txt&), NULL,OFN_HIDEREADONLY|OFN_ALLOWMULTISELECT,
  szFilter, NULL );
  dlg.m_ofn.lpstrFile = szLargeBuf;
  #ifdef UNICODE
  dlg.m_ofn.nMaxFile = 4096;
  #else
  dlg.m_ofn.nMaxFile = sizeof (szLargeBuf);
  #endif
想读入多文件,但总是最多读入8个文件,超过8个读不进来,设断点检查发现,如果想读入8个文件,程序运行到 if (dlgOpen-DoModal()==IDOK)就跳出if语句,不执行下面的语句。难怪!但是究竟怎么才能读入多个文件那,我搜索DoModal函数源代码,在文件DLGFILE.CPP中找到。发现函数中有个判断语句 DWORD nOffset = lstrlen(m_ofn.lpstrFile)+1; ASSERT(nOffset = m_ofn.nMaxFile);而nMaxFile最大文件数在构造函数中为空,如果不指定nMaxFile的值,判断语句必然从DoModal函数中跳出。所以我在if (dlgOpen-DoModal()==IDOK)前面写入下面语句CString str; dlgOpen-m_ofn.lpstrFile=str.GetBuffer(100000); str.ReleaseBuffer(); dlgOpen-m_ofn.nMaxFile = 5000;一切搞定! 但是要记住,m_ofn是不可见的,但是写上去不会报错。
CFileDialog如何实现文件多选
      CFileDialog类设置OFN_ALLOWMULTISELECT 标志可以实现文件多选功能,但是文件的数量是有限制的,如果要突破这个限制,就必须自己提供缓冲区。例子如下:
CString fileExtensions = "jpg文件(*.jpg) |*.jpg||";                                      
CFileDialog fileDlg(TRUE,
                             NULL,
                             NULL,
                             OFN_ALLOWMULTISELECT | OFN_ENABLESIZING | OFN_HIDEREADONLY,
                              fileExtensions);
const int MIN_FILE_NUMBER = 10;                                                           //至少允许选择10个文件
fileDlg.m_ofn.lpstrFile = new TCHAR[_MAX_PATH * MIN_FILE_NUMBER]; //重新定义缓冲区大小         
memset(fileDlg.m_ofn.lpstrFile, 0, _MAX_PATH * MIN_FILE_NUMBER);  //初始化定义的缓冲区
fileDlg.m_ofn.nMaxFile = _MAX_PATH * MIN_FILE_NUMBER;
if (IDOK == fileDlg.DoModal())
{
       POSITION pos = fileDlg.GetStartPosition();
       while (NULL != pos)
       {
              TRACE(fileDlg.GetNextPathName(pos));                                //获取文件名
              //使用文件...
        }
 }
delete[] fileDlg.m_ofn.lpstrFile;     //最后别忘了释放内存
展开更多 50%)
分享

猜你喜欢

CFileDialog设置多选的问题解决

编程语言 网络编程
CFileDialog设置多选的问题解决

《尘埃3》运行问题解决

电脑网络
《尘埃3》运行问题解决

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

mysql常见问题解决

编程语言 网络编程
mysql常见问题解决

CSS Hacks和问题解决

Web开发
CSS Hacks和问题解决

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

MYSQL EMS的乱码问题解决

编程语言 网络编程
MYSQL EMS的乱码问题解决

ERROR/AndroidRuntime(17121)的问题解决

编程语言 网络编程
ERROR/AndroidRuntime(17121)的问题解决

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

JSP彩色验证码的实例代码

JSP彩色验证码的实例代码

jsp Hibernate 函数简介

jsp Hibernate 函数简介
下拉加载更多内容 ↓