我最近用到了这方面的内容,给大家介绍一下我用到的方法~(页底有源码)
这个思路大概分两种:
从CFileDialog派生一个子类,OPENFILENAME的flags不设置OFN_EXPLORER(使用传统风格),这个需要多写几行代码,稍微麻烦一点,不过这样的复用性很好~
另外一种就是我用到的办法:用一个钩子过程和一个定制的对话框模板来做
我写了个示例,方法如下:
在您已有的应用程序中新建一个对话框,设置其属性为WS_CHILD、WS_CLIPSIBLINGS、WS_CLIPCHILDREN,照
下图勾选
设置子对话框属性,是因为这个模板是默认的文件对话框的子对话框;
而设置WS_CLIPSIBLINGS,就是使此子对话框的绘制不会覆盖默认文件对话框的控件
然后加一个静态控件,将ID设为stc32,我们的默认的文件对话框,就会替代这个区域显示。这里需要补充说明一点的是,不管这个静态控件拖得多么小,实际运行的时候,默认文件对话框部分都会撑大的!
然后就是作为演示的内容了~
加一个复选框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,再由默认的钩子函数处理消息 } |
贴一些运行截图:
切换选择不同的文件,会在下方显示文件大小:
如果上面左图,选中了复选框,则弹出:
选择大文件:
————————–


看一下,不太懂。我只知道VC中,要从WinMain函数进入!
如果是MFC的话,WinMain是隐藏了的,用户看不见