views:

1643

answers:

3

Hi, 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 .lnk spec [PDF] 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.

+4  A: 

Basically call the Windows API directly. Here is a good example found after Googling:

import os, sys
import pythoncom
from win32com.shell import shell, shellcon

shortcut = pythoncom.CoCreateInstance (
  shell.CLSID_ShellLink,
  None,
  pythoncom.CLSCTX_INPROC_SERVER,
  shell.IID_IShellLink
)
desktop_path = shell.SHGetFolderPath (0, shellcon.CSIDL_DESKTOP, 0, 0)
shortcut_path = os.path.join (desktop_path, "python.lnk")
persist_file = shortcut.QueryInterface (pythoncom.IID_IPersistFile)
persist_file.Load (shortcut_path)

shortcut.SetDescription ("Updated Python %s" % sys.version)
mydocs_path = shell.SHGetFolderPath (0, shellcon.CSIDL_PERSONAL, 0, 0)
shortcut.SetWorkingDirectory (mydocs_path)

persist_file.Save (shortcut_path, 0)

This is from http://timgolden.me.uk/python/win32_how_do_i/create-a-shortcut.html.

You can search for "python ishelllink" for other examples.

Also, the API reference helps too: http://msdn.microsoft.com/en-us/library/bb774950(VS.85).aspx

Gerald Kaszuba
+5  A: 

Alternatively, you could try using SHGetFolderPath(). The following code might work, but I'm not on a Windows machine right now so I can't test it.

import ctypes

shell32 = ctypes.windll.shell32

# allocate MAX_PATH bytes in buffer
video_folder_path = ctypes.create_string_buffer(260)

# 0xE is CSIDL_MYVIDEO
# 0 is SHGFP_TYPE_CURRENT
# If you want a Unicode path, use SHGetFolderPathW instead
if shell32.SHGetFolderPathA(None, 0xE, None, 0, video_folder_path) >= 0:
    # success, video_folder_path now contains the correct path
else:
    # error
Adam Rosenfield
This seems like it should work, but ctypes is saying it can't call that function (as well as several other documented shell32 functions). I'm running Python 2.6 on Windows XP SP3.
Bill Williams
Works, with two issues.1) The function is actually called SHGetFolderPathA (notice the A at the end)2) The "My Videos" folder's ID is 0xE. 0x37 is the "Public/Common Videos" folder.I got it to work. Thanks!
WindPower
Good catch on those - I fixed the answer.
Adam Rosenfield
+4  A: 

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)
SaoPauloooo
Thank goodness I found this! I was about to give up and write a vbs script and call it from my python script. This is much better. +1
Matthew Scouten