CFileDialog с OFN_ALLOWMULTISELECT неверные результаты для ярлыков - PullRequest
0 голосов
/ 22 января 2019

Может кто-нибудь сообщить мне, что я здесь не так делаю?

Проект 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"

Если я выберу их обоих из диалогового окна «Открытие файла», сгенерированного приведенным выше кодом, мой результат strPaths станет следующим, что неверно:

D:\Folder\Project_A\Release\Name of Project A.exe
D:\Folder\Project_A\Release\Name of Project B.exe

Второй путь неверен!

Ответы [ 2 ]

0 голосов
/ 22 января 2019

Использование функций GetStartPosition() и GetNextPathName() - беспорядок.Например, они используют API старого стиля , который зависит от правильного размера буфера возврата, определенного с помощью 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 );
}
0 голосов
/ 22 января 2019

Звучит как ошибка в CFileDialog.

Как правило, возвращаемые пути представляют собой объединение отображаемого в данный момент пути к каталогу и выбранных имен файлов. В случае файла lnk, возможно, CFileDialog извлекает только целевое имя файла и объединяет его с путем к родительской папке файла lnk, а не просто возвращает полный целевой путь, который находится внутри lnk файл. Трудно сказать наверняка, не видя фактического исходного кода для CFileDialog.

Чтобы избежать этого, вы можете включить флаг OFN_NODEREFERENCELINKS при вызове диалогового окна, чтобы получить полные пути к фактическим lnk файлам, а затем вы можете вручную разрешить их цели, используя IShellLink после закрытия диалога.

...