Получить текст Treeview (SysTreeView32) элементов, используя Win32 API - PullRequest
0 голосов
/ 02 мая 2018

Я пишу приложение, чтобы автоматизировать некоторые повторяющиеся задачи на моей работе. Одна из задач, которую я хочу выполнить, - это возможность автоматизировать процесс создания диска восстановления из «RecoveryDrive.exe» в Windows 10. Весь процесс завершен, но на одном этапе человеку нужно выбрать диск. в элементе управления SysTreeView32.

Я попытался найти, как получить текст текущего выбранного TreeNodeItem.

У меня есть дескриптор элемента управления, но когда я пытаюсь прочитать его, используя пример кода, найденный в Интернете, происходит сбой приложения recoveryDrive.

Я подозреваю, что это связано с несовпадением 64-бит / 32-бит с используемыми мной методами API и, возможно, с несовпадением кодировки ASCI и Unicode ... Я также думаю, что мне нужно использовать LocalAlloc внутри целевого приложения.

здесь - вставка кода в текущем состоянии .

У этого также есть 3 страницы, от которых я основал свой код. Сбой приложения в функции GetTreeItemText при использовании sendMessage.

Я нашел пример того, как сделать это в C ++, но я не совсем понимаю.

 public static string GetTreeItemText(IntPtr treeViewHwnd, IntPtr hItem)
            {
                int ret;
                TVITEM tvi = new TVITEM();
                IntPtr pszText = LocalAlloc(0x40, MY_MAXLVITEMTEXT);

                tvi.mask = TVIF_TEXT;
                tvi.hItem = hItem;
                tvi.cchTextMax = MY_MAXLVITEMTEXT;
                tvi.pszText = pszText;

                ret = SendMessageTVI(treeViewHwnd, TVM_GETITEM, 0, ref tvi);
                string buffer = Marshal.PtrToStringUni((IntPtr)tvi.pszText,
                MY_MAXLVITEMTEXT);

                //char[] arr = buffer.ToCharArray(); //<== use this array to look at the bytes in debug mode

                LocalFree(pszText);
                return buffer;
            }

1 Ответ

0 голосов
/ 02 мая 2018

LPARAM сообщения TVM_GETITEM является указателем на структуру TVITEM. Дело в том, что структура ДОЛЖНА быть размещена в том же процессе, который владеет элементом управления TreeView. Таким образом, при отправке TVM_GETITEM через границы процесса вы должны использовать VirtualAllocEx() для выделения TVITEM и его pszText буфера в адресном пространстве целевого процесса, а затем использовать WriteProcessMemory() / ReadProcessMemory() для записи / чтения данных этой структуры.

Попробуйте что-то вроде этого (вы можете найти объявления для функций Win32 API, используемых в PInvoke.net ):

public static string GetTreeItemText(IntPtr treeViewHwnd, IntPtr hItem)
{
    string itemText;

    uint pid;
    GetWindowThreadProcessId(treeViewHwnd, out pid);

    IntPtr process = OpenProcess(ProcessAccessFlags.VirtualMemoryOperation | ProcessAccessFlags.VirtualMemoryRead | ProcessAccessFlags.VirtualMemoryWrite | ProcessAccessFlags.QueryInformation, false, pid);
    if (process == IntPtr.Zero)
        throw new Exception("Could not open handle to owning process of TreeView", new Win32Exception());

    try
    {
        uint tviSize = Marshal.SizeOf(typeof(TVITEM));

        uint textSize = MY_MAXLVITEMTEXT;
        bool isUnicode = IsWindowUnicode(treeViewHwnd);
        if (isUnicode)
            textSize *= 2;

        IntPtr tviPtr = VirtualAllocEx(process, IntPtr.Zero, tviSize + textSize, AllocationType.Commit, MemoryProtection.ReadWrite);
        if (tviPtr == IntPtr.Zero)
            throw new Exception("Could not allocate memory in owning process of TreeView", new Win32Exception());

        try
        {
            IntPtr textPtr = IntPtr.Add(tviPtr, tviSize);

            TVITEM tvi = new TVITEM();
            tvi.mask = TVIF_TEXT;
            tvi.hItem = hItem;
            tvi.cchTextMax = MY_MAXLVITEMTEXT;
            tvi.pszText = textPtr;

            IntPtr ptr = Marshal.AllocHGlobal(tviSize);
            try
            {
                Marshal.StructureToPtr(tvi, ptr, false);
                if (!WriteProcessMemory(process, tviPtr, ptr, tviSize, IntPtr.Zero))
                    throw new Exception("Could not write to memory in owning process of TreeView", new Win32Exception());
            }
            finally
            {
                Marshal.FreeHGlobal(ptr);
            }

            if (SendMessage(treeViewHwnd, isUnicode ? TVM_GETITEMW : TVM_GETITEMA, 0, tviPtr) != 1)
                throw new Exception("Could not get item data from TreeView");

            ptr = Marshal.AllocHGlobal(textSize);
            try
            {
                int bytesRead;
                if (!ReadProcessMemory(process, textPtr, ptr, textSize, out bytesRead))
                    throw new Exception("Could not read from memory in owning process of TreeView", new Win32Exception());

                if (isUnicode)
                    itemText = Marshal.PtrToStringUni(ptr, bytesRead / 2);
                else
                    itemText = Marshal.PtrToStringAnsi(ptr, bytesRead);
            }
            finally
            {
                Marshal.FreeHGlobal(ptr);
            }
        }
        finally
        {
            VirtualFreeEx(process, tviPtr, 0, FreeType.Release);
        }
    }
    finally
    {
        CloseHandle(process);
    }

    //char[] arr = itemText.ToCharArray(); //<== use this array to look at the bytes in debug mode

    return itemText;
}
...