有时候,为了方便用户使用我们编写的程序,需要在桌面,快速启动或程序组中创建程序的快捷方式。下面就介绍在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