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

Creating and Resolving shell links

By , 10 May 2002
 

Introduction

ShortCut is a .NET class that allows you to create shortcuts to files as well as resolve existing shortcuts. The class was coded in Managed C++ and makes ample use of IJW. I have compiled the class as a Class Library under the namespace ShortCutLib. Thus you can now use it from your C# and VB .NET programs. Simply add a reference to the DLL. This is yet another example of how Managed C++ eases the transition between managed and unmanaged code so easily. It just works!

Sample Usage [C#]

using System;
using ShortCutLib;

namespace ShortCutTest
{
    class Class1
    {
        [STAThread]
        static void Main(string[] args)
        {
            ShortCut sc = new ShortCut();

            //Creating a shortcut
            sc.FilePath = "C:\\windows\\notepad.exe";
            sc.LnkPath = "c:\\abc.lnk";
            sc.LnkDesc = "This runs notepad";
            sc.WorkDir = "C:\\";
            sc.CreateLink();

            //Resolving a shortcut
            sc.LnkPath = "C:\\xyz.lnk";
            sc.ResolveLink();

            Console.WriteLine("File is {0}",sc.FilePath);
            Console.WriteLine("Description is {0}",sc.LnkDesc);
            Console.WriteLine("Woirking Dir is {0}",sc.WorkDir);
        }
    }
}

Source Listing (only the main header and cpp file)

For those of you who only have beta 2, you can use the following two source listings:

// ShortCut.h

#pragma once

using namespace System;
using namespace System::Runtime::InteropServices;

namespace ShortCutLib
{
    public __gc class ShortCut
    {
        private:
            String* m_filepath;
            String* m_workdir;
            String* m_lnkdesc;
            String* m_lnkpath;

            HRESULT _CreateLink(LPCWSTR FilePath, LPCWSTR LnkPath, 
                                LPCWSTR LnkDesc,LPCWSTR WorkDir);
            HRESULT _ResolveLink(LPCWSTR LnkFile, LPWSTR FilePath,
                                 LPWSTR LnkDesc,LPWSTR WorkDir);

        public:     
            __property String* get_FilePath()
            {
                return m_filepath;
            }
            __property void set_FilePath(String *str)
            {
                m_filepath = str;
            }
            __property String* get_WorkDir()
            {
                return m_workdir;
            }
            __property void set_WorkDir(String *str)
            {
                m_workdir = str;
            }
            __property String* get_LnkDesc()
            {
                return m_lnkdesc;
            }
            __property void set_LnkDesc(String *str)
            {
                m_lnkdesc = str;
            }
            __property String* get_LnkPath()
            {
                return m_lnkpath;
            }
            __property void set_LnkPath(String *str)
            {
                m_lnkpath = str;
            }
                
            bool CreateLink()
            {
                IntPtr strfilepath = Marshal::StringToCoTaskMemUni(FilePath);
                IntPtr strlnkpath = Marshal::StringToCoTaskMemUni(LnkPath);
                IntPtr strlnkdesc = Marshal::StringToCoTaskMemUni(LnkDesc);
                IntPtr strworkdir = Marshal::StringToCoTaskMemUni(WorkDir);
                
                HRESULT hres = _CreateLink((LPCWSTR)strfilepath.ToPointer(),
                                           (LPCWSTR)strlnkpath.ToPointer(),
                                           (LPCWSTR)strlnkdesc.ToPointer(),
                                           (LPCWSTR)strworkdir.ToPointer());

                Marshal::FreeCoTaskMem(strfilepath);
                Marshal::FreeCoTaskMem(strlnkpath);
                Marshal::FreeCoTaskMem(strlnkdesc);
                Marshal::FreeCoTaskMem(strworkdir);

                return (hres==S_OK);
            }

            bool ResolveLink()
            {
                wchar_t strfilepath[MAX_PATH];
                wchar_t strworkdir[MAX_PATH];
                wchar_t strlnkdesc[INFOTIPSIZE];

                IntPtr strlnkpath = Marshal::StringToCoTaskMemUni(LnkPath);         
                
                HRESULT hres = _ResolveLink((LPCWSTR)strlnkpath.ToPointer(),
                    strfilepath, strlnkdesc, strworkdir);

                FilePath = strfilepath;
                LnkDesc = strlnkdesc;
                WorkDir = strworkdir;
                    
                Marshal::FreeCoTaskMem(strlnkpath);         

                return (hres==S_OK);
            }
    };
}
// This is the main DLL file.

#include "stdafx.h"
#using <mscorlib.dll>
#include <Shlobj.h>
#include <crtdbg.h>
#include <atldef.h>
#include <atlconv.h>

#include "ShortCut.h"


HRESULT ShortCutLib::ShortCut::_CreateLink(LPCWSTR FilePath, 
    LPCWSTR LnkPath, LPCWSTR LnkDesc,LPCWSTR WorkDir) 
{ 
    USES_CONVERSION;
    CoInitialize(NULL);
    IShellLink* psl;             
    HRESULT  hres = CoCreateInstance(CLSID_ShellLink, NULL, 
            CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *) &psl); 
    if (SUCCEEDED(hres)) 
    { 
        IPersistFile* ppf; 
         
        psl->SetPath(W2A(FilePath)); 
        psl->SetWorkingDirectory(W2A(WorkDir));
        psl->SetDescription(W2A(LnkDesc)); 
            
        hres = psl->QueryInterface(IID_IPersistFile,(LPVOID*)&ppf); 
 
        if (SUCCEEDED(hres)) 
        {    
            hres = ppf->Save(LnkPath, TRUE); 
            ppf->Release(); 
        } 
        psl->Release(); 
    }
    CoUninitialize();
    return hres; 
} 

HRESULT ShortCutLib::ShortCut::_ResolveLink(LPCWSTR LnkFile, LPWSTR FilePath,
                                            LPWSTR LnkDesc,LPWSTR WorkDir) 
{ 
    CoInitialize(NULL);
    HRESULT hres; 
    IShellLink* psl; 
    WIN32_FIND_DATA wfd; 
    char strfilepath[MAX_PATH];     
    char strlnkdesc[INFOTIPSIZE];
    char strworkdir[MAX_PATH];

    USES_CONVERSION;
 
    hres = CoCreateInstance(CLSID_ShellLink, NULL, 
            CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *) &psl); 
    if (SUCCEEDED(hres)) 
    { 
        IPersistFile* ppf;         
        hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf); 
        if (SUCCEEDED(hres)) 
        { 
            hres = ppf->Load(LnkFile, STGM_READ); 
            if (SUCCEEDED(hres)) 
            {               
                hres = psl->Resolve(GetDesktopWindow(), 0); 
                if (SUCCEEDED(hres)) 
                { 
                    hres = psl->GetPath(strfilepath,MAX_PATH, &wfd, 
                                           SLGP_UNCPRIORITY );
                    
                    if (SUCCEEDED(hres)) 
                    {            
                        wcscpy(FilePath, A2W(strfilepath)); 
                        hres = psl->GetDescription(strlnkdesc,INFOTIPSIZE);
                    }

                    if (SUCCEEDED(hres)) 
                    {
                        wcscpy(LnkDesc,A2W(strlnkdesc));
                        hres = psl->GetWorkingDirectory(strworkdir,MAX_PATH);
                    }

                    if (SUCCEEDED(hres)) 
                    {
                        wcscpy(WorkDir,A2W(strworkdir));
                    }
                } 
            }         
            ppf->Release(); 
        }     
        psl->Release(); 
    } 
    CoUninitialize();
    return hres; 
} 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Nish Sivakumar
United States United States
Member
Nish is a real nice guy who has been writing code since 1990 when he first got his hands on an 8088 with 640 KB RAM. Originally from sunny Trivandrum in India, he has been living in various places over the past few years and often thinks it’s time he settled down somewhere.
 
Nish has been a Microsoft Visual C++ MVP since October, 2002 - awfully nice of Microsoft, he thinks. He maintains an MVP tips and tricks web site - www.voidnish.com where you can find a consolidated list of his articles, writings and ideas on VC++, MFC, .NET and C++/CLI. Oh, and you might want to check out his blog on C++/CLI, MFC, .NET and a lot of other stuff - blog.voidnish.com.
 
Nish loves reading Science Fiction, P G Wodehouse and Agatha Christie, and also fancies himself to be a decent writer of sorts. He has authored a romantic comedy Summer Love and Some more Cricket as well as a programming book – Extending MFC applications with the .NET Framework.
 
Nish's latest book C++/CLI in Action published by Manning Publications is now available for purchase. You can read more about the book on his blog.
 
Despite his wife's attempts to get him into cooking, his best effort so far has been a badly done omelette. Some day, he hopes to be a good cook, and to cook a tasty dinner for his wife.

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

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalrunning under 64 bit OS?memberThomas Ramaglia7 Jun '11 - 11:04 
I can't seem to get this to run under windows server 2008 R2 (64 bit). Is it possible? Can you help?
QuestionWhat about LNK to installed app (not pointed to exe, created by MSI)memberMember 323162121 May '09 - 3:34 
Do you anybody know, how to get target exe in such lnk? For example, if you install MS Office 2007 target lnk are not pointed to word.exe etc. , but to windows installer\[some GUID]\[exe with icon], but how to resolve correct exe (exe, that is executed, when you doubleclick that LNK)?
GeneralCorrectionmemberMember 74870021 May '08 - 21:51 
Code causes problems - application hangs, after function ResolveLink call.
Parameters SLR_ANY_MATCH | SLR_NO_UI | SLR_UPDATE were added in psl->Resolve.
 
Here modification in function ResolveLink:
 
...
hres = ppf->Load(LnkFile, STGM_READ);
if (SUCCEEDED(hres))
{
hres = psl->Resolve(GetDesktopWindow(), SLR_ANY_MATCH | SLR_NO_UI | SLR_UPDATE);
 
...
 

BR,
Rudi.
GeneralA2W conversionmembersheshidar27 Jul '06 - 19:50 
Hi..All..
what is A2W converter, how it is used.
why we write USING_CONVERSION, before using convertors.
Thanq..

 
sheshidar
GeneralLinking under VS2005membermarad0124 May '06 - 4:43 
It gave me unresolved external g_pfnGetThreadACP under VS2005. Including atlbase.h solved the problem.
GeneralRe: Linking under VS2005 [modified]memberthomasa88_26 Jun '06 - 12:51 
thx =)
 
- thomasa88
 
-- modified at 19:11 Monday 26th June, 2006
 
Im not very good on c++ compile flags, how should they be set for vs 2005? Right now I just changed /MT to /MD
QuestionShortcutLib can't handle http links?memberdommer16 Feb '05 - 9:25 
I've tried to use the lib in the following way:
 
//Creating a shortcut
ShortCut sc = new ShortCut();
sc.FilePath = "http://google.dk";
sc.LnkPath = "c:\\a b c.lnk";
sc.LnkDesc = "This runs notepad";
sc.WorkDir = "C:\\";
sc.CreateLink();
 
//Resolving a shortcut
sc.LnkPath = "C:\\a b c.lnk";
sc.ResolveLink();
 
Console.WriteLine("File is {0}",sc.FilePath);
Console.WriteLine("Description is {0}",sc.LnkDesc);
Console.WriteLine("Woirking Dir is {0}",sc.WorkDir);
 
The link is successfully created, and is working fine with an http address,
but when you try to resolve it, the filepath is empty?
 
The documentaion for IShellLink don't say anything about http links,
do anybody have a clue?
 
I'm using the lib in relation to Explorer favorites and there for i need to work with http links.
 
Troels Richter
Thinksharp.dk
QuestionIs there a chance to get the library in native c# code?memberrleins3 Jun '04 - 3:06 
Hello Nish,
 
i want to use this great feature, but my intend ist to avoid the distribution of more than one file (the .exe file).
In this case i can't generate a .dll and ship them along with the .exe.
 
Now the question:
Is there a chance to get the contents of the library in c# instead of c++?
In this case i can copy the source directly into my project (visual studio .net) and compile it.
 
thx in advance
AnswerRe: Is there a chance to get the library in native c# code?staffNishant S3 Jun '04 - 3:52 
I guess someone could re-code the class in C#, but it'd mean using a lot of DllImport calls and stuff. Won't be all that smooth I guess, but surely doable.
 
Nish
 

Now with my own blog - void Nish(char* szBlog);
 
My MVP tips, tricks and essays web site - www.voidnish.com
GeneralGreat Code, but where is the &quot;iconpath&quot; propertysusssoftcell6 Mar '04 - 2:13 
I would use this class too, if there was an "iconpath" property that allowed me to specify the path to the icon for the shortcut.
GeneralCreate MSI LinkssussAnonymous20 Oct '03 - 1:50 
I want to create MSI Links on the Desktop. Is there a solution?
 
Thanks
Matthias
GeneralCPP ShortCut SourcememberRussell Mangel15 Oct '03 - 16:42 
I downloaded the shortcut project and compiled it, and referenced the dll using C#.
 
It is working perfectly. Excellant work, you have saved me time.Smile | :)
 
Also I liked your approach, as you used C++ to write the utility, in my opinion this is the best way to implement shortcuts for .NET languages.
 
Have a great week!Cool | :cool:
 
Russell Mangel
Las Vegas, NV
 

 
Russell Mangel
Las Vegas, NV
GeneralRe: CPP ShortCut SourcestaffNishant S15 Oct '03 - 17:42 
Thanks Russel Smile | :)
 
Nish
 

Extending MFC Applications with the .NET Framework [NW] (coming soon...)
Summer Love and Some more Cricket [NW] (My first novel)
Shog's review of SLASMC [NW]
This post was made from Trivandrum city, India on a 0.0001 KB/s net connection
GeneralAccess is denied: 'ShortCut'memberw3home11 Apr '03 - 0:03 
I tried to use your code, by adding a reference to the DLL,
but i get an error message when compiling my project (called TestPictures)
 
The strange thing is that i get no error messages when adding the reference in my project. The DLL is located in My InetPub/wwwroot/bin directory. I also checked the properties of the DLL (ok for read and execute), but still that doesn't work Frown | :(
 
Can you please help me on that point ?
 
The message i get is the following one :
 
Server Error in '/TestPictures' Application.
-------------------------------------------------------------------
 
Access is denied: 'ShortCut'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
 
Exception Details: System.IO.FileLoadException: Access is denied: 'ShortCut'.
 
Source Error:
 
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
 

 

Assembly Load Trace: The following information can be helpful to determine why the assembly 'ShortCut' could not be loaded.
 

=== Pre-bind state information ===
LOG: DisplayName = ShortCut, Version=1.0.1196.18153, Culture=neutral, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///c:/inetpub/wwwroot/TestPictures
LOG: Initial PrivatePath = bin
Calling assembly : TestPictures, Version=1.0.1196.19450, Culture=neutral, PublicKeyToken=null.
===
 
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Post-policy reference: ShortCut, Version=1.0.1196.18153, Culture=neutral, PublicKeyToken=null
LOG: Attempting download of new URL file:///C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/Temporary ASP.NET Files/testpictures/06cd0ac2/161adc7/ShortCut.DLL.
LOG: Attempting download of new URL file:///C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/Temporary ASP.NET Files/testpictures/06cd0ac2/161adc7/ShortCut/ShortCut.DLL.
LOG: Attempting download of new URL file:///c:/inetpub/wwwroot/TestPictures/bin/ShortCut.DLL.
 

 
Stack Trace:
 
[FileLoadException: Access is denied: 'ShortCut'.]
TestPictures.WebForm3.Page_Load(Object sender, EventArgs e) +0
System.Web.UI.Control.OnLoad(EventArgs e) +67
System.Web.UI.Control.LoadRecursive() +35
System.Web.UI.Page.ProcessRequestMain() +731
 


 
Johanna
GeneralRe: Access is denied: 'ShortCut'editorNishant S13 Apr '03 - 9:03 
I haven't done ASP.NET but I think this might be some IIS permission issue. I suggest that you post this in the C# and/or the ASP.NET forums. Perhaps someone might be able to help you.
 
Sorry for the rather useless answer Frown | :(
 
Nish
 

Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

Review by Shog9
Click here for review[NW]

GeneralRe: Access is denied: 'ShortCut'memberMarco Morreale30 Jun '03 - 2:19 
I have the same problem. Did you find a solution?
Thanks
Marco
GeneralShortcut file not createdmemberschmiddy25 Mar '03 - 17:20 
I think this code is very useful. The only problem is that I have no idea if the shortcut file is created or not.
 
Eg.
 
sc.FilePath = filename;
....
sc.CreateLink();
 
// Then manually check if the link has been created
 
if (!File.Exists(filename))
{
// Inform the user the shortcut was not created
}

 
I thought it may be better to return a value / throw an exception when the actual shortcut is not created.
 
Matt
GeneralRe: Shortcut file not creatededitorNishant S25 Mar '03 - 18:05 
schmiddy wrote:
I thought it may be better to return a value
 
CreateLink returns true if the shortcut was successfully created and false if it failed
 
Nish
 

Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

Review by Shog9
Click here for review[NW]

GeneralRe: Shortcut file not createdsussAnonymous25 Mar '03 - 18:12 
Don't I feel stoopid Smile | :)
 
thanks
GeneralRe: Shortcut file not creatededitorNishant S25 Mar '03 - 18:14 
Anonymous wrote:
Don't I feel stoopid
 
We all do at times Smile | :)
 
Nish
 

Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

Review by Shog9
Click here for review[NW]

GeneralFans!memberMustafa Demirhan11 May '02 - 14:11 
Hey Nish,
 
I think you have a lot of fans here. I realized that your first two ratings are two 1s. There are some guys here who love you (I think). Poke tongue | ;-P
 
I dont know what their problem is but it is for sure that you deserve much better ratings. Wink | ;)
 
Mustafa Demirhan
http://www.macroangel.com
Sonork ID 100.9935:zoltrix
GeneralRe: Fans!memberNish [BusterBoy]11 May '02 - 14:19 
Mustafa Demirhan wrote:
I think you have a lot of fans here. I realized that your first two ratings are two 1s. There are some guys here who love you (I think).
 
I dont know what their problem is but it is for sure that you deserve much better ratings.

 
Hello Mustafa,
 
It's been a while since I saw you. And you are not on Sonork [zoltrix] too these days.
 
Yeah, this article seems to have displeased a few Smile | :)
 
Nish
 

Regards,
Nish
Native CPian.
Born and brought up on CP.
With the CP blood in him.

GeneralRe: Fans!memberMustafa Demirhan11 May '02 - 14:24 
Nish [BusterBoy] wrote:
It's been a while since I saw you. And you are not on Sonork [zoltrix] too these days.
 
Unfortunately! I can rarely find some time to visit CodeProject. Cry | :(( But things will be better in a week. My final exams will end this week. Big Grin | :-D
 
Mustafa Demirhan
http://www.macroangel.com
Sonork ID 100.9935:zoltrix
GeneralRe: Fans!memberNish [BusterBoy]11 May '02 - 14:36 
Good luck with your examinations Smile | :)
 
Nish
 

Regards,
Nish
Native CPian.
Born and brought up on CP.
With the CP blood in him.

GeneralUse PtrToStringCharsmemberMCPPKing11 May '02 - 5:39 
Instead of using Marhsal.CoTaskMemAlloc etc. (in your case) You can very easily convert String* to wchar_t* using PtrToStringChars function. this is defined in vcclr.hSmile | :)
 
Note that in that case you don't need to Free the memory.
 
King of Managed C++
GeneralRe: Use PtrToStringCharsmemberNish [BusterBoy]11 May '02 - 5:38 
Thanks King of MC++.
I saw that function, but I felt it has the same dangers associated with CString::GetBuffer
 
Nish
 

Regards,
Nish
Native CPian.
Born and brought up on CP.
With the CP blood in him.

GeneralSorry about the horizontal scrolling! And the messy indentation.memberNish [BusterBoy]11 May '02 - 4:40 
I donno what's causing the whole article to scroll horizontally Frown | :(
 
Regards
Nish
 
p.s. I am also confused by the bad-indentation within the code blocks. The indentation was okay in the Article Wizard Preview. But now it seems slightly messed up Frown | :(
 

Regards,
Nish
Native CPian.
Born and brought up on CP.
With the CP blood in him.

GeneralRe: Sorry about the horizontal scrolling! And the messy indentation.memberShog911 May '02 - 5:55 
It's pretty bad, Nish.
Better prod one of those new sub-editors into fixing it for ya Smile | :)
 
--------

Higher education helps your earning capacity. Ask any college professor.

--Shog9 --


GeneralRe: Sorry about the horizontal scrolling! And the messy indentation.memberNish [BusterBoy]11 May '02 - 6:34 
The sub-editors are all assigned sections. And none of them have been assigned the MC++ section. I'll have to wait for Chris to come back from his mom's place Frown | :(
I wonder whether his mom has internet access!
 
Nish
 

Regards,
Nish
Native CPian.
Born and brought up on CP.
With the CP blood in him.

GeneralRe: Sorry about the horizontal scrolling! And the messy indentation.editorAndrew Peace11 May '02 - 13:03 
The problem has been resolved.
 
--
Andrew.
GeneralRe: Sorry about the horizontal scrolling! And the messy indentation.memberNish [BusterBoy]11 May '02 - 14:12 
Andrew Peace wrote:
The problem has been resolved.
 
Thanks a LOT, Andrew
 
Nish
 

Regards,
Nish
Native CPian.
Born and brought up on CP.
With the CP blood in him.

GeneralRe: Sorry about the horizontal scrolling! And the messy indentation.subeditorMichael Dunn11 May '02 - 12:23 
It's because you're using evil hard-coded tabs! Replace them with 4 spaces and it'll look nicer.
 
--Mike--
Buy me stuff! (Link fixed now)
Like the Google toolbar? Then check out UltraBar, with more features & customizable search engines!
My really out-of-date homepage
Big fan of Alyson Hannigan and Jamie Salé.
Sonork - 100.10414 AcidHelm

GeneralRe: Sorry about the horizontal scrolling! And the messy indentation.memberNish [BusterBoy]11 May '02 - 14:14 
Michael Dunn wrote:
It's because you're using evil hard-coded tabs! Replace them with 4 spaces and it'll look nicer
 
Thanks for the tip Mike. Next time I'll use spaces instead of tabs Smile | :)
 
Nish
 

Regards,
Nish
Native CPian.
Born and brought up on CP.
With the CP blood in him.

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 11 May 2002
Article Copyright 2002 by Nish Sivakumar
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid