使用 pywin32 从选定的资源管理器窗口返回所有文件的列表 [英] Return a list of all files from the selected Explorer Window with pywin32

查看:115
本文介绍了使用 pywin32 从选定的资源管理器窗口返回所有文件的列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前使用

从检查器中,我注意到某些对象具有名为DirectUI"的不同 frameworkId,并且它们似乎没有从 EnumChildWindows 函数中显示出来.这是一个问题,因为包含所有文件的对象实际上被称为项目视图"窗格,它是DirectUI"(参考第二张图).所以它甚至没有被检测到.如果未检测到,如何读取其中的所有文件?我知道名字在那里是因为你可以在树中看到它们(在下图中)

如何让 Win32API 与 DirectUI 一起使用以读取文件名?
有没有更简单的方法来检索所有文件的名称列表?

解决方案

shell 有一个 专用 COM API 用于此类事情,可通过 pywin32 访问.

这是我想出的工作代码:

导入操作系统导入系统导入 win32con导入 win32api导入 win32gui导入 win32com.client导入pythoncom从 win32com.shell 导入 shell,shellcon# 从给定的资源管理器窗口或所有资源管理器窗口获取路径列表.def get_explorer_files( hwndOfExplorer = 0, selectedOnly = False ):路径 = []# 创建 IShellWindows 的实例(我在 pywin32 中找不到常量)CLSID_IShellWindows = "{9BA05972-F6A8-11CF-A442-00A0C90A8F39}"shellwindows = win32com.client.Dispatch(CLSID_IShellWindows)# 循环所有当前打开的资源管理器窗口对于 shellwindows 中的窗口:# 跳过我们不感兴趣的窗口.如果 hwndOfExplorer != 0 和 hwndOfExplorer != window.HWnd:继续# 获取 IServiceProvider 接口sp = window._oleobj_.QueryInterface( pythoncom.IID_IServiceProvider )# 查询 IShellBrowser 的 IServiceProvidershBrowser = sp.QueryService( shell.SID_STOPLevelBrowser, shell.IID_IShellBrowser )# 获取活动的 IShellView 对象shView = shBrowser.QueryActiveShellView()# 获取一个 IDataObject,其中包含视图的项目(仅选择或全部).aspect = shellcon.SVGIO_SELECTION if selectedOnly else shellcon.SVGIO_ALLVIEWitems = shView.GetItemObject(aspect, pythoncom.IID_IDataObject)# 获取拖放剪贴板格式的路径.我们实际上并不使用# 剪贴板,但这种格式可以很容易地提取文件路径.# 如果您想获得 ITEMIDLIST,请使用 CFSTR_SHELLIDLIST 而不是 CF_HDROP#(又名 PIDL)格式,但那时您不能使用简单的 DragQueryFileW() API.data = items.GetData((win32con.CF_HDROP, None, pythoncom.DVASPECT_CONTENT, -1, pythoncom.TYMED_HGLOBAL ))# 使用拖放 API 提取单个路径.numPaths = shell.DragQueryFileW( data.data_handle, -1 )路径.扩展([shell.DragQueryFileW( data.data_handle, i ) \对于 i 在范围内( numPaths )])如果 hwndOfExplorer != 0:休息返回路径尝试:# 使用 hwnd 值 0 列出所有资源管理器窗口的文件...硬件 = 0# ... 或限制到给定的窗口:#hwnd = win32gui.GetForegroundWindow()selectedOnly = False打印( *get_explorer_files( hwnd, selectedOnly ), sep="\n" )除了作为 e 的例外:打印(错误:",e)

哇,这是一个很好的谜题(因为我实际上是一个 C++ 人)!

要了解这些内容,我建议研究 原始 MSDN 文档,然后尝试将其映射到 pywin32 代码.

Shell API(以及一般的 COM)一开始可能有点让人不知所措,但适应现有的示例代码通常并不难.一个很好的来源是 Raymond Chen 的博客.

对于pywin32示例,pywin32安装的这个文件夹中有一些演示:

Lib\site-packages\win32comext\shell\demos\

I'm currently on Python 3 using the Win32 api. For window inspection, I'm using the Microsoft Inspect Tool. Currently, I have the following code that enumerates through all the windows:

def getSelectedFile():

    def callback(handle, hwnds):
        print(str(handle) + " - class name: " + win32gui.GetClassName(handle) + "-- name: " + win32gui.GetWindowText(handle))
        return True

    hwnd = win32gui.GetForegroundWindow()
    if hwnd:
        if win32gui.GetClassName(hwnd) == 'CabinetWClass':  # this is the main explorer window
            win32gui.EnumChildWindows(hwnd, callback, None)

And this would output the following:

