创建 MFC 对话框让用户选择文件路径

Posted

技术标签:

【中文标题】创建 MFC 对话框让用户选择文件路径【英文标题】:Creating MFC dialog to let the user choose file path 【发布时间】:2015-11-26 02:12:47 【问题描述】:

正如标题所说,我正在尝试创建基于 MFC 对话框的应用程序,让用户选择文件目标文件夹。

我通过使用CMFCShellTreeCtrl 来做到这一点。然而,不知何故,只有一个根项目是 Desktop。我想查看我的电脑C盘等所有项目。

请您告诉我出了什么问题以及如何解决。谢谢。

编辑:对不起,我忘了发布我的代码。 (非常简单的浏览对话框)

// BrowseDlg.cpp : implementation file
//

#include "stdafx.h"
#include "MFC Grab to FTP.h"
#include "BrowseDlg.h"
#include "afxdialogex.h"


// CBrowseDlg dialog

IMPLEMENT_DYNAMIC(CBrowseDlg, CDialog)

CBrowseDlg::CBrowseDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CBrowseDlg::IDD, pParent)




CBrowseDlg::~CBrowseDlg()



void CBrowseDlg::DoDataExchange(CDataExchange* pDX)

    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_PATH, m_PathTree);



BEGIN_MESSAGE_MAP(CBrowseDlg, CDialog)
    ON_NOTIFY(TVN_SELCHANGED, IDC_PATH, &CBrowseDlg::OnTvnSelchangedMfcshelltree1)
    ON_BN_CLICKED(IDOK, &CBrowseDlg::OnBnClickedOk)
END_MESSAGE_MAP()


// CBrowseDlg message handlers

BOOL CBrowseDlg::OnInitDialog()

    CDialog::OnInitDialog();

    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        
    

    // Set the icon for this dialog.  The framework does this automatically
    // when the application's main window is not a dialog
    m_PathTree.Expand(m_PathTree.GetRootItem(),TVE_EXPAND);

    return TRUE;  // return TRUE  unless you set the focus to a control


void CBrowseDlg::OnTvnSelchangedMfcshelltree1(NMHDR *pNMHDR, LRESULT *pResult)

    LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
    // TODO: Add your control notification handler code here
    *pResult = 0;



void CBrowseDlg::OnBnClickedOk()

    m_PathTree.GetItemPath(path,m_PathTree.GetSelectedItem());

    // TODO: Add your control notification handler code here
    CDialog::OnOK();

//

#pragma once
#include "afxshelltreectrl.h"


// CBrowseDlg dialog
// header file
class CBrowseDlg : public CDialog

    DECLARE_DYNAMIC(CBrowseDlg)

public:
    CBrowseDlg(CWnd* pParent = NULL);   // standard constructor
    virtual ~CBrowseDlg();

// Dialog Data
    enum  IDD = IDD_BROWSER ;

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnTvnSelchangedMfcshelltree1(NMHDR *pNMHDR, LRESULT *pResult);
    CString path;
    CMFCShellTreeCtrl m_PathTree;
    afx_msg void OnBnClickedOk();
    virtual BOOL OnInitDialog();
;

【问题讨论】:

【参考方案1】:

问题是CShellManager 没有初始化。您必须手动完成。要初始化它,您需要在您的CWinApp 派生类的OnInitInstance() 中调用CWinAppEx::InitShellManager()

【讨论】:

【参考方案2】:

如果您只想选择一个文件夹,可以使用CMFCShellTreeCtrl 的替代方法:IFileDialog

这是我的选择文件夹对话框的代码(相当复杂,因为我仍然希望使用 XFolderDialog 支持 Windows XP):

HINSTANCE hEasyCTXP_DLL = NULL;

