VC 为程序创建快捷方式的详细讲解

长平狐 发布于 2012/12/10 17:19
阅读 88
收藏 0
 

有时候,为了方便用户使用我们编写的程序,需要在桌面,快速启动或程序组中创建程序的快捷方式。下面就介绍在VC下如何为程序创建快捷方式。

一.得到桌面,快速启动或程序组的路径

这里介绍二个win32 API函数来完成这个任务。

第一个函数 获得系统特殊路径

HRESULT SHGetSpecialFolderLocation(

HWND hwndOwner,  int nFolder, PIDLIST_ABSOLUTE *ppidl

);

第一个参数表示所有者窗口句柄,一般传入NULL就可以了。

第二个参数要示是一个整数id,决定哪个目录是待查找目录,它的取值可能是

CSIDL_BITBUCKET            回收站

CSIDL_CONTROLS            控制面板

CSIDL_DESKTOP              Windows桌面desktop;

CSIDL_DESKTOPDIRECTORY   desktop的目录;

CSIDL_DRIVES                我的电脑

CSIDL_FONTS                 字体目录

CSIDL_NETHOOD             网上邻居

CSIDL_NETWORK             网上邻居virtual folder

CSIDL_PERSONAL             我的文档

CSIDL_PRINTERS              打印机

CSIDL_PROGRAMS             程序组

CSIDL_RECENT                最近打开文档

CSIDL_SENDTO                发送到菜单项

CSIDL_STARTMENU            快速启动菜单

CSIDL_STARTUP               启动目录

CSIDL_TEMPLATES            临时文档

第三个参数表示一个条目标识符列表指针,可以传入一个LPITEMIDLIST类型变量,再从这个变量中得到表示路径的字符串。使用完后,要用void CoTaskMemFree(void * pv)来释放资源。

 

第二个函数 将一个条目标识符列表转换为一个文件系统路径

BOOL SHGetPathFromIDList( 

PCIDLIST_ABSOLUTE pidl,  LPTSTR pszPath

);

第一个参数 pidl就是用第一个函数所得到的条目标识符列表指针。

第二个参数pszPath返回表示路径的字符串。

 

这二个函数的头文件均为<shlobj.h>并要引入shell32.lib。

下面给出了一个程序,用来列举你电脑上一些系统特殊路径:

#include <stdio.h>
#include <windows.h>
#include <shlobj.h>
#pragma comment(lib, "shell32.lib")

int main()
{
	const int ENDNUMBER = -1;//哨兵,在遍历数组时遇到此数表示已经到达了数组的最后。
	//设置这个后,你可以在nFolders数组中任意添加删除数据而不用在遍历数组时考虑其中有多少个数据。

	CoInitialize(NULL);
	int nFolders[] = {
		CSIDL_BITBUCKET, CSIDL_CONTROLS, CSIDL_DESKTOP, CSIDL_DESKTOPDIRECTORY, 
		CSIDL_DRIVES, CSIDL_FONTS, CSIDL_NETHOOD, CSIDL_NETWORK, CSIDL_PERSONAL, 
		CSIDL_PRINTERS, CSIDL_PROGRAMS, CSIDL_RECENT, CSIDL_SENDTO, CSIDL_STARTMENU, 
		CSIDL_STARTUP, CSIDL_TEMPLATES, ENDNUMBER
	};

	HRESULT       hr;
	LPITEMIDLIST  ppidl; 
	char          szPath[MAX_PATH];

	int i = 0;	
	while (nFolders[i] != ENDNUMBER)
	{
		hr = SHGetSpecialFolderLocation(NULL, nFolders[i], &ppidl); 
		if (hr != S_OK)
		{
			printf("SHGetSpecialFolderLocation Error\n");
		}
		else
		{
			if (SHGetPathFromIDList(ppidl, szPath))
				printf("%s\n", szPath);
			else
				printf("SHGetPathFromIDList Error\n");
			CoTaskMemFree(ppidl);
		}

		i++;
	}
	CoUninitialize();
	return 0;
}

由于系统的差异,有时会输出“SHGetPathFromIDList Error”,在我电脑上就输出了5次。有了这个例子,相信不难写出得到桌面桌面(CSIDL_DESKTOP),快速启动(CSIDL_APPDATA),程序组(CSIDL_PROGRAMS)的路径函数。

