本文目录导读:

我来通过一个完整的Python案例,演示如何实现Windows右键菜单扩展。
使用注册表(简单方式)
为特定文件类型添加右键菜单
import winreg
import os
import sys
import json
class RightClickMenu:
def __init__(self):
self.script_path = sys.executable if getattr(sys, 'frozen', False) else __file__
def add_menu_for_txt(self, menu_name, python_script):
"""为.txt文件添加右键菜单"""
try:
# 打开.txt文件的注册表项
key_path = r"*\shell"
key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, key_path, 0, winreg.KEY_SET_VALUE)
# 创建菜单项
menu_key = winreg.CreateKey(key, menu_name)
winreg.SetValue(menu_key, '', winreg.REG_SZ, menu_name)
# 设置命令
command_key = winreg.CreateKey(menu_key, 'command')
command = f'"{sys.executable}" "{python_script}" "%1"'
winreg.SetValue(command_key, '', winreg.REG_SZ, command)
winreg.CloseKey(command_key)
winreg.CloseKey(menu_key)
winreg.CloseKey(key)
print(f"成功添加 '{menu_name}' 右键菜单")
return True
except Exception as e:
print(f"添加右键菜单失败: {e}")
return False
def remove_menu(self, menu_name):
"""移除右键菜单"""
try:
key_path = r"*\shell"
key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, key_path, 0, winreg.KEY_SET_VALUE)
winreg.DeleteKey(key, menu_name + "\\command")
winreg.DeleteKey(key, menu_name)
winreg.CloseKey(key)
print(f"成功移除 '{menu_name}' 右键菜单")
return True
except Exception as e:
print(f"移除右键菜单失败: {e}")
return False
# 右键菜单处理脚本示例
def txt_processor():
"""处理选中文件的脚本"""
import sys
if len(sys.argv) > 1:
file_path = sys.argv[1]
print(f"处理文件: {file_path}")
# 读取文件内容
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
# 示例:统计文件信息
info = {
'文件名': os.path.basename(file_path),
'大小': f"{len(content)} 字符",
'行数': len(content.splitlines()),
'单词数': len(content.split())
}
print(json.dumps(info, ensure_ascii=False, indent=2))
except Exception as e:
print(f"处理文件失败: {e}")
if __name__ == "__main__":
# 使用示例
menu = RightClickMenu()
print("1. 添加右键菜单")
print("2. 移除右键菜单")
print("3. 处理文件测试")
choice = input("请选择操作: ")
if choice == '1':
menu_name = input("请输入菜单名称: ")
script_path = input("请输入Python脚本路径: ")
menu.add_menu_for_txt(menu_name, script_path)
elif choice == '2':
menu_name = input("请输入要移除的菜单名称: ")
menu.remove_menu(menu_name)
elif choice == '3':
txt_processor()
使用自定义类(高级方式)
import winreg
import os
import sys
import subprocess
from pathlib import Path
class AdvancedRightClickMenu:
"""高级右键菜单管理器"""
def __init__(self, app_name="MyPythonApp"):
self.app_name = app_name
self.registry_base = r"Software\Classes"
def add_menu_to_all_files(self, menu_text, icon_path="", command=""):
"""为所有文件添加右键菜单"""
base_key = winreg.HKEY_CLASSES_ROOT
shell_path = r"*\shell"
try:
# 打开或创建shell键
with winreg.OpenKey(base_key, shell_path, 0, winreg.KEY_SET_VALUE) as shell_key:
# 创建菜单项
with winreg.CreateKey(shell_key, self.app_name) as app_key:
# 设置菜单显示文本
winreg.SetValueEx(app_key, "", 0, winreg.REG_SZ, menu_text)
# 设置图标(可选)
if icon_path:
winreg.SetValueEx(app_key, "Icon", 0, winreg.REG_SZ, icon_path)
# 设置扩展验证
winreg.SetValueEx(app_key, "AppliesTo", 0, winreg.REG_SZ, "System.FileName")
# 创建命令键
with winreg.CreateKey(app_key, "command") as cmd_key:
if command:
cmd = f'"{sys.executable}" "{command}" "%1"'
else:
# 使用当前脚本
cmd = f'"{sys.executable}" "{__file__}" "%1"'
winreg.SetValueEx(cmd_key, "", 0, winreg.REG_SZ, cmd)
print(f"成功添加右键菜单: {menu_text}")
return True
except Exception as e:
print(f"添加菜单失败: {e}")
return False
def add_menu_to_folder(self, menu_text, command=""):
"""为文件夹添加右键菜单"""
base_key = winreg.HKEY_CLASSES_ROOT
shell_path = r"Directory\shell"
try:
with winreg.OpenKey(base_key, shell_path, 0, winreg.KEY_SET_VALUE) as shell_key:
with winreg.CreateKey(shell_key, self.app_name) as app_key:
winreg.SetValueEx(app_key, "", 0, winreg.REG_SZ, menu_text)
with winreg.CreateKey(app_key, "command") as cmd_key:
if command:
cmd = f'"{sys.executable}" "{command}" "%1"'
else:
cmd = f'"{sys.executable}" "{__file__}" "%1"'
winreg.SetValueEx(cmd_key, "", 0, winreg.REG_SZ, cmd)
print(f"成功添加文件夹右键菜单: {menu_text}")
return True
except Exception as e:
print(f"添加菜单失败: {e}")
return False
def add_submenu(self, menu_text, submenu_items):
"""添加子菜单(多级菜单)"""
base_key = winreg.HKEY_CLASSES_ROOT
shell_path = r"*\shell"
try:
with winreg.OpenKey(base_key, shell_path, 0, winreg.KEY_SET_VALUE) as shell_key:
with winreg.CreateKey(shell_key, self.app_name) as app_key:
winreg.SetValueEx(app_key, "", 0, winreg.REG_SZ, menu_text)
winreg.SetValueEx(app_key, "SubCommands", 0, winreg.REG_SZ, "")
winreg.SetValueEx(app_key, "MUIVerb", 0, winreg.REG_SZ, menu_text)
# 创建子菜单项
for i, (sub_text, sub_cmd) in enumerate(submenu_items, 1):
sub_key_name = f"{self.app_name}\\shell\\item{i}"
with winreg.CreateKey(base_key, sub_key_name) as sub_key:
winreg.SetValueEx(sub_key, "MUIVerb", 0, winreg.REG_SZ, sub_text)
with winreg.CreateKey(sub_key, "command") as cmd_key:
cmd = f'"{sys.executable}" "{sub_cmd}" "%1"'
winreg.SetValueEx(cmd_key, "", 0, winreg.REG_SZ, cmd)
print(f"成功添加子菜单: {menu_text}")
return True
except Exception as e:
print(f"添加子菜单失败: {e}")
return False
def remove_menu(self):
"""移除右键菜单"""
paths = [
f"*\\shell\\{self.app_name}",
f"Directory\\shell\\{self.app_name}",
f"*\\shell\\{self.app_name}\\shell",
]
base_key = winreg.HKEY_CLASSES_ROOT
for path in paths:
try:
# 递归删除子键
self._delete_key_recursive(base_key, path)
except:
pass
print(f"成功移除右键菜单: {self.app_name}")
def _delete_key_recursive(self, base_key, key_path):
"""递归删除注册表键"""
try:
with winreg.OpenKey(base_key, key_path, 0, winreg.KEY_READ) as key:
# 获取子键列表
i = 0
while True:
try:
sub_key = winreg.EnumKey(key, i)
self._delete_key_recursive(base_key, f"{key_path}\\{sub_key}")
i += 1
except WindowsError:
break
winreg.DeleteKey(base_key, key_path)
except Exception:
pass
# 实际处理脚本
class FileProcessor:
"""文件处理器示例"""
@staticmethod
def analyze_file(file_path):
"""分析文件"""
if not os.path.exists(file_path):
return {"error": "文件不存在"}
file_size = os.path.getsize(file_path)
file_ext = os.path.splitext(file_path)[1]
file_name = os.path.basename(file_path)
result = {
"文件名": file_name,
"扩展名": file_ext,
"大小": f"{file_size / 1024:.2f} KB",
"路径": file_path
}
# 如果是文本文件,读取内容
if file_ext in ['.txt', '.py', '.md', '.json', '.xml', '.html', '.css', '.js']:
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
result.update({
"字符数": len(content),
"行数": len(content.splitlines()),
"单词数": len(content.split())
})
except:
result["编码"] = "无法读取"
return result
@staticmethod
def backup_file(file_path):
"""备份文件"""
if os.path.exists(file_path):
backup_path = file_path + ".backup"
import shutil
shutil.copy2(file_path, backup_path)
return {"success": True, "backup_path": backup_path}
return {"success": False, "error": "源文件不存在"}
def main():
"""主入口"""
import sys
if len(sys.argv) > 1:
file_path = sys.argv[1]
processor = FileProcessor()
# 分析文件
info = processor.analyze_file(file_path)
print("文件分析结果:")
for key, value in info.items():
print(f"{key}: {value}")
else:
# 管理界面
menu = AdvancedRightClickMenu("PythonTools")
print("右键菜单管理器")
print("=" * 30)
print("1. 为所有文件添加 '文件分析' 菜单")
print("2. 为文件夹添加 '文件夹分析' 菜单")
print("3. 添加子菜单(分析/备份)")
print("4. 移除所有菜单")
print("5. 退出")
choice = input("请选择 (1-5): ")
if choice == '1':
# 添加文件分析菜单
menu.add_menu_to_all_files("Python 文件分析")
elif choice == '2':
# 添加文件夹菜单
menu.add_menu_to_folder("Python 文件夹分析")
elif choice == '3':
# 添加子菜单
submenu_items = [
("分析文件", __file__),
("备份文件", __file__)
]
menu.add_submenu("Python 工具", submenu_items)
elif choice == '4':
# 移除菜单
menu.remove_menu()
elif choice == '5':
print("退出程序")
sys.exit(0)
if __name__ == "__main__":
main()
使用 pywin32(最完整)
import win32con
import win32api
import win32security
import pythoncom
import sys
import os
class ContextMenuHandler:
"""Windows右键菜单COM组件"""
def __init__(self):
self._reg_clsid = "{YOUR_GUID}" # 需要生成GUID
self._reg_progid = "PythonContextMenu"
self._reg_desc = "Python Context Menu Handler"
def register(self):
"""注册COM组件"""
import win32com.server.register
win32com.server.register.UseCommandLine(
self._reg_clsid,
self._reg_progid,
self._reg_desc,
"PythonContextMenu.ContextMenu"
)
def unregister(self):
"""注销COM组件"""
import win32com.server.unregister
win32com.server.unregister.UseCommandLine(
self._reg_clsid,
self._reg_progid
)
# 实际右键菜单处理
def handle_right_click():
"""处理右键点击事件"""
import sys
if len(sys.argv) > 1:
selected_files = sys.argv[1:]
print("选中的文件:")
for file in selected_files:
print(f" - {file}")
# 在这里添加你的处理逻辑
# 批量重命名、压缩、加密等
if __name__ == "__main__":
# 检查是否传递了文件参数
if len(sys.argv) > 1:
handle_right_click()
else:
# 注册/注销菜单
handler = ContextMenuHandler()
print("1. 注册右键菜单")
print("2. 注销右键菜单")
choice = input("请选择: ")
if choice == '1':
handler.register()
print("右键菜单已注册")
elif choice == '2':
handler.unregister()
print("右键菜单已注销")
使用示例
创建处理脚本 process_files.py
import sys
import os
import json
from datetime import datetime
def process_selected_file(file_path):
"""处理选中的文件"""
print(f"""
==================== 文件处理结果 ====================
文件路径: {file_path}
处理时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
=================================================
""")
# 获取文件信息
if os.path.exists(file_path):
stat = os.stat(file_path)
info = {
"文件大小": f"{stat.st_size / 1024:.2f} KB",
"创建时间": datetime.fromtimestamp(stat.st_ctime).strftime('%Y-%m-%d %H:%M:%S'),
"修改时间": datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S'),
"访问时间": datetime.fromtimestamp(stat.st_atime).strftime('%Y-%m-%d %H:%M:%S')
}
print("文件信息:")
for key, value in info.items():
print(f" {key}: {value}")
# 如果是文本文件,添加内容分析
if file_path.endswith(('.txt', '.py', '.md', '.log')):
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
print(f"\n文本分析:")
print(f" 字符数: {len(content)}")
print(f" 行数: {len(content.splitlines())}")
except:
print("\n无法读取文件内容")
if __name__ == "__main__":
if len(sys.argv) > 1:
file_path = sys.argv[1]
process_selected_file(file_path)
else:
print("请右键点击文件,然后选择此程序")
安装脚本 install_menu.py
import winreg
import sys
import os
def install_right_click_menu():
"""安装右键菜单"""
script_path = os.path.abspath("process_files.py")
menu_name = "Python 文件分析"
try:
# 为所有文件添加菜单
key_path = r"*\shell"
key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, key_path, 0, winreg.KEY_SET_VALUE)
# 创建菜单项
menu_key = winreg.CreateKey(key, menu_name)
winreg.SetValue(menu_key, '', winreg.REG_SZ, menu_name)
# 设置命令
command_key = winreg.CreateKey(menu_key, 'command')
command = f'"{sys.executable}" "{script_path}" "%1"'
winreg.SetValue(command_key, '', winreg.REG_SZ, command)
winreg.CloseKey(command_key)
winreg.CloseKey(menu_key)
winreg.CloseKey(key)
print(f"✓ 右键菜单 '{menu_name}' 安装成功!")
print(f" 执行脚本: {script_path}")
except Exception as e:
print(f"✗ 安装失败: {e}")
sys.exit(1)
def uninstall_right_click_menu():
"""卸载右键菜单"""
menu_name = "Python 文件分析"
try:
key_path = r"*\shell"
key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, key_path, 0, winreg.KEY_SET_VALUE)
# 删除命令子键和菜单主键
try:
winreg.DeleteKey(key, menu_name + "\\command")
winreg.DeleteKey(key, menu_name)
except:
pass # 键可能已经不存在
winreg.CloseKey(key)
print(f"✓ 右键菜单 '{menu_name}' 已卸载")
except Exception as e:
print(f"✗ 卸载失败: {e}")
sys.exit(1)
if __name__ == "__main__":
print("右键菜单安装工具")
print("=" * 30)
print("1. 安装右键菜单")
print("2. 卸载右键菜单")
choice = input("请选择 (1-2): ")
if choice == '1':
install_right_click_menu()
elif choice == '2':
uninstall_right_click_menu()
else:
print("无效选择")
注意事项
- 管理员权限:修改注册表需要管理员权限
- 安全考虑:不要添加恶意功能
- 测试环境:先在测试环境验证
- 备份注册表:修改前备份
- GUID生成:使用COM组件时需要唯一GUID
这些示例涵盖了不同复杂度的右键菜单实现,你可以根据需求选择合适的方案。