Python - 在当前 Windows 资源管理器中获取所选文件

时间:2023-04-26
本文介绍了Python - 在当前 Windows 资源管理器中获取所选文件的路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时送ChatGPT账号..

我正在尝试 这个 在 Python 2.7 中.我在 C#这里,但我无法在 Python 中重新创建它.here 的答案确实解释了这个概念我明白,但我不知道如何进行.

I am trying to do this in Python 2.7. I have found an answer for it in C# here, but I am having trouble recreating it in Python. The answer suggested here does explain the concept which I understand, but I have no idea how to get it going.

基本上我只想标记一个文件,按 Winkey+C 并复制其路径.我知道如何做热键部分(pyhk,win32 [RegisterHotKey]),但我的问题是解决文件路径.

Basically I just want to mark a file, press Winkey+C and have its path copied. I know how to do the hotkey part (pyhk, win32 [RegisterHotKey]), but my trouble is working around with the filepath.

提前致谢!

推荐答案

这需要大量的破解,但粗略的解决方案如下:

it takes a lot of hacking around, but a rough solution is below:

#!python3
import win32gui, time
from win32con import PAGE_READWRITE, MEM_COMMIT, MEM_RESERVE, MEM_RELEASE, PROCESS_ALL_ACCESS, WM_GETTEXTLENGTH, WM_GETTEXT
from commctrl import LVM_GETITEMTEXT, LVM_GETITEMCOUNT, LVM_GETNEXTITEM, LVNI_SELECTED
import os
import struct
import ctypes
import win32api

GetWindowThreadProcessId = ctypes.windll.user32.GetWindowThreadProcessId
VirtualAllocEx = ctypes.windll.kernel32.VirtualAllocEx
VirtualFreeEx = ctypes.windll.kernel32.VirtualFreeEx
OpenProcess = ctypes.windll.kernel32.OpenProcess
WriteProcessMemory = ctypes.windll.kernel32.WriteProcessMemory
ReadProcessMemory = ctypes.windll.kernel32.ReadProcessMemory
memcpy = ctypes.cdll.msvcrt.memcpy

def readListViewItems(hwnd, column_index=0):
    # Allocate virtual memory inside target process
    pid = ctypes.create_string_buffer(4)
    p_pid = ctypes.addressof(pid)
    GetWindowThreadProcessId(hwnd, p_pid) # process owning the given hwnd
    hProcHnd = OpenProcess(PROCESS_ALL_ACCESS, False, struct.unpack("i",pid)[0])
    pLVI = VirtualAllocEx(hProcHnd, 0, 4096, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)
    pBuffer = VirtualAllocEx(hProcHnd, 0, 4096, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)

    # Prepare an LVITEM record and write it to target process memory
    lvitem_str = struct.pack('iiiiiiiii', *[0,0,column_index,0,0,pBuffer,4096,0,0])
    lvitem_buffer = ctypes.create_string_buffer(lvitem_str)
    copied = ctypes.create_string_buffer(4)
    p_copied = ctypes.addressof(copied)
    WriteProcessMemory(hProcHnd, pLVI, ctypes.addressof(lvitem_buffer), ctypes.sizeof(lvitem_buffer), p_copied)

    # iterate items in the SysListView32 control
    num_items = win32gui.SendMessage(hwnd, LVM_GETITEMCOUNT)
    item_texts = []
    for item_index in range(num_items):
        win32gui.SendMessage(hwnd, LVM_GETITEMTEXT, item_index, pLVI)
        target_buff = ctypes.create_string_buffer(4096)
        ReadProcessMemory(hProcHnd, pBuffer, ctypes.addressof(target_buff), 4096, p_copied)
        item_texts.append(target_buff.value)

    VirtualFreeEx(hProcHnd, pBuffer, 0, MEM_RELEASE)
    VirtualFreeEx(hProcHnd, pLVI, 0, MEM_RELEASE)
    win32api.CloseHandle(hProcHnd)
    return item_texts

def getSelectedListViewItem(hwnd):
    return win32gui.SendMessage(hwnd, LVM_GETNEXTITEM, -1, LVNI_SELECTED)

def getSelectedListViewItems(hwnd):
    items = []
    item = -1
    while True:
        item = win32gui.SendMessage(hwnd, LVM_GETNEXTITEM, item, LVNI_SELECTED)
        if item == -1:
            break
        items.append(item)
    return items

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

w=win32gui

while True:
    time.sleep(5)
    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) == 'ComboBoxEx32'): # the address bar
                    addr_children = list(set(searchChildWindows(child)))
                    for addr_child in addr_children:
                        if (w.GetClassName(addr_child) == 'Edit'):
                            addr_edit = addr_child
                    pass
                elif (w.GetClassName(child) == 'SysListView32'): # the list control within the window that shows the files
                    file_view = child
            if addr_edit:
                path = getEditText(addr_edit)
            else:
                print('something went wrong - no address bar found')
                path = ''

            if file_view:
                files = [item.decode('utf8') for item in readListViewItems(file_view)]
                indexes = getSelectedListViewItems(file_view)
                print('path: %s' % path)
                print('files: %s' % files)
                print('selected files:')
                for index in indexes:
                    print("	%s - %s" % (files[index], os.path.join(path, files[index])))
            else:
                print('something went wrong - no file view found')

所以它的作用是不断检查活动窗口是否属于资源管理器窗口使用的类,然后遍历子小部件以查找地址栏和文件列表视图.然后它从列表视图中提取文件列表并请求选定的索引.它还从地址栏中获取并解码文本.
然后将底部的信息组合为您提供完整路径、文件夹路径、文件名或其任意组合.

so what this does is keep checking if the active window is of the class the explorer window uses, then iterates through the children widgets to find the address bar and the file list view. Then it extracts the list of files from the listview and requests the selected indexes. it also gets and decodes the text from the address bar.
at the bottom the info is then combined to give you the complete path, the folder path, the file name or any combination thereof.

我已经在 windows xp 上用 python3.4 测试过这个,但是你需要安装 win32gui 和 win32 conn 包.

I have tested this on windows xp with python3.4, but you will need to install the win32gui and win32 conn packages.

这篇关于Python - 在当前 Windows 资源管理器中获取所选文件的路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持html5模板网!

上一篇:打印出整个目录树 下一篇:如何在 Python 中获取最新目录

相关文章

最新文章