質問
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
...
}
このコードを、同じことを行う 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 フォーム TreeView コントロールを使用しないのはなぜですか?このコントロールを使用している場合は、コントロールの CheckBoxes プロパティを true に設定してチェック ボックスを有効にし、チェックされた状態で表示するノードに Checked プロパティを設定します。
ルート ノードのコレクションを取得するには、TreeView の Nodes プロパティを使用します。これにより、TreeNodeCollection が返され、これにインデックスを付けたり項目を追加したりできます。