Python:获取资源管理器中选定文件的列表(Windows 7)

标签 python contextmenu windows-explorer

在工作中,我可以选择多个 .xlsx 文件,右键单击一个文件可以让我选择将这些文件组合成一个 .pdf。现在我想在我的一个脚本中使用相同的功能。也就是说,选择多个文件并将这些文件的路径作为参数发送给 Python 脚本。

我很快花了一个小时来寻找解决方案,但我还没有找到任何好的答案。似乎有一些 C# 答案,但我不知道如何将代码转换为 Python。甚至有可能实现它吗?

编辑 - 示例脚本:

import sys, os
for file in sys.argv:
    print(file)
os.system("PAUSE")

最佳答案

我知道在这里发布答案有点晚,但我几个月前尝试过 Olav 的解决方案,但它没有完全起作用:工作目录是脚本的工作目录,所以我不得不删除如果它工作的条件,但它选择了所有 Windows 资源管理器窗口中的所有文件(我也想要,所以它对我来说部分工作)。但是回到这个之后,我想到了这个想法。我不知道这个答案是否适用于其他人,但对我来说并不完全,所以我认为我可以改进它并在此处发布我的解决方案。

此代码是 James Kent 的答案的混合体: https://stackoverflow.com/a/43892579/8228163 (由我更正为至少在 Windows 7 下工作)和 Olav 的回答以及结果对我有用 - 该脚本仅在当前 Windows 资源管理器窗口中检测文件。我认为所有这些都适用于 Vista(不确定,这里运行 7)到 10,但我不完全确定。另一个答案是与 XP 一起使用。当我在 Windows 10 上启动此脚本时,我认为它有效,但我不再有 10,所以我不确定(我再次使用 7,所以对于 7 这个有效)。

import win32gui, time
from win32con import PAGE_READWRITE, MEM_COMMIT, MEM_RESERVE, MEM_RELEASE, PROCESS_ALL_ACCESS, WM_GETTEXTLENGTH, WM_GETTEXT
from commctrl import LVS_OWNERDATA, LVM_GETITEMCOUNT, LVM_GETNEXTITEM, LVNI_SELECTED
import os
import struct
import ctypes
import win32api
import datetime
import win32com.client as win32
import win32ui
import psutil
import subprocess
import time
import urllib.parse

clsid = '{9BA05972-F6A8-11CF-A442-00A0C90A8F39}' #Valid for IE as well!

def getEditText(hwnd):
    # api returns 16 bit characters so buffer needs 1 more char for null and twice the num of chars
    buf_size = (win32gui.SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0) +1 ) * 2
    target_buff = ctypes.create_string_buffer(buf_size)
    win32gui.SendMessage(hwnd, WM_GETTEXT, buf_size, ctypes.addressof(target_buff))
    return target_buff.raw.decode('utf16')[:-1]# remove the null char on the end

def _normaliseText(controlText):
    '''Remove '&' characters, and lower case.
    Useful for matching control text.'''
    return controlText.lower().replace('&', '')

def _windowEnumerationHandler(hwnd, resultList):
    '''Pass to win32gui.EnumWindows() to generate list of window handle,
    window text, window class tuples.'''
    resultList.append((hwnd, win32gui.GetWindowText(hwnd), win32gui.GetClassName(hwnd)))

def searchChildWindows(currentHwnd,
               wantedText=None,
               wantedClass=None,
               selectionFunction=None):
    results = []
    childWindows = []
    try:
        win32gui.EnumChildWindows(currentHwnd,
                      _windowEnumerationHandler,
                      childWindows)
    except win32gui.error:
        # This seems to mean that the control *cannot* have child windows,
        # i.e. not a container.
        return
    for childHwnd, windowText, windowClass in childWindows:
        descendentMatchingHwnds = searchChildWindows(childHwnd)
        if descendentMatchingHwnds:
            results += descendentMatchingHwnds

        if wantedText and \
            not _normaliseText(wantedText) in _normaliseText(windowText):
                continue
        if wantedClass and \
            not windowClass == wantedClass:
                continue
        if selectionFunction and \
            not selectionFunction(childHwnd):
                continue
        results.append(childHwnd)
    return results


