Вопрос

В приложении 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, которую вы затем можете индексировать или добавлять элементы.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top