CFileDialog OFN_ALLOWMULTISELECT 不正确的快捷方式结果
CFileDialog with OFN_ALLOWMULTISELECT incorrect results for shortcuts
谁能告诉我我做错了什么?
MFC 项目,我正在使用 CFileDialog
让用户选择多个文件,例如:
CFileDialog fd(TRUE, NULL, NULL,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ALLOWMULTISELECT,
NULL, this);
if(fd.DoModal() == IDOK)
{
//Multi-selection
CString strPaths;
POSITION fileNamesPosition = fd.GetStartPosition();
while(fileNamesPosition != NULL)
{
if(!strPaths.IsEmpty())
strPaths += L"\n";
strPaths += fd.GetNextPathName(fileNamesPosition);
}
AfxMessageBox(strPaths);
}
所以如果说,有两个快捷方式文件:
shortcut_1.lnk
文件引用:"D:\Folder\Project_B\Release\Name of Project B.exe"
和shortcut_2.lnk
指的是"D:\Folder\Project_A\Release\Name of Project A.exe"
如果我从上面代码生成的 "File Open" 对话框中选择它们,我的结果 strPaths
将变为以下,这是不正确的:
D:\Folder\Project_A\Release\Name of Project A.exe
D:\Folder\Project_A\Release\Name of Project B.exe
第二条路径错误!
听起来像是 CFileDialog
中的错误。
通常,返回的路径是当前显示的目录路径和所选文件名的串联。在 lnk
文件的情况下,也许 CFileDialog
只是提取目标文件名并将其连接到 lnk
文件的父文件夹的路径,而不是仅仅返回完整的目标lnk
文件中的路径。如果没有看到 CFileDialog
.
的实际源代码,很难确定
为避免这种行为,您可以在调用对话框时包含 OFN_NODEREFERENCELINKS
标志,这样您就可以获得实际 lnk
文件的完整路径,然后您可以使用手动解析它们的目标IShellLink
对话框关闭后。
使用GetStartPosition()
和GetNextPathName()
函数是一团糟。一方面,他们使用旧式 API which depends on a correct return buffer size defined via OPENFILENAME
struct。 MFC 不会 处理这个问题!正如您的问题所示,即使缓冲区大小足够大,它也存在链接问题。
使用 Vista+ API 可以避免头痛,可通过 CFileDialog::GetIFileOpenDialog()
获得。
这是一个工作代码示例:
CFileDialog fd( TRUE, NULL, NULL,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ALLOWMULTISELECT,
NULL, nullptr );
if (fd.DoModal() == IDOK)
{
//Multi-selection
CString strPaths;
CComPtr<IFileOpenDialog> piod = fd.GetIFileOpenDialog();
ASSERT( piod );
CComPtr<IShellItemArray> pResults;
if( SUCCEEDED( piod->GetResults( &pResults ) ) )
{
DWORD count = 0; pResults->GetCount( &count );
for( DWORD i = 0; i < count; ++i )
{
CComPtr<IShellItem> pItem;
if( SUCCEEDED( pResults->GetItemAt( i, &pItem ) ) )
{
CComHeapPtr<wchar_t> pPath;
if( SUCCEEDED( pItem->GetDisplayName( SIGDN_FILESYSPATH, &pPath ) ) )
{
if( !strPaths.IsEmpty() )
strPaths += L"\n";
strPaths += pPath;
}
}
}
}
AfxMessageBox( strPaths );
}
谁能告诉我我做错了什么?
MFC 项目,我正在使用 CFileDialog
让用户选择多个文件,例如:
CFileDialog fd(TRUE, NULL, NULL,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ALLOWMULTISELECT,
NULL, this);
if(fd.DoModal() == IDOK)
{
//Multi-selection
CString strPaths;
POSITION fileNamesPosition = fd.GetStartPosition();
while(fileNamesPosition != NULL)
{
if(!strPaths.IsEmpty())
strPaths += L"\n";
strPaths += fd.GetNextPathName(fileNamesPosition);
}
AfxMessageBox(strPaths);
}
所以如果说,有两个快捷方式文件:
shortcut_1.lnk
文件引用:"D:\Folder\Project_B\Release\Name of Project B.exe"
和shortcut_2.lnk
指的是"D:\Folder\Project_A\Release\Name of Project A.exe"
如果我从上面代码生成的 "File Open" 对话框中选择它们,我的结果 strPaths
将变为以下,这是不正确的:
D:\Folder\Project_A\Release\Name of Project A.exe
D:\Folder\Project_A\Release\Name of Project B.exe
第二条路径错误!
听起来像是 CFileDialog
中的错误。
通常,返回的路径是当前显示的目录路径和所选文件名的串联。在 lnk
文件的情况下,也许 CFileDialog
只是提取目标文件名并将其连接到 lnk
文件的父文件夹的路径,而不是仅仅返回完整的目标lnk
文件中的路径。如果没有看到 CFileDialog
.
为避免这种行为,您可以在调用对话框时包含 OFN_NODEREFERENCELINKS
标志,这样您就可以获得实际 lnk
文件的完整路径,然后您可以使用手动解析它们的目标IShellLink
对话框关闭后。
使用GetStartPosition()
和GetNextPathName()
函数是一团糟。一方面,他们使用旧式 API which depends on a correct return buffer size defined via OPENFILENAME
struct。 MFC 不会 处理这个问题!正如您的问题所示,即使缓冲区大小足够大,它也存在链接问题。
使用 Vista+ API 可以避免头痛,可通过 CFileDialog::GetIFileOpenDialog()
获得。
这是一个工作代码示例:
CFileDialog fd( TRUE, NULL, NULL,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ALLOWMULTISELECT,
NULL, nullptr );
if (fd.DoModal() == IDOK)
{
//Multi-selection
CString strPaths;
CComPtr<IFileOpenDialog> piod = fd.GetIFileOpenDialog();
ASSERT( piod );
CComPtr<IShellItemArray> pResults;
if( SUCCEEDED( piod->GetResults( &pResults ) ) )
{
DWORD count = 0; pResults->GetCount( &count );
for( DWORD i = 0; i < count; ++i )
{
CComPtr<IShellItem> pItem;
if( SUCCEEDED( pResults->GetItemAt( i, &pItem ) ) )
{
CComHeapPtr<wchar_t> pPath;
if( SUCCEEDED( pItem->GetDisplayName( SIGDN_FILESYSPATH, &pPath ) ) )
{
if( !strPaths.IsEmpty() )
strPaths += L"\n";
strPaths += pPath;
}
}
}
}
AfxMessageBox( strPaths );
}