在桌面建立 LNK 快捷方式
有時候,為了方便使用者使用我們編寫的程式,需要在桌面,快速啟動或程式組中建立程式的快捷方式。下面就介紹在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
第二個函式將一個條目識別符號列表轉換為一個檔案系統路徑
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)
{
BOOLflag = SHGetPathFromIDList(ppidl, pszDesktopPath);
CoTaskMemFree(ppidl);
return flag;
}
return FALSE;
}
//得到快速啟動欄的路徑
BOOL GetIEQuickLaunchPath(char *pszIEQueickLaunchPath)
{
LPITEMIDLIST ppidl;
if (SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &ppidl) == S_OK)
{
BOOLflag = 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)
{
BOOLflag = SHGetPathFromIDList(ppidl, pszProgramsPath);
CoTaskMemFree(ppidl);
return flag;
}
return FALSE;
}
/*
函式功能:對指定檔案在指定的目錄下建立其快捷方式
函式引數:
lpszFileName 指定檔案,為NULL表示當前程序的EXE檔案。
lpszLnkFileDir 指定目錄,不能為NULL。
lpszLnkFileName 快捷方式名稱,為NULL表示EXE檔名。
wHotkey 為0表示不設定快捷鍵
pszDescription 備註
iShowCmd 執行方式,預設為常規視窗
*/
BOOL CreateFileShortcut(LPCSTRlpszFileName, LPCSTRlpszLnkFileDir, LPCSTRlpszLnkFileName, LPCSTRlpszWorkDir, WORDwHotkey, LPCTSTRlpszDescription, int iShowCmd = SW_SHOWNORMAL)
{
if (lpszLnkFileDir == NULL)
return FALSE;
HRESULThr;
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';
}
//儲存快捷方式到指定目錄下
WCHARwsz[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")
效果如圖: