Click here to Skip to main content
Click here to Skip to main content

How to create and resolve a shortcut

By , 6 Oct 2003
 

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

/**********************************************************************
* 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;
}

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Igor Vigdorchik
Web Developer
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberAndreas Strauss25 Oct '12 - 6:43 
GeneralWhy this article is similiar with "http://msdn.microsoft.com/en-us/library/aa969393.aspx"membertransoft13 Jun '11 - 11:17 
http://msdn.microsoft.com/en-us/library/aa969393.aspx[^]
GeneralRe: Why this article is similiar with "http://msdn.microsoft.com/en-us/library/aa969393.aspx"memberIgor Vigdorchik18 Jul '11 - 12:34 
Generalhttp://msdn.microsoft.com/en-us/library/aa969393.aspxmembertransoft13 Jun '11 - 11:16 
GeneralHow about shortcut under "Start" "All Programs"?membertransoft13 Jun '11 - 7:36 
Generalhttp linkmemberlimelect23 May '11 - 2:37 
GeneralResolving can be simpler : AfxResolveShortcutmemberAlexandre GRANVAUD17 Jan '10 - 23:17 
GeneralRe: Resolving can be simpler : AfxResolveShortcutmemberYogurt25 Jan '11 - 10:39 
Generalcreate url shortcutmemberKeith K. S. Lee21 Aug '08 - 23:11 
GeneralRe: create url shortcutmemberIgor Vigdorchik22 Aug '08 - 15:58 
GeneralDoesn't work anything!!!memberCapitanevs12 Nov '07 - 3:04 
GeneralRe: Doesn't work anything!!!memberIgor Vigdorchik12 Nov '07 - 5:34 
GeneralVery Helpful. ThanksmemberSoftwareGeek13 Aug '07 - 23:49 
Generalcant include atlbase.hmembermohsen nourian1 Feb '06 - 20:31 
GeneralRe: cant include atlbase.hmemberIgor Vigdorchik2 Feb '06 - 5:45 
GeneralDelete the UNC path informationmemberasimeqi12 Apr '05 - 8:42 
GeneralArgumentsmemberVadimeti14 Nov '04 - 4:07 
GeneralRe: ArgumentsmemberIgor Vigdorchik14 Nov '04 - 7:46 
GeneralGetPath may "succeed" without returning a pathmember--.-4 Nov '04 - 9:59 
GeneralRe: GetPath may &quot;succeed&quot; without returning a pathmemberIgor Vigdorchik4 Nov '04 - 10:49 
GeneralRe: GetPath may &quot;succeed&quot; without returning a pathmember--.-4 Nov '04 - 11:32 
GeneralRe: GetPath may &quot;succeed&quot; without returning a pathmemberIgor Vigdorchik4 Nov '04 - 11:43 
GeneralRe: GetPath may "succeed" without returning a pathmemberAbraxas2325 Dec '11 - 15:32 
QuestionRelease?sussAnonymous13 Sep '04 - 23:09 
AnswerRe: Release?memberIgor Vigdorchik19 Sep '04 - 5:18 
GeneralproblemmemberMister Transistor30 Jun '04 - 1:48 
GeneralRe: problemmemberIgor Vigdorchik30 Jun '04 - 3:21 
GeneralRe: problemmemberMister Transistor2 Jul '04 - 0:57 
GeneralRe: problemmemberIgor Vigdorchik2 Jul '04 - 4:32 
GeneralThankssussbasudevc7 Apr '04 - 3:55 
GeneralRe: ThanksmemberIgor Vigdorchik10 Apr '04 - 2:36 
GeneralMissing Directorymemberbruno leclerc23 Mar '04 - 23:32 
GeneralRe: Missing Directorymemberronyy724 Mar '04 - 14:37 
GeneralRe: Missing DirectorymemberIgor Vigdorchik24 Mar '04 - 15:50 
Generalfile name &gt; MAX_PATHmemberronyy717 Mar '04 - 13:09 
QuestionWhat to includemember--.-10 Feb '04 - 15:38 
AnswerRe: What to includesussRivael11 May '04 - 0:00 
Generalget info from MSOffice shortcutmemberSergey K3 Feb '04 - 5:42 
GeneralRe: get info from MSOffice shortcutmemberIgor Vigdorchik3 Feb '04 - 13:43 
GeneralRe: get info from MSOffice shortcutmemberSergey K3 Feb '04 - 19:53 
GeneralRe: get info from MSOffice shortcutmemberIgor Vigdorchik4 Feb '04 - 13:47 
GeneralRe: get info from MSOffice shortcutmemberSergey K4 Feb '04 - 20:19 
GeneralRe: get info from MSOffice shortcutmemberShaun Harrington28 Jun '06 - 14:27 
GeneralRe: get info from MSOffice shortcut [modified]memberShaun Harrington28 Jun '06 - 15:12 
GeneralRe: get info from MSOffice shortcutmemberShaun Harrington28 Jun '06 - 15:15 
GeneralRe: get info from MSOffice shortcutmemberIgor Vigdorchik28 Jun '06 - 16:50 
GeneralRe: get info from MSOffice shortcutmemberShaun Harrington30 Jun '06 - 4:07 
GeneralRe: get info from MSOffice shortcutmemberIgor Vigdorchik6 Jul '06 - 11:14 
GeneralRe: get info from MSOffice shortcutmemberShaun Harrington20 Jul '06 - 23:46 
GeneralRe: get info from MSOffice shortcutmemberBillJam1112 Jul '06 - 6:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 7 Oct 2003
Article Copyright 2003 by Igor Vigdorchik
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid