CFileDialog的钩子函数解决对话框的多选之DoModal问题

乌居

乌居

2016-02-19 11:54

今天图老师小编要向大家分享个CFileDialog的钩子函数解决对话框的多选之DoModal问题教程,过程简单易学,相信聪明的你一定能轻松get!

前几天领导问我一个问题:就是使用CFileDialog类在设置多选时选中的文件所放的文件缓冲区不知设置多大合适,设置小了DoModal返回为失败, 通过CommDlgExtendedError函数获取错误码为FNERR_BUFFERTOOSMALL(即缓冲区太小),设置大了又浪费内存。(我们 一次要选几百个文件,实在不知设置多大合适)。

      我谈了我的思路:CFileDialog的数据成员m_ofn有一个数据成员为钩子函数指针,通过设置这个函数,可以勾取CFileDialog的相关消 息,比如用户改变路径的消息,然后获取当前路径的文件个数,以此为依据来设置缓冲区的大小。领导不是很明白我的思路,他上网搜了搜,找到一种方法,就是通过派生CFileDialog类的方法来做,具体如下:

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)

     Multiple Selection in a File Dialog

    上面的链接提到的方法确实可行。但是我也相信我的方法是可行的。下班后我上网搜索了一下,发现微软官网上有一个对此问题的解决办法,链接如下:

如何处理在 Windows 中 FNERR_BUFFERTOOSMALL 

     该链接提供的代码适合的是Win 32的程序,并不适合MFC的程序,而且我建了一个Win32的程序测试该例子的代码时,发现一个问题,就是当选择的文件过多时,就是需要分配的缓冲区比较多时,使用链接中的HeapAlloc函数会出现错误,错误提示如下:

 

     因此要将链接中分配内存和释放的内存的HeapAlloc和HeapFree函数分别用C++的new和delete操作符替换。

      在微软官网提供的做法的基础上我摸索出用在MFC程序的做法,具体代码如下:
代码如下:

// 钩子函数
UINT_PTR CALLBACK MyOFNHookProc( HWND hdlg, // handle to child dialog box
UINT uiMsg, // message identifier
WPARAM wParam, // message parameter
LPARAM lParam // message parameter
)
{
int nResult = FALSE;
if (hdlg == NULL)
return 0;
#ifdef _DEBUG
// from "_AfxCommDlgProc()" of the file "dlgcomm.cpp"
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
if (pThreadState-m_pAlternateWndInit != NULL)
pThreadState-m_pAlternateWndInit = NULL;
#endif
switch(uiMsg)
{
case WM_NOTIFY:
{
LPOFNOTIFY pOfn = (LPOFNOTIFY)lParam;
switch(pOfn-hdr.code)
{
case CDN_SELCHANGE:
{
TCHAR dummy_buffer;
// Get the required size for the 'files' buffer
HWND hOwner = GetParent(hdlg);
HWND hParent = GetParent(hOwner);
UINT nfiles = CommDlg_OpenSave_GetSpec(hOwner, &dummy_buffer, 1);
// Get the required size for the 'folder' buffer
int cbLength = CommDlg_OpenSave_GetSpec(GetParent(hdlg), NULL, 0);
cbLength += _MAX_PATH;
if(cbLength(pOfn-lpOFN)-nMaxFile)
{
delete (pOfn-lpOFN)-lpstrFile;
(pOfn-lpOFN)-lpstrFile = new TCHAR[cbLength];
ZeroMemory((pOfn-lpOFN)-lpstrFile,cbLength);
(pOfn-lpOFN)-nMaxFile = cbLength;
}
nResult = TRUE;
break;
}
default:
break;
}
break;
}
default:
break;
}
return nResult;
}
#define NAMEBUF 1024
// 调用函数
void CMultiSelectDlg::OnButton1()
{
m_listbox.ResetContent();
m_static.SetWindowText(_T("0 files selected"));
TCHAR szFilters[]= _T("MyType Files (*.doc)|*.doc||");
// Create an Open dialog; the default file name extension is ".doc".
CFileDialog fileDlg(TRUE, _T("doc"), _T("*.doc"),
OFN_FILEMUSTEXIST | OFN_HIDEREADONLY|OFN_ALLOWMULTISELECT, szFilters);
fileDlg.m_ofn.lpstrFile=new TCHAR[NAMEBUF]; // 重新定义lpstrFile 缓冲大小
memset(fileDlg.m_ofn.lpstrFile,0,NAMEBUF); // 初始化定义的缓冲
fileDlg.m_ofn.nMaxFile = NAMEBUF; // 重定义nMaxFile
fileDlg.m_ofn.lpfnHook = (LPOFNHOOKPROC)MyOFNHookProc;
INT_PTR ret = fileDlg.DoModal();
if (ret == IDOK)
{
int width = 0;
CString str;
CDC *pDC = m_listbox.GetDC();
int saved = pDC-SaveDC();
pDC-SelectObject(GetFont());
UINT count = 0;
POSITION pos = fileDlg.GetStartPosition();
while (pos)
{
str = fileDlg.GetNextPathName(pos);
m_listbox.AddString(str);
CSize size(0, 0);
size = pDC-GetTextExtent(str);
width = width size.cx ? width : size.cx;
++count;
}
pDC-RestoreDC(saved);
ReleaseDC(pDC);
m_listbox.SetHorizontalExtent(width + 5);
str.Format(_T("%u files selected"), count);
m_static.SetWindowText(str);
}
DWORD dwCode = CommDlgExtendedError();
if (FNERR_BUFFERTOOSMALL==dwCode)
{
AfxMessageBox(_T("获取文件路径失败!"));
}
delete []fileDlg.m_ofn.lpstrFile;
fileDlg.m_ofn.lpstrFile = NULL;
}

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)

    另外使用钩子函数的一个严重缺点是程序必须使用Unicode字符集进行编译,使用多字节字符集编译程序执行后FNERR_BUFFERTOOSMALL的错误(这一点已经测试过,我比较难以理解的是为何在这一点上微软不予支持多字节程序)。我的测试环境为: VS C++ 2005 + sp1,Win XP + sp3,unicode字符集。

展开更多 50%)
分享

猜你喜欢

CFileDialog的钩子函数解决对话框的多选之DoModal问题

编程语言 网络编程
CFileDialog的钩子函数解决对话框的多选之DoModal问题

关于 CFileDialog 对话框多选功能的一个问题

C语言教程 C语言函数
关于 CFileDialog 对话框多选功能的一个问题

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

再谈 CFileDialog 对话框的定制

C语言教程 C语言函数
再谈 CFileDialog 对话框的定制

一个定制CFileDialog对话框的实例

C语言教程 C语言函数
一个定制CFileDialog对话框的实例

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

CFileDialog设置多选的问题解决

编程语言 网络编程
CFileDialog设置多选的问题解决

vc的对话框-

编程语言 网络编程
vc的对话框-

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

C#中使用SendMessage

C#中使用SendMessage

使用HttpWebRequest向网站模拟上传数据

使用HttpWebRequest向网站模拟上传数据
下拉加载更多内容 ↓