I'm trying to read the target file/directory of a shortcut (.lnk
) file from Python. Is there a headache-free way to do it? The spec is way over my head. I don't mind using Windows-only APIs.
My ultimate goal is to find the "(My) Videos"
folder on Windows XP and Vista. On XP, by default, it's at %HOMEPATH%\My Documents\My Videos
, and on Vista it's %HOMEPATH%\Videos
. However, the user can relocate this folder. In the case, the %HOMEPATH%\Videos
folder ceases to exists and is replaced by %HOMEPATH%\Videos.lnk
which points to the new "My Videos"
folder. And I want its absolute location.
How to open an LNK file. Opening an LNK file, by double-clicking it or right-clicking it and selecting Open, opens the file, folder, or program to which the LNK file points. Advanced users can edit an LNK file's properties by right-clicking the file and selecting Properties.
Normally, most of LNK-files are located on the following paths: For Windows 7 to 10: C:\Users\%USERNAME%\AppData\Roaming\Microsoft\Windows\Recent. For Windows XP: C:\Documents and Settings\%USERNAME%\Recent.
Just drag and drop them into the Notepad window. If you open them via the Open dialog, Notepad will open the exe file pointed to by the . lnk file.
An LNK file is a Windows Shortcut that serves as a pointer to open a file, folder, or application. LNK files are based on the Shell Link binary file format, which holds information used to access another data object.
Create a shortcut using Python (via WSH)
import sys import win32com.client shell = win32com.client.Dispatch("WScript.Shell") shortcut = shell.CreateShortCut("t:\\test.lnk") shortcut.Targetpath = "t:\\ftemp" shortcut.save()
Read the Target of a Shortcut using Python (via WSH)
import sys import win32com.client shell = win32com.client.Dispatch("WScript.Shell") shortcut = shell.CreateShortCut("t:\\test.lnk") print(shortcut.Targetpath)
I know this is an older thread but I feel that there isn't much information on the method that uses the link specification as noted in the original question.
My shortcut target implementation could not use the win32com module and after a lot of searching, decided to come up with my own. Nothing else seemed to accomplish what I needed under my restrictions. Hopefully this will help other folks in this same situation.
It uses the binary structure Microsoft has provided for MS-SHLLINK.
import struct path = 'myfile.txt.lnk' target = '' with open(path, 'rb') as stream: content = stream.read() # skip first 20 bytes (HeaderSize and LinkCLSID) # read the LinkFlags structure (4 bytes) lflags = struct.unpack('I', content[0x14:0x18])[0] position = 0x18 # if the HasLinkTargetIDList bit is set then skip the stored IDList # structure and header if (lflags & 0x01) == 1: position = struct.unpack('H', content[0x4C:0x4E])[0] + 0x4E last_pos = position position += 0x04 # get how long the file information is (LinkInfoSize) length = struct.unpack('I', content[last_pos:position])[0] # skip 12 bytes (LinkInfoHeaderSize, LinkInfoFlags, and VolumeIDOffset) position += 0x0C # go to the LocalBasePath position lbpos = struct.unpack('I', content[position:position+0x04])[0] position = last_pos + lbpos # read the string at the given position of the determined length size= (length + last_pos) - position - 0x02 temp = struct.unpack('c' * size, content[position:position+size]) target = ''.join([chr(ord(a)) for a in temp])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With