简体   繁体   English

允许用户在基于对话框的 MFC 应用程序上选择文件夹和文件

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

============================== UPDATE ============================== ============================== 更新 ================== ============

I've tried using what Barrnet Chou suggested.我试过使用 Barrnet Chou 的建议。 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:我已经使用评论中提到的实现创建了SelectDialog.hSelectDialog.cpp文件,我已经在主.cpp文件中包含了SelectDialog.h并且我尝试使用我的主.cpp文件中的代码,如下所示:

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.我也尝试添加标志FOS_PICKFOLDERS作为IInspectable提到的,当我调用构造函数ofd varibale,但它并没有帮助的。 any ideas about what I've missed?关于我错过了什么的任何想法?

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

I'm writing a dialog based MFC application on Visual Studio 2017 in C++.我正在用 C++ 在 Visual Studio 2017 上编写一个基于对话框的 MFC 应用程序。 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.在用户选择所需的文件或文件夹后,我想将路径保存到pFile变量中以备后用。

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方法#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方法#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问题:仅允许用户选择方法#1 所附图片中看到的文件

Method #3方法#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方法#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问题:仅允许用户选择方法#3 所附图片中的文件夹

Method #5方法#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.为此,我尝试使用IFileDialog ,但我不确定如何使用它来选择文件或文件夹。 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.我已经看到了一些诸如这个来自微软的文档文件和一个从Git和也这样一个从堆栈溢出的问题,但我没能运用它们。 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.我真的很感激如果有人能解释我如何使用 IFileDialog 使用户能够选择文件和文件夹,或者如果有任何其他解决方案可以解决这个问题,我想尝试一下。

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 .如果你想同时选择文件和文件夹,我建议你可以参考下面的例子: 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.详细实现: 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 )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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