使用win32 api获取Treeview(SysTreeView32)项目文本

时间:2018-05-02 04:02:37

标签: c# winapi sendmessage win32gui

我正在编写一个应用程序,以便在我的工作中自动完成一些重复性任务。 我希望做的任务之一是能够自动执行从Windows 10中的“RecoveryDrive.exe”创建恢复驱动器的过程。所有过程都已完成,但只需一步,人类需要选择驱动器在SysTreeView32控件中。

我试图找到如何获取当前所选treeNodeItem的文本。

我有控件的句柄,但是当我尝试阅读它时,使用在线找到的代码示例,recoveryDrive应用程序崩溃了。

我怀疑这与我正在使用的api方法与64位/ 32位不匹配可能与ASCI和Unicode编码不匹配...我还认为我需要在目标应用程序内部使用LocalAlloc处理或内存

here is the pasteBin of the code in the present state

它还有我根据代码编写的3页。当我使用sendMessage时,应用程序在GetTreeItemText函数中崩溃。

我已经找到了一些关于如何在C ++中执行此操作的示例,但我并不理解它。

private static final String supportedCharacters = "abc...";

Constraint passConstraint = new LengthConstraint(6, "Password invalid") {
   @Override
   public boolean isValid(Object value) {
       String s = (String)v;
       for(int i = 0 ; i < s.length() ; i++) {
          if(!supportedCharacters.contains(s.charAt(i)) return false;
       }
       return super.isValid(value) 
   }
};

1 个答案:

答案 0 :(得分:2)

LPARAM消息的TVM_GETITEM是指向TVITEM结构的指针。问题是,该结构必须在拥有TreeView控件的同一进程中分配。因此,在跨进程边界发送TVM_GETITEM时,必须使用VirtualAllocEx()在目标进程的地址空间中分配TVITEM及其pszText缓冲区,然后使用{ {3}} / WriteProcessMemory()来写/读取该结构的数据。

尝试这样的事情(你可以找到ReadProcessMemory()使用的Win32 API函数的声明):

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;
}