我需要更改外部应用程序拥有的 TreeView(确切地说是“SysTreeView32”)项目中的复选框状态 - 用于自动化目的。我已经有了 TreeView 句柄和 TreeViewItem 句柄。我还找到了一些如何设置复选框状态的示例,但由于某种原因,它不起作用(SendMessage 返回 0 或使整个应用程序崩溃)。但是对于代码。我已经尝试过的是:
TVITEM 结构:
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]
internal struct TVITEM
{
public int mask;
public IntPtr hItem;
public int state;
public int stateMask;
[MarshalAs(UnmanagedType.LPTStr)]
public string pszText;
public int cchTextMax;
public int iImage;
public int iSelectedImage;
public int cChildren;
public IntPtr lParam;
}
SendMessage 的 pinvoke:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, ref TVITEM lParam);
还有我的方法:
internal static void SetTreeNodeState(int treeViewHandler, int treeViewItemHandler, bool state)
{
TVITEM tvItem = new TVITEM();
tvItem.mask = TVIF_STATE | TVIF_HANDLE;
tvItem.hItem = (IntPtr)treeViewItemHandler;
tvItem.stateMask = TVIS_STATEIMAGEMASK;
tvItem.state = (state ? 2 : 1) << 12;
var result = SendMessage((IntPtr)treeViewHandler, TVM_SETITEMW, IntPtr.Zero, ref tvItem);
}
这是最接近的方法(我认为,最后我没有使目标应用程序崩溃一次)。当然,我已经尝试使用 Spy++ 嗅探目标树视图的消息。我担心的是,Spy++ 显示 SendMessage 的 LParam 实际上是“TVITEMEXW”,但我可以找到有关该结构的任何信息。
通常我也尝试过与 TVM_GETITEMW 相同的想法,但是我没有使应用程序崩溃,SendMessage 总是返回零。
我在做什么错?
好的,感谢 David Heffernan,我想通了。我为 SendMessage 创建了重载,它通过 ref 接受 lParam 作为对象:
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, Int32 nSize, out IntPtr lpNumberOfBytesRead);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, AllocationType dwFreeType);
private static IntPtr SendMessage<T>(Process process, IntPtr hWnd, int msg, int wParam, ref T lParam)
{
uint size = (uint)Marshal.SizeOf(lParam);
byte[] buffer = new byte[size];
IntPtr processHandle = process.Handle;
IntPtr pPointer = VirtualAllocEx(processHandle, IntPtr.Zero, size, AllocationType.Commit | AllocationType.Reserve, MemoryProtection.ReadWrite);
IntPtr inputPtr = Marshal.AllocHGlobal((int)size);
IntPtr outputPtr = Marshal.AllocHGlobal((int)size);
Marshal.StructureToPtr(lParam, inputPtr, false);
WriteProcessMemory(processHandle, pPointer, inputPtr, size, out UIntPtr nNbBytesWritten);
IntPtr resultPtr = SendMessage(hWnd, msg, wParam, pPointer);
ReadProcessMemory(processHandle, pPointer, buffer, buffer.Length, out IntPtr nNbBytesRead);
Marshal.Copy(buffer, 0, outputPtr, (int)size);
T result = Marshal.PtrToStructure<T>(outputPtr);
lParam = result;
Marshal.FreeHGlobal(inputPtr);
Marshal.FreeHGlobal(outputPtr);
VirtualFreeEx(processHandle, pPointer, 0, AllocationType.Release);
return resultPtr;
}
使用示例
为给定的树视图项设置复选框状态:
internal static void SetTreeNodeState(IntPtr treeViewHandle, IntPtr treeViewItemHandle, bool state)
{
TVITEM tvItem = new TVITEM
{
mask = TVIF_STATE | TVIF_HANDLE,
hItem = treeViewItemHandle,
stateMask = TVIS_STATEIMAGEMASK,
state = (uint)(state ? 2 : 1) << 12
};
Process process = Process.GetProcessesByName("ProcessName")[0];
IntPtr ptr = SendMessage(process, treeViewHandle, TVM_SETITEMW, 0, ref tvItem);
}
获取给定树视图项的复选框状态:
internal static bool GetTreeNodeState( IntPtr treeViewHandle, IntPtr treeViewItemHandle)
{
TVITEM tvItem = new TVITEM
{
mask = TVIF_STATE | TVIF_HANDLE,
hItem = treeViewItemHandle,
stateMask = TVIS_STATEIMAGEMASK,
state = 0
};
Process process = Process.GetProcessesByName("ProcessName")[0];
IntPtr ptr = SendMessage(process, treeViewHandle, TVM_GETITEMW, 0, ref tvItem);
if (ptr != IntPtr.Zero)
{
uint iState = tvItem.state >> 12;
return iState == 2 ? true : false;
}
return false;
}
电视项目:
[StructLayout(LayoutKind.Sequential)]
internal struct TVITEM
{
public uint mask;
public IntPtr hItem;
public uint state;
public uint stateMask;
public IntPtr pszText;
public int cchTextMax;
public int iImage;
public int iSelectedImage;
public int cChildren;
public IntPtr lParam;
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句