Introduction
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.
Code
HRESULT CreateShortcut( LPCTSTR lpszFileName,
LPCTSTR lpszDesc,
LPCTSTR lpszShortcutPath)
{
HRESULT hRes = E_FAIL;
DWORD dwRet = 0;
CComPtr<IShellLink> ipShellLink;
TCHAR szPath[MAX_PATH];
LPTSTR lpszFilePart;
WCHAR wszTemp[MAX_PATH];
dwRet = GetFullPathName(lpszFileName,
sizeof(szPath) / sizeof(TCHAR),
szPath, &lpszFilePart);
if (!dwRet)
return hRes;
hRes = CoCreateInstance(CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink,
(void**)&ipShellLink);
if (SUCCEEDED(hRes))
{
CComQIPtr<IPersistFile> ipPersistFile(ipShellLink);
hRes = ipShellLink->SetPath(szPath);
if (FAILED(hRes))
return hRes;
hRes = ipShellLink->SetDescription(lpszDesc);
if (FAILED(hRes))
return hRes;
#if !defined _UNICODE
MultiByteToWideChar(CP_ACP, 0,
lpszShortcutPath, -1, wszTemp, MAX_PATH);
#else
wcsncpy(wszTemp, lpszShortcutPath, MAX_PATH);
#endif
hRes = ipPersistFile->Save(wszTemp, TRUE);
}
return hRes;
}
HRESULT ResolveShortcut( LPCTSTR lpszShortcutPath,
LPTSTR lpszFilePath)
{
HRESULT hRes = E_FAIL;
CComPtr<IShellLink> ipShellLink;
TCHAR szPath[MAX_PATH];
TCHAR szDesc[MAX_PATH];
WIN32_FIND_DATA wfd;
WCHAR wszTemp[MAX_PATH];
lpszFilePath[0] = '\0';
hRes = CoCreateInstance(CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink,
(void**)&ipShellLink);
if (SUCCEEDED(hRes))
{
CComQIPtr<IPersistFile> ipPersistFile(ipShellLink);
#if !defined _UNICODE
MultiByteToWideChar(CP_ACP, 0, lpszShortcutPath,
-1, wszTemp, MAX_PATH);
#else
wcsncpy(wszTemp, lpszShortcutPath, MAX_PATH);
#endif
hRes = ipPersistFile->Load(wszTemp, STGM_READ);
if (SUCCEEDED(hRes))
{
hRes = ipShellLink->Resolve(NULL, SLR_UPDATE);
if (SUCCEEDED(hRes))
{
hRes = ipShellLink->GetPath(szPath,
MAX_PATH, &wfd, SLGP_RAWPATH);
if (FAILED(hRes))
return hRes;
hRes = ipShellLink->GetDescription(szDesc,
MAX_PATH);
if (FAILED(hRes))
return hRes;
lstrcpyn(lpszFilePath, szPath, MAX_PATH);
}
}
}
return hRes;
}
Using the code
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.