我最近用到了这方面的内容,给大家介绍一下我用到的方法~(页底有源码

这个思路大概分两种:

从CFileDialog派生一个子类,OPENFILENAME的flags不设置OFN_EXPLORER(使用传统风格),这个需要多写几行代码,稍微麻烦一点,不过这样的复用性很好~

另外一种就是我用到的办法:用一个钩子过程和一个定制的对话框模板来做

我写了个示例,方法如下:

在您已有的应用程序中新建一个对话框,设置其属性为WS_CHILD、WS_CLIPSIBLINGS、WS_CLIPCHILDREN,照dlgProp下图勾选

设置子对话框属性,是因为这个模板是默认的文件对话框的子对话框;

而设置WS_CLIPSIBLINGS,就是使此子对话框的绘制不会覆盖默认文件对话框的控件

然后加一个静态控件,将ID设为stc32,我们的默认的文件对话框,就会替代这个区域显示。这里需要补充说明一点的是,不管这个静态控件拖得多么小,实际运行的时候,默认文件对话框部分都会撑大的!

staticProp

然后就是作为演示的内容了~

加一个复选框IDC_CHECK, 一个静态控件IDC_STACK_INFO

在例子中,我们的主对话框就一个按钮,点击即可打开自定义的文件对话框。所以针对此按钮添加一个消息响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void COpdTestDlg::OnBtnOpen()
{
	// TODO: Add your control notification handler code here
	TCHAR szFileName[MAX_PATH] = {0};
 
	OPENFILENAME ofn;
	ZeroMemory(&ofn, sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = m_hWnd;
	ofn.hInstance = AfxGetInstanceHandle();
	ofn.lpstrFilter = _T("所有文件(*.*)\0*.*\0");
	ofn.lpstrFile = szFileName;//以后从这里得到文件名
	ofn.nMaxFile = MAX_PATH;
	ofn.Flags = OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLETEMPLATE
		| OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
	ofn.lpfnHook = OFNHookProc;
	ofn.lpTemplateName = MAKEINTRESOURCE(IDD_OPD);
 
	GetOpenFileName(&ofn);
	if(szFileName[0])
	{
		CString strInfo;
		strInfo.Format(_T("文件名:\"%s\";\n复选框是否被选中: %s"),
			szFileName, bChecked ? _T("是") : _T("否"));
		MessageBox(strInfo);
	}
}

注意这里就不是用的CFileDialog的一个对象,然后DoModal那种方式了。取而代之的是用的一个API:GetOpenFileName,调用它之后该对话框应会模态显示,然后就可以取得文件名了!

注意到ofn.lpstrFile = szFileName;GetOpenFileName之后,文件名的内容就存放到szFileName当中了

下面是实现钩子过程:

主要是截获WM_NOTIFY消息,根据不同的CDN_XXXXX,做不同的处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
UINT CALLBACK OFNHookProc(HWND hdlg,
						  UINT uiMsg,
						  WPARAM wParam,
						  LPARAM lParam)
{
	if(uiMsg == WM_DRAWITEM)
	{
		//在这里画控件,这里省略
 
		return 1;//返回1,默认的钩子函数将被忽略
	}
	else if(uiMsg == WM_NOTIFY)
	{
		LPNMHDR pnmh = (LPNMHDR)lParam;
		switch(pnmh->code)
		{
		case CDN_INITDONE:
			{
				bChecked = 0;
				dwFileSize = 0;
 
				SetDlgItemText(hdlg, IDC_STATIC_INFO, _T("未选择"));
 
			}
			break;
		case CDN_SELCHANGE:
			{
				CString strFilePath;
				SendMessage(GetParent(hdlg), CDM_GETFILEPATH, 1024,
					(LPARAM)(LPCSTR)strFilePath);
				TRACE("%s\n", strFilePath);
				CString strTmp = strFilePath;//拷贝一个
 
				DWORD dwRet = GetFileAttributes((LPCSTR)strFilePath);
				if(!(dwRet & FILE_ATTRIBUTE_DIRECTORY))
				{
					/*
					如果下面直接用strFilePath会提示:“一未命名文件中
					包含无效的路径”,原因不解
					*/
					CFile file((LPCTSTR)strTmp, CFile::modeRead | CFile::typeBinary);
					dwFileSize = file.GetLength();
					file.Close();
					CString strFileSize;
					strFileSize.Format(_T("文件大小:%ld 字节"), dwFileSize);
					SetDlgItemText(hdlg, IDC_STATIC_INFO, (LPCSTR)strFileSize);
				}
			}
			break;
		case CDN_FILEOK:
			bChecked = (BOOL)IsDlgButtonChecked(hdlg, IDC_CHECK);
 
			if(!bChecked/*未选中,表示用户不知道这个规则*/ &&
				(dwFileSize < 0/*溢出了*/ || dwFileSize > 5242880/*即5M*/))
			{
				AfxMessageBox(_T("文件大小>5M了~\n复选框将自动勾选上!"));
				//反正用户看不见,注释掉,哈哈
				//CheckDlgButton(hdlg, IDC_CHECK, 1);
				bChecked = 1;
			}
 
			break;
		}
	}
 
	return 0;//返回0,再由默认的钩子函数处理消息
}

贴一些运行截图:

切换选择不同的文件,会在下方显示文件大小:

main 点击“打开”后显示:msg4

如果上面左图,选中了复选框,则弹出:

msg1

选择大文件:

msg3 点击“打开”后显示:msg2

————————–

附件下载

OpdTest.rar

附件下载