代码之家  ›  专栏  ›  技术社区  ›  Kenn Zelleriation

协助将commctrl命令移植到c#

  •  1
  • Kenn Zelleriation  · 技术社区  · 16 年前

    在C++应用程序中,我有一个指向第三方进程中运行的窗口的HWND。此窗口包含扩展COM TreeView控件的控件。我对获取此控件的检查状态感兴趣。
    我使用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:重新创建此代码。(

    建议?

    2 回复  |  直到 16 年前
        1
  •  2
  •   Frank Krueger    16 年前

    我们有以下来自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_用户+消息。当这些消息跨进程发送时,数据参数的地址 未被修改,由此产生的进程可能导致访问冲突。不管怎样,这都是个问题 你使用的语言(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
  •  1
  •   Mike Dimmick    16 年前

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

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