简体   繁体   中英

Enable user to choose folders and files on dialog based MFC app

============================== UPDATE ==============================

I've tried using what Barrnet Chou suggested. I've created SelectDialog.h and SelectDialog.cpp files with the implementation mentioned in the comment, I've included SelectDialog.h in the main .cpp file and I've tried using the code from my main .cpp file as follows:

CSelectDialog ofd(TRUE, _T("*.*"), NULL, OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT,
                                            _T("All files and folders(*.*)|*.*||"));
    CString path, nFile, info;

    if (ofd.DoModal() != IDOK)
        return;

    for (int i = 0; i < ofd.m_SelectedItemList.GetCount(); i++) {
        nFile = ofd.GetFileName();
        path = ofd.GetFolderPath();
        info = ofd.m_SelectedItemList[i].GetString();
    }

    MessageBox(path);
    MessageBox(nFile);
    MessageBox(info);

I don't know what did I do wrong, but I'm still having the same problem, I can only choose files and not folders. I've also tried adding the flag FOS_PICKFOLDERS as IInspectable mentioned when I call the constructor of ofd varibale, but it didn't help either. any ideas about what I've missed?

============================== ==============================

I'm writing a dialog based MFC application on Visual Studio 2017 in C++. I want to enable the user to choose a file or folder into which he will write later. After the user will choose the desired file or folder I want to save the path into pFile variable for later use.

I've seen some questions on this subject, but all the answers to those posts provide only one functionality - either to choose a file or a folder.

what I've tried:

Method #1

OPENFILENAME file;

    TCHAR szFileName[MAX_PATH] = _T("");

    SecureZeroMemory(&file, sizeof(file));

    file.lStructSize = sizeof(OPENFILENAME);
    file.hwndOwner = NULL;
    file.lpstrFilter = NULL;
    file.lpstrFile = szFileName;
    file.nMaxFile = MAX_PATH;
    file.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
    file.lpstrDefExt = "txt";

    GetSaveFileName(&file);
    
    pFile = file.lpstrFile;

Problem: Allows to choose only files as seen in the picture below:

在此处输入图片说明

Method #2

    CFileDialog dlgFile(TRUE);
    CString fileName;
    const int c_cMaxFiles = 100;
    const int c_cbBuffSize = (c_cMaxFiles * (MAX_PATH + 1)) + 1;
    dlgFile.GetOFN().lpstrFile = fileName.GetBuffer(c_cbBuffSize);
    dlgFile.GetOFN().nMaxFile = c_cbBuffSize;

    CString file_name, dir_path;
    if (dlgFile.DoModal() == IDOK) {
        file_name = dlgFile.GetFileName();
        dir_path = dlgFile.GetFolderPath();
        pFile = dir_path + "\\" + file_name;
    }
    fileName.ReleaseBuffer();

Problem: Allows user to select files only as seen at the picture attached to Method #1

Method #3

    LPCSTR m_strFolderPath = ("C:\\"); // Just for sample    
    LPCSTR m_strDisplayName;

    CFolderDialog dlg(_T("Dialog Title"), m_strFolderPath, this);

    if (dlg.DoModal() == IDOK)
    {
        pFile = dlg.GetFolderPath();
    }

Problem: Allows the user to choose folders only as seen in the picture below:

在此处输入图片说明

Method #4

BROWSEINFO   bi;
    ZeroMemory(&bi, sizeof(bi));
    TCHAR   szDisplayName[MAX_PATH];
    szDisplayName[0] = (TCHAR)("");

    bi.hwndOwner = NULL;
    bi.pidlRoot = NULL;
    bi.pszDisplayName = szDisplayName;
    bi.lpszTitle = _T("Please select a folder for storing received files :");
    bi.ulFlags = BIF_RETURNONLYFSDIRS;
    bi.lParam = NULL;
    bi.iImage = 0;

    LPITEMIDLIST   pidl = SHBrowseForFolder(&bi);
    TCHAR   szPathName[MAX_PATH];
    if (NULL != pidl)
    {
        BOOL bRet = SHGetPathFromIDList(pidl, szPathName);
        if (FALSE == bRet)
            return;
        AfxMessageBox(szPathName);
    }

Problem: Allows user to select folders only as seen at the picture attached to Method #3

Method #5

I've tried using IFileDialog for this purpose, but I'm not sure how to use it to choose a file or a folder. I think that's the solution I need, and I'll appreciate it if anyone could refer me to some examples for how to use it? I've seen some such as this from Microsoft Docs documentation and this one from git and also this and that one from stack overflow questions but I wasn't able to apply them. I've tried constructing something similar by using the previously mentioned codes, but I only got this far:

IFileDialog *pfd;
    IFileSaveDialog *pfsd;
    HRESULT hr = pfd->QueryInterface(&pfsd);
    LPWSTR *pszName;
    if (SUCCEEDED(hr)) {
        hr = pfd->GetFileName(pszName);
        if (SUCCEEDED(hr)) {
            MessageBox((LPCSTR)pszName);
        }
    }

