如何使用Python 2.7移动Windows桌面图标?

我正在尝试编写一个python例程来保存和恢复桌面图标位置。 我在Windows 7 x64上使用32位Python 2.7。 使用这里的信息(堆栈交换),我能够从Windows用来存储这个信息的外部进程列表视图中读取图标名称和位置,但是当使用LVM_SETITEMPOSITION设置新的位置(或者恢复位置)时,我失败了。 所有的图标最终都在桌面上的同一个位置。 “自动排列”和“alignment网格”closures。 相关的代码是底部。 警告:如果你运行这个代码所有的图标将在一堆:(

import ctypes class LVITEMW(ctypes.Structure): _fields_ = [ ('mask', ctypes.c_uint32), ('iItem', ctypes.c_int32), ('iSubItem', ctypes.c_int32), ('state', ctypes.c_uint32), ('stateMask', ctypes.c_uint32), ('pszText', ctypes.c_uint64), ('cchTextMax', ctypes.c_int32), ('iImage', ctypes.c_int32), ('lParam', ctypes.c_uint64), # On 32 bit should be c_long ('iIndent',ctypes.c_int32), ('iGroupId', ctypes.c_int32), ('cColumns', ctypes.c_uint32), ('puColumns', ctypes.c_uint64), ('piColFmt', ctypes.c_int64), ('iGroup', ctypes.c_int32), ] class POINT(ctypes.Structure): _fields_ = [('x', ctypes.c_int), ('y', ctypes.c_int)] def icon_save_restore(savedicons=None, restore=False): import struct, commctrl, win32gui, win32con, win32api dthwnd = win32gui.FindWindow(None, 'Program Manager') ukhwnd = win32gui.GetWindow(dthwnd, win32con.GW_CHILD) slvhwnd = win32gui.GetWindow(ukhwnd, win32con.GW_CHILD) pid = ctypes.create_string_buffer(4) p_pid = ctypes.addressof(pid) ctypes.windll.user32.GetWindowThreadProcessId(slvhwnd, p_pid) hProcHnd = ctypes.windll.kernel32.OpenProcess(win32con.PROCESS_ALL_ACCESS, False, struct.unpack("i",pid)[0]) pBuffertxt = ctypes.windll.kernel32.VirtualAllocEx(hProcHnd, 0, 4096, win32con.MEM_RESERVE|win32con.MEM_COMMIT, win32con.PAGE_READWRITE) copied = ctypes.create_string_buffer(4) p_copied = ctypes.addressof(copied) lvitem = LVITEMW() lvitem.mask = ctypes.c_uint32(commctrl.LVIF_TEXT) lvitem.pszText = ctypes.c_uint64(pBuffertxt) lvitem.cchTextMax = ctypes.c_int32(4096) lvitem.iSubItem = ctypes.c_int32(0) pLVI = ctypes.windll.kernel32.VirtualAllocEx(hProcHnd, 0, 4096, win32con.MEM_RESERVE| win32con.MEM_COMMIT, win32con.PAGE_READWRITE) win32api.SetLastError(0) ctypes.windll.kernel32.WriteProcessMemory(hProcHnd, pLVI, ctypes.addressof(lvitem), ctypes.sizeof(lvitem), p_copied) num_items = win32gui.SendMessage(slvhwnd, commctrl.LVM_GETITEMCOUNT) if restore is False: p = POINT() pBufferpnt = ctypes.windll.kernel32.VirtualAllocEx(hProcHnd, 0, ctypes.sizeof(p), win32con.MEM_RESERVE|win32con.MEM_COMMIT, win32con.PAGE_READWRITE) icons = {} for i in xrange(num_items): # Get icon text win32gui.SendMessage(slvhwnd, commctrl.LVM_GETITEMTEXT, i, pLVI) target_bufftxt = ctypes.create_string_buffer(4096) ctypes.windll.kernel32.ReadProcessMemory(hProcHnd, pBuffertxt, ctypes.addressof(target_bufftxt), 4096, p_copied) key = target_bufftxt.value # Get icon position win32api.SendMessage(slvhwnd, commctrl.LVM_GETITEMPOSITION, i, pBufferpnt) p = POINT() ctypes.windll.kernel32.ReadProcessMemory(hProcHnd, pBufferpnt, ctypes.addressof(p), ctypes.sizeof(p), p_copied) icons[key] = (i,p) ctypes.windll.kernel32.VirtualFreeEx(hProcHnd, pLVI, 0, win32con.MEM_RELEASE) ctypes.windll.kernel32.VirtualFreeEx(hProcHnd, pBuffertxt, 0, win32con.MEM_RELEASE) ctypes.windll.kernel32.VirtualFreeEx(hProcHnd, pBufferpnt, 0, win32con.MEM_RELEASE) win32api.CloseHandle(hProcHnd) return icons else: # RESTORE ICON POSITIONS PROBLEM IS HERE SOMEWHERE!!! win32gui.SendMessage(slvhwnd, win32con.WM_SETREDRAW, 0, 0) for i in xrange(num_items): # Get icon text win32gui.SendMessage(slvhwnd, commctrl.LVM_GETITEMTEXT, i, pLVI) target_bufftxt = ctypes.create_string_buffer(4096) ctypes.windll.kernel32.ReadProcessMemory(hProcHnd, pBuffertxt, ctypes.addressof(target_bufftxt), 4096, p_copied) key = target_bufftxt.value if key in savedicons.keys(): # Set icon position p = savedicons[key][1] # p is ctypes POINT p_lng = point_to_long(p) # explicitly convert to HIWORD/LOWORD and c_long # Reserve space for input variable in foreign process and get pointer to it the that memory space pBufferpnt = ctypes.windll.kernel32.VirtualAllocEx(hProcHnd, 0, ctypes.sizeof(p_lng), win32con.MEM_RESERVE|win32con.MEM_COMMIT, win32con.PAGE_READWRITE) # Write the desired coordinates in to the space just created ret = ctypes.windll.kernel32.WriteProcessMemory(hProcHnd, pBufferpnt, ctypes.addressof(p_lng), ctypes.sizeof(p_lng), p_copied) if ret == 0: raise WindowsError # Send the message to change the position for that item's index and the pointer to the new position ret = win32gui.SendMessage(slvhwnd, commctrl.LVM_SETITEMPOSITION, i, pBufferpnt) if ret == 0: raise WindowsError # Release the reserved memory for the variable (I recognize that I probably don't need to aLloc/free this within the loop) ctypes.windll.kernel32.VirtualFreeEx(hProcHnd, pBufferpnt, 0, win32con.MEM_RELEASE) win32gui.SendMessage(slvhwnd, win32con.WM_SETREDRAW, 1, 0) ctypes.windll.kernel32.VirtualFreeEx(hProcHnd, pLVI, 0, win32con.MEM_RELEASE) ctypes.windll.kernel32.VirtualFreeEx(hProcHnd, pBuffertxt, 0, win32con.MEM_RELEASE) win32api.CloseHandle(hProcHnd) return None def point_to_long(p): ret = (py * 0x10000) + (px & 0xFFFF) return ctypes.c_long(ret) if __name__ == '__main__': mysavedicons = icon_save_restore(restore=False) icon_save_restore(mysavedicons, restore=True) 

我认为可能有1)与32位和64位内存地址空间有关的问题,但其他组件我写LVITEM结构或读取图标文本工作正常或2)有一些问题在我正在转换坐标信息或调用GETITEMPOSITION的SendMessage。 任何见解或帮助将不胜感激。

事实证明,有使用32位地址(LVM_SETITEMPOSITION32)的版本,我希望MSDN将在他们的文档中交叉引用: https ://msdn.microsoft.com/en-us/library/windows/desktop/bb761194 ( v = vs.85)的.aspx

这直接接受POINT结构,所以不需要尝试转换成HIWORD / LOWORD。 在发布之前,我确实尝试了使用32位移位和longlong(64位版本的long),这对LVM_SETITEMPOSITION不起作用。 无论如何,随着变化,一切都按预期工作。