zoukankan      html  css  js  c++  java
  • 打开文件对话框在xp和win7上的实现文件任意多选

    作者:朱金灿

    来源:http://blog.csdn.net/clever101

       

           在xp系统上进行文件多选,实际上其文件字符串数组的缓冲区是有限,并不能支持选择任意多个文件,为此以前我还写过一篇文章:使用CFileDialog的钩子函数解决对话框的多选问题。实际上这种做法在vista系统及win7系统上并不支持。那么如何在vista系统及win7系统支持打开文件对话框任意多选文件呢?我想到windows是一个基于com的系统,没准使用com接口能做到。事实上是这样的,需要使用一个叫IFileOpenDialog的接口类。下面是示例代码:



    // Return the file system path for a given IShellItem.
    static bool PathFromShellItem ( IShellItem* pItem, CString& sPath )
    {
    	HRESULT hr;
    	LPOLESTR pwsz = NULL;
    
    	hr = pItem->GetDisplayName ( SIGDN_FILESYSPATH, &pwsz );
    
    	if ( FAILED(hr) )
    		return false;
    
    	sPath = pwsz;
    	CoTaskMemFree ( pwsz );
    	return true;
    }
    
    // Convert a pipe-separated list of filter strings into a vector of
    // COMDLG_FILTERSPEC. The vector<CString> is needed to actually hold the strings
    // that the COMDLG_FILTERSPEC structs will point to.
    static bool BuildFilterSpecList (_U_STRINGorID szFilterList,
    								 COMDLG_FILTERSPEC*& pVecFilter,int& nFilterNum )
    {
    	std::vector<CString> vecsFilterParts;
    	CString sFilterList = szFilterList.m_lpstr;
    	CString sToken;
    	int nIdx = 0;
    
    	// Split the passed-in filter list on pipe characters (MFC-style)
    	for(;;)
    	{
    		sToken = sFilterList.Tokenize(_T("|"), nIdx );
    		if ( sToken.IsEmpty() )
    			break;
    
    		vecsFilterParts.push_back ( sToken );
    	}
    
    	// There should be an even number of tokens in the string
    	if ( vecsFilterParts.size() & 1 )
    	{
    		ATLASSERT(0);
    		vecsFilterParts.pop_back();
    	}
       
    	if(vecsFilterParts.empty())
    		return false;
    
        nFilterNum = vecsFilterParts.size()/2.0;
        pVecFilter = new COMDLG_FILTERSPEC[nFilterNum];
    
    	// Use each pair of tokens for a COMDLG_FILTERSPEC struct.
    	/*for (std::vector<CString>::size_type i = 0; i < vecsFilterParts.size(); i += 2 )*/
    	for (std::vector<CString>::size_type i = 0; i <nFilterNum; i++)
    	{
    		USES_CONVERSION;
         
    		int j = i*2;
    
    		std::wstring strName = A2W(vecsFilterParts[j]);
            pVecFilter[i].pszName = new WCHAR[strName.length()+1];
            memset((void*)pVecFilter[i].pszName,'',(strName.length()+1)*sizeof(WCHAR));
            wcsncpy((wchar_t*)pVecFilter[i].pszName,strName.c_str(),strName.length());
    
    		j = j+1;
    		std::wstring strSpec = A2W(vecsFilterParts[j]);
    		pVecFilter[i].pszSpec = new WCHAR[strSpec.length()+1];
    		memset((void*)pVecFilter[i].pszSpec,'',(strSpec.length()+1)*sizeof(WCHAR));
    		wcsncpy((wchar_t*)pVecFilter[i].pszSpec,strSpec.c_str(),strSpec.length());
    	}
    //	return !vecFilters.empty();
    	return true;
    }
    
    void CMultiSelectDlg::OnBnClickedBtnVista()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	HRESULT hr;
    	CComPtr<IFileOpenDialog> pDlg;
    //	std::vector<CString> vecsFilterParts;
    //	std::vector<COMDLG_FILTERSPEC> vecFilters;
    
    	COMDLG_FILTERSPEC* pVecFilter = NULL;;
        int nFilterNum = 0;
    
    //	std::vector<std::wstring> vecFilters;
    
    	CString sDlgTitle = _T("Multi-selection File Open Dialog");
    	CString sOKButtonLabel = _T("确定");
    	CString sFilenameLabel = _T("文件名(N):");
    	DWORD dwFlags = 0;
    
    	// Create the file-open dialog COM object.
    	hr = pDlg.CoCreateInstance( __uuidof(FileOpenDialog) );
    
    	if ( FAILED(hr) )
    		return;
    
    	// Tell the dlg to load the state data associated with this GUID:
    	// {7D5FE367-E148-4a96-B326-42EF237A3662}
    	// This is not strictly necessary for our app (normally you'd wand loads
    	// and saves to share the same state data) but I'm putting this in for the demo.
    	static const GUID guidFileOpen = { 0x7D5FE367, 0xE148, 0x4A96, { 0xB3, 0x26, 0x42, 0xEF, 0x23, 0x7A, 0x36, 0x62 } };
    
    	hr = pDlg->SetClientGuid ( guidFileOpen );
    
    	// Call this helper function to convert a pipe-separated file spec list 
    	// (like MFC uses) to a vector of COMDLG_FILTERSPEC.
    	if ( BuildFilterSpecList(_T("Text files (*.txt)|*.txt|Executable files (*.exe;*.dll)|*.exe;*.dll|All files (*.*)|*.*|"),
    		pVecFilter,nFilterNum))
    		hr = pDlg->SetFileTypes(nFilterNum,pVecFilter);
    
    	// Set some other properties of the dialog. It's not the end of the world if
    	// any of these calls fail.
    	 USES_CONVERSION; 
    	hr = pDlg->SetTitle (A2W(sDlgTitle));
    	hr = pDlg->SetOkButtonLabel(A2W(sOKButtonLabel));
    	hr = pDlg->SetFileNameLabel(A2W(sFilenameLabel));
    
    	// Set the multi-select option flag.
    	hr = pDlg->GetOptions ( &dwFlags );
    	hr = pDlg->SetOptions ( dwFlags | FOS_ALLOWMULTISELECT );
    
    	// Set up our event listener.
    //	CComObjectStackEx<CDlgEventHandler> cbk;
    
    	// Show the dialog!
    	hr = pDlg->Show ( m_hWnd );
    
    	//if ( bAdvised )
    	//	pDlg->Unadvise ( dwCookie );
    
    	// Get the list of selected items and add each filename to the list ctrl.
    	if ( SUCCEEDED(hr) )
    	{
    		CComPtr<IShellItemArray> pItemArray;
    
    		hr = pDlg->GetResults ( &pItemArray );
    
    		if ( SUCCEEDED(hr) )
    		{
    			DWORD cSelItems;
    			hr = pItemArray->GetCount ( &cSelItems );
    
    			if ( SUCCEEDED(hr) )
    			{
    				int nCount = 0;
    				for ( DWORD j = 0; j < cSelItems; j++ )
    				{
    					CComPtr<IShellItem> pItem;
    					hr = pItemArray->GetItemAt ( j, &pItem );
    					if ( SUCCEEDED(hr) )
    					{
    						CString sPath;
    						if ( PathFromShellItem ( pItem, sPath ) )
    						{
    							m_listbox.AddString(sPath);
    							nCount++;
    						}
    					}
    				}
    				CString str;
    				str.Format(_T("%u files selected"), nCount);
    				m_static.SetWindowText(str);
    			}
    		}
    	}
        
    	for (int i  = 0;i<nFilterNum;i++)
    	{
    		delete []pVecFilter[i].pszName;
    		delete []pVecFilter[i].pszSpec;
    	}
    	delete []pVecFilter;
    }

     

            值得注意的是这个做法并不兼容xp系统,因此在使用哪种做法时需要你先对操作系统的版本进行判断。我专门写了一个例程供大家参考:VC文件多选对话框

     

    参考文献:

     

    1. WindowsVista for Developers——第六部分:新的文件对话框

     

    2. IFileDialog使用指南

  • 相关阅读:
    远程连接Mysql报错 java.sql.SQLException:null,message from server ... is not allowed to connect
    使用 java.util.Properties 读取配置文件中的参数
    重载Prometheus配置
    Redis的 SLAVEOF 命令
    Redis为什么不能使用一主一从哨兵
    iptables添加开放端口
    解决172.17 或者172.18 机房环境下harbor服务器不通的问题
    利用sshpass批量导入ssh-key
    ZABBIX_PROXy
    zabbix_server.conf
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6470137.html
Copyright © 2011-2022 走看看