문제

C++ 앱에는 타사 프로세스에서 실행되는 창을 가리키는 hWnd가 있습니다.이 창에는 COM TreeView 컨트롤을 확장하는 컨트롤이 포함되어 있습니다.이 컨트롤의 CheckState를 얻고 싶습니다.
commctrl.h에서 TreeView_GetRoot(hwnd)를 사용하여 HTREEITEM을 가져오기 위해 hWnd를 사용합니다.

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#에서 이 코드를 다시 만드는 방법을 모르겠습니다 :(

제안?

도움이 되었습니까?

해결책

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;
}
}

다른 팁

Windows Forms TreeView 컨트롤을 사용하지 않는 이유는 무엇입니까?이 컨트롤을 사용하는 경우 컨트롤의 CheckBoxes 속성을 true로 설정하여 확인란을 활성화하고 선택 표시하려는 노드의 Checked 속성을 설정합니다.

루트 노드 컬렉션을 얻으려면 TreeView의 Nodes 속성을 사용하십시오.그러면 항목을 인덱싱하거나 추가할 수 있는 TreeNodeCollection이 반환됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top