PathCatcher is a Windows utility that allows one to right-click on a file or a folder or a group of files and folders in Explorer and save its path to the clipboard.
To install, save the code as PathCatcher.py, then double-click the PathCatcher.py file. Afterwards, PathCatcher will appear in the Explorer right-click menu.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | """
PathCatcher is a Windows utility that allows one to right-click on
a folder or a file in Explorer and save its path to the clipboard.
If this module is run by itself, it installs PathCatcher to the registry.
After it is installed, when one clicks on a file or folder, "PathCatcher"
appears in the right-click menu.
This module also contains some useful code for accessing the Windows
clipboard and registry.
Requires ctypes -- download from SourceForge.
Jack Trainor 2007
"""
import sys
import os, os.path
import win32api
import win32con
import ctypes
import time
""" Abbreviations for readability """
OpenClipboard = ctypes.windll.user32.OpenClipboard
EmptyClipboard = ctypes.windll.user32.EmptyClipboard
GetClipboardData = ctypes.windll.user32.GetClipboardData
SetClipboardData = ctypes.windll.user32.SetClipboardData
CloseClipboard = ctypes.windll.user32.CloseClipboard
GlobalLock = ctypes.windll.kernel32.GlobalLock
GlobalAlloc = ctypes.windll.kernel32.GlobalAlloc
GlobalUnlock = ctypes.windll.kernel32.GlobalUnlock
memcpy = ctypes.cdll.msvcrt.memcpy
""" Windows Clipboard utilities """
def GetClipboardText():
text = ""
if OpenClipboard(0):
hClipMem = GetClipboardData(win32con.CF_TEXT)
GlobalLock.restype = ctypes.c_char_p
text = GlobalLock(hClipMem)
GlobalUnlock(hClipMem)
CloseClipboard()
return text
def SetClipboardText(text):
buffer = ctypes.c_buffer(text)
bufferSize = ctypes.sizeof(buffer)
hGlobalMem = GlobalAlloc(win32con.GHND, bufferSize)
GlobalLock.restype = ctypes.c_void_p
lpGlobalMem = GlobalLock(hGlobalMem)
memcpy(lpGlobalMem, ctypes.addressof(buffer), bufferSize)
GlobalUnlock(hGlobalMem)
if OpenClipboard(0):
EmptyClipboard()
SetClipboardData(win32con.CF_TEXT, hGlobalMem)
CloseClipboard()
""" Windows Registry utilities """
def OpenRegistryKey(hiveKey, key):
keyHandle = None
try:
curKey = ""
keyItems = key.split('\\')
for keyItem in keyItems:
if curKey:
curKey = curKey + "\\" + keyItem
else:
curKey = keyItem
keyHandle = win32api.RegCreateKey(hiveKey, curKey)
except Exception, e:
keyHandle = None
print "OpenRegistryKey failed:", e
return keyHandle
def ReadRegistryValue(hiveKey, key, name):
""" Simple api to read one value from Windows registry.
If 'name' is empty string, reads default value."""
data = typeId = None
try:
hKey = win32api.RegOpenKeyEx(hiveKey, key, 0, win32con.KEY_ALL_ACCESS)
data, typeId = win32api.RegQueryValueEx(hKey, name)
win32api.RegCloseKey(hKey)
except Exception, e:
print "ReadRegistryValue failed:", e
return data, typeId
def WriteRegistryValue(hiveKey, key, name, typeId, data):
""" Simple api to write one value to Windows registry.
If 'name' is empty string, writes to default value."""
try:
keyHandle = OpenRegistryKey(hiveKey, key)
win32api.RegSetValueEx(keyHandle, name, 0, typeId, data)
win32api.RegCloseKey(keyHandle)
except Exception, e:
print "WriteRegistry failed:", e
""" misc utilities """
def GetPythonwExePath():
""" Get path to current version of pythonw.exe """
pythonExePath = ""
try:
pythonwExeName = "pythonw.exe"
pythonInstallHiveKey = win32con.HKEY_LOCAL_MACHINE
pythonInstallKey = r"Software\Python\PythonCore\%s\InstallPath" % sys.winver
pythonInstallDir, typeId = ReadRegistryValue(pythonInstallHiveKey, pythonInstallKey, "")
pythonwExePath = os.path.join(pythonInstallDir, pythonwExeName)
except Exception, e:
print "GetPythonExePath failed:", e
return pythonwExePath
def GetModulePath():
""" Get path to this module """
return GetModulePath.func_code.co_filename
def WriteLastTime():
secsString = str(time.time())
WriteRegistryValue(win32con.HKEY_CLASSES_ROOT, r"*\shell\PathCatcher\time", "", win32con.REG_SZ, secsString)
def ReadLastTime():
secs = 0.0
secsString, dateTypId = ReadRegistryValue(win32con.HKEY_CLASSES_ROOT, r"*\shell\PathCatcher\time", "")
if secsString:
secs = float(secsString)
return secs
def AccumulatePaths(path):
""" Windows creates a Python process for each selected file on right-click.
Check to see if this invocation is part of current batch and accumulate to clipboard """
lastTime = ReadLastTime()
now = time.time()
if (now - lastTime) < 1.0:
SetClipboardText(GetClipboardText() + "\n" + path)
else:
SetClipboardText(path)
WriteLastTime()
#########################################################
def InstallPathCatcher():
""" Installs PathCatcher to the Windows registry """
command = '"%s" "%s" "%s"' % (GetPythonwExePath(), GetModulePath(), "%1")
WriteRegistryValue(win32con.HKEY_CLASSES_ROOT, r"*\shell\PathCatcher\Command", "", win32con.REG_SZ, command)
WriteRegistryValue(win32con.HKEY_CLASSES_ROOT, r"Folder\shell\PathCatcher\Command", "", win32con.REG_SZ, command)
WriteLastTime()
#########################################################
if __name__ == "__main__":
if len(sys.argv) > 1:
""" If invoked through a right-click, there will be a path argument """
path = sys.argv[1]
AccumulatePaths(path)
else:
""" If module is run by itself, install PathCatcher to registry """
InstallPathCatcher()
raw_input("PathCatcher installed.\nPress RETURN...")
|
I find it quite tedious to drill down to a particular file or folder in a tiny file dialog window. Often I've already opened that folder in Explorer. It's much easier to do so directly from Explorer. Also handy for acquiring paths for use in source code.
I have extended this utility so that it will handle a group of files or folders selected in Explorer and return their paths in the clipboard.
Note that Windows invokes a separate Python process for each selected item, so a large group of selections will take a noticeable amount of time, approximately a fraction of a second apiece. Wait for the wait cursor to stop flickering before pasting from the clipoard or invoking PathCatcher again.
Also, the order of selected paths returned by PathCatcher depends on the order that Windows calls PathCatcher. In practice this means that the list of paths will usually be in reverse of how they appear in the Explorer window.
Multi-selection. How could you do exactly the same, but selecting more than one file or directory and having them in the clipboard?
Thanks! Nicolas
You got it! Sorry for the delay.