Get Windows Shortcut (.lnk) Details

| | |

The below will help you get the full path of a Windows shortcut (.lnk) in your program. The below examples specifically create a command-line executable file but you could use the function in your program just as well.

View the full code in GitHub at https://github.com/dkittell/lnk-parser

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace lnk_parser_cSharp
{

	public class Functions
	{
		public static string GetShortcutTarget(string file)
		{
			try
			{
				if (System.IO.Path.GetExtension(file).ToLower() != ".lnk")
				{
					throw new Exception("Supplied file must be a .LNK file");
				}

				FileStream fileStream = File.Open(file, FileMode.Open, FileAccess.Read);
				using (System.IO.BinaryReader fileReader = new BinaryReader(fileStream))
				{
					fileStream.Seek(0x14, SeekOrigin.Begin);     // Seek to flags
					uint flags = fileReader.ReadUInt32();        // Read flags
					if ((flags & 1) == 1)
					{                      // Bit 1 set means we have to
										   // skip the shell item ID list
						fileStream.Seek(0x4c, SeekOrigin.Begin); // Seek to the end of the header
						uint offset = fileReader.ReadUInt16();   // Read the length of the Shell item ID list
						fileStream.Seek(offset, SeekOrigin.Current); // Seek past it (to the file locator info)
					}

					long fileInfoStartsAt = fileStream.Position; // Store the offset where the file info
																 // structure begins
					uint totalStructLength = fileReader.ReadUInt32(); // read the length of the whole struct
					fileStream.Seek(0xc, SeekOrigin.Current); // seek to offset to base pathname
					uint fileOffset = fileReader.ReadUInt32(); // read offset to base pathname
															   // the offset is from the beginning of the file info struct (fileInfoStartsAt)
					fileStream.Seek((fileInfoStartsAt + fileOffset), SeekOrigin.Begin); // Seek to beginning of
																						// base pathname (target)
					long pathLength = (totalStructLength + fileInfoStartsAt) - fileStream.Position - 2; // read
																										// the base pathname. I don't need the 2 terminating nulls.
					char[] linkTarget = fileReader.ReadChars((int)pathLength); // should be unicode safe
					var link = new string(linkTarget);

					int begin = link.IndexOf("\0\0");
					if (begin > -1)
					{
						int end = link.IndexOf("\\\\", begin + 2) + 2;
						end = link.IndexOf('\0', end) + 1;

						string firstPart = link.Substring(0, begin);
						string secondPart = link.Substring(end);

						return firstPart + secondPart;
					}
					else {
						return link;
					}
				}
			}
			catch
			{
				return "";
			}
		}
	}

	class Program
	{
		static void Main(string[] args)
		{
			if (args.Length == 0)
			{
				System.Console.WriteLine("Please try again with a file path");
			}
			else
			{
				System.Console.WriteLine("LNK File: " + args[0]);
				System.Console.WriteLine("LNK Path: " + Functions.GetShortcutTarget(args[0]));
			}
		}
	}
}
C:\temp>lnk_parser_cSharp.exe "C:\Virtual Machine Images.lnk"
LNK File: C:\Virtual Machine Images.lnk
LNK Path: C:\Virtual Machines

VB.Net example converted from C# example above.

Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Threading.Tasks
Imports System.IO

Public Class Functions
	Public Shared Function GetShortcutTarget(file__1 As String) As String
		Try
			If System.IO.Path.GetExtension(file__1).ToLower() <> ".lnk" Then
				Throw New Exception("Supplied file must be a .LNK file")
			End If

			Dim fileStream As FileStream = File.Open(file__1, FileMode.Open, FileAccess.Read)
			Using fileReader As System.IO.BinaryReader = New BinaryReader(fileStream)
				fileStream.Seek(&H14, SeekOrigin.Begin)
				' Seek to flags
				Dim flags As UInteger = fileReader.ReadUInt32()
				' Read flags
				If (flags And 1) = 1 Then
					' Bit 1 set means we have to
					' skip the shell item ID list
					fileStream.Seek(&H4C, SeekOrigin.Begin)
					' Seek to the end of the header
					Dim offset As UInteger = fileReader.ReadUInt16()
					' Read the length of the Shell item ID list
					' Seek past it (to the file locator info)
					fileStream.Seek(offset, SeekOrigin.Current)
				End If

				Dim fileInfoStartsAt As Long = fileStream.Position
				' Store the offset where the file info
				' structure begins
				Dim totalStructLength As UInteger = fileReader.ReadUInt32()
				' read the length of the whole struct
				fileStream.Seek(&HC, SeekOrigin.Current)
				' seek to offset to base pathname
				Dim fileOffset As UInteger = fileReader.ReadUInt32()
				' read offset to base pathname
				' the offset is from the beginning of the file info struct (fileInfoStartsAt)
				fileStream.Seek((fileInfoStartsAt + fileOffset), SeekOrigin.Begin)
				' Seek to beginning of
				' base pathname (target)
				Dim pathLength As Long = (totalStructLength + fileInfoStartsAt) - fileStream.Position - 2
				' read
				' the base pathname. I don't need the 2 terminating nulls.
				Dim linkTarget As Char() = fileReader.ReadChars(CInt(pathLength))
				' should be unicode safe
				Dim link = New String(linkTarget)

				Dim begin As Integer = link.IndexOf(vbNullChar & vbNullChar)
				If begin > -1 Then
					Dim [end] As Integer = link.IndexOf("\\", begin + 2) + 2
					[end] = link.IndexOf(ControlChars.NullChar, [end]) + 1

					Dim firstPart As String = link.Substring(0, begin)
					Dim secondPart As String = link.Substring([end])

					Return firstPart & secondPart
				Else
					Return link
				End If
			End Using
		Catch
			Return ""
		End Try
	End Function
End Class


Module Module1
	Sub Main(args As String())
		If args.Length = 0 Then
			System.Console.WriteLine("Please try again with a file path")
		Else
			System.Console.WriteLine("LNK File: " + args(0))
			System.Console.WriteLine(Convert.ToString("LNK Path: ") & Functions.GetShortcutTarget(args(0)))
		End If
	End Sub
End Module
C:\temp>lnk_parser_vbNet.exe "C:\Virtual Machine Images.lnk"
LNK File: C:\Virtual Machine Images.lnk
LNK Path: C:\Virtual Machines

References: C# – https://blez.wordpress.com/2013/02/18/get-file-shortcuts-target-with-c/

All information on this site is shared with the intention to help. Before any source code or program is ran on a production (non-development) system it is suggested you test it and fully understand what it is doing not just what it appears it is doing. I accept no responsibility for any damage you may do with this code.