不过要稍稍注意下快捷启动,要再加上"\\Microsoft\\Internet Explorer\\Quick Launch"。

 

二.创建快捷方式文件

完成第一步的任务后接下来的问题是如何创建快捷方式文件即.lnk文件。首先要了解快捷方式文件要设置什么,然后了了解怎样设置。

2.1快捷方式文件有哪些要设置的内容

下面给出了Spy++和Kmplayer Plus二个程序的快捷方式。

快捷方式必须设置目标,起始位置,快捷键,备注都可以选择性的设置,运行方式一般取默认值----常规窗口。

 

2.2如何设置快捷方式文件的内容

这要用到二个COM接口IShellLink和IPersistFile。由于篇幅问题,这里只讲解二个接口的部分函数。

IShellLink的部分函数

HRESULT SetPath(LPCTSTR pszFile);             设置目标

HRESULT SetWorkingDirectory(LPCTSTR pszDir);  设置起始位置

HRESULT SetHotkey(WORD wHotkey);           设置快捷键

HRESULT SetShowCmd(int iShowCmd);           设置运行方式

       有三种选择SW_SHOWNORMAL常规窗口

SW_SHOWMAXIMIZED最大化SW_SHOWMINNOACTIVE最小化

HRESULT SetDescription(LPCTSTR pszName);      设置备注

要特别说下SetHotkey()中的参数WORD wHotkey。MSDN上对其的解释为:

The address of the hot key. The virtual key code is in the low-order byte, and the modifier flags are in the high-order byte. The modifier flags can be a combination of the following values.

HOTKEYF_ALT        ALT key

HOTKEYF_CONTROL   CTRL key

HOTKEYF_EXT        Extended key

HOTKEYF_SHIFT      SHIFT key

意思就是对这个WORD值,低位上是virtual key code,高位上可以是ALT,CTRL等组合键。可以用MAKEWORD(low, high)来生成一个WORD,如Ctrl+F12可以用MAKEWORD(VK_F12, HOTKEYF_CONTROL)表示。

 

IPersistFile的部分函数

HRESULT Save(          保存快捷方式

  LPCOLESTR pszFileName, BOOL fRemember

);

第一个参数是要保存文件的文件名,要求是绝对路径。

第二个参数涉及COM的持续性问题(注1),一般传入TRUE即可。

 

要创建COM对象可以用CoCreateInstance()函数(见注2)和QueryInterface()函数(见注3)。下面给出了创建的代码:

IShellLink     *pLink;   //IShellLink对象指针

IPersistFile    *ppf;      //IPersisFil对象指针

创建IShellLink实例

CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,IID_IShellLink,(void**)&pLink);

从IShellLink对象中获取IPersistFile接口

pLink->QueryInterface(IID_IPersistFile, (void**)&ppf);

创建之后就可以对pLink设置目标,快捷键,备注等,设置完后再用ppf创建快捷方式文件就可以了。当然最后要记得释放资源,pLink->Release(); ppf->Release()。

 

三.已封装好的函数代码

下面给出封装好的函数代码,可以在程序中直接使用(在XP+VC6.0下测试过)。

