python - 有没有办法获取shell :appsfolder on Windows 10?的完整路径

标签 python windows

我希望能够在 python 脚本中列出 shell:appsfolder 中的文件,但需要使用 os.list 的完整路径来执行此操作。有没有办法获得完整路径(或者有人知道)?或者,是否有其他方法可以列出这些文件?我可以“cd”到它吗?

该脚本背后的想法是自动创建所有 Windows 应用商店应用程序的快捷方式(我认为它们具有“长名称”属性)并将这些快捷方式提取到程序 Launchy 可以检测到它们的文件夹中。我不喜欢每次下载或删除应用程序时都必须手动完成创建快捷方式(并重命名它以删除“-快捷方式)的过程,因此我认为我应该自动化它。

最佳答案

这里的函数有望实现您想要的功能,为“应用程序”虚拟文件夹(即 FOLDERID_AppsFolder)中列出的 Windows 应用商店应用程序创建快捷方式。为了对 Windows 应用商店应用程序进行分类,它会在应用程序用户模型 ID 中查找感叹号,因为 AUMID 的形式应为“PackageFamily!ApplicationID”(请参阅​​ Automate Launching UWP Apps )。为了可靠性,它会将每个包系列与用户注册的包系列进行交叉检查。

import os
import ctypes
import pywintypes
import pythoncom
import winerror

try:
    import winreg
except ImportError:
    # Python 2
    import _winreg as winreg
    bytes = lambda x: str(buffer(x))

from ctypes import wintypes
from win32com.shell import shell, shellcon
from win32com.propsys import propsys, pscon

# KNOWNFOLDERID
# https://msdn.microsoft.com/en-us/library/dd378457
# win32com defines most of these, except the ones added in Windows 8.
FOLDERID_AppsFolder = pywintypes.IID('{1e87508d-89c2-42f0-8a7e-645a0f50ca58}')

# win32com is missing SHGetKnownFolderIDList, so use ctypes.

_ole32 = ctypes.OleDLL('ole32')
_shell32 = ctypes.OleDLL('shell32')

_REFKNOWNFOLDERID = ctypes.c_char_p
_PPITEMIDLIST = ctypes.POINTER(ctypes.c_void_p)

_ole32.CoTaskMemFree.restype = None
_ole32.CoTaskMemFree.argtypes = (wintypes.LPVOID,)

_shell32.SHGetKnownFolderIDList.argtypes = (
    _REFKNOWNFOLDERID, # rfid
    wintypes.DWORD,    # dwFlags
    wintypes.HANDLE,   # hToken
    _PPITEMIDLIST)     # ppidl

def get_known_folder_id_list(folder_id, htoken=None):
    if isinstance(folder_id, pywintypes.IIDType):
        folder_id = bytes(folder_id)
    pidl = ctypes.c_void_p()
    try:
        _shell32.SHGetKnownFolderIDList(folder_id, 0, htoken,
            ctypes.byref(pidl))
        return shell.AddressAsPIDL(pidl.value)
    except WindowsError as e:
        if e.winerror & 0x80070000 == 0x80070000:
            # It's a WinAPI error, so re-raise it, letting Python
            # raise a specific exception such as FileNotFoundError.
            raise ctypes.WinError(e.winerror & 0x0000FFFF)
        raise
    finally:
        if pidl:
            _ole32.CoTaskMemFree(pidl)

def enum_known_folder(folder_id, htoken=None):
    id_list = get_known_folder_id_list(folder_id, htoken)
    folder_shell_item = shell.SHCreateShellItem(None, None, id_list)
    items_enum = folder_shell_item.BindToHandler(None,
        shell.BHID_EnumItems, shell.IID_IEnumShellItems)
    for item in items_enum:
        yield item

def list_known_folder(folder_id, htoken=None):
    result = []
    for item in enum_known_folder(folder_id, htoken):
        result.append(item.GetDisplayName(shellcon.SIGDN_NORMALDISPLAY))
    result.sort(key=lambda x: x.upper())
    return result

def create_shortcut(shell_item, shortcut_path):
    id_list = shell.SHGetIDListFromObject(shell_item)
    shortcut = pythoncom.CoCreateInstance(shell.CLSID_ShellLink, None,
        pythoncom.CLSCTX_INPROC_SERVER, shell.IID_IShellLink)
    shortcut.SetIDList(id_list)
    persist = shortcut.QueryInterface(pythoncom.IID_IPersistFile)
    persist.Save(shortcut_path, 0)

def get_package_families():
    families = set()
    subkey = (r'Software\Classes\Local Settings\Software\Microsoft'
              r'\Windows\CurrentVersion\AppModel\Repository\Families')
    with winreg.OpenKey(winreg.HKEY_CURRENT_USER, subkey) as hkey:
        index = 0
        while True:
            try:
                families.add(winreg.EnumKey(hkey, index))
            except OSError as e:
                if e.winerror != winerror.ERROR_NO_MORE_ITEMS:
                    raise
                break
            index += 1
    return families

def update_app_shortcuts(target_dir):
    package_families = get_package_families()
    for item in enum_known_folder(FOLDERID_AppsFolder):
        try:
            property_store = item.BindToHandler(None,
                shell.BHID_PropertyStore, propsys.IID_IPropertyStore)
            app_user_model_id = property_store.GetValue(
                pscon.PKEY_AppUserModel_ID).ToString()
        except pywintypes.error:
            continue
        # AUID template: Packagefamily!ApplicationID
        if '!' not in app_user_model_id:
            continue
        package_family, app_id = app_user_model_id.rsplit('!', 1)
        if package_family not in package_families:
            continue
        name = item.GetDisplayName(shellcon.SIGDN_NORMALDISPLAY)
        shortcut_path = os.path.join(target_dir, '%s.lnk' % name)
        create_shortcut(item, shortcut_path)
        print('{}: {}'.format(name, app_user_model_id))

示例

if __name__ == '__main__':
    desktop = shell.SHGetFolderPath(0, shellcon.CSIDL_DESKTOP, 0, 0)
    target_dir = os.path.join(desktop, 'Windows Store Apps')
    if not os.path.exists(target_dir):
        os.mkdir(target_dir)
    update_app_shortcuts(target_dir)

关于python - 有没有办法获取shell :appsfolder on Windows 10?的完整路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43618668/

相关文章:

python - 使用 Python/Pandas 仅插入 TimeSerie 的一个值

python - 如何使用 Pandas 映射嵌套在字典中的元组的索引?

python - 带有 seaborn PairGrid 图的 ipywidgets

python - Google App Engine 开发服务器删除 virtualenv 的站点包

c++ - MinGW 可以毫不费力地复制大多数 unix 系统调用吗?

windows - 适用于 Windows CE 和 Windows 桌面的 PCIe 驱动程序

Python 正则表达式捕获问题

windows - LogonUser -> 来自系统服务的 CreateProcessAsUser

Windows 命令行脚本根据用户定义的起始变量递减 FOR 循环中的变量

c# - 如何使用 C# 删除 StartMenu 快捷方式