2016-05-28 10 views
1

thisをPython 2.7で実行しようとしています。私はC#hereで答えを見つけましたが、Pythonで問題を再現しています。答えはhereが私が理解している概念を説明していると示唆しましたが、私はそれをどのように進めるのか考えていません。Python - 現在のWindowsエクスプローラで選択したファイルのパスを取得

基本的にファイルをマークし、Winkey + Cキーを押してパスをコピーするだけです。私はホットキーの部分(pyhk、Win32 [RegisterHotKey])を行う方法を知っていますが、私の問題はファイルパスで解決しています。

ありがとうございます!

答えて

0

申し訳ありませんが、達成しようとしているのは、ファイルが選択された複数のエクスプローラウィンドウ、複数のディスプレイ、さらに複数のターミナルセッションを同じマシン上で実行できるためです。

2

それは周りのハッキングの多くがかかりますが、大まかな解決策は以下の通りです:

#!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 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 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)] 
       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') 

アクティブウィンドウがクラスであればそう何これが行うことを反復処理し、その後、エクスプローラウィンドウを使用してチェックしておくれます子ウィジェットを使用してアドレスバーとファイルリストビューを検索します。リストからファイルのリストを抽出し、選択された索引を要求するとき。アドレスバーからテキストを取得してデコードします。
最後に、情報が結合されて完全なパス、フォルダパス、ファイル名、またはそれらの任意の組み合わせが与えられます。

私はこれをWindows XPでpython3.4でテストしましたが、win32guiとwin32 connパッケージをインストールする必要があります。

+1

また、ファイルエクスプローラを開いてデスクトップをポイントしない限り、これはアドレスバーからパスをプルするため、デスクトップ上では機能しません。現在は単一のファイル選択のみを処理しています –

関連する問題