VC++实现打开文件和打开所在文件夹的功能(附源码)

Posted dvlinker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VC++实现打开文件和打开所在文件夹的功能(附源码)相关的知识,希望对你有一定的参考价值。

       在使用IM软件将文件接收完成,或者使用下载软件将文件下载完成时,都会有打开文件和打开文件坐在文件夹的入口,如下:

打开文件是直接将文件打开,打开所在文件夹则是打开文件所在的目录并选中该文件。下面我们就来看看实现打开文件及打开所在文件夹这两个功能的实现细节。

       对于打开文件,我们只需要调用ShellExecute,传入“open”参数和要打开的文件的完整路径即可,执行这句代码后,系统会启动适当的程序去打开这个文件。此处有个细节需要考虑一下,要判断ShellExecute API函数的返回值,如果文件打开失败(系统找不到合适的程序来打开该文件),则需要将如下的系统窗口弹出来,让用户选择使用哪个程序打开(下面的代码中会有涉及):(以win10系统的截图为例)

       对于打开文件所在文件夹,除了要打开文件所在的目录,还要选中该文件。调用ShellExecute是实现不了这样的效果的,可以调用系统的一个专用的API函数SHOpenFolderAndSelectItems即可。此处也需要考虑一个细节,SHOpenFolderAndSelectItems在个别情况下可能会调用失败,如果调用失败,则再去调用ShellExecute粗略地实现。这些细节在下面展示的代码会有充分的说明。

       上述两个功能点,细节上还要考虑的更全面一点,都要考虑文件不存在的情况(可能文件被删除了),要做相应的处理。我们在开发软件时,要尽量考虑的全面一些,将各种可能的场景和问题都考虑进去,这一点显得尤为重要!

        相关的代码如下所示:(以richedit中显示“打开文件”和“打开所在文件夹”的超链接为例)

void CRichEditUI::OnURLClick( ENLINK *pLink )

	ASSERT(pLink);

	if ( WM_LBUTTONDOWN == pLink->msg )
	
		m_bDownUrl = TRUE;
	
	if ( WM_LBUTTONUP == pLink->msg )
	
		if ( !m_bDownUrl )
		
			return;
		

		m_bDownUrl = FALSE;
		SetSel( pLink->chrg );

		CStdString strSelText;
		strSelText = GetSelText();
		CStdString strLeft = strSelText.Left( 2 );

		TCHAR achFilePath[MAX_PATH] =  0 ;
		CStdString strFilePath;
		CStdString strFilePathParam;

		// 对于文件传输,传输结束后在界面中会显示“打开文件”和“打开所在文件夹”的链接
		if ( 0 == _tcscmp( strSelText, _T("打开文件") ) ) 
		
			// 1、打开文件(链接或按钮)

			// 获取目标文件的完整路径
			strFilePath = GetFilePath( pLink->chrg.cpMin ); 
			if ( _taccess( strFilePath, 0 ) != 0 ) 
			
				// 如果文件不存在,则要给出文件不存在的提示
				::MessageBox( NULL, _T("文件不存在,文件打开失败!"), _T("提示"), MB_OK);
				return;
			

			// 加上双引号以防路径中有空格导致ShellExecute参数解析错误
			strFilePathParam.Format( _T("\\"%s\\""), strFilePath ); 
			int nRet = (int)ShellExecute( NULL, _T("open"), strFilePathParam, NULL, NULL, SW_SHOWNORMAL );
			if ( SE_ERR_NOASSOC == nRet ) 
			
				// 没有相关的程序能够打开该文件,需要自动弹出系统的“打开方式->选择程序...”对话框
				CStdString strCmd;
				strCmd.Format( _T("shell32, OpenAs_RunDLL  %s"), strFilePath.GetData() );
				ShellExecute( NULL, _T("open"), _T("rundll32.exe"), strCmd, NULL, SW_SHOWNORMAL );
			
		
		else if ( 0 == _tcscmp( strSelText, STRING_OPEN_THE_FOLDER ) ) 
		
			// 2、“打开所在文件夹”链接
			strFilePath = GetFilePath( pLink->chrg.cpMin ); 
			if ( _taccess( strFilePath, 0 ) != 0 ) 
			
				// 当前文件不存在,可能已经被删除
				CStdString strPathName = strFilePath.Left( strFilePath.ReverseFind('\\\\') );
				if ( 0 == _taccess( strPathName, 0 ) ) 
				
					// 文件夹存在,可以打开文件夹
					// 如果文件夹已经打开,此时再用ShellExecute执行打开所在文件夹的操作,会将文件夹最前显示,
					ShellExecute( NULL, _T("open"), _T("explorer.exe"), strPathName, NULL, SW_SHOWNORMAL );
				
				else 
				
					// 如果所在文件夹不存在,则要给出文件夹不存在的提示
					::MessageBox( NULL, _T("所在文件夹不存在,打开失败!"), _T("提示"), MB_OK);
				

				return;
			

			// 当前文件存在,则打开所在文件夹并选中文件
			bool bOpenRet = OpenFolderAndSelFile( strFilePath );
			if ( !bOpenRet )
			
				// 有时会出现SHOpenFolderAndSelectItems调用失败的情况,比如标准用户下提权到
				// 管理员权限时会返回操作失败,迅雷也有类似的问题。此时再借助ShellExecute来
				// 打开,ShellExecute有点小问题,就是如果所在文件夹已经打开,不能选中目标文
				// 件,不过在SHOpenFolderAndSelectItems调用失败时,也可以使用
				CStdString strParameter;
				strParameter.Format( _T("/select, \\"%s\\""), strFilePath );
				ShellExecute( NULL, _T("open"), _T("explorer.exe"), strParameter, NULL, SW_SHOWNORMAL );
			
		