// Select Folder Dialog -- uses either CXFolderDialog or IFileDialog
// to open a folder picker dialog depending on OS version
// returns "" if Cancel was pressed or something else went wrong
// Note: This is just multi-byte code and not yet unicode compatible!
BOOL SelectFolder(LPSTR sFolder, LPCTSTR sTitle = "Choose Folder")

    OSVERSIONINFOEX osvi;
    ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
    osvi.dwOSVersionInfoSize = sizeof(osvi);
    if (GetVersionEx((OSVERSIONINFO *)&osvi) && osvi.dwMajorVersion >= 6) // Vista or higher?
    
        if (!(hEasyCTXP_DLL = LoadLibrary("XPHelper.dll")))
        
            AfxMessageBox("Error opening Select Folder dialog. XPHelper.dll may not be installed properly.");
            return FALSE;
        
        else
        
            BOOL (__cdecl *pSelectFolder)(LPSTR, LPCTSTR);
            pSelectFolder = (BOOL (__cdecl *)(LPSTR, LPCTSTR))GetProcAddress(hEasyCTXP_DLL, "SelectFolder");
            if (pSelectFolder) 
            
                return (*pSelectFolder)(sFolder, sTitle);
            
            else
            
                AfxMessageBox("Error opening Select Folder dialog. (SelectFolder() function entry point not found.)");
                return FALSE;
            
           
    
    else // XP
       
        CXFolderDialog dlg(sFolder);        
        dlg.SetTitle(sTitle);
        if (dlg.DoModal() == IDOK)
        
            CString csPath = dlg.GetPath();
            strcpy(sFolder, (LPCTSTR)csPath);
            return TRUE;
        
        else
            return FALSE;
    

我在 XPHelper.dll 中提供的函数来了。此dll仅延迟加载,如果使用Vista或更高版本的操作系统,因此主程序不会因为Windows XP中缺少依赖项而失败:

// sFolder should be at least MAX_FILE in size!
extern "C" BOOL SelectFolder(LPSTR sFolder, LPCTSTR sTitle)

    BOOL bRet = TRUE;

    IFileDialog *pfd;
    LPWSTR pwstrPath;
    HRESULT hr;
    if (SUCCEEDED(hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd))))
    
        DWORD dwOptions;
        hr = pfd->GetOptions(&dwOptions);
        if (SUCCEEDED(hr))
            hr = pfd->SetOptions(dwOptions | FOS_PICKFOLDERS);  // put IFileDialog in folder mode
        if (SUCCEEDED(hr))
        
            WCHAR wcTitle[MAX_PATH+1];
            if (MultiByteToWideChar(CP_ACP, 0, sTitle, (int)min(strlen(sTitle), MAX_PATH), wcTitle, sizeof(MAX_PATH + 1)))
            
                wcTitle[min(strlen(sTitle), MAX_PATH)] = '\0';
                pfd->SetTitle(wcTitle);         // Set dialog title
            

            char *cp = sFolder;
            WCHAR wcDefaultPath[MAX_PATH+1];
            IShellItem *psi;
            if (MultiByteToWideChar(CP_ACP, 0, cp, (int)strlen(cp), wcDefaultPath, MAX_PATH + 1))
            
                wcDefaultPath[strlen(cp)] = '\0';
                if (SUCCEEDED(::SHCreateItemFromParsingName(wcDefaultPath, NULL, IID_PPV_ARGS(&psi))))
                
                    hr = pfd->SetFileName(wcDefaultPath);
                    hr = pfd->SetFolder(psi);
                    psi->Release();
                
            
        
        if (SUCCEEDED(hr))
            hr = pfd->Show(AfxGetMainWnd()->GetSafeHwnd());
        if (SUCCEEDED(hr))
        
            IShellItem *psi;
            if (SUCCEEDED(pfd->GetResult(&psi)))
            
                if(SUCCEEDED(psi->GetDisplayName(SIGDN_FILESYSPATH, &pwstrPath)))
                
                    int nSize = (int)wcslen(pwstrPath);
                    WideCharToMultiByte(CP_ACP, 0, pwstrPath, nSize, sFolder, MAX_PATH+1, NULL, NULL);
                    sFolder[nSize] = '\0';
                    ::CoTaskMemFree(pwstrPath);
                
                else
                
                    AfxMessageBox("IShellItem::GetDisplayName() failed.");
                    bRet = FALSE;
                

                psi->Release();
            
            else
            
                AfxMessageBox("IFileDialog failed.");
                bRet = FALSE;
            
        
        pfd->Release();
    

    if(!SUCCEEDED(hr))
        bRet = FALSE;       

    return bRet;

【讨论】:

以上是关于创建 MFC 对话框让用户选择文件路径的主要内容,如果未能解决你的问题,请参考以下文章

mfc编程,要用户选择一个文件夹,然后返回此文件夹的路径。不是要选择文件,是要文件夹的路径。

java导出文件时让用户选择路径怎么弄啊?最好有代码……

MFC 中的路径选择组件

MFC点击按钮打开对话框选择文件夹(不是文件)

MFC点击按钮打开对话框选择文件夹(不是文件)

MFC C++:如何将某个文件实际保存到系统中,而不仅仅是打开另存为对话框