通用选择框的功能拓展

来源:互联网 发布:mysql 博客 编辑:程序博客网 时间:2024/05/19 19:12

最近自己写一个网盘客户端,需要用到上传(混合选择文件和文件夹)功能,这个时候,查看了2个软件是如何处理的

百度云管家,他的上传调用了一个XP样式的选择对话框,很明显这个对话框是用OPENFILENAME结构体调用GetOpenFileName来实现的

在MFC框架中CFileDialog类如果在构造时候带了bVistaStyle为FALSE那么就会在DoModal()中调用 GetOpenFileName来打开此窗口

可以注意的是,这个时候CFileDialog的窗口句柄并非直接看到的对话框,用SPY查看了一下,发现CFileDialog的窗口句柄是这个选择窗口的子窗口

2个窗口类都是#32770,所以在C#中可以拦截这2个窗口的处理函数,通过拦截

CDN_SELCHANGE,CDN_FOLDERCHANGE,以及向父#32770窗口发送 CDM_GETFILEPATH,CDM_GETFOLDERPATH,CDM_GETSPEC消息,可以实现监听选择项发生变化,目录变化等事件,并获取当前选择项。

同时可以拦截按下确定按钮的WM_COMMAND消息,来确认当前选择的是否可以一起上传。

可以说第一类通过替换窗口消息处理函数,可以达到大部分功能。

第一类的缺点是,窗口样式是XP的,不是很美观大气


腾讯QQ,他的上传调用了一个新样式的选择对话框,这个对话框是用COM组件的形式来调用的。同样MFC中也是CFileDialog类的实现


在构造函数中当bVistaStyle为TRUE时,CFileDialog会创建一个COM组件,同时设置好一些COM组件的接口变量,

例如

IFileDialog接口m_pIFileDialog成员

IFileDialogCustomize接口m_pIFileDialogCustomize成员

还有几个相关的接口。

先不论这些,先研究CFileDialog窗口句柄是否是打开的这个对话框,发现并不是,而且也没有父子关系。

但是可以通过相应一些消息来获取选择窗口的句柄。

通过拦截OnCreate消息:

类新增成员变量IOleWindow * pWindow;

static_cast<IFileDialog*>(m_pIFileDialog)->QueryInterface(IID_IOleWindow, (void**)&pWindow);

获取COM组件提供的一个IOleWindow接口

当第一次响应OnFolderChange的时候

类新增成员变量 HWND OlehWnd;//选择窗口的句柄

类新增成员变量LPOFNHOOKPROC pCache;//旧的窗口消息处理过程

if (OlehWnd == NULL)
{
HRESULT hr = S_OK;
if (pWindow != NULL)
hr = pWindow->GetWindow(&OlehWnd);
if (hr == S_OK)
{
if (::IsWindow(OlehWnd) && ::IsWindow(m_ofn.hwndOwner))
{
pCache = (LPOFNHOOKPROC)SetWindowLong(OlehWnd, GWL_WNDPROC, (LONG)Hook);
}
}
}

这样就可以子类化这个选择窗口,监听他的消息,来实现自己判断选择的文件或文件夹能否一起上传

如果能够上传,就得自己模拟关闭窗口了

可以看到QQ使用的这种方式,面板也是比较漂亮。

0 0