Python - Get Path of Selected File in Current Windows Explorer -
i trying this in python 2.7. have found answer in c# here, having trouble recreating in python. answer suggested here explain concept understand, have no idea how going.
basically want mark file, press winkey+c , have path copied. know how hotkey part (pyhk, win32 [registerhotkey]), trouble working around filepath.
thanks in advance!
it takes lot of hacking around, rough solution below:
#!python3 import win32gui, time win32con import page_readwrite, mem_commit, mem_reserve, mem_release, process_all_access, wm_gettextlength, wm_gettext 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 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 lvitem record , write 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 syslistview32 control num_items = win32gui.sendmessage(hwnd, lvm_getitemcount) item_texts = [] 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 getedittext(hwnd): # buf_size = 1 + win32gui.sendmessage(hwnd, wm_gettextlength, 0, 0) # print(buf_size) # buffer = ' ' * buf_size # print(win32gui.sendmessage(hwnd, wm_gettext, buf_size, buffer)) # return buffer[:buf_size] #def getedittext2(hwnd): # api returns 16 bit characters buffer needs 1 more char null , twice 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 null char on end def _normalisetext(controltext): '''remove '&' characters, , lower case. useful matching control text.''' return controltext.lower().replace('&', '') def _windowenumerationhandler(hwnd, resultlist): '''pass win32gui.enumwindows() 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: # seems mean control *cannot* have child windows, # i.e. not container. return childhwnd, windowtext, windowclass in childwindows: descendentmatchinghwnds = searchchildwindows(childhwnd) if descendentmatchinghwnds: results += descendentmatchinghwnds if wantedtext , \ not _normalisetext(wantedtext) in _normalisetext(windowtext): continue if wantedclass , \ not windowclass == wantedclass: continue if selectionfunction , \ 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'): # 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 child in children: if (w.getclassname(child) == 'comboboxex32'): # address bar addr_children = list(set(searchchildwindows(child))) addr_child in addr_children: if (w.getclassname(addr_child) == 'edit'): addr_edit = addr_child pass elif (w.getclassname(child) == 'syslistview32'): # list control within window shows 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') item in readlistviewitems(file_view)] index = getselectedlistviewitem(file_view) selected_file = files[index] print('files: %s' % files) print('selected file: %s' % selected_file) print('path: %s' % path) print('file path: %s' % os.path.join(path, selected_file)) else: print('something went wrong - no file view found')
so keep checking if active window of class explorer window uses, iterates through children widgets find address bar , file list view. when extracts list of files listvies , requests selected index. gets , decodes text address bar.
@ bottom info combined give complete path, folder path, file name or combination thereof.
i have tested on windows xp python3.4, need install win32gui , win32 conn packages.
Comments
Post a Comment