C# 使用win32 api获取Treeview(SYSTREView32)项目文本

C# 使用win32 api获取Treeview(SYSTREView32)项目文本,c#,winapi,sendmessage,win32gui,C#,Winapi,Sendmessage,Win32gui,我正在编写一个应用程序来自动化我工作中的一些重复任务。 我希望完成的任务之一是能够自动执行在windows 10中从“RecoveryDrive.exe”创建恢复驱动器的过程。所有过程都已完成,但在一个步骤中,用户需要在SYSTREVIEW32控件中选择驱动器 我试图找到如何获取当前选定树的文本 我拥有控件的句柄,但当我尝试使用在线找到的代码示例读取它时,recoveryDrive应用程序崩溃 我怀疑这与64位/32位与我使用的api方法不匹配有关,可能与ASCI和Unicode编码不匹配有关。

我正在编写一个应用程序来自动化我工作中的一些重复任务。 我希望完成的任务之一是能够自动执行在windows 10中从“RecoveryDrive.exe”创建恢复驱动器的过程。所有过程都已完成,但在一个步骤中,用户需要在SYSTREVIEW32控件中选择驱动器

我试图找到如何获取当前选定树的文本

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

我怀疑这与64位/32位与我使用的api方法不匹配有关,可能与ASCI和Unicode编码不匹配有关。。。我还认为我需要在目标应用程序句柄或内存中使用LocalAlloc

它也有我基于代码的3页。当我使用sendMessage时,GetTreeItemText函数中的应用程序崩溃

我在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;
            }
public静态字符串GetTreeItemText(IntPtr treeViewHwnd,IntPtr hItem)
{
int ret;
TviItem tvi=新的TviItem();
IntPtr pszText=LocalAlloc(0x40,MY_MAXLVITEMTEXT);
tvi.mask=TVIF_文本;
tvi.hItem=hItem;
tvi.cchTextMax=MY_MAXLVITEMTEXT;
tvi.pszText=pszText;
ret=SendMessageTVI(树视图,TVM\U获取项,0,参考tvi);
字符串缓冲区=Marshal.PtrToStringUni((IntPtr)tvi.pszText,
我的_MAXLVITEMTEXT);

//char[]arr=buffer.ToCharArray();//TVM_GETITEM
消息的
LPRAM
是指向
TVTItem
结构的指针。问题是,必须在拥有TreeView控件的同一进程中分配该结构。因此,当跨进程边界发送
TVM_GETITEM
时,必须使用来分配
TVTItem
及其
pszText
在目标进程的地址空间中缓冲,然后使用/写入/读取该结构的数据

尝试类似的方法(您可以在以下位置找到Win32 API函数的声明):

public静态字符串GetTreeItemText(IntPtr treeViewHwnd,IntPtr hItem)
{
字符串项文本;
uint-pid;
GetWindowThreadProcessId(树视图,输出pid);
IntPtr process=OpenProcess(ProcessAccessFlags.VirtualMemoryOperation | ProcessAccessFlags.VirtualMemoryRead | ProcessAccessFlags.VirtualMemoryWrite | ProcessAccessFlags.QueryInformation,false,pid);
if(进程==IntPtr.Zero)
抛出新异常(“无法打开TreeView所属进程的句柄”,new Win32Exception());
尝试
{
uint tviSize=封送处理大小(类型(TVITEM));
uint textSize=MY_MAXLVITEMTEXT;
bool-isUnicode=IsWindowUnicode(treeViewHwnd);
如果(isUnicode)
textSize*=2;
IntPtr-tviPtr=VirtualAllocEx(进程,IntPtr.Zero,tviSize+textSize,AllocationType.Commit,MemoryProtection.ReadWrite);
if(tviPtr==IntPtr.Zero)
抛出新异常(“无法在TreeView的拥有进程中分配内存”,new Win32Exception());
尝试
{
IntPtr textPtr=IntPtr.Add(tviPtr,tviSize);
TviItem tvi=新的TviItem();
tvi.mask=TVIF_文本;
tvi.hItem=hItem;
tvi.cchTextMax=MY_MAXLVITEMTEXT;
tvi.pszText=textPtr;
IntPtr ptr=Marshal.AllocHGlobal(tviSize);
尝试
{
Marshal.StructureToPtr(tvi、ptr、false);
if(!WriteProcessMemory(进程、tviPtr、ptr、tviSize、IntPtr.Zero))
抛出新异常(“无法在TreeView的拥有进程中写入内存”,new Win32Exception());
}
最后
{
弗里赫全球元帅(ptr);
}
if(SendMessage(treeViewHwnd,isUnicode?TVM_GETITEMW:TVM_GETITEMA,0,tviPtr)!=1)
抛出新异常(“无法从TreeView获取项目数据”);
ptr=Marshal.AllocHGlobal(textSize);
尝试
{
int字节读取;
if(!ReadProcessMemory(进程、文本ptr、ptr、文本大小、输出字节读取))
抛出新异常(“在TreeView的拥有进程中无法从内存读取”,new Win32Exception());
如果(isUnicode)
itemText=Marshal.PtrToStringUni(ptr,字节读/2);
其他的
itemText=Marshal.PtrToStringAnsi(ptr,bytesRead);
}
最后
{
弗里赫全球元帅(ptr);
}
}
最后
{
VirtualFreeEx(进程,tviPtr,0,FreeType.Release);
}
}
最后
{
闭柄(过程);
}

//char[]arr=itemText.ToCharArray();//为什么不使用UIAutomation?您在另一个进程中访问内存,必须使用
VirtualAllocEx
分配内存。调用方和目标之间的32位/64位匹配也很重要。ANSI/Unicode匹配不重要(我认为只要源应用程序是Unicode就可以)在C#中,与此方法相比,使用UI自动化应该要容易得多。我认为只有核心消息会自动封送,因此在控件上使用跨进程SendMessage将不起作用。@Bughlehad它确实起作用,您只需手动封送内存缓冲区相关:代码的容器!它看起来会起作用。我没有找到正确的方法WriteProcessMemory和ReadProcessMemory.and Marshal.SizeOf(TVTItem)的声明引发错误:“TVTItem”是一种类型,在给定上下文中无效。如果您能提供帮助,我将能够对其进行测试:)@Benoit声明位于。
封送
具有以a作为输入的a。我只是忘记了
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;
}