[WTL/ATL]_[初级]_[选择文件或文件夹]

博客指出之前介绍的打开对话框选择文件夹方法有问题,不建议使用。介绍了WTL库里用于选择文件和文件夹的工具类,如选择单个文件、多个文件及选择文件夹的类,还提到这些类主要是对相关函数的调用,关键在于参数初始化,定制复杂文件夹选择类需自行继承实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

场景

  1. 之前在文章选择目录对话框里介绍了打开对话框选择文件夹的方法. 但是这两种方式总也有些小问题. 不建议使用了。

  2. 如果选择文件和文件夹都需要那么麻烦的话, WTL界面库按道理来说应该会集成了这类工具类.

说明

  1. WTL库里其实就有两个类来选择文件或文件夹CFileDialogCFolderDialog, 在MFC里有CFileDialogCFolderPickerDialog相对应.

  2. WTL里选择单个文件使用CFileDialog, 选择多个文件是CMultiFileDialog,当然CMultiFileDialogCFileDialog的子类,在<atldlgs.h>文件里. WTL是开源的, 也可以看到类里其实就是对Win32GetOpenFileNameGetSaveFileName的调用,复杂的是对参数OPENFILENAME的初始化.

	CFileDialogImpl(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
			LPCTSTR lpszDefExt = NULL,
			LPCTSTR lpszFileName = NULL,
			DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
			LPCTSTR lpszFilter = NULL,
			HWND hWndParent = NULL)
	{
		memset(&m_ofn, 0, sizeof(m_ofn)); // initialize structure to 0/NULL
		m_szFileName[0] = _T('\0');
		m_szFileTitle[0] = _T('\0');

		m_bOpenFileDialog = bOpenFileDialog;

#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
		m_ofn.lStructSize = bOpenFileDialog ? sizeof(m_ofn) : sizeof(OPENFILENAME);
#else
		m_ofn.lStructSize = sizeof(m_ofn);
#endif

#if (_WIN32_WINNT >= 0x0500)
		// adjust struct size if running on older version of Windows
		if(AtlIsOldWindows())
		{
			ATLASSERT(sizeof(m_ofn) > OPENFILENAME_SIZE_VERSION_400);   // must be
			m_ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
		}
#endif // (_WIN32_WINNT >= 0x0500)
		m_ofn.lpstrFile = m_szFileName;
		m_ofn.nMaxFile = _MAX_PATH;
		m_ofn.lpstrDefExt = lpszDefExt;
		m_ofn.lpstrFileTitle = (LPTSTR)m_szFileTitle;
		m_ofn.nMaxFileTitle = _MAX_FNAME;
#ifndef _WIN32_WCE
		m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLESIZING;
#else // CE specific
		m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK;
#endif // !_WIN32_WCE
		m_ofn.lpstrFilter = lpszFilter;
		m_ofn.hInstance = ModuleHelper::GetResourceInstance();
		m_ofn.lpfnHook = (LPOFNHOOKPROC)T::StartDialogProc;
		m_ofn.hwndOwner = hWndParent;

		// setup initial file name
		if(lpszFileName != NULL)
		SecureHelper::strncpy_x(m_szFileName, _countof(m_szFileName), lpszFileName, _TRUNCATE);
	}

	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
	{
		ATLASSERT((m_ofn.Flags & OFN_ENABLEHOOK) != 0);
		ATLASSERT(m_ofn.lpfnHook != NULL);   // can still be a user hook

		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);

		if(m_ofn.hwndOwner == NULL)   // set only if not specified before
			m_ofn.hwndOwner = hWndParent;

		ATLASSERT(m_hWnd == NULL);

#if (_ATL_VER >= 0x0800)
		// Allocate the thunk structure here, where we can fail gracefully.
		BOOL bRetTh = m_thunk.Init(NULL, NULL);
		if(bRetTh == FALSE)
		{
			::SetLastError(ERROR_OUTOFMEMORY);
			return -1;
		}
