在 C++ 应用程序中,我有一个 hWnd 指向在第三方进程中运行的窗口。该窗口包含扩展 COM TreeView 控件的控件。我有兴趣获取该控件的 CheckState。
我使用 hWnd 从 commctrl.h 中使用 TreeView_GetRoot(hwnd) 获取 HTREEITEM

hwnd 指向窗口,hItem 是 TreeView_GetRoot(hwnd) 的返回值。它们的用法如下:

int iCheckState = TreeView_GetCheckState(hwnd,  hItem);
switch (iCheckState)
{
   case 0:
      // (unchecked)
   case 1:
      // checked
   ...
}

我希望将此代码移植到执行相同操作的 C# 应用程序中(关闭 TreeView 控件的 CheckState)。我没用过COM,对COM比较陌生。

我尝试使用 .NET mscomctl 但找不到与 TreeView_GetRoot 或 TreeView_GetCheckState 等效的方法。我完全陷入困境,不知道如何在 C# 中重新创建此代码:(

建议?

有帮助吗?

解决方案

我们从 CommCtrl.h 中得到了这些定义:

#define TreeView_SetItemState(hwndTV, hti, data, _mask) \
{ TVITEM _ms_TVi;\
  _ms_TVi.mask = TVIF_STATE; \
  _ms_TVi.hItem = (hti); \
  _ms_TVi.stateMask = (_mask);\
  _ms_TVi.state = (data);\
  SNDMSG((hwndTV), TVM_SETITEM, 0, (LPARAM)(TV_ITEM *)&_ms_TVi);\
}

#define TreeView_SetCheckState(hwndTV, hti, fCheck) \
  TreeView_SetItemState(hwndTV, hti, INDEXTOSTATEIMAGEMASK((fCheck)?2:1), TVIS_STATEIMAGEMASK)

我们可以使用 PInvoke 将其转换为 C#。首先,我们将这些宏作为功能实现,然后添加需要其他支持以使这些功能正常工作。这是我的第一次尝试。您应该仔细检查我的代码,尤其是在结构的编组时。此外,您可能需要发布消息跨线程而不是调用sendmessage。

最后,我不确定这是否会起作用,因为我相信通用控件使用wm_user+消息。当这些消息发送交叉过程时,数据参数的地址将未修改,并且结果过程可能会导致访问违规。无论您使用什么语言(C ++或C#),这都是一个问题,所以也许我在这里错(您说您有一个工作C ++程序)。

static class Interop {

public static IntPtr TreeView_SetCheckState(HandleRef hwndTV, IntPtr hti, bool fCheck) {
    return TreeView_SetItemState(hwndTV, hti, INDEXTOSTATEIMAGEMASK((fCheck) ? 2 : 1), (uint)TVIS.TVIS_STATEIMAGEMASK);
}

public static IntPtr TreeView_SetItemState(HandleRef hwndTV, IntPtr hti, uint data, uint _mask) {
    TVITEM _ms_TVi = new TVITEM();
    _ms_TVi.mask = (uint)TVIF.TVIF_STATE;
    _ms_TVi.hItem = (hti);
    _ms_TVi.stateMask = (_mask);
    _ms_TVi.state = (data);
    IntPtr p = Marshal.AllocCoTaskMem(Marshal.SizeOf(_ms_TVi));
    Marshal.StructureToPtr(_ms_TVi, p, false);
    IntPtr r = SendMessage(hwndTV, (int)TVM.TVM_SETITEMW, IntPtr.Zero, p);
    Marshal.FreeCoTaskMem(p);
    return r;
}

private static uint INDEXTOSTATEIMAGEMASK(int i) { return ((uint)(i) << 12); }

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(HandleRef hWnd, int msg, IntPtr wParam, IntPtr lParam);

private enum TVIF : uint {
    TVIF_STATE = 0x0008
}

private enum TVIS : uint {
    TVIS_STATEIMAGEMASK = 0xF000
}

private enum TVM : int {
    TV_FIRST = 0x1100,
    TVM_SETITEMA = (TV_FIRST + 13),
    TVM_SETITEMW = (TV_FIRST + 63)
}

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

其他提示

为什么不使用 Windows 窗体 TreeView 控件?如果您使用此控件,请将控件的 CheckBoxes 属性设置为 true 以启用复选框,并在要显示为选中的节点上设置 Checked 属性。

要获取根节点的集合,请使用 TreeView 的 Nodes 属性。这将返回一个 TreeNodeCollection,然后您可以为其建立索引或添加项目。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top