I'd really appreciate If anyone could explain me how to use IFileDialog to enable the user to choose files and folders, or if there's any other solution for this problem, I'd like to try it.

Thank you.

If you want to select files and folders at the same time, I suggest that you could refer to the following example: CSelectDialog .

Instructions:

CSelectDialog ofd(TRUE, _T("*.*"), NULL, OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT, _T("All files and folders(*.*)|*.*||") );
 
if( ofd.DoModal() != IDOK )
    return;
 
for( int i=0; i<ofd.m_SelectedItemList.GetCount(); i++ ){
    //... 
}

Detailed implementation: 1.

#pragma once
 
#include <dlgs.h> // for (MULTI)FILEOPENORD
 
// CSelectDialog
class CSelectDialog : public CFileDialog
{
    DECLARE_DYNAMIC(CSelectDialog)
 
public:
    CSelectDialog(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
        LPCTSTR lpszDefExt = NULL,
        LPCTSTR lpszFileName = NULL,
        DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT |
                        OFN_EXPLORER & (~OFN_SHOWHELP),
        LPCTSTR lpszFilter = NULL,
        CWnd* pParentWnd = NULL);
    virtual ~CSelectDialog();
    
protected:
    virtual void OnInitDone();
    virtual void OnFolderChange();
    virtual BOOL OnFileNameOK();
    static LRESULT CALLBACK WindowProcNew(HWND hwnd,UINT message, WPARAM wParam, LPARAM lParam);
    DECLARE_MESSAGE_MAP()
 
public:
    static CString m_strCurrendDirectory;
    static CStringArray m_SelectedItemList; /*this list includes files and folders
                                            are selected by user. */
    static WNDPROC m_wndProc;
};
#include "stdafx.h"
#include "SelectDialog.h"
 
#pragma warning( push )
#pragma warning( disable : 4311 4312 )
// CSelectDialog
CString CSelectDialog::m_strCurrendDirectory;
CStringArray CSelectDialog::m_SelectedItemList;
WNDPROC CSelectDialog::m_wndProc = NULL;
 
IMPLEMENT_DYNAMIC(CSelectDialog, CFileDialog)
 
CSelectDialog::CSelectDialog(BOOL bOpenFileDialog,
                             LPCTSTR lpszDefExt,
                             LPCTSTR lpszFileName,
                             DWORD dwFlags,
                             LPCTSTR lpszFilter,
                             CWnd* pParentWnd)
                             :CFileDialog(
                             bOpenFileDialog,
                             lpszDefExt,
                             lpszFileName,
                             dwFlags | OFN_EXPLORER | OFN_HIDEREADONLY & (~OFN_SHOWHELP),
                             lpszFilter,
                             pParentWnd)
{
    dwFlags |= (OFN_EXPLORER | OFN_HIDEREADONLY & (~OFN_SHOWHELP));
};
 
CSelectDialog::~CSelectDialog()
{
};
 
BEGIN_MESSAGE_MAP(CSelectDialog, CFileDialog)
END_MESSAGE_MAP()
 
// CSelectDialog message handlers
BOOL CSelectDialog::OnFileNameOK()
{
    if (CFileDialog* pDlg = (CFileDialog*)CWnd::FromHandle(GetParent()->m_hWnd))
    {
        CWnd* pWnd = pDlg->GetDlgItem(lst2);    //getting list
        if (pWnd == NULL)
            return FALSE;
 
        m_SelectedItemList.RemoveAll();         // emptying list
        
        CListCtrl* wndLst1 = (CListCtrl*)(pWnd->GetDlgItem(1));
 
        int nSelected = wndLst1->GetSelectedCount();
        if (!nSelected)     // nothing selected -- don't retrieve list
            return FALSE;
        CString strItemText, strDirectory = m_strCurrendDirectory;
        if (strDirectory.Right(1) != _T("\\"))
            strDirectory += _T("\\");
 
        CString fileslist = _T("");
        pDlg->SendMessage(CDM_GETSPEC, (WPARAM)MAX_PATH,
            (LPARAM)fileslist.GetBuffer(MAX_PATH));
        fileslist.ReleaseBuffer();
 
        strItemText = strDirectory + fileslist;
        if(nSelected == 1 && fileslist != _T(""))
        {
            m_SelectedItemList.Add(strItemText);
            return CFileDialog::OnFileNameOK();
        }
    }
    ::MessageBeep( MB_ICONQUESTION );
    return 1; //don't let the dialog to close
};
 
void CSelectDialog::OnFolderChange()
{
    m_strCurrendDirectory = GetFolderPath();
    CFileDialog::OnFolderChange();
};
 
