创建 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 对话框让用户选择文件路径的主要内容,如果未能解决你的问题,请参考以下文章