使用GetOpenFileName 选择文件夹

关键字: GetOpenFileName CFileDialog SDK Folder

我一直不喜欢默认的文件夹选择. 相反地,我喜欢MFC中的CFileDialog这种对话框.
如何使用SDK,实现CFileDialog对话框选择文件夹, 是我要解释和举例的.

1. CFileDialog 的实现. CFileDialog 是MFC的类,实现了定制Open, Save, 这些Common Dialog 的定制. 其内部一般是使GetOpenFileName实现的.  CFileDialog 中有一个 m_ofn 结构, 是 OPENFILENAME 类型. 他的详细实现在 dlgfile.cpp 中.  有趣的是,在我的 vc9 中, CFileDialog 对Vista有特殊处置, 如果系统是Vista,而且设置了VistaStyle, 则CFileDialog使用 IFileDialog 接口而不是 GetOpenFileName,这个和我们关系不大,而且我也不打算把简单问题复杂化. 一般而言, MFC 设置 m_ofn 的 flag 中包括了 OFN_ENABLEHOOK | OFN_EXPLORER, 这样可以指定HookProc函数指针, 他可以接受各种消息.MFC的是这样写的: m_ofn.lpfnHook = (COMMDLGPROC)_AfxCommDlgProc; 这是默认的Common Dialog 处理函数.

2. 我们的实现. 前面说到这里,我们基本上已经知道如何实现选择对话框的要求了. 
(1).首先设置 m_ofn.lpstrFile
      WCHAR wcsFolderPath[MAX_PATH] = {0};
      ::wcscpy( wcsFolderPath, L"*..*" );
      m_ofn.lpstrFile  = wcsFolderPath;m_ofn.nMaxFile = sizeof( wcsFolderPath ) /sizeof(WCHAR);   
      "*..*" 将实现屏蔽所有文件,只显示对话框的效果
(2).设置 m_ofn.hInstance = (HMODULE)GetCurrentProcess();//不要使用NULL,可能造成无法定制的问题
(3).设置HookProc: m_ofn.lpfnHook = (COMMDLGPROC)MyFolderProc; 
做完这些事,然后你在MyFolderProc中尝试截获 WM_COMMAND IDOK, IDCANCEL 这些消息,结果是: 你什么都截获不到.
很遗憾,HookProc处理的是一个类似"伪"对话框的一个句柄, 使用spy++, 你会发现,真正处理消息的是HookProc中对话框句柄的父句柄.所以我们应该这么做:
  1. LONG g_lOriWndProc = NULL;
  2. BOOL g_bReplaced = FALSE;
  3. UINT_PTR static __stdcall  MyFolderProc(  HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam )
  4. {
  5.         if( hdlg != NULL &&  g_bReplaced  == FALSE )
  6.         {
  7.             WCHAR wcsClassName1[MAX_PATH];
  8.             WCHAR wcsClassName2[MAX_PATH];
  9.             HWND hParent = ::GetParent( hdlg );
  10.             ::GetClassNameW( hParent, wcsClassName1 , sizeofWCAR(wcsClassName1) );
  11.             ::GetClassNameW( hdlg     , wcsClassName2 , sizeofWCAR(wcsClassName2) );
  12.             if( 0== ::wcscmp( wcsClassName1, wcsClassName2 ) )
  13.             {
  14.                 g_bReplaced  = TRUE;
  15.                  g_lOriWndProc  = ::SetWindowLongW( ::GetParent( hdlg ), GWL_WNDPROC , (LONG)_WndProc );
  16.             }
  17.         }
  18.         if( uiMsg == WM_NOTIFY )
  19.         {
  20.             LPOFNOTIFY lpOfNotify = (LPOFNOTIFY)lParam;
  21.             if( lpOfNotify->hdr.code == CDN_FOLDERCHANGE )
  22.             {
  23.                                   // your codes here
  24.             }
  25.         }
  26.     }
  27.     return FALSE;
  28. }
  29. LRESULT static __stdcall  _WndProc ( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam  )
  30. {
  31.     if( uMsg == WM_COMMAND )
  32.     {
  33.         if( wParam == IDOK )
  34.         {
  35.             //Your codes
  36.         }
  37.     }
  38.     return CallWndProc( (WNDPROC) g_lOriWndProc , hwnd, uMsg, wParam ,lParam );
  39. }
上面这段代码揭示了如何定制Common Dialog 中的FileDialog. 你可以截获IDOK.
但是有一个问题,你选择一个文件夹,然后点击按钮"打开", 你会发现他默认打开这个对话框,而不会关闭对话框,返回对话框所选择的文件夹路径. 
如何解决这个问题? 
很容易, 我们在截获IDOK时, 发送消息 CDM_GETFOLDERPATH , 获取文件夹路径,写入目标缓存, 然后发送消息 IDCANCEL,对话框就会关闭了.
我就是如此实现的. 
我把GetOpenFileName封装成了一个简单的类,设置一个_bOK, 来标识究竟是单击了ok,还是真的单击了cancel (因为我最后发送了IDCANCEL消息,如果不设置_bOK,无法辨别到底是OK,还是cancel ).

网上有CFolderDialog这个简单的类,但是是MFC的,对我来说还是如鲠在喉, 所以在这里用SDK的方法实现之.
希望大家对Windows 有更深的理解.
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值