void CSelectDialog::OnInitDone()
{
    m_strCurrendDirectory = GetFolderPath();
    CWnd* pFD = GetParent();
 
    HideControl(edt1);
    HideControl(cmb1);
    HideControl(stc2);
 
    //HideControl(cmb13);
    //HideControl(stc3);
 
    CRect rectCancel; pFD->GetDlgItem(IDCANCEL)->GetWindowRect(&rectCancel);
    pFD->ScreenToClient(&rectCancel);
 
    CRect rectOK; pFD->GetDlgItem(IDOK)->GetWindowRect(&rectOK);
    pFD->ScreenToClient(&rectOK);
    pFD->GetDlgItem(IDOK)->SetWindowPos(0,rectCancel.left - rectOK.Width() - 5, rectCancel.top, 0,0, SWP_NOZORDER | SWP_NOSIZE);
 
    CRect rectList2; pFD->GetDlgItem(lst1)->GetWindowRect(&rectList2);
    pFD->ScreenToClient(&rectList2);
    pFD->GetDlgItem(lst1)->SetWindowPos(0,0,0,rectList2.Width(), abs(rectList2.top - (rectCancel.top - 5)), SWP_NOMOVE | SWP_NOZORDER);
 
    CRect rectStatic;pFD->GetDlgItem(stc3)->GetWindowRect(&rectStatic);
    pFD->ScreenToClient(&rectStatic);
    pFD->GetDlgItem(stc3)->SetWindowPos(0,rectCancel.left - 375,rectCancel.top + 5, rectStatic.Width(), rectStatic.Height(), SWP_NOZORDER);
 
    CRect rectEdit1;pFD->GetDlgItem(cmb13)->GetWindowRect(&rectEdit1);
    pFD->ScreenToClient(&rectEdit1);
    pFD->GetDlgItem(cmb13)->SetWindowPos(0,rectCancel.left - 320,rectCancel.top, rectEdit1.Width() - 15, rectEdit1.Height(), SWP_NOZORDER);
 
    SetControlText(stc3, _T("Item name:"));
    SetControlText(IDOK, _T("Select"));
 
    m_wndProc = (WNDPROC)::SetWindowLong(pFD->m_hWnd, GWL_WNDPROC, (long)WindowProcNew);
    pFD->CenterWindow();
};
 
LRESULT CALLBACK CSelectDialog::WindowProcNew(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (message ==  WM_COMMAND)
    {
        if (HIWORD(wParam) == BN_CLICKED)
        {
            if (LOWORD(wParam) == IDOK)
            {
                if (CFileDialog* pDlg = (CFileDialog*)CWnd::FromHandle(hwnd))
                {
                    m_SelectedItemList.RemoveAll();         // emptying list
                    CWnd* pWnd = pDlg->GetDlgItem(lst2);    //getting list
                    if (pWnd == NULL)
                        return FALSE;
 
                    CListCtrl* wndLst1 = (CListCtrl*)(pWnd->GetDlgItem(1));
 
                    int nSelected = wndLst1->GetSelectedCount();
                    if (!nSelected)     // nothing selected -- don't retrieve list
                        return FALSE;
                    CString strItemText, strDirectory = m_strCurrendDirectory;
                    if (strDirectory.Right(1) != _T("\\"))
                        strDirectory += _T("\\");
 
                    int nItem = wndLst1->GetNextItem(-1,LVNI_SELECTED);
                    CString fileslist = _T("");
                    pDlg->SendMessage(CDM_GETSPEC, (WPARAM)MAX_PATH,
                        (LPARAM)fileslist.GetBuffer(MAX_PATH));
                    fileslist.ReleaseBuffer();
                    //   Add directory names to list
                    while((nSelected--) > 0)
                    {
                        strItemText = wndLst1->GetItemText(nItem,0);
                        strItemText = strDirectory + strItemText;
                        DWORD attr = GetFileAttributes(strItemText);
                        if((attr != 0xFFFFFFFF) && (attr & FILE_ATTRIBUTE_DIRECTORY))
                            m_SelectedItemList.Add(strItemText);                            
                        nItem = wndLst1->GetNextItem(nItem, LVNI_SELECTED);
                    }
                    //   Add FILE names to list
                    strItemText = _T("");
                    nSelected = wndLst1->GetSelectedCount();
                    if(nSelected > m_SelectedItemList.GetCount())
                    {
                        int MoreThanOnFile = fileslist.Find(_T("\""));
                        if(MoreThanOnFile != -1)
                        {
                            for(int i=0; i<fileslist.GetLength(); i++)
                                if(fileslist[i] != '\"')
                                {
                                    strItemText.AppendFormat(_T("%c"),fileslist[i]);
                                    if(fileslist[i-1] == '\"' && fileslist[i] == ' ')
                                        strItemText.Delete(strItemText.GetLength()-1);
                                }
                                else if(!strItemText.IsEmpty())
                                {
                                    m_SelectedItemList.Add((strDirectory+strItemText));
                                    strItemText.Empty();
                                }
                        }
                        else
                            m_SelectedItemList.Add(strDirectory+fileslist);
                    }
                    pDlg->EndDialog(IDOK);
                    return NULL;
                } // if IDOK
            }
        } // if BN_CLICKED
    }// if WM_COMMAND
    return CallWindowProc(m_wndProc, hwnd, message, wParam, lParam);
}


#pragma warning( pop )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM