This topic describes how to use the Windows API and COM library to create short-cut files (link files). These files have the extension .lnk and are used for linking to EXE files, document files and other types of file. They store the name of the target file, the logged folder to use when the target file is run, command line arguments passed to the target file, and other information. Short-cuts have many uses:
- They can be created with path names and arguments of commonly-run programs and documents. The short-cut can be double clicked or run at a later time, making it possible to start the program or document without re-entering the full path name and arguments.
- They are used in the menus shown when Start - Programs is clicked, since each menu item is actually a short-cut file. To add a new menu item, create a short-cut to the target file, then copy the short-cut to the Start menu\programs folder or sub-folders. This causes the short-cut to be added to the menus, and if the new short-cut is selected from the menu, the target file is run.
- They can be added to the Windows Desktop folder to make the short-cut available on the desktop.
- They can be added to the Windows Start menu\programs\startup folder. This makes the target program run whenever the computer starts.
- When programs are installed on a new computer, short-cut files can also be installed on the new computer, in the Windows Start menu\programs folder or sub-folders. This makes the installed program available from the Start button on the new computer.
Short-cut files are small binary files (very) approximately 1000 bytes in size. They are stored using a Microsoft proprietary binary format, and are created and modified using Windows API COM (Component Object Model) functions.
The remainder of this topic describes the fields in the short-cut, how to create a short-cut, and a sample program that creates short-cuts. Because this is a Windows API article, this topic concludes by discussing how to create short-cuts in other languages that don't offer direct COM support. Short-cut creation is discussed using Visual Basic and Ubercode - these discussions are relevant because they show that COM and the Windows API are truly language-independent concepts, and can be used by new and existing computer languages.
Anatomy of a short-cut
It's easy to understand a short-cut by viewing its properties from Windows Explorer. Use Windows Explorer to find a short-cut file (e.g. by searching for files with the extension .lnk), click the right mouse button on the short-cut file, choose Properties from the menu, and then click on Shortcut in the Properties dialog. The short-cut properties look like this (the exact details vary with different versions of Windows):
The short-cut dialog shows the most important fields, but bear in mind short-cuts have extra fields that are not shown in the dialog. Here is the complete list of fields:
Most of the fields in this list can be set by code when the short-cut file is created. This is shown next.
Using the code
CoInitialize() to initialize the COM library.
CoCreateInstance() to create an
IShellLink object. This object represents the short-cut stored in memory, and its fields are then set as required.
QueryInterface() to create an
IPersistFile object, required for saving the short-cut to disk. After the
IPersistFile object is created, it is used for saving the short-cut to a file.
- After saving the short-cut, use
Release() to close the two objects.
- Finally, call
CoUninitialize() to close the COM library.
The most important steps are 2, 3 and 4 given above. These are shown in the
CreateShortCut() function shown next:
static HRESULT CreateShortCut(LPSTR pszTargetfile, LPSTR pszTargetargs,
LPSTR pszLinkfile, LPSTR pszDescription,
int iShowmode, LPSTR pszCurdir,
LPSTR pszIconfile, int iIconindex)
hRes = E_INVALIDARG;
(pszTargetfile != NULL) && (strlen(pszTargetfile) > 0) &&
(pszTargetargs != NULL) &&
(pszLinkfile != NULL) && (strlen(pszLinkfile) > 0) &&
(pszDescription != NULL) &&
(iShowmode >= 0) &&
(pszCurdir != NULL) &&
(pszIconfile != NULL) &&
(iIconindex >= 0)
hRes = CoCreateInstance(
hRes = pShellLink->lpVtbl->SetPath(pShellLink,
hRes = pShellLink->lpVtbl->SetArguments(pShellLink,
if (strlen(pszDescription) > 0)
hRes = pShellLink->lpVtbl->SetDescription(pShellLink,
if (iShowmode > 0)
hRes = pShellLink->lpVtbl->SetShowCmd(pShellLink,
if (strlen(pszCurdir) > 0)
hRes = pShellLink->lpVtbl->SetWorkingDirectory(pShellLink,
if (strlen(pszIconfile) > 0 && iIconindex >= 0)
hRes = pShellLink->lpVtbl->SetIconLocation(pShellLink,
hRes = pShellLink->lpVtbl->QueryInterface(
iWideCharsWritten = MultiByteToWideChar(CP_ACP, 0,
hRes = pPersistFile->lpVtbl->Save(pPersistFile,
The code works as follows. Firstly the inputs are validated, to avoid program errors caused by
NULL pointers or missing arguments. Assuming the inputs are valid,
CoCreateInstance() is called to create the
IShellLink was successfully created, the fields in the short-cut can be set. This is done by
SetIconLocation(). Some of these fields are optional, for example if no description was passed into the function,
SetDescription() is not called.
After setting the fields, the short-cut exists only in memory. The next step is to use
QueryInterface() to create the
IPersistFile object. The call to
QueryInterface() (instead of
IPersistFile to the
IShellLink object. This means
IPersistFile knows what to save when it is told to write to a file.
IPersistFile was created, the name of the short-cut file (pszLinkfile) is converted to a Unicode string. Then
Save() method is called, which saves the short-cut to an actual file. The end result is the short-cut which now exists as a .lnk file on the disk.
Before the function returns, both objects are tidied up by calling their
Release() functions. This frees any memory used and closes any files. The function returns the
HRESULT value produced by the COM functions - this is a positive integer value or zero indicating success, or a negative value if the functions have failed.
HRESULT values can be tested with the
This topic also includes a sample program for creating short-cuts, provided as C source code. The file has no external dependencies other than the Windows API, so it can be compiled by creating a new console-mode project, adding the source file and compiling it. The compiled program makelink.exe should run under any version of Windows, from Windows 95 onwards. When the sample program is run without any parameters, it shows a help screen as follows:
The help screen shows how the program is called up. For example if you type:
makelink c:\windows\notepad.exe "" mylink.lnk ""
this creates a short-cut file mylink.lnk in the current directory. The empty strings "" represent the arguments and description which are not required. When mylink.lnk is double-clicked, it runs the Notepad program. As another example if you type:
makelink c:\windows\write.exe c:\windows\tips.txt mylink.lnk ""
this creates a short-cut file mylink.lnk in the current directory. When activated, the short-cut will run the Windows write.exe program and make it open the Windows tips file.
If you read through the source code of the sample program, you will see the following functions:
ShowHelp() - shows the command line arguments.
ShowError() - this is called if an error occurs. It prints the error details to the console window.
GetArguments() - this parses the command line arguments passed to the program.
CreateShortCut() - function that creates the short-cut file, as shown previously.
main() - checks the command line arguments. If -h was used, or if the arguments are invalid, this shows the help page and quits. If the arguments are valid, this calls
CreateShortCut() to create the short-cut file.
Short-cuts in other languages - Ubercode
It is interesting to see how short-cut are created using other computer languages. The main complication is that not all languages allow direct calls to the COM library. Programs in these languages must either provide link creation code as an inbuilt function in the language, or must use other techniques to access the COM library.
For example Ubercode is a modern computer language with ease-of-use as its main objective. Ubercode syntax is as simple as possible, consistent with being useful for real-world applications, and consistent with being compilable to Windows EXE files and allowing simple distribution to other computers. To implement short-cuts, Ubercode includes built-in library functions that directly permit the creation of short-cuts. Here is a sample program:
Ubercode 1 class MakeShortCut
public function main()
linkfile <- "mylink.lnk"
result <- FileCreateShortcut("c:\windows\notepad.exe",
"", linkfile, "")
if SUCCEEDED(result) then
"Return code = " + Str(result) + NL +
"Successfully created " + linkfile)
"Return code = " + Str(result) + NL +
"Could not create " + linkfile)
MakeShortCut containing a single function
main. The class is therefore a main class that compiles to an EXE file. The code in function
main works as follows:
First the name of the short-cut file is copied to a string variable, then
FileCreateShortcut() is called. This is an inbuilt library function that takes the same argument as the makelink program shown previously (Ubercode allows functions to have optional arguments). After
FileCreateShortcut() returns, the result of the call is checked, and a success or failure message is shown. When the program terminates, the short-cut file will exist on disk.
If you want to experiment more with this code and with the Ubercode Developer Environment, it can be downloaded from the Ubercode website.
Short-cuts in other languages - Visual Basic
Most versions of Microsoft Visual Basic provide direct access to the COM library, so short-cuts can be created using Visual Basic. Here is a program that creates a short-cut. This example is loosely based on the Microsoft Windows Script Technologies help file v5.6, under the topic Creating a shortcut. This example has been tested with VBScript v5.6, and should also run under Visual Basic version 5 and version 6:
dim objShell, strDesktopPath, objLink
set objShell = CreateObject("WScript.Shell")
strDesktopPath = objShell.SpecialFolders("Desktop")
set objLink =
objShell.CreateShortcut(strDesktopPath & "\mylink.lnk")
objLink.Arguments = "c:\windows\tips.txt"
objLink.Description = "Shortcut to Notepad.exe"
objLink.TargetPath = "c:\windows\notepad.exe"
objLink.WindowStyle = 1
objLink.WorkingDirectory = "c:\windows"
This works as follows. The program starts running at the first line of module-level code (i.e. code not in a function or subroutine), which is the line of code
call CreateShortCut(). The
CreateShortCut() routine declares its variables, then creates the COM object
objShell using "
WScript.Shell". The string variable
strDesktopPath is initialized with the full path to the Windows desktop. The call
objShell.CreateShortcut creates an actual
IShellLink object which is stored in the
objLink variable. The fields of
objLink are set, and these fields have the same meanings and values as in the short-cut properties dialog shown previously. Refer to the section Anatomy of a short-cut for more details on the fields.
After setting the fields,
objLink.Save uses the
IPersistFile object to save the short-cut file to disk. Visual Basic automatically cleans up COM objects, so it is not necessary to call the
Release method for the objects before the subroutine returns.
To run the example, save the code to a file with the extension .vbs, for example makelink.vbs. Open a command window and type wscript makelink.vbs to run it. After the Visual Basic file finishes running, the short-cut mylink.lnk should exist on the Windows desktop. If double-clicked, the short-cut will run Windows Notepad, and open the Windows tips file.
This article discussed the uses of short-cuts and their internal structure. It showed a C function for creating a short-cut and provided C source code for a command-line program that creates short-cuts. The article then discussed short-cut creation using other languages. The purpose of the discussion was to show COM functions are available in the same way as other Windows API functions - there is nothing special about COM that requires it to be called from C++ or from Microsoft scripting languages.
I hope you enjoyed the article. Any suggestions or feedback is welcome.
I am a developer with over 10 years experience, primarily using C, Microsoft Visual Studio, the Win32 API, Borland Delphi, Pascal dialects such as Virtual Pascal and FPC Pascal, and several versions of Basic.
Areas that interest me most are language design, VHLL (very high level languages), design for ease-of-use, and design of languages for beginner programmers. I have contributed to the Ubercode website (http://www.ubercode.com) and the Visual Fred site (http://www.visualfred.com), both experimental languages designed for beginners.