MFC CFileDialog 多选文件,取得的文件路径错误BUG如何解决?

h2052519 2016-03-30 11:41:53
加精

代码如下:
CFileDialog OpenDialog(TRUE,NULL,L"",OFN_ALLOWMULTISELECT | OFN_ENABLESIZING | OFN_HIDEREADONLY);
if(OpenDialog.DoModal())
{
POSITION pos;
pos = OpenDialog.GetStartPosition();
CString path;
while(pos !=NULL)
{
path += OpenDialog.GetNextPathName(pos);
path +=L"\n";
}
MessageBox(path);
}

当多选文件不在同一目录下,出现BUG。
在一个目录下搜索文件名,选中几个不在同一文件夹下面的文件





这样用GetNextPathName 取得的文件路径都不对啊。

结论:GetNextPathName 所得到的文件名,是用GetPathName 加上文件名组合起来的。当多选的文件不在同一目录就出现BUG。
...全文
1759 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
paschen 2016-04-01
  • 打赏
  • 举报
回复
引用 7 楼 lx624909677 的回复:
//同时打开N个文件
void COpenNFileDlg::OnButton1() 
{
    CString pathName,fileName,fileTitle;
 
    char* filters = _T("PCM文件(*.pcm)|*.pcm");
 
    //创建一个可以选择多个文件的CFileDialog
    CFileDialog fileDlg(true,NULL,"*.pcm",OFN_ALLOWMULTISELECT | OFN_ENABLESIZING | OFN_HIDEREADONLY,filters);
     
    //最多可以打开500个文件
    fileDlg.m_ofn.nMaxFile = 500 * MAX_PATH;
     
    char* ch = new TCHAR[fileDlg.m_ofn.nMaxFile];
    fileDlg.m_ofn.lpstrFile = ch;
 
    //对内存块清零
    ZeroMemory(fileDlg.m_ofn.lpstrFile,sizeof(TCHAR) * fileDlg.m_ofn.nMaxFile);
 
    //显示文件对话框,获得文件名集合
    if(fileDlg.DoModal() == IDOK){
         
        //获取第一个文件的位置
        POSITION pos_file;
        pos_file = fileDlg.GetStartPosition();
         
        //用CString数组存放文件的路径
        CArray<CString, CString> ary_filename;
        //存放文件的标题
        CArray<CString, CString> ary_fileTitle;
 
        //循环读出每个路径并存放在数组中
        while(pos_file != NULL){
             
            //将文件路径存放在数组中
            pathName = fileDlg.GetNextPathName(pos_file);
            ary_filename.Add(pathName);
             
            //获取文件名 
            //从字符串的后面往前遍历,如果遇到'\'则结束遍历,'\'右边的字符串则为文件名
            int length = pathName.GetLength();      
            for(int i = length -1; i>0;i--)
            {
                if('\' == pathName. GetAt(i))
                {//判断当前字符是否是'\'
                    fileName = pathName.Right(length - i -1);
                    break;//跳出循环
                }
            }//endfor
 
            //获取文件名(不包含后缀)
            //采用CString的Left(int count)截取CString中从左往右数的count个字符
            //fileName.GetLength()-4中的4表示".dat"四个字符
 
            fileTitle = fileName.Left(fileName.GetLength()-4);
            //AfxMessageBox(fileTitle);
            ary_fileTitle.Add(fileTitle);//将文件名(不包含后缀)添加到数组中
        }       
    }
    delete[] ch;
}
试试这样
这个方法和楼主的没有什么不同,他下面只是将完整的路径分割出文件名与路径,而且代码风格也不好,比如有时使用的是多字节下的char,有时用的又是通用的TCHAR
paschen 2016-04-01
  • 打赏
  • 举报
回复
引用 6 楼 cutmelon 的回复:
CFileDialog在vista之后最好不要直接用GetFileName之类了,给你个解决办法吧
	CFileDialog OpenDialog(TRUE,NULL,"",OFN_ALLOWMULTISELECT|OFN_ENABLESIZING|OFN_HIDEREADONLY);
	if (OpenDialog.DoModal())
	{
		CString path;
		IShellItemArray *pResult=OpenDialog.GetResults();
		DWORD dwCount=0;
		IShellItem *pItem;
		WCHAR *pFilePath;
		pResult->GetCount(&dwCount);
		for (DWORD i=0;i<dwCount;i++)
		{
			pResult->GetItemAt(i,&pItem);
			pItem->GetDisplayName(SIGDN_FILESYSPATH,&pFilePath);
			path+=pFilePath;
			path+="\n";
		}
		AfxMessageBox(path);
	}
这个解决方法很赞,虽然网上全是教用GetFileName的
伊航 2016-04-01
  • 打赏
  • 举报
回复
引用 9 楼 u012636291 的回复:
可以结贴了,谢谢各位!
引用 7 楼 lx624909677 的回复:
//同时打开N个文件
void COpenNFileDlg::OnButton1() 
{
    CString pathName,fileName,fileTitle;
 
    char* filters = _T("PCM文件(*.pcm)|*.pcm");
 
    //创建一个可以选择多个文件的CFileDialog
    CFileDialog fileDlg(true,NULL,"*.pcm",OFN_ALLOWMULTISELECT | OFN_ENABLESIZING | OFN_HIDEREADONLY,filters);
     
    //最多可以打开500个文件
    fileDlg.m_ofn.nMaxFile = 500 * MAX_PATH;
     
    char* ch = new TCHAR[fileDlg.m_ofn.nMaxFile];
    fileDlg.m_ofn.lpstrFile = ch;
 
    //对内存块清零
    ZeroMemory(fileDlg.m_ofn.lpstrFile,sizeof(TCHAR) * fileDlg.m_ofn.nMaxFile);
 
    //显示文件对话框,获得文件名集合
    if(fileDlg.DoModal() == IDOK){
         
        //获取第一个文件的位置
        POSITION pos_file;
        pos_file = fileDlg.GetStartPosition();
         
        //用CString数组存放文件的路径
        CArray<CString, CString> ary_filename;
        //存放文件的标题
        CArray<CString, CString> ary_fileTitle;
 
        //循环读出每个路径并存放在数组中
        while(pos_file != NULL){
             
            //将文件路径存放在数组中
            pathName = fileDlg.GetNextPathName(pos_file);
            ary_filename.Add(pathName);
             
            //获取文件名 
            //从字符串的后面往前遍历,如果遇到'\'则结束遍历,'\'右边的字符串则为文件名
            int length = pathName.GetLength();      
            for(int i = length -1; i>0;i--)
            {
                if('\' == pathName. GetAt(i))
                {//判断当前字符是否是'\'
                    fileName = pathName.Right(length - i -1);
                    break;//跳出循环
                }
            }//endfor
 
            //获取文件名(不包含后缀)
            //采用CString的Left(int count)截取CString中从左往右数的count个字符
            //fileName.GetLength()-4中的4表示".dat"四个字符
 
            fileTitle = fileName.Left(fileName.GetLength()-4);
            //AfxMessageBox(fileTitle);
            ary_fileTitle.Add(fileTitle);//将文件名(不包含后缀)添加到数组中
        }       
    }
    delete[] ch;
}
试试这样
我觉得也是。
h2052519 2016-03-31
  • 打赏
  • 举报
回复
可以结贴了,谢谢各位!
h2052519 2016-03-31
  • 打赏
  • 举报
回复
6楼方法正确,今天也看到了CFileDialog 有UpdateOFNFromShellDialog 这样一个成员函数,里面一段代码也是用同样的方法来取得文件名的。 IShellItemArray *ppenum = NULL; HRESULT hr = pfod->GetResults(&ppenum); if (SUCCEEDED(hr)) { IEnumShellItems *ppenumShellItems; hr = ppenum->EnumItems(&ppenumShellItems); if (SUCCEEDED(hr)) { IShellItem *rgelt[1]; ULONG celtFetched = 0; if (ppenumShellItems->Next(1, rgelt, &celtFetched) == S_OK) { CStringW strTmp; LPTSTR pszFileName = m_ofn.lpstrFile; LPWSTR wcPathName = NULL; hr = rgelt[0]->GetDisplayName(SIGDN_FILESYSPATH, &wcPathName); if (SUCCEEDED(hr)) { 非常感谢。
赵4老师 2016-03-31
  • 打赏
  • 举报
回复
OFN_ALLOWMULTISELECT Specifies that the File Name list box allows multiple selections. If you also set the OFN_EXPLORER flag, the dialog box uses the Explorer-style user interface; otherwise, it uses the old-style user interface. If the user selects more than one file, the lpstrFile buffer returns the path to the current directory followed by the filenames of the selected files. The nFileOffset member is the offset, in bytes or characters, to the first filename, and the nFileExtension member is not used. For Explorer-style dialog boxes, the directory and filename strings are NULL separated, with an extra NULL character after the last filename. This format enables the Explorer-style dialogs to return long filenames that include spaces. For old-style dialog boxes, the directory and filename strings are separated by spaces and the function uses short filenames for filenames with spaces. You can use theFindFirstFile function to convert between long and short filenames.
paschen 2016-03-31
  • 打赏
  • 举报
回复
帮你测试了,确实有这问题,帮顶,另外帮你移到MFC版块
lx624909677 2016-03-31
  • 打赏
  • 举报
回复
//同时打开N个文件
void COpenNFileDlg::OnButton1() 
{
    CString pathName,fileName,fileTitle;
 
    char* filters = _T("PCM文件(*.pcm)|*.pcm");
 
    //创建一个可以选择多个文件的CFileDialog
    CFileDialog fileDlg(true,NULL,"*.pcm",OFN_ALLOWMULTISELECT | OFN_ENABLESIZING | OFN_HIDEREADONLY,filters);
     
    //最多可以打开500个文件
    fileDlg.m_ofn.nMaxFile = 500 * MAX_PATH;
     
    char* ch = new TCHAR[fileDlg.m_ofn.nMaxFile];
    fileDlg.m_ofn.lpstrFile = ch;
 
    //对内存块清零
    ZeroMemory(fileDlg.m_ofn.lpstrFile,sizeof(TCHAR) * fileDlg.m_ofn.nMaxFile);
 
    //显示文件对话框,获得文件名集合
    if(fileDlg.DoModal() == IDOK){
         
        //获取第一个文件的位置
        POSITION pos_file;
        pos_file = fileDlg.GetStartPosition();
         
        //用CString数组存放文件的路径
        CArray<CString, CString> ary_filename;
        //存放文件的标题
        CArray<CString, CString> ary_fileTitle;
 
        //循环读出每个路径并存放在数组中
        while(pos_file != NULL){
             
            //将文件路径存放在数组中
            pathName = fileDlg.GetNextPathName(pos_file);
            ary_filename.Add(pathName);
             
            //获取文件名 
            //从字符串的后面往前遍历,如果遇到'\'则结束遍历,'\'右边的字符串则为文件名
            int length = pathName.GetLength();      
            for(int i = length -1; i>0;i--)
            {
                if('\' == pathName. GetAt(i))
                {//判断当前字符是否是'\'
                    fileName = pathName.Right(length - i -1);
                    break;//跳出循环
                }
            }//endfor
 
            //获取文件名(不包含后缀)
            //采用CString的Left(int count)截取CString中从左往右数的count个字符
            //fileName.GetLength()-4中的4表示".dat"四个字符
 
            fileTitle = fileName.Left(fileName.GetLength()-4);
            //AfxMessageBox(fileTitle);
            ary_fileTitle.Add(fileTitle);//将文件名(不包含后缀)添加到数组中
        }       
    }
    delete[] ch;
}
试试这样
cutmelon 2016-03-31
  • 打赏
  • 举报
回复
CFileDialog在vista之后最好不要直接用GetFileName之类了,给你个解决办法吧
	CFileDialog OpenDialog(TRUE,NULL,"",OFN_ALLOWMULTISELECT|OFN_ENABLESIZING|OFN_HIDEREADONLY);
	if (OpenDialog.DoModal())
	{
		CString path;
		IShellItemArray *pResult=OpenDialog.GetResults();
		DWORD dwCount=0;
		IShellItem *pItem;
		WCHAR *pFilePath;
		pResult->GetCount(&dwCount);
		for (DWORD i=0;i<dwCount;i++)
		{
			pResult->GetItemAt(i,&pItem);
			pItem->GetDisplayName(SIGDN_FILESYSPATH,&pFilePath);
			path+=pFilePath;
			path+="\n";
		}
		AfxMessageBox(path);
	}

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