其中OpenFolderAndSelFile函数的实现如下:

bool CRichEditUI::OpenFolderAndSelFile( CStdString strFilePath )

	LPITEMIDLIST pidl = NULL;
	LPCITEMIDLIST cpidl = NULL;
	LPSHELLFOLDER pDesktopFolder = NULL;
	WCHAR wfilePath[MAX_PATH+1] =  0 ;

	// 主工程已经初始化了COM库,此处不用在初始化了
	//::CoInitialize( NULL );

	if ( SUCCEEDED( SHGetDesktopFolder( &pDesktopFolder ) ) )
	
		// IShellFolder::ParseDisplayName要传入宽字节
		LPWSTR lpWStr = NULL;
#ifdef _UNICODE
		_tcscpy( wfilePath, strFilePath );
		lpWStr = wfilePath;
#else
		MultiByteToWideChar( CP_ACP, 0, strFilePath.GetData(), -1, wfilePath, MAX_PATH ); 
		lpWStr = wfilePath;
#endif

		HRESULT hr = pDesktopFolder->ParseDisplayName( NULL, 0, lpWStr, NULL, &pidl, NULL );
		if ( FAILED( hr ) )
		
			pDesktopFolder->Release();
			//::CoUninitialize();
			return false;
		

		cpidl = pidl;

		hr = SHOpenFolderAndSelectItems( cpidl, 0, NULL, 0 ); // 第二个参数cidl置为0,表示是选中文件
		if ( FAILED( hr ) )
		
			pDesktopFolder->Release();
			//::CoUninitialize();
			return false;
		

    pDesktopFolder->Release();

	//::CoUninitialize();
	return true;

以上是关于VC++实现打开文件和打开所在文件夹的功能(附源码)的主要内容,如果未能解决你的问题,请参考以下文章

VC++使用fprintf函数实现写日志文件的功能(附源码)

VC++调用HtmlHelp打开chm帮助文档(附源码)

VC++判断目标文件是否被独占(附源码)

迅雷中的“打开文件所在目录”并定位文件的vc实现方法

VC++打开或关闭目标进程的声音(扬声器)(附源码)

VC++ 功能强大的API函数FindFirstFile使用介绍(附源码)