Python:在资源管理器中获取选定文件的列表(WIndows 7) [英] Python: Get a list of selected files in Explorer (WIndows 7)

查看:116
本文介绍了Python:在资源管理器中获取选定文件的列表(WIndows 7)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

At work I can select multiple .xlsx files, and right clicking on one file will give me the option of combining the files to make a .pdf. Now I want to use the same functionality in one of my scripts. That is, selecting multiple files and send the paths of these files as arguments to a Python script.

我已经花了一个小时的时间来寻找解决方案,但是我还没有找不到任何好的答案。似乎有一些C#答案,但是我不知道如何将代码转换为Python。

I've spent soon an hour searching for solutions, but I haven't found any good answers. It seems there are some C# answers, but I don't know how to convert the code to Python. Is it even possible to achieve it at all?

编辑-示例脚本:

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


推荐答案

我知道这有点晚了,但我在这里尝试了Olav的解决方案几个月前,它还不能完全正常工作:工作目录是脚本的工作目录,因此我必须删除if条件才能使其工作,但是它选择了所有Windows资源管理器窗口中的所有文件(我也希望如此)对我来说部分起作用)。但是现在我回到继续我的项目(助理)的过程中,我发现我确实需要这项工作,所以我考虑了这个想法(这并不难想到,但花了几个月的时间我才有了... )。我不知道此答案是否对其他任何人都有用,但对我而言,它并不完全适用,因此我认为我可以改进它,并在此处发布解决方案。这段代码混合了这个答案(我在同一脚本中也一直在使用,但从未想过让它们一起工作): https://stackoverflow.com/a/43892579/8228163 (我更正为至少可以在Windows 7下工作)和Olav的答案,结果对我有用-脚本仅在当前环境中检测文件Windows资源管理器窗口。我认为所有这些功能都可以从Vista(也许我不知道它的版本早于7)到10。但是我不确定。另一个答案是使用XP。当我在Windows 10上启动此脚本时,我认为它可以工作,但是我已经没有10了,所以我不确定(我再次使用7,所以7可以正常工作)。

I know this is a "bit" late to post an answer here, but I had tried Olav's solution some months ago and it didn't work completely: the working directory was the script's working directory, so I had to delete the if condition for it to work, but it selected all the files in all Windows Explorer windows (which I wanted too, so it worked partially for me). But now I came back to continue my project (an assistant) and I found out I really needed this working, so I thought on this idea (which is not that hard to think of, but took months for me to have it...). I don't know if this answer worked for anyone else, but for me it didn't completely so I thought I could improve it and post my solution here. This code is a mix of this answer (which I've been using too in the same script, but never thought of getting them to work together): https://stackoverflow.com/a/43892579/8228163 (corrected by me to work at least under Windows 7) and Olav's answer and the result worked for me - the script detects the files only in the current Windows Explorer window. I think all of this works from Vista (maybe, I don't know as it's older than 7) to 10, but I'm not completely sure. The other answer was made to work with XP. When I started this script on Windows 10, I think it worked, but I don't have 10 anymore so I don't know for sure (I'm using 7 again, so for 7 this works).

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资源管理器中打开的地址之一,并从活动窗口获取文件。这两个答案的副本都有其局限性。因此,就像奥拉夫(Olav)的回答编辑:至少在使用上下文菜单时尚不起作用一样,这也可能不会起作用,因为它是相同的代码-只是工作目录不同(尽管,我不知道他的意思,但是对于我测试过的方法,它确实有效。就像詹姆斯·肯特(James Kent)的回答一样,它不适用于桌面,仅适用于使用Windows资源管理器打开的窗口。
encoding ='ISO 8859-1'是因为我是葡萄牙语,但可以更改,只需确保两个目录在没有%?s的情况下相等,否则将不起作用!

This looks for the active Windows Explorer window, gets that window's address and then the address is used on Olav's answer for it to check if that address is equal to one of the addresses opened in Windows Explorer, getting the files from the active window. Btw, as this is script is a modified copy of both answers, it has the limitations from these. So, like it's on Olav's answer " Doesn't work yet, at least when using context menu", then this won't probably work either, as it's the same code - it's just the working directory which is different (though, I don't know what he meant with that, but for what I've tested, it worked). And like it's on James Kent's answer, this doesn't work for desktop, only for opened windows using Windows Explorer. The encoding='ISO 8859-1' is because I'm portuguese, but it can be changed, JUST make sure both directories are equal without %?s or that won't work!

由于这个问题只有将近5年,OP可能不再需要它了,但是我需要它并且在任何地方都没有它,所以我想我可以在这里发表,也许帮助其他想要这样做的人。脚本中的代码可用于了解当前Windows资源管理器窗口上的文件,以及获取XP以上版本的Windows(不确定Vista)上的当前Windows资源管理器窗口路径。对于XP,请参阅原始答案( https://stackoverflow.com/a/43892579/8228163 )并获取所有Windows资源管理器窗口中的文件,只需从Olav的答案中删除if条件即可。

As this question has only almost 5 years, the OP probably won't need it anymore, but I needed it and didn't have it anywhere, so I thought I could post this here and maybe help others who want to do this. The code in the script can be used to know the files on the current Windows Explorer window and to get the current Windows Explorer window path on Windows above XP (not sure about Vista). For XP, see the the original answer (https://stackoverflow.com/a/43892579/8228163) and to get the files from all Windows Explorer windows, just remove the if condition from Olav's answer.

感谢Olav和James Kent的答案,因为我花了更多时间尝试以了解如何执行此操作(我是Python /任何语言的入门者-仅编写一年代码,因此将花费很多时间,也许我必须将其与另一种语言混用)。再次感谢OP,也感谢OP提出问题并让合适的人员在正确的时间回答! (因为Olav在链接上引用的来源已不存在。)

Thanks Olav and James Kent for the answers, because I would have taken MUCH more time trying to find out how to do this (I'm a Python/any language begginner - just coding for a year, so it would have taken really much time, maybe I'd have to mix it with another laguage). Thanks again, and to the OPs too for asking the questions and having the right people answering at the right time! (as the source which Olav quoted on the link no longer exists).

希望这会有所帮助!干杯!

Hope this helps! Cheers!

这篇关于Python:在资源管理器中获取选定文件的列表(WIndows 7)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