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

2016-02-19 11:54 36 1 收藏

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

【 tulaoshi.com - 编程语言 】

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

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

     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;
}

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

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

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

来源:https://www.tulaoshi.com/n/20160219/1599015.html

延伸阅读
标签: PS PS教程
      横轴代表像素本身的两度,竖轴代表新调节的亮度。中间的直线代表目前输入与输出之间的关系。可以单击某个Channels,进行Curves设置,或按Shift键选择两个以上的Channels.     在图像中准备要调节亮度的地方按下鼠标,一个圆出现在Curves对话框中的直线上。拖动这个圆即可调节图...
自绘对话框 作者:Alon 下载示例源代码 闲来无事,写了一个简单的对话框界面,希望给需要的朋友有所帮助。 界面如下: 界面很单调,我只是想说明一下如何实现界面的自绘。如果有需要,也可以绘制更复杂漂亮的界面。 程序的实现也不复杂,接下来就跟着我一步一步做。...
标签: Web开发
    1.将下面一段代码插入head与/head之间: script function rusure() {  question = confirm("确实要去进入吗?")  if (question !="0") { window.open("","测试公告窗口","width=340,height=163,toolbar=0,status=0,menubar=0,resize=0"); } } /script     2.在链接标签内加入onclick()语句...
解决打开CAD图纸显示“cad指定字体给样式”对话框问题   当我们打开DWG图纸也就是CAD文件的时候,您可能会遇到弹出关于cad指定字体给样式的对话框,对话框一直提示:未找到类似gbcbig字体,怎么办?只能一直取消,才能完全打开图纸。。点N次鼠标才行。。。 其实不管哪个autoCAD版本,只要缺少对应的字体,CAD软件打开图纸,都会弹...
(1) 参数 typedef struct { DWORD lStructSize; HWND hwndOwner; HWND hInstance; COLORREF rgbResult; COLORREF * lpCustColors; DWORD Flags; LPARAM lCustData; LPCCHOOKPROC lpfnHook; LPCTSTR lpTemplateName; } CHOOSECOLOR, *LPCHOOSECOLOR; (2) API...

经验教程

914

收藏

70
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部