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="
" )
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:
Libsite-packageswin32comextshelldemos
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…