分类: C/C++
2008-08-26 11:07:01
Shortcut is a file with an extension .lnk. Each of these files contain a special COM object that points to another file. Usually, when you try to open a .lnk file, the system opens a file which this shortcut points to.
Let's do the following experiment. Create a text file (file with an extension .txt) somewhere. Then create a shortcut pointing to this file (send me a private e-mail if you do not know how to create a shortcut manually). Then try to open the shortcut with Microsoft Word, using File->Open command and select just created shortcut. MS Word will do it correctly: it will open the text file that is pointed by this shortcut. Now do the same with Notepad. Instead of the text file content, you will see garbage. It means that Notepad has no idea how to deal with shortcuts.
So we came to a conclusion: in Windows a program should have a built-in support for shortcuts in order to handle them correctly.
In this article I will show how to do it. I will present 2 functions: how to create and resolve the shortcut. The code is well commented (in my opinion) and self-explanatory.
/********************************************************************** * Function......: CreateShortcut * Parameters....: lpszFileName - string that specifies a valid file name * lpszDesc - string that specifies a description for a shortcut * lpszShortcutPath - string that specifies a path and file name of a shortcut * Returns.......: S_OK on success, error code on failure * Description...: Creates a Shell link object (shortcut) **********************************************************************/ HRESULT CreateShortcut(/*in*/ LPCTSTR lpszFileName, /*in*/ LPCTSTR lpszDesc, /*in*/ LPCTSTR lpszShortcutPath) { HRESULT hRes = E_FAIL; DWORD dwRet = 0; CComPtr<IShellLink> ipShellLink; // buffer that receives the null-terminated string // for the drive and path TCHAR szPath[MAX_PATH]; // buffer that receives the address of the final //file name component in the path LPTSTR lpszFilePart; WCHAR wszTemp[MAX_PATH]; // Retrieve the full path and file name of a specified file dwRet = GetFullPathName(lpszFileName, sizeof(szPath) / sizeof(TCHAR), szPath, &lpszFilePart); if (!dwRet) return hRes; // Get a pointer to the IShellLink interface hRes = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&ipShellLink); if (SUCCEEDED(hRes)) { // Get a pointer to the IPersistFile interface CComQIPtr<IPersistFile> ipPersistFile(ipShellLink); // Set the path to the shortcut target and add the description hRes = ipShellLink->SetPath(szPath); if (FAILED(hRes)) return hRes; hRes = ipShellLink->SetDescription(lpszDesc); if (FAILED(hRes)) return hRes; // IPersistFile is using LPCOLESTR, so make sure // that the string is Unicode #if !defined _UNICODE MultiByteToWideChar(CP_ACP, 0, lpszShortcutPath, -1, wszTemp, MAX_PATH); #else wcsncpy(wszTemp, lpszShortcutPath, MAX_PATH); #endif // Write the shortcut to disk hRes = ipPersistFile->Save(wszTemp, TRUE); } return hRes; } /********************************************************************* * Function......: ResolveShortcut * Parameters....: lpszShortcutPath - string that specifies a path and file name of a shortcut * lpszFilePath - string that will contain a file name * Returns.......: S_OK on success, error code on failure * Description...: Resolves a Shell link object (shortcut) *********************************************************************/ HRESULT ResolveShortcut(/*in*/ LPCTSTR lpszShortcutPath, /*out*/ LPTSTR lpszFilePath) { HRESULT hRes = E_FAIL; CComPtr<IShellLink> ipShellLink; // buffer that receives the null-terminated string // for the drive and path TCHAR szPath[MAX_PATH]; // buffer that receives the null-terminated // string for the description TCHAR szDesc[MAX_PATH]; // structure that receives the information about the shortcut WIN32_FIND_DATA wfd; WCHAR wszTemp[MAX_PATH]; lpszFilePath[0] = '\0'; // Get a pointer to the IShellLink interface hRes = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&ipShellLink); if (SUCCEEDED(hRes)) { // Get a pointer to the IPersistFile interface CComQIPtr<IPersistFile> ipPersistFile(ipShellLink); // IPersistFile is using LPCOLESTR, // so make sure that the string is Unicode #if !defined _UNICODE MultiByteToWideChar(CP_ACP, 0, lpszShortcutPath, -1, wszTemp, MAX_PATH); #else wcsncpy(wszTemp, lpszShortcutPath, MAX_PATH); #endif // Open the shortcut file and initialize it from its contents hRes = ipPersistFile->Load(wszTemp, STGM_READ); if (SUCCEEDED(hRes)) { // Try to find the target of a shortcut, // even if it has been moved or renamed hRes = ipShellLink->Resolve(NULL, SLR_UPDATE); if (SUCCEEDED(hRes)) { // Get the path to the shortcut target hRes = ipShellLink->GetPath(szPath, MAX_PATH, &wfd, SLGP_RAWPATH); if (FAILED(hRes)) return hRes; // Get the description of the target hRes = ipShellLink->GetDescription(szDesc, MAX_PATH); if (FAILED(hRes)) return hRes; lstrcpyn(lpszFilePath, szPath, MAX_PATH); } } } return hRes; }
The following code will show how you may use these functions.
void HowToCreateShortcut() { LPCTSTR lpszFileName = _T("C:\\Work\\Window.exe"); LPCTSTR lpszShortcutDesc = _T("Anything can go here"); LPCTSTR lpszShortcutPath = _T("C:\\Documents and Settings\\Administrator\\Desktop\\Sample Shortcut.lnk"); CreateShortcut(lpszFileName, lpszShortcutDesc, lpszShortcutPath); } void HowToResolveShortcut() { LPCTSTR lpszShortcutPath = _T("C:\\Documents and Settings\\Administrator\\Desktop\\Sample Shortcut.lnk"); TCHAR szFilePath[MAX_PATH]; ResolveShortcut(lpszShortcutPath, szFilePath); }
That's it.