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/