【问题标题】:Assistance porting commctrl commands to C#协助将 commctrl 命令移植到 C#
【发布时间】:2010-09-09 20:10:29
【问题描述】:

在 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,比较陌生。

我已尝试使用 .NET mscomctl,但找不到与 TreeView_GetRoot 或 TreeView_GetCheckState 等效的方法。我完全被卡住了,不知道如何在 C# 中重新创建这段代码:(

建议?

【问题讨论】:

    标签: c# com treeview


    【解决方案1】:

    我们从 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;
    }
    }
    

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 窗口归第三方所有。我无法控制它。此应用的开发者选择使用 COM 对象的扩展来实现控件。
      猜你喜欢
      • 2011-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-17
      • 2011-12-17
      • 1970-01-01
      • 2012-08-15
      • 1970-01-01
      相关资源
      最近更新 更多