使用 SendMessage 设置 TreeViewItem 复选框状态

用户1916778

我需要更改外部应用程序拥有的 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 总是返回零。

我在做什么错?

用户1916778

好的,感谢 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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

使用var设置复选框状态

使用JSX设置复选框默认状态的正确方法

设置状态不会更新下拉复选框-使用挂钩

使用 PHP 或 jQuery 设置 Bootstrap-Switch 复选框选中状态

使用jQuery设置复选框的“ checked”

是否可以在样式化组件中不使用三元的情况下根据复选框的状态设置复选框的子项样式?

如何设置未选中的复选框1选中复选框2并设置未选中的复选框2使用脚本选中复选框1时?

使用 nodejs 捕获复选框的状态

使用 setState 更改复选框的状态

使用复选框记住Gridview状态

如何使用getComponent()设置子组件的复选框setSelected()

使用 Javascript/Jquery 设置复选框的值

如何使用 wtforms 设置复选框标签的类?

使用jQuery和Boostrap设置复选框样式

Angular 2使用ngFor设置和绑定复选框

如何使用标签设置多个附加复选框的样式

如何使用CSS设置复选框样式

使用jquery设置复选框时遇到麻烦

使用Jquery设置复选框值的模型验证错误

仅使用CSS设置复选框的样式

无法使用CSS设置复选框样式?

如何使用python在jira中设置多复选框

如何使用php变量设置复选框的值?

如何使用 setStyle() 内联设置复选框的 css 样式

使用API SendMessage设置窗口大小

单击时,如何设置复选框为选中状态?

设置复选框状态时如何避免重建UI?

设置复选框为jQuery选中状态

React:如何为复选框数组设置动态状态