用VC6打开XP风格通用文件对话框

来源:互联网 发布:python廖海峰 编辑:程序博客网 时间:2024/06/06 18:39

   一般地,VC6中使用CFileDialog来打开windows通用打开文件对话框和保存文件对话框。但,遗憾地是,很多人告诉我(包括我头头),也许也会这么告诉你,CFileDialog只能打开win98风格的对话框,如下图一。

 

图一,标准文件打开对话框

   但我们是不会满足的,看着别人程序里漂亮的XP风格对话框,难道我们只能扩展CFileDialog,自己实现(所有我认识的人都是这么告诉我的)?

   其实,只需简单的一步,就可以用VC6的CFileDialog来打开XP风格文件对话框,如图二,

 


图二 XP风格的通用文件对话框,带左侧"我的电脑"按钮

 

目前,在VC6.0中, 我知道有四种方法可以实现调用XP风格通用文件对话框:

一。设置CFileDialog的 m_ofn 成员变量的 lStructSize 值

  1. CFileDialog   dlg(TRUE);
  2. dlg.m_ofn.lStructSize = 88;//76将是win98风格

    但请注意,1. 不能设置 m_ofn.Flags 的 OFN_ENABLEHOOK 标志和 m_ofn.lpfnHook 变量,否则还将是98风格。2.这个方法好像只适合Win2000及winXP版本windows,不支持95和98.

   这是因为,新的Open对话框是用一个新版本的commdlg.dll实现的,显示它的函数是GetOpenFileName,与在Windows   9x   和Windows   NT下使用的相同。然而,GetOpenFileName现在使用一个新版本的OPENFILENAME;9x下该结构的size是76,很不幸,进入NT时代,它被扩展成88。另一方面,“如果OPENFILENAME有旧的大小,Windows   2000使用OFN_ENABLEHOOK来决定运行哪个对话框。如果OPENFILENAME使用hook过程(或者设置了ORN_ENABLETEMPLATE),Windows   2000按照旧的风格显示对话框;否则,显示新的对话框。”

 

