协助将commctrl命令移植到C#
在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 ... }
我正在寻找将此代码移植到执行相同功能的Capp中(关闭TreeView控件的CheckState)。我从没使用过COM,因此很陌生。
我尝试使用.NET mscomctl,但是找不到与TreeView_GetRoot或者TreeView_GetCheckState等效的方法。我完全被卡住了,不知道如何在C :(
有什么建议吗?
解决方案
回答
为什么不使用Windows窗体TreeView控件?如果使用此控件,请将控件的CheckBoxes属性设置为true以启用复选框,然后在要显示为选中状态的节点上设置Checked属性。
要获取根节点的集合,请使用TreeView的Nodes属性。这将返回一个TreeNodeCollection,我们可以将其编入索引或者添加项目。
回答
我们有来自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)
我们可以将其转换为Cusing PInvoke。首先,我们将这些宏实现为函数,然后添加任何内容
需要其他支持才能使这些功能正常工作。这是我的第一枪。你应该仔细检查我的
代码,尤其是在处理结构的编组时。此外,我们可能想发布消息跨线程
而不是调用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; } }