def explorer_fileselection():
    global clsid
    address_1=""
    files = []
    shellwindows = win32.Dispatch(clsid)
    w=win32gui
    window = w.GetForegroundWindow()
    #print("window: %s" % window)
    if (window != 0):
        if (w.GetClassName(window) == 'CabinetWClass'): # the main explorer window
            #print("class: %s" % w.GetClassName(window))
            #print("text: %s " %w.GetWindowText(window))
            children = list(set(searchChildWindows(window)))
            addr_edit = None
            file_view = None
            for child in children:
                if (w.GetClassName(child) == 'WorkerW'): # the address bar
                    addr_children = list(set(searchChildWindows(child)))
                    for addr_child in addr_children:
                        if (w.GetClassName(addr_child) == 'ReBarWindow32'):
                            addr_edit = addr_child
                            addr_children = list(set(searchChildWindows(child)))
                            for addr_child in addr_children:
                                if (w.GetClassName(addr_child) == 'Address Band Root'):
                                    addr_edit = addr_child
                                    addr_children = list(set(searchChildWindows(child)))
                                    for addr_child in addr_children:
                                        if (w.GetClassName(addr_child) == 'msctls_progress32'):
                                            addr_edit = addr_child
                                            addr_children = list(set(searchChildWindows(child)))
                                            for addr_child in addr_children:
                                                if (w.GetClassName(addr_child) == 'Breadcrumb Parent'):
                                                    addr_edit = addr_child
                                                    addr_children = list(set(searchChildWindows(child)))
                                                    for addr_child in addr_children:
                                                        if (w.GetClassName(addr_child) == 'ToolbarWindow32'):
                                                            text=getEditText(addr_child)
                                                            if "\\" in text:
                                                                address_1=getEditText(addr_child)[text.index(" ")+1:]
                                                                print("Address --> "+address_1)

    for window in range(shellwindows.Count):
        window_URL = urllib.parse.unquote(shellwindows[window].LocationURL,encoding='ISO 8859-1')
        window_dir = window_URL.split("///")[1].replace("/", "\\")
        print("Directory --> "+window_dir)
        if window_dir==address_1:
            selected_files = shellwindows[window].Document.SelectedItems()
            for file in range(selected_files.Count):
                files.append(selected_files.Item(file).Path)
            print("Files --> "+str(files))

while True:
    explorer_fileselection()
    time.sleep(1)

这会查找事件的 Windows 资源管理器窗口,获取该窗口的地址,然后在 Olav 的回答中使用该地址来检查该地址是否等于在 Windows 资源管理器中打开的地址之一,从事件的窗口获取文件 window 。顺便说一句,因为这是脚本是两个答案的修改副本,所以它有其局限性:

  • 就像 Olav 的回答“编辑:还没有工作,至少在使用上下文菜单时”,那么这可能也不会工作,因为它是相同的代码 - 只是工作目录不同(虽然,我不知道他的意思,但根据我的测试,它有效)。
  • 就像 James Kent 的回答一样,这不适用于桌面,仅适用于使用 Windows 资源管理器打开的窗口。 encoding='ISO 8859-1' 是因为我是葡萄牙语,但它可以更改,只需确保两个目录相等且没有 %?s 否则将不起作用!

注意:对于 Windows XP,请参阅原始答案 ( https://stackoverflow.com/a/43892579/8228163 ) 并从所有 Windows 资源管理器窗口获取文件,只需从 Olav 的答案中删除 if 条件。

感谢 Olav 和 James Kent 的回答,因为我会花更多的时间来尝试找出如何做到这一点(我是 Python/任何语言的初学者)。

希望对您有所帮助!干杯!

关于Python:获取资源管理器中选定文件的列表(Windows 7),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21241708/

相关文章:

python - 在 tkinter GUI 中导入 matplotlib 图。显示错误()

python - 如何使用 Python 3 在 OpenCV 3 上正确加载 cv2.KeyPoint 和描述符?

c# - 在 WPF 中打开 ContextMenu 时保留 DataGrid IsSelectionActive?

macos - Cocoa 中的选项 (⌥) + 上下文菜单?

python - 为什么打开资源管理器窗口并通过Python的子进程选择文件会返回错误代码1

python - 为每个单词添加链接,考虑标点符号、缩写和 Unicode

python - 从 API 获取 header

macos - 如何实现 NSCollectionView 的上下文菜单

windows - 如何刷新 Windows 资源管理器

windows - Windows 中目录/文件夹的 TreeView ?