二。设置m_ofn的Flags

    使m_ofn.Flags值包含 OFN_EXPLORER  | OFN_ALLOWMULTISELECT,但不能包含OFN_ENABLEHOOK ,否则将仍是旧风格对话框。

   遗憾的是,因为不含有 OFN_ENABLEHOOK 标记,在 CFileDialog.DoModal()时,将会ASSERT,因为有如下判断:

  1. int CFileDialog::DoModal()
  2. {
  3.     ASSERT_VALID(this);
  4.     ASSERT(m_ofn.Flags & OFN_ENABLEHOOK);
  5.     ASSERT(m_ofn.lpfnHook != NULL);

   但因为是ASSERT,说明在release版本下是没问题的,仅Debug版下会ASSERT,当然,若你愿意,您也可以点忽略继续执行。

 

三。直接使用API函数GetOpenFileName

    CFileDialog也是调用的SDK中的GetOpenFileName API函数,可以直接设置它的Flags,这个我未试过,请参考MSDN。

 

四。派生CFileDialog类

   这个解决方案来自MSDN,http://msdn.microsoft.com/zh-cn/magazine/cc301412(en-us).aspx

 

  由CFileDialog类 派生一个CFileDialogEx类,貌似该类可以在9x系统下弹出XP风格的对话框;遗憾地是,从我有记忆起,我仅高中阶段用过95/98;现在是找一个来测试都困难。。。

    完整代码附录如下,编译测试通过:

  1. // FileDialogEx.h : header file
  2. //
  3. //   Windows   2000   version   of   OPENFILENAME.   
  4. //   The   new   version   has   three   extra   members.   
  5. //   This   is   copied   from   commdlg.h   
  6. //  
  7. #if !defined(AFX_FILEDIALOGEX_H__A7F5E19C_B48A_481E_94D9_7922B9E2449E__INCLUDED_)
  8. #define AFX_FILEDIALOGEX_H__A7F5E19C_B48A_481E_94D9_7922B9E2449E__INCLUDED_
  9. #if _MSC_VER > 1000
  10. #pragma once
  11. #endif // _MSC_VER > 1000
  12. struct   OPENFILENAMEEX   :   public   OPENFILENAME   {     
  13.     void   *                 pvReserved;   
  14.     DWORD                   dwReserved;   
  15.     DWORD                   FlagsEx;   
  16. };   
  17. /////////////////////////////////////////////////////////////////////////////   
  18. //   CFileDialogEx:   Encapsulate   Windows-2000   style   open   dialog.   
  19. //   
  20. class   CFileDialogEx   :   public   CFileDialog   {   
  21.     DECLARE_DYNAMIC(CFileDialogEx)   
  22. public:   
  23.     CFileDialogEx(BOOL   bOpenFileDialog,   //   TRUE   for   open,   FALSE   for   FileSaveAs   
  24.         LPCTSTR   lpszDefExt   =   NULL,   
  25.         LPCTSTR   lpszFileName   =   NULL,   
  26.         DWORD   dwFlags   =   OFN_HIDEREADONLY   |   OFN_OVERWRITEPROMPT,   
  27.         LPCTSTR   lpszFilter   =   NULL,   
  28.         CWnd*   pParentWnd   =   NULL);   
  29.     
  30.     //   override   
  31.     virtual   int   DoModal();   
  32.     
  33. protected:   
  34.     OPENFILENAMEEX   m_ofnEx; //   new   Windows   2000   version   of   OPENFILENAME   
  35.     
  36.     virtual   BOOL   OnNotify(WPARAM   wParam,   LPARAM   lParam,   LRESULT*   pResult);   
  37.     
  38.     //   virtual   fns   that   handle   various   notifications   
  39.     virtual   BOOL   OnFileNameOK();   
  40.     virtual   void   OnInitDone();   
  41.     virtual   void   OnFileNameChange();   
  42.     virtual   void   OnFolderChange();   
  43.     virtual   void   OnTypeChange();   
  44.     
  45.     DECLARE_MESSAGE_MAP()   
  46.         //{{AFX_MSG(CFileDialogEx)   
  47.         //}}AFX_MSG   
  48. };   
  49. //{{AFX_INSERT_LOCATION}}
  50. // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
  51. #endif // !defined(AFX_FILEDIALOGEX_H__A7F5E19C_B48A_481E_94D9_7922B9E2449E__INCLUDED_)
CFileDialogEx.cpp
  1. //   MSDN   --   August   2000   
  2. //   If   this   code   works,   it   was   written   by   Paul   DiLascia.   
  3. //   If   not,   I   don't   know   who   wrote   it.   
  4. //   Largely   based   on   original   implementation   by   Michael   POSThttp://expert.csdn.net/Expert/reply.C++   6.0,   runs   on   Windows   98   and   probably   NT   too.   
  5. //   
  6. //   CFileDialogEx   implements   a   CFileDialog   that   uses   the   new   Windows   
  7. //   2000   style   open/save   dialog.   Use   companion   class   CDocManagerEx   in   an   
  8. //   MFC   framework   app.   
  9. //   
  10. #include   "stdafx.h"   
  11. #include   <afxpriv.h>   
  12. #include   "FileDialogEx.h"   
  13. #ifdef   _DEBUG   
  14. #define   new   DEBUG_NEW   
  15. #undef   THIS_FILE   
  16. static   char   THIS_FILE[]   =   __FILE__;   
  17. #endif   
  18. static   BOOL   IsWin2000();   
  19. IMPLEMENT_DYNAMIC(CFileDialogEx,   CFileDialog)   
  20. CFileDialogEx::CFileDialogEx(BOOL   bOpenFileDialog,   LPCTSTR   lpszDefExt,   
  21.                              LPCTSTR   lpszFileName,   DWORD   dwFlags,   LPCTSTR   lpszFilter,   CWnd*   pParentWnd)   :   
  22. CFileDialog(bOpenFileDialog,   lpszDefExt,   lpszFileName,   
  23.             dwFlags,   lpszFilter,   pParentWnd)   
  24. {   
  25. }   
  26. BEGIN_MESSAGE_MAP(CFileDialogEx,   CFileDialog)   
  27. //{{AFX_MSG_MAP(CFileDialogEx)   
  28. //}}AFX_MSG_MAP   
  29. END_MESSAGE_MAP()   
  30. BOOL   IsWin2000()     
  31. {   
  32.     OSVERSIONINFOEX   osvi;   
  33.     BOOL   bOsVersionInfoEx;   
  34.     
  35.     //   Try   calling   GetVersionEx   using   the   OSVERSIONINFOEX   structure,   
  36.     //   which   is   supported   on   Windows   2000.   
  37.     //   
  38.     //   If   that   fails,   try   using   the   OSVERSIONINFO   structure.   
  39.     
  40.     ZeroMemory(&osvi,   sizeof(OSVERSIONINFOEX));   
  41.     osvi.dwOSVersionInfoSize   =   sizeof(OSVERSIONINFOEX);   
  42.     
  43.     if(   !(bOsVersionInfoEx   =   GetVersionEx   ((OSVERSIONINFO   *)   &osvi))   )   
  44.     {   
  45.         //   If   OSVERSIONINFOEX   doesn't   work,   try   OSVERSIONINFO.   
  46.         
  47.         osvi.dwOSVersionInfoSize   =   sizeof   (OSVERSIONINFO);   
  48.         if   (!   GetVersionEx   (   (OSVERSIONINFO   *)   &osvi)   )     
  49.             return   FALSE;   
  50.     }   
  51.     
  52.     switch   (osvi.dwPlatformId)   
  53.     {   
  54.     case   VER_PLATFORM_WIN32_NT:   
  55.         
  56.         if   (   osvi.dwMajorVersion   >=   5   )   
  57.             return   TRUE;   
  58.         
  59.         break;   
  60.     }   
  61.     return   FALSE;     
  62. }   
  63. //////////////////   
  64. //   DoModal   override   copied   mostly   from   MFC,   with   modification   to   use   
  65. //   m_ofnEx   instead   of   m_ofn.   
  66. //   
  67. int   CFileDialogEx::DoModal()   
  68. {   
  69.     ASSERT_VALID(this);   
  70.     ASSERT(m_ofn.Flags   &   OFN_ENABLEHOOK);   
  71.     ASSERT(m_ofn.lpfnHook   !=   NULL);   //   can   still   be   a   user   hook   
  72.     
  73.     //   zero   out   the   file   buffer   for   consistent   parsing   later   
  74.     ASSERT(AfxIsValidAddress(m_ofn.lpstrFile,   m_ofn.nMaxFile));   
  75.     DWORD   nOffset   =   lstrlen(m_ofn.lpstrFile)+1;   
  76.     ASSERT(nOffset   <=   m_ofn.nMaxFile);   
  77.     memset(m_ofn.lpstrFile+nOffset,   0,   (m_ofn.nMaxFile-nOffset)*sizeof(TCHAR));   
  78.     
  79.     //   WINBUG:   This   is   a   special   case   for   the   file   open/save   dialog,   
  80.     //     which   sometimes   pumps   while   it   is   coming   up   but   before   it   has   
  81.     //     disabled   the   main   window.   
  82.     HWND   hWndFocus   =   ::GetFocus();   
  83.     BOOL   bEnableParent   =   FALSE;   
  84.     m_ofn.hwndOwner   =   PreModal();   
  85.     AfxUnhookWindowCreate();   
  86.     if   (m_ofn.hwndOwner   !=   NULL   &&   ::IsWindowEnabled(m_ofn.hwndOwner))   
  87.     {   
  88.         bEnableParent   =   TRUE;   
  89.         ::EnableWindow(m_ofn.hwndOwner,   FALSE);   
  90.     }   
  91.     
  92.     _AFX_THREAD_STATE*   pThreadState   =   AfxGetThreadState();   
  93.     ASSERT(pThreadState->m_pAlternateWndInit   ==   NULL);   
  94.     
  95.     if   (m_ofn.Flags   &   OFN_EXPLORER)   
  96.         pThreadState->m_pAlternateWndInit   =   this;   
  97.     else   
  98.         AfxHookWindowCreate(this);   
  99.     
  100.     memset(&m_ofnEx,   0,   sizeof(m_ofnEx));   
  101.     memcpy(&m_ofnEx,   &m_ofn,   sizeof(m_ofn));   
  102.     if   (IsWin2000())   
  103.         m_ofnEx.lStructSize   =   sizeof(m_ofnEx);   
  104.     
  105.     int   nResult;   
  106.     if   (m_bOpenFileDialog)   
  107.         nResult   =   ::GetOpenFileName((OPENFILENAME*)&m_ofnEx);   
  108.     else   
  109.         nResult   =   ::GetSaveFileName((OPENFILENAME*)&m_ofnEx);   
  110.     
  111.     memcpy(&m_ofn,   &m_ofnEx,   sizeof(m_ofn));   
  112.     m_ofn.lStructSize   =   sizeof(m_ofn);   
  113.     
  114.     if   (nResult)   
  115.         ASSERT(pThreadState->m_pAlternateWndInit   ==   NULL);   
  116.     pThreadState->m_pAlternateWndInit   =   NULL;   
  117.     
  118.     //   WINBUG:   Second   part   of   special   case   for   file   open/save   dialog.   
  119.     if   (bEnableParent)   
  120.         ::EnableWindow(m_ofnEx.hwndOwner,   TRUE);   
  121.     if   (::IsWindow(hWndFocus))   
  122.         ::SetFocus(hWndFocus);   
  123.     
  124.     PostModal();   
  125.     return   nResult   ?   nResult   :   IDCANCEL;   
  126. }   
  127. //////////////////   
  128. //   When   the   open   dialog   sends   a   notification,   copy   m_ofnEx   to   m_ofn   in   
  129. //   case   handler   function   is   expecting   updated   information   in   the   
  130. //   OPENFILENAME   struct.   
  131. //   
  132. BOOL   CFileDialogEx::OnNotify(WPARAM   wParam,   LPARAM   lParam,   LRESULT*   pResult)   
  133. {   
  134.     memcpy(&m_ofn,   &m_ofnEx,   sizeof(m_ofn));   
  135.     m_ofn.lStructSize   =   sizeof(m_ofn);   
  136.     
  137.     return   CFileDialog::OnNotify(   wParam,   lParam,   pResult);   
  138. }   
  139. ////////////////////////////////////////////////////////////////   
  140. //   The   following   functions   are   provided   for   testing   purposes,   to   
  141. //   demonstrate   that   they   in   fact   called;   ie,   that   MFC's   internal   dialog   
  142. //   proc   is   hooked   up   properly.   Delete   them   if   you   like.   
  143. //   
  144. BOOL   CFileDialogEx::OnFileNameOK()   
  145. {   
  146.     TRACE(_T("CFileDialogEx::OnFileNameOK/n"));   
  147.     return   CFileDialog::OnFileNameOK();   
  148. }   
  149. void   CFileDialogEx::OnInitDone()   
  150. {   
  151.     TRACE(_T("CFileDialogEx::OnInitDone/n"));   
  152.     CFileDialog::OnInitDone();   
  153. }   
  154. void   CFileDialogEx::OnFileNameChange()   
  155. {   
  156.     TRACE(_T("CFileDialogEx::OnFileNameChange/n"));   
  157.     CFileDialog::OnFileNameChange();   
  158. }   
  159. void   CFileDialogEx::OnFolderChange()   
  160. {   
  161.     TRACE(_T("CFileDialogEx::OnFolderChange/n"));   
  162.     CFileDialog::OnFolderChange();   
  163. }   
  164. void   CFileDialogEx::OnTypeChange()   
  165. {   
  166.     TRACE(_T("OnTypeChange(),   index   =   %d/n"),   m_ofn.nFilterIndex);   
  167.     CFileDialog::OnTypeChange();   
  168. }   

    然后直接调用CFileDialogEx类即可(VC6 SP6 + WinXP测试通过):

  1. CFileDialogEx d(TRUE);
  2. d.DoModal();

   本文写作过程中查阅了大量资料,向这些同行们表示敬意和感谢!最后,骂一句CSDN的Programmer,MD,贴两张图片都让我累死。FK。

 

===================================

非注明转载的文章和blog在未特殊声明情况下一般为本人原创或整理,
原创文章版权归沙漠孤狐(lonefox)所有;转载文章版权归原作者所有;

http://blog.csdn.net/boythl

欢迎转载,但请注明出处,保留作者和版权信息。

===================================

原创粉丝点击