VC++ 创建桌面、开始菜单快捷方式(附源码)

       很多公司的软件安装包不再使用InstallShied、InnoSetup等打包工具,他们自己编写代码去制作安装包,这样就能灵活地控制打包的流程、实现酷炫的UI界面。自制安装包的一个重要的一项就是创建桌面和开始菜单的快捷方式,这其中可能会产生一些bug,我们都遇到过,在此将这块的内容分享给大家。

VC++ 创建桌面、开始菜单快捷方式(附源码)_第1张图片

 1、创建快捷方式

       创建快捷方式的代码是通用的,不管是创建桌面快捷方式,还是创建开始菜单快捷方式,都要调用下面封装的接口CreateFileShortcut:(该接口中主要使用前两个参数lpszTargetFilePath和lpszLnkPath,后面几个参数基本不用的)

/**
* 创建快捷方式
*
* @param lpszTargetFilePath 指定快捷方式指向的实际文件路径
* @param lpszLnkPath 快捷方式文件本身的完整路径
* @param wHotkey 为0表示不设置快捷键 
* @param lpszDescription 备注
* @param iShowCmd 显示方式
* @return  TRUE:成功,FALSE:失败
*/
BOOL CreateFileShortcut( LPCTSTR lpszTargetFilePath, LPCTSTR lpszLnkPath, WORD wHotkey, 
	LPCTSTR lpszDescription, int iShowCmd )
{    
    if ( lpszTargetFilePath  == NULL || lpszLnkPath == NULL ) 
	{
        return FALSE;
	}

    HRESULT hr;    
    IShellLink   *pLink;  // IShellLink对象指针    
    IPersistFile *ppf;    // IPersisFil对象指针 

    //::CoInitialize( NULL );
    
    // 创建IShellLink对象    
    hr = CoCreateInstance( CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pLink );    
	if (  FAILED( hr ) )  
	{
		//::CoUninitialize()
		return FALSE;
	}
    
    // 从IShellLink对象中获取IPersistFile接口    
    hr = pLink->QueryInterface( IID_IPersistFile, (void**)&ppf );    
    if ( FAILED( hr ) )        
    {        
        pLink->Release();  
		//::CoUninitialize()
        return FALSE;        
    }    
    
    // 快捷方式指向的实际文件路径    
    if ( lpszTargetFilePath != NULL )
	{
		CString strWorkDirectry = lpszTargetFilePath;
		strWorkDirectry = strWorkDirectry.Left( strWorkDirectry.ReverseFind( _T('\\') ) );

        pLink->SetPath( lpszTargetFilePath );
		pLink->SetWorkingDirectory( strWorkDirectry );

		// 解决快捷图标不刷新、更改图标时找不到文件的问题
		// 快捷方式文件的图标就是其指向的exe文件的图标
		pLink->SetIconLocation( lpszTargetFilePath, 0 ); 

		IShellLinkDataList *pShellLinkDataList = NULL;
		hr = pLink->QueryInterface( IID_IShellLinkDataList, (void**)&pShellLinkDataList );
		if ( FAILED(hr) )
		{
			ppf->Release();
			pLink->Release();
			return FALSE;
		}

		// 避免64系统中图标路径被解析成环境变量,导致快捷方式图标异常
		// 这个地方的代码是用API Monitor工具探测互联网大厂软件的函数调用记录添加上来的
		DWORD dwFlags = SLDF_DEFAULT;
		pShellLinkDataList->GetFlags( &dwFlags );
		if ( (dwFlags & SLDF_HAS_EXP_ICON_SZ) == SLDF_HAS_EXP_ICON_SZ )
		{
			pShellLinkDataList->SetFlags( SLDF_DEFAULT );
			pShellLinkDataList->RemoveDataBlock( EXP_SZ_ICON_SIG );
		}

		pShellLinkDataList->Release();
    }   
    
    // 设置快捷键    
    if ( wHotkey != 0 )
    {  
        pLink->SetHotkey( wHotkey );
    }
    
    // 设置备注    
    if ( lpszDescription != NULL )
    {
        pLink->SetDescription( lpszDescription );
    }
    
    // 显示方式    
    pLink->SetShowCmd( iShowCmd );    
    
    // 保存快捷方式到指定目录下    
    // 要将路径字符串转化成宽字节字符串,COM接口ppf->Save要传入宽字符
	BOOL bUnicode = FALSE;
	WCHAR* pwTemp = NULL;
#ifdef _UNICODE
	pwTemp = (LPTSTR)lpszLnkPath;
	bUnicode = TRUE;
#else
	int nLen = MultiByteToWideChar( CP_ACP, 0, lpszLnkPath, -1, NULL, 0 );
	pwTemp = new WCHAR[nLen+1];
	memset( pwTemp, 0, (nLen+1)*sizeof(WCHAR) );
	MultiByteToWideChar( CP_ACP, 0, lpszLnkPath, -1, pwTemp, nLen+1, NULL, NULL );
#endif
    
    hr = ppf->Save( pwTemp, TRUE ); 

    ppf->Release();    
    pLink->Release(); 

	if ( !bUnicode && pwTemp != NULL )
	{
		delete []pwTemp;
		pwTemp = NULL;
	}

	//::CoUninitialize();

    return SUCCEEDED( hr );    
}

2、创建桌面快捷方式

        下面是在公共桌面中创建快捷方式:

// 得到公共用户桌面
BOOL GetPublicUserDesktopPath( TCHAR *pszDesktopPath )
{
	LPITEMIDLIST  ppidl = NULL;  
	if ( SHGetSpecialFolderLocation( NULL, CSIDL_COMMON_DESKTOPDIRECTORY, &ppidl ) == S_OK )
	{
		BOOL flag =  SHGetPathFromIDList( ppidl, pszDesktopPath );

		CoTaskMemFree( ppidl );
		return flag;
	}

	return FALSE;
}

// 在公共用户桌面上创建快捷方式
void CreateDesktopShortCut()
{
	::CoInitialize( NULL );

	TCHAR achDesktopDir[MAX_PATH] = { 0 };    
	BOOL bRet = GetPublicUserDesktopPath( achDesktopDir );
	if ( !bRet )
	{
		::CoUninitialize();
		return;
	}

	CString strTargetExePath;  // 快捷方式指向的exe路径
	CString strLnkPath;        // 快捷方式文件本省的路径
	
	// ... // 路径获取部分省略
	
	CreateFileShortcut( strTargetExePath, strLnkPath, 0, NULL );

	::CoUninitialize(); 
}

3、创建开始菜单快捷方式

// 得到 开始->程序组 的路径
BOOL CProcessLogic::GetProgramsPath( TCHAR *pszProgramsPath )
{
	LPITEMIDLIST  ppidl;
	if ( SHGetSpecialFolderLocation( NULL, CSIDL_COMMON_PROGRAMS, &ppidl ) == S_OK )    
	{        
		BOOL flag = SHGetPathFromIDList( ppidl, pszProgramsPath );   

		CoTaskMemFree( ppidl );        
		return flag;
	} 

	return FALSE;    
}

void CreateStartMenuShortCut()
{
	::CoInitialize( NULL );

	TCHAR achProgramsDir[MAX_PATH] = { 0 };    
	BOOL bRet = GetProgramsPath( achProgramsDir );
	if ( !bRet )
	{
		::CoUninitialize();
		return;
	}

	// 创建文件夹:C:\Documents and Settings\All Users\「开始」菜单\程序1\
	CString strTLLnkDir = _T("程序1"); 
	CreateDirectory( strTLLnkDir, NULL ); // 创建程序1文件夹

	// 创建 程序1\程序1.lnk
	CString strTargetPath; // 快捷方式指向的exe路径
	CString strLnkPath;// 快捷方式文件本省的路径
	
	// ... // 路径获取部分省略
	
	CreateFileShortcut( strTargetPath, strLnkPath, 0, NULL );
	
	::CoUninitialize();
}

你可能感兴趣的:(VC++常用功能代码封装,桌面快捷方式,开始菜单快捷方式,创建)