我试图在桌面上移动图标,一切都很好,直到select了图片旋转的主题。 使用基本的Windows 7主题, SysListView32
是SHELLDLL_DefView
子代,而SHELLDLL_DefView
又是Progman
。
但是,当选取图片旋转桌面主题时, SysListView32
变成SHELLDLL_DefView
子WorkerW
,而SHELLDLL_DefView
又变成了WorkerW
子WorkerW
。 有超过1个。我应该如何去寻找正确的HWND指向正确的WorkerW
。 枚举所有的桌面窗口,并检查每个类名WorkerW?
[DllImport("user32.dll", SetLastError = true)] static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd); [DllImport("user32.DLL")] public static extern IntPtr FindWindowEx(IntPtr hwndParent,IntPtr hwndChildAfter, string lpszClass, string lpszWindow); [DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindow(string lpClassName, string lpWindowName); enum GetWindow_Cmd : uint { GW_HWNDFIRST = 0, GW_HWNDLAST = 1, GW_HWNDNEXT = 2, GW_HWNDPREV = 3, GW_OWNER = 4, GW_CHILD = 5, GW_ENABLEDPOPUP = 6 }
在我的main()
例如,我做了以下调用:
IntPtr HWND = FindWindow("Progman",null); HWND = GetWindow(HWND, GetWindow_Cmd.GW_CHILD); HWND = GetWindow(HWND, GetWindow_Cmd.GW_CHILD);
非常感谢Hans在他的机器上试用这个功能,而对于Sertac来说,SysListView32将父母从“Progman”变成了“WorkerW”类名。 我的解决方案是首先尝试在Progman的孩子里面找到SysListView32:
hwndIcon = NativeMethods.FindWindow("Progman", null); hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SHELLDLL_DefView", null); hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SysListView32", "FolderView");
如果hwndIcon返回IntPtr.Zero,我尝试枚举桌面下的所有窗口,然后找到那些类名为“WorkerW”(我在委托GetSysListViewContainer(…))中执行此操作,我发现“唯一的一,“即。 有一个孩子的那个。 这是包含SHELLDLL_DefView,其本身包含SysListView32,其本身包含桌面上的每个图标的句柄:
hwndIcon = NativeMethods.FindWindow("Progman", null); hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SHELLDLL_DefView", null); hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SysListView32", "FolderView"); if (hwndIcon == IntPtr.Zero) { IntPtr hDesktop = NativeMethods.GetDesktopWindow(); IntPtr hwnd = IntPtr.Zero; EnumWindowsProc ewp = new EnumWindowsProc(GetSysListViewContainer); EnumWindows(ewp, 0); hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SHELLDLL_DefView", null); hwndIcon = NativeMethods.FindWindowEx(hwndIcon, IntPtr.Zero, "SysListView32", "FolderView"); }
随着以下我得到一个桌面图标计数:
int vItemCount = NativeMethods.SendMessage(hwndIcon, LVM_GETITEMCOUNT, 0, 0); string vText; int vProcessId = 0;
并通过这个我遍历所有的图标:
NativeMethods.GetWindowThreadProcessId(hwndIcon, ref vProcessId); IntPtr vProcess = NativeMethods.OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, vProcessId); IntPtr foo = IntPtr.Zero; IntPtr vPointer = NativeMethods.VirtualAllocEx(vProcess, IntPtr.Zero, sizeof(uint), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); for (int j = 0; j < vItemCount; j++) { byte[] vBuffer = new byte[256]; LVITEM[] vItem = new LVITEM[1]; vItem[0].mask = LVIF_TEXT; vItem[0].iItem = j; vItem[0].iSubItem = 0; vItem[0].cchTextMax = vBuffer.Length; vItem[0].pszText = (IntPtr)((int)vPointer + Marshal.SizeOf(typeof(LVITEM))); uint vNumberOfBytesRead = 0; WriteProcessMemory(vProcess, vPointer, Marshal.UnsafeAddrOfPinnedArrayElement(vItem, 0), Marshal.SizeOf(typeof(LVITEM)), ref vNumberOfBytesRead); SendMessage(hwndIcon, LVM_GETITEMW, j, vPointer.ToInt32()); ReadProcessMemory(vProcess, (IntPtr)((int)vPointer + Marshal.SizeOf(typeof(LVITEM))), Marshal.UnsafeAddrOfPinnedArrayElement(vBuffer, 0), vBuffer.Length, out vNumberOfBytesRead); // Get the name of the Icon vText = Encoding.Unicode.GetString(vBuffer, 0, (int)vNumberOfBytesRead); // Get Icon location SendMessage(hwndIcon, LVM_GETITEMPOSITION, j, vPointer.ToInt32()); Point[] vPoint = new Point[1]; foo = Marshal.UnsafeAddrOfPinnedArrayElement(vPoint, 0); ReadProcessMemory(vProcess, vPointer, Marshal.UnsafeAddrOfPinnedArrayElement(vPoint, 0), Marshal.SizeOf(typeof(Point)), out vNumberOfBytesRead); //and ultimaely move icon. SendMessage(hwndIcon, LVM_SETITEMPOSITION, j, lParam[0]);
所以要回顾一下,我需要弄清楚为什么我无法得到所有桌面图标存储在Windows中的listview容器的句柄。 当没有背景旋转的时候,原来的代码我工作得很好,但是没有得到ListSysView32的句柄。
有没有更好的方式从.Net做到这一点? KJ
这是一个丑陋的,简单的方法来得到一个SysListView32
的处理程序(C ++代码)
HWND hWndLV = ::GetShellWindow(); hWndLV = ::GetNextWindow( ::GetNextWindow(hWndLV, GW_HWNDPREV), GW_HWNDPREV); hWndLV = ::GetFirstChild(hWndLV); hWndLV = ::GetNextWindow(hWndLV, GW_HWNDNEXT); hWndLV = ::GetFirstChild(hWndLV);