Dra*_*eel 1 winapi pywin32 winforms python-3.x
我目前正在使用Win32 api 使用 Python 3。对于窗口检查,我使用 Microsoft Inspect Tool。目前,我有以下代码枚举所有窗口:
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)
Run Code Online (Sandbox Code Playgroud)
这将输出以下内容:
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:
Run Code Online (Sandbox Code Playgroud)
这太棒了。但还要注意,通过查看 Inspect 工具,这些对象的FrameworkId仅为“Win32”(如图所示)。
从检查器中,我注意到某些对象具有名为“DirectUI”的不同框架Id,并且它们似乎没有从 EnumChildWindows 函数中显示出来。这是一个问题,因为包含所有文件的对象实际上称为“Items View”窗格,并且它是“DirectUI”(参见第二张图片)。所以它甚至没有被检测到。如果没有检测到,如何读取里面的所有文件?我知道这些名字在那里,因为你可以在树中看到它们(如下图所示)
如何让 Win32API 与 DirectUI 一起使用以读取文件名?
有没有更简单的方法来检索所有文件的名称列表?
shell 有一个专门用于此类操作的COM API ,可以通过 pywin32 访问它。
这是我想出的工作代码:
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 )
Run Code Online (Sandbox Code Playgroud)
哇,这是一个很好的谜题(因为我实际上是一个 C++ 人)!
为了理解这些内容,我建议学习原始的 MSDN 文档,然后尝试将其映射到pywin32 代码。
Shell API(以及一般的 COM)一开始可能有点让人不知所措,但改编现有的示例代码通常并不困难。Raymond Chen 的博客是一个很好的来源。
对于pywin32示例,pywin32安装的此文件夹中有一些演示:
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 )
Run Code Online (Sandbox Code Playgroud)