19269320 - class name: BrowserFrameGripperClass-- name: 
526990 - class name: WorkerW-- name: 
395922 - class name: ReBarWindow32-- name: 
13371224 - class name: TravelBand-- name: 
2559382 - class name: ToolbarWindow32-- name: 
11076870 - class name: Address Band Root-- name: 
2230638 - class name: msctls_progress32-- name: 
7930970 - class name: Breadcrumb Parent-- name: 
6292500 - class name: ToolbarWindow32-- name: Address: Libraries\Pictures
8980342 - class name: ToolbarWindow32-- name: 
9568934 - class name: UniversalSearchBand-- name: 
11403790 - class name: Search Box-- name: 
7407762 - class name: SearchEditBoxWrapperClass-- name: 
23266054 - class name: DirectUIHWND-- name: 
7078564 - class name: ShellTabWindowClass-- name: Pictures
11732514 - class name: DUIViewWndClassName-- name: 
12584158 - class name: DirectUIHWND-- name: 
1118546 - class name: CtrlNotifySink-- name: 
987636 - class name: NamespaceTreeControl-- name: Namespace Tree Control
8193258 - class name: Static-- name: Namespace Tree Control
24314574 - class name: SysTreeView32-- name: Tree View
21103510 - class name: CtrlNotifySink-- name: 
1642968 - class name: Shell Preview Extension Host-- name: Shell Preview Extension Host
1577368 - class name: CtrlNotifySink-- name: 
2036036 - class name: SHELLDLL_DefView-- name: ShellView
24380214 - class name: DirectUIHWND-- name: 
1969552 - class name: CtrlNotifySink-- name: 
594366 - class name: ScrollBar-- name: 
987466 - class name: CtrlNotifySink-- name: 
17827752 - class name: ScrollBar-- name: 
2035978 - class name: CtrlNotifySink-- name: 
4851916 - class name: Button-- name: Save
13174848 - class name: CtrlNotifySink-- name: 
7145486 - class name: Button-- name: Cancel
1509810 - class name: WorkerW-- name: 
12781114 - class name: ReBarWindow32-- name: 
11405468 - class name: ToolbarWindow32-- name: 
1315080 - class name: msctls_statusbar32-- name: 

Which is great. But also notice that these objects have a frameworkId of ONLY "Win32" by looking at the Inspect tool (as you can see in the picture).

From the inspector, I noticed that some objects have a different frameworkId named "DirectUI", and they don't seem to show up from the EnumChildWindows function. This is a problem, because the object that contains all the files is actually called "Items View" pane, and it is "DirectUI" (refer to the second picture). So it's not even getting detected. If it's not detected, how can I read all the files inside it? I know that the names are there because you can see them in the tree (in the picture below)

How can I get Win32API to work with DirectUI in order to read the file names?
Is there an easier way of retrieving a list of names of all the files?

解决方案

The shell has a dedicated COM API for things like this, which can be accessed through pywin32.

Here is working code I've come up with:

import os
import sys
import win32con
import win32api
import win32gui
import win32com.client
import pythoncom
from win32com.shell import shell, shellcon

# Get list of paths from given Explorer window or from all Explorer windows.
def get_explorer_files( hwndOfExplorer = 0, selectedOnly = False ):
    paths = []

    # Create instance of IShellWindows (I couldn't find a constant in pywin32)
    CLSID_IShellWindows = "{9BA05972-F6A8-11CF-A442-00A0C90A8F39}"
    shellwindows = win32com.client.Dispatch(CLSID_IShellWindows)

    # Loop over all currently open Explorer windows
    for window in shellwindows:
        # Skip windows we are not interested in.
        if hwndOfExplorer != 0 and hwndOfExplorer != window.HWnd:
            continue

        # Get IServiceProvider interface
        sp = window._oleobj_.QueryInterface( pythoncom.IID_IServiceProvider )

        # Query the IServiceProvider for IShellBrowser
        shBrowser = sp.QueryService( shell.SID_STopLevelBrowser, shell.IID_IShellBrowser )

        # Get the active IShellView object
        shView = shBrowser.QueryActiveShellView()

        # Get an IDataObject that contains the items of the view (either only selected or all). 
        aspect = shellcon.SVGIO_SELECTION if selectedOnly else shellcon.SVGIO_ALLVIEW
        items = shView.GetItemObject( aspect, pythoncom.IID_IDataObject )

        # Get the paths in drag-n-drop clipboard format. We don't actually use 
        # the clipboard, but this format makes it easy to extract the file paths.
        # Use CFSTR_SHELLIDLIST instead of CF_HDROP if you want to get ITEMIDLIST 
        # (aka PIDL) format, but you can't use the simple DragQueryFileW() API then. 
        data = items.GetData(( win32con.CF_HDROP, None, pythoncom.DVASPECT_CONTENT, -1, pythoncom.TYMED_HGLOBAL ))

        # Use drag-n-drop API to extract the individual paths.
        numPaths = shell.DragQueryFileW( data.data_handle, -1 )
        paths.extend([
            shell.DragQueryFileW( data.data_handle, i ) \
                for i in range( numPaths )
        ])

        if hwndOfExplorer != 0:
            break

    return paths

try:
    # Use hwnd value of 0 to list files of ALL explorer windows...
    hwnd = 0  
    # ... or restrict to given window:
    #hwnd = win32gui.GetForegroundWindow()
    selectedOnly = False
    print( *get_explorer_files( hwnd, selectedOnly ), sep="\n" )
except Exception as e:
    print( "ERROR: ", e )

Wow, that was a nice puzzle (as I'm actually a C++ guy)!

To understand that stuff I suggest studying the original MSDN documentation, then try to map that to pywin32 code.

Shell API (and COM in general) can be a little bit overwhelming at first but it's usually not that difficult to adapt existing example code. A great source for that is the blog of Raymond Chen.

For pywin32 samples, there are some demos in this folder of the pywin32 installation:

Lib\site-packages\win32comext\shell\demos\

这篇关于使用 pywin32 从选定的资源管理器窗口返回所有文件的列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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