Помощь в переносе команд commctrl на C#.
Вопрос
В приложении C++ у меня есть hWnd, указывающий на окно, работающее в стороннем процессе.Это окно содержит элементы управления, расширяющие элемент управления COM TreeView.Я заинтересован в получении CheckState этого элемента управления.
Я использую hWnd для получения HTREEITEM с помощью TreeView_GetRoot(hwnd) из commctrl.h
hwnd указывает на окно, а hItem — это возвращаемое значение из TreeView_GetRoot(hwnd).Они используются следующим образом:
int iCheckState = TreeView_GetCheckState(hwnd, hItem);
switch (iCheckState)
{
case 0:
// (unchecked)
case 1:
// checked
...
}
Я хочу перенести этот код в приложение C#, которое делает то же самое (отключает CheckState элемента управления TreeView).Я никогда не использовал 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)
Мы можем перевести это на C# с помощью 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;
}
}
Другие советы
Почему вы не используете элемент управления TreeView Windows Forms?Если вы используете этот элемент управления, установите для свойства CheckBoxes элемента управления значение true, чтобы включить флажки, и установите свойство Checked для узлов, которые вы хотите отображать отмеченными.
Чтобы получить коллекцию корневых узлов, используйте свойство Nodes TreeView.Это возвращает TreeNodeCollection, которую вы затем можете индексировать или добавлять элементы.