#endif // (_ATL_VER >= 0x0800)

		ModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBase*)this);

		BOOL bRet;
		if(m_bOpenFileDialog)
#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
			bRet = ::GetOpenFileNameEx(&m_ofn);
		else
			bRet = ::GetSaveFileName((LPOPENFILENAME)&m_ofn);
#else
			bRet = ::GetOpenFileName(&m_ofn);
		else
			bRet = ::GetSaveFileName(&m_ofn);
#endif

		m_hWnd = NULL;

		return bRet ? IDOK : IDCANCEL;
	}
  1. CFolderDialog是选择文件夹的工具类, 界面也是标准界面,看代码主要是对SHBrowseForFolder的调用,最重要的也是调用参数的初始化. 想要定制复杂的文件夹选择类也是可以的, 不过需要自己继承并实现CDialogImpl.

CFolderDialogImpl(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS) : 
		m_lpstrInitialFolder(NULL), m_pidlInitialSelection(NULL), m_bExpandInitialSelection(false), m_pidlSelected(NULL), m_hWnd(NULL)
{
	memset(&m_bi, 0, sizeof(m_bi)); // initialize structure to 0/NULL

	m_bi.hwndOwner = hWndParent;
	m_bi.pidlRoot = NULL;
	m_bi.pszDisplayName = m_szFolderDisplayName;
	m_bi.lpszTitle = lpstrTitle;
	m_bi.ulFlags = uFlags;
	m_bi.lpfn = BrowseCallbackProc;
	m_bi.lParam = (LPARAM)static_cast<T*>(this);

	m_szFolderPath[0] = 0;
	m_szFolderDisplayName[0] = 0;
}

INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
{
	if(m_bi.hwndOwner == NULL)   // set only if not specified before
		m_bi.hwndOwner = hWndParent;

	// Clear out any previous results
	m_szFolderPath[0] = 0;
	m_szFolderDisplayName[0] = 0;
	::CoTaskMemFree(m_pidlSelected);

	INT_PTR nRet = IDCANCEL;
	m_pidlSelected = ::SHBrowseForFolder(&m_bi);

	if(m_pidlSelected != NULL)
	{
		nRet = IDOK;

		// If BIF_RETURNONLYFSDIRS is set, we try to get the filesystem path.
		// Otherwise, the caller must handle the ID-list directly.
		if((m_bi.ulFlags & BIF_RETURNONLYFSDIRS) != 0)
		{
			if(::SHGetPathFromIDList(m_pidlSelected, m_szFolderPath) == FALSE)
				nRet = IDCANCEL;
		}
	}

	return nRet;
}

例子

void CWTLSchoolView::SelectOneFile(HWND hwnd)
{
	OutputDebugString(L"SelectOneFile \n");
	CFileDialog filedialog(TRUE);
	if(IDOK == filedialog.DoModal(hwnd)){
		std::wstring path = filedialog.m_szFileName;
		OutputDebugString((path+L"\n").c_str());
	}
}

void CWTLSchoolView::SelectMultiFiles(HWND hwnd)
{
	OutputDebugString(L"SelectMultiFiles \n");
	CMultiFileDialog dialog;
	if(IDOK == dialog.DoModal(hwnd)){
		CString path;
		bool result = dialog.GetFirstPathName(path);
		while(result){
			OutputDebugString((path+L"\n"));
			result = dialog.GetNextPathName(path);
		}
	}
}

void CWTLSchoolView::SelectOneFolder(HWND hwnd)
{
	OutputDebugString(L"SelectOneFolder \n");
	CFolderDialog folder(NULL,L"Select a dir",BIF_RETURNONLYFSDIRS|BIF_USENEWUI);
	if(IDOK == folder.DoModal()){
		std::wstring dir  = folder.m_szFolderPath;
		OutputDebugString((dir+L"\n").c_str());
	}
}

输出

选择文件夹
在这里插入图片描述
只能选择一个文件
在这里插入图片描述
选择多个文件
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Peter(阿斯拉达)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值