使用 win32 获取 Treeview(SysTreeView32) 项目文本 api
Get Treeview(SysTreeView32) items text using win32 api
我正在编写一个应用程序来自动执行我工作中的一些重复性任务。
我希望完成的任务之一是能够自动执行从 "RecoveryDrive.exe" 在 windows 10 中创建恢复驱动器的过程。所有过程都已完成,但在一个步骤中,人类需要select SysTreeView32 控件中的驱动器。
我试图找到如何获取当前 selected treeNodeItem 的文本。
我有控件的句柄,但是当我尝试使用在线找到的代码示例读取它时,recoveryDrive 应用程序崩溃了。
我怀疑这与 64 位/32 位与我正在使用的 api 方法不匹配以及可能 ASCI 和 Unicode 编码不匹配有关......我还认为我需要在内部使用 LocalAlloc目标应用程序句柄或内存
here is the pasteBin of the code in the present state.
它还有我的代码所基于的第 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;
}
TVM_GETITEM
消息的 LPARAM
是指向 TVITEM
结构的指针。问题是,该结构必须在拥有 TreeView 控件的同一进程中分配。因此,当跨进程边界发送 TVM_GETITEM
时,您必须使用 VirtualAllocEx()
to allocate the TVITEM
and its pszText
buffer in the address space of the target process, and then use WriteProcessMemory()
/ReadProcessMemory()
到 write/read 该结构的数据。
尝试这样的事情(您可以找到 PInvoke.net 中使用的 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;
}
我正在编写一个应用程序来自动执行我工作中的一些重复性任务。 我希望完成的任务之一是能够自动执行从 "RecoveryDrive.exe" 在 windows 10 中创建恢复驱动器的过程。所有过程都已完成,但在一个步骤中,人类需要select SysTreeView32 控件中的驱动器。
我试图找到如何获取当前 selected treeNodeItem 的文本。
我有控件的句柄,但是当我尝试使用在线找到的代码示例读取它时,recoveryDrive 应用程序崩溃了。
我怀疑这与 64 位/32 位与我正在使用的 api 方法不匹配以及可能 ASCI 和 Unicode 编码不匹配有关......我还认为我需要在内部使用 LocalAlloc目标应用程序句柄或内存
here is the pasteBin of the code in the present state.
它还有我的代码所基于的第 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;
}
TVM_GETITEM
消息的 LPARAM
是指向 TVITEM
结构的指针。问题是,该结构必须在拥有 TreeView 控件的同一进程中分配。因此,当跨进程边界发送 TVM_GETITEM
时,您必须使用 VirtualAllocEx()
to allocate the TVITEM
and its pszText
buffer in the address space of the target process, and then use WriteProcessMemory()
/ReadProcessMemory()
到 write/read 该结构的数据。
尝试这样的事情(您可以找到 PInvoke.net 中使用的 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;
}