//得到当前桌面路径
BOOL GetDesktopPath(char *pszDesktopPath)
{
	LPITEMIDLIST  ppidl = NULL; 
	
	if (SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &ppidl) == S_OK)
	{
		BOOL flag =	SHGetPathFromIDList(ppidl, pszDesktopPath);
		CoTaskMemFree(ppidl);
		return flag;
	}

	return FALSE;
}	
//得到快速启动栏的路径
BOOL GetIEQuickLaunchPath(char *pszIEQueickLaunchPath)
{	
	LPITEMIDLIST  ppidl; 			
	
	if (SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &ppidl) == S_OK)
	{
		BOOL flag =	SHGetPathFromIDList(ppidl, pszIEQueickLaunchPath);
		strcat(pszIEQueickLaunchPath, "\\Microsoft\\Internet Explorer\\Quick Launch");
		CoTaskMemFree(ppidl);
		return flag;
	}

	return FALSE;
}
//得到 开始->程序组 的路径
BOOL GetProgramsPath(char *pszProgramsPath)
{
	LPITEMIDLIST  ppidl; 
	
	if (SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAMS, &ppidl) == S_OK)
	{
		BOOL flag = SHGetPathFromIDList(ppidl, pszProgramsPath);
		CoTaskMemFree(ppidl);
		return flag;
	}

	return FALSE;
}
/*
函数功能:对指定文件在指定的目录下创建其快捷方式
函数参数:
lpszFileName    指定文件,为NULL表示当前进程的EXE文件。
lpszLnkFileDir  指定目录,不能为NULL。
lpszLnkFileName 快捷方式名称,为NULL表示EXE文件名。
wHotkey         为0表示不设置快捷键
pszDescription  备注
iShowCmd        运行方式,默认为常规窗口
*/
BOOL CreateFileShortcut(LPCSTR lpszFileName, LPCSTR lpszLnkFileDir, LPCSTR lpszLnkFileName,	LPCSTR lpszWorkDir, WORD wHotkey, LPCTSTR lpszDescription, int iShowCmd = SW_SHOWNORMAL)
{
	if (lpszLnkFileDir == NULL)
		return FALSE;

	HRESULT hr;
	IShellLink     *pLink;  //IShellLink对象指针
	IPersistFile   *ppf; //IPersisFil对象指针
	
	//创建IShellLink对象
	hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pLink);
	if (FAILED(hr))
		return FALSE;
	
	//从IShellLink对象中获取IPersistFile接口
	hr = pLink->QueryInterface(IID_IPersistFile, (void**)&ppf);
	if (FAILED(hr))
	{
		pLink->Release();
		return FALSE;
	}
	
	//目标
	if (lpszFileName == NULL)
		pLink->SetPath(_pgmptr);
	else
		pLink->SetPath(lpszFileName);
	
	//工作目录
	if (lpszWorkDir != NULL)
		pLink->SetPath(lpszWorkDir);
	
	//快捷键
	if (wHotkey != 0)
		pLink->SetHotkey(wHotkey);
	
	//备注
	if (lpszDescription != NULL)
		pLink->SetDescription(lpszDescription);
	
	//显示方式
	pLink->SetShowCmd(iShowCmd);


	//快捷方式的路径 + 名称
	char szBuffer[MAX_PATH];
	if (lpszLnkFileName != NULL) //指定了快捷方式的名称
		sprintf(szBuffer, "%s\\%s", lpszLnkFileDir, lpszLnkFileName);
	else   
	{
		//没有指定名称,就从取指定文件的文件名作为快捷方式名称。
		char *pstr;
		if (lpszFileName != NULL)
			pstr = strrchr(lpszFileName, '\\');
		else
			pstr = strrchr(_pgmptr, '\\');

		if (pstr == NULL)
		{	
			ppf->Release();
			pLink->Release();
			return FALSE;
		}
		//注意后缀名要从.exe改为.lnk
		sprintf(szBuffer, "%s\\%s", lpszLnkFileDir, pstr);
		int nLen = strlen(szBuffer);
		szBuffer[nLen - 3] = 'l';
		szBuffer[nLen - 2] = 'n';
		szBuffer[nLen - 1] = 'k';
	}
	//保存快捷方式到指定目录下
	WCHAR  wsz[MAX_PATH];  //定义Unicode字符串
	MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, wsz, MAX_PATH);
	
	hr = ppf->Save(wsz, TRUE);
	
	ppf->Release();
	pLink->Release();
	return SUCCEEDED(hr);
}

调用如下例:

int main()
{
	char  szPath[MAX_PATH];
	CoInitialize(NULL);

	GetDesktopPath(szPath);
	if (CreateFileShortcut(NULL, szPath, NULL, NULL, MAKEWORD(VK_F12, HOTKEYF_CONTROL), "That is a test"))
		printf("创建成功\n");

	CoUninitialize();
	return 0;
}

头文件及引用库:

#include <stdio.h>

#include <windows.h>

#include <shlobj.h>

#pragma comment(lib, "shell32.lib")

效果如图:

有兴趣的话,可以将代码进一步的整理。

 

 

注1          参见http://www.vckbase.com/document/viewdoc/?id=1546

注2          参见http://baike.baidu.com/view/1141927.htm

注3          参见http://baike.baidu.com/view/5395542.htm

转载请标明出处。原文地址:http://blog.csdn.net/morewindows/article/details/6686683


原文链接:http://blog.csdn.net/morewindows/article/details/6686683
加载中
返回顶部
顶部