桌面图标操作 - 如何在启用带图片旋转的主题时获取SysListView32的句柄

时间:2011-01-29 02:41:24

标签: c# windows winapi findwindow aero-glass

我正在尝试在桌面上移动图标,一切正常,直到选择了具有图片旋转的主题。对于基本的Windows 7主题,SysListView32SHELLDLL_DefView的孩子,而Progman的孩子又是SysListView32的孩子。

但是,当选择图片轮换桌面主题时,SHELLDLL_DefView会成为WorkerW的孩子,后者又成为WorkerW的孩子。有超过1.如何找到指向右[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 } 的正确HWND。枚举所有桌面窗口,并使用类名WorkerW检查每个窗口?

main()

例如,在我的IntPtr HWND = FindWindow("Progman",null); HWND = GetWindow(HWND, GetWindow_Cmd.GW_CHILD); HWND = GetWindow(HWND, GetWindow_Cmd.GW_CHILD); 中,我进行了以下调用:

{{1}}

2 个答案:

答案 0 :(得分:3)

非常感谢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,它本身包含桌面上每个Icon的句柄:

       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]);

所以回顾一下,我需要弄清楚为什么我无法获得listview容器的句柄,其中所有桌面图标都存储在Windows中。原始代码在没有背景旋转的情况下运行良好,但是当它存在时无法获得ListSysView32的句柄。

有没有更好的办法从.Net做到这一点? KJ

答案 1 :(得分:0)

这是获取SysListView32处理程序的丑陋而简单的方法(C ++代码)

HWND hWndLV = ::GetShellWindow();
hWndLV = ::GetNextWindow( ::GetNextWindow(hWndLV, GW_HWNDPREV), GW_HWNDPREV);
hWndLV = ::GetFirstChild(hWndLV);
hWndLV = ::GetNextWindow(hWndLV, GW_HWNDNEXT);
hWndLV = ::GetFirstChild(hWndLV);