Управление значками на рабочем столе - как получить дескриптор SysListView32, когда включены темы с поворотом изображения - PullRequest
2 голосов
/ 29 января 2011

Я пытаюсь перемещать значки по рабочему столу, все работает хорошо, пока не выбрана тема с поворотом изображения. В базовой теме Windows 7 SysListView32 является дочерним по отношению к SHELLDLL_DefView, что, в свою очередь, является дочерним по отношению к Progman.

Но когда выбрана тема рабочего стола с поворотом изображения, SysListView32 становится дочерним для SHELLDLL_DefView, который, в свою очередь, становится дочерним для 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);

Ответы [ 2 ]

3 голосов
/ 29 января 2011

Большое спасибо Гансу за то, что он попробовал это на своем компьютере, и за Sertac за подсказку, что SysListView32 меняет родителей с «Progman» на имя класса «WorkerW».Мое решение состояло в том, чтобы сначала попытаться найти SysListView32 в дочерних элементах Progman:

       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,Исходный код, который я работал хорошо, когда не было фонового вращения, но не смог получить дескриптор ListSysView32, когда был.

Есть ли лучший способ сделать это из .Net?кдж

0 голосов
/ 30 января 2013

Это ужасный и простой способ получить обработчик для SysListView32 (код C ++)

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