遍历和查找外部程序 Tree-View 中的项目

 

  图一

  翻阅SDK手册中关于Tree-View控件的相关章节,发现了几个有用的消息:

  TVM_GETNEXTITEM:得到项目的句柄(参数:TVGN_ROOT得到根句柄,TVGN_NEXTVISIBLE得到下一个可见项目的句柄);

  TVM_EXPAND:展开或折叠指定项目(参数:TVE_EXPAND展开指定项目);

  TVM_SELECTITEM:选中指定项目。

  利用这些消息和SendMessage()函数,我们可以很容易写出遍历代码。

  二:具体实践

  在本文所提供的DEMO中,有一段将十六进制字符串转换成十进制无符号长整型的代码,作用是将用户输入的十六进制TV句柄值转换成十进制并存放在变量dec_sum中。此代码不列入本文讨论的范畴,大家不闲弱智的话就将就着用吧。下面是实现遍历功能的关键代码:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*  Tree-View Control_Demo_SeqShow 1.0 版
*  版权所有 (C) 2006 天津 赵春生
*  2006.08.28
*  本程序能顺序遍历TV控件中的所有项目。
*  代码在Win2000P+SP4 + VC6+SP6测试通过。
*/
if (error==0) //如果在数据验证转换的过程中未出现错误(error==0时无错误)
{
  
   //下面为核心部分:顺序显示(选中)指定Tree-View控件中的所有Item.
  
  hwnd= HWND (dec_sum); //得到转换后的数据
  
   //得到根句柄
  tvitem.hItem=(HTREEITEM)::SendMessage(hwnd, TVM_GETNEXTITEM,TVGN_ROOT, 0x0);
  ::SendMessage(hwnd, TVM_SELECTITEM,TVGN_CARET, ( long )tvitem.hItem); //选中状态
  
   while (( long )tvitem.hItem)
  {
     //当此项目能展开时
     while (::SendMessage(hwnd, TVM_EXPAND,TVE_EXPAND, ( long )tvitem.hItem))
    {
       //选择下一个可见项目
      tvitem.hItem=(HTREEITEM)::SendMessage(hwnd,
          TVM_GETNEXTITEM,TVGN_NEXTVISIBLE,
          ( long )tvitem.hItem);
       //选中状态
      ::SendMessage(hwnd, TVM_SELECTITEM,TVGN_CARET, ( long )tvitem.hItem);
       continue ;
    }
    
     //当不能再展开的时候,选择下一个可见项目
    tvitem.hItem=(HTREEITEM)::SendMessage(hwnd,
        TVM_GETNEXTITEM,TVGN_NEXTVISIBLE,
        ( long )tvitem.hItem);
     //选中状态
    ::SendMessage(hwnd, TVM_SELECTITEM,TVGN_CARET,
          ( long )tvitem.hItem);
    
  }
}
 
//释放内存
CloseHandle(hwnd);
//顺序显示(选中)完毕
三:TV_Demo_SeqShow的使用方法(图2):

  图二

  用SPY++的[Find Window]功能获得目标TV的句柄;

  将句柄值输入到TV_Demo_SeqShow中的[Tree-View Control''s Handle:];

  点击[GO!];

  如果你把[Windows 资源管理器]中的[文件夹]作为目标,那你可要作好心理准备了……如果实在忍受不了这种刺激,干脆把管理器关掉就可以了。

  第二部分:查找外部程序Tree-View中的项目

  一:程序说明:

  我们已经成功得对外部程序Tree-View中的项目进行了遍历,如果能在遍历的过程中读取每一个项目的名称,结合我们给定的项目名进行比较,那么查找某个项目的问题将变得易如反掌。由此可见:关键的问题是如何读取项目的名称。

  读取项目的名称要发送TVM_GETITEM消息,由于该消息需要为LPARAM参数提供一个TV_ITEM结构的地址,在跨进程发送消息的前提下,为了使外部程序正常使用该内存地址,所以我们必须将TV_ITEM结构插入到目标进程的地址空间中去,代码如下:

双击代码全选
1
2
ptvitem=(TVITEM*)VirtualAllocEx(hProcess,NULL, sizeof (TVITEM),MEM_COMMIT,PAGE_READWRITE); //分配内存
WriteProcessMemory(hProcess,ptvitem,&tvitem, sizeof (TVITEM),NULL); //写入内存
在写入内存之前,要将TV_ITEM结构配置好:
双击代码全选
1
2
3
tvitem.mask=TVIF_TEXT;
tvitem.cchTextMax=512;
tvitem.pszText=pItem;
mask要设置成TVIF_TEXT,因为我们需要的是pszText的值;cchTextMax可以设置得稍微大一些,cchTextMax=512即可;hItem的值用来指定究竟哪个项目来接收TVM_GETITEM消息,该值在遍历的过程中动态获得;重要的是用来存放项目名称的缓冲区地址,即pszText参数的设置:和TV_ITEM结构一样,也要把她插入到目标进程的地址空间中去:
双击代码全选
1
pItem=( char *)VirtualAllocEx(hProcess,NULL,16,MEM_COMMIT,PAGE_READWRITE);
二:具体实践:

  作为演示,下面的这段程序将在我们指定的Tree-View控件中查找我们需要的项目,在发现第一个部分匹配的项目后,程序将停止运行,不再进行查找操作。作为演示程序,程序并没有做速度上的优化,大家在具体应用的过程中可自行修改。程序找到目标后的效果图(图 三):

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*  Tree-View Control_Demo_SeqSearch 1.0 版
*  版权所有 (C) 2006 天津 赵春生
*  2006.08.28
*  本程序能按用户指定的项目名称顺序查找TV控件中的项目。
*  代码在Win2000P+SP4 + VC6+SP6测试通过。
*/
if (error==0) //如果在数据验证转换的过程中未出现错误(error==0时无错误)
{
  
   //下面为核心部分:按用户指定的项目名称顺序查找Tree-View控件中的Item.
  
  hwnd= HWND (dec_sum); //得到转换后的数据
  
  GetWindowThreadProcessId(hwnd, &PID);
  
  hProcess=OpenProcess(PROCESS_ALL_ACCESS, false ,PID);
   if (!hProcess)
    MessageBox( "获取进程句柄操作失败!" , "错误!" );
   else
  {
    ptvitem=(TVITEM*)VirtualAllocEx(hProcess,
          NULL,
           sizeof (TVITEM),
          MEM_COMMIT,
          PAGE_READWRITE);
    pItem=( char *)VirtualAllocEx(hProcess,
          NULL,
          16,
          MEM_COMMIT,
          PAGE_READWRITE);
    
     if (!ptvitem)
      MessageBox( "无法分配内存!" , "错误!" );
     else
    {
      MessageBox( "本演示程序将按用户指定的项目名称顺序查找。" , "提示" );
      
      tvitem.mask=TVIF_TEXT;
      tvitem.cchTextMax=512;
      tvitem.pszText=pItem;
      
       //得到根句柄
      tvitem.hItem=(HTREEITEM)::SendMessage(hwnd,
              TVM_GETNEXTITEM,
              TVGN_ROOT,
              0x0);
       //选中状态
      ::SendMessage(hwnd,
            TVM_SELECTITEM,
            TVGN_CARET,
            ( long )tvitem.hItem);
      
       //将设置好的结构插入目标进程
      WriteProcessMemory(hProcess,
              ptvitem,
              &tvitem,   
               sizeof (TVITEM), NULL);
       //发送TVM_GETITEM消息
      ::SendMessage(hwnd,
            TVM_GETITEM,
            0,
            ( LPARAM )ptvitem);
       //获取pszText
      ReadProcessMemory(hProcess, pItem, ItemBuf, 512, NULL);
       //MessageBox(ItemBuf,"ITEM TEXT");
       if ( strnicmp( ItemBuf,
            str_item_text,
             strlen (str_item_text) ) == 0)
      {
        MessageBox( "已经找到!" , "恭喜" );
        Bingo=1;
         //如果根就是我们要找的目标,那么程序执行到这里就可以结束了。
        tvitem.hItem=(HTREEITEM)0x0;
      }
      
       while (( long )tvitem.hItem)
      {
         //当此项目能展开时
         while (::SendMessage(hwnd,
                TVM_EXPAND,
                TVE_EXPAND,
                ( long )tvitem.hItem))
        {
           //选择下一个可见项目
          tvitem.hItem=(HTREEITEM)::SendMessage(hwnd,
              TVM_GETNEXTITEM,TVGN_NEXTVISIBLE,
              ( long )tvitem.hItem);
           //选中状态
          ::SendMessage(hwnd,
            TVM_SELECTITEM,TVGN_CARET,
            ( long )tvitem.hItem);
           //将设置好的结构插入目标进程
          WriteProcessMemory(hProcess,
              ptvitem,
              &tvitem,
               sizeof (TVITEM),
              NULL);
           //发送TVM_GETITEM消息
          ::SendMessage(hwnd,
            TVM_GETITEM,
            0,
            ( LPARAM )ptvitem);
           //获取pszText
          ReadProcessMemory(hProcess,
              pItem,
              ItemBuf,
              512,
              NULL);
           //MessageBox(ItemBuf,"ITEM TEXT");
           if ( strnicmp( ItemBuf,
                str_item_text,
                 strlen (str_item_text) ) == 0)
          {
            MessageBox( "已经找到!" , "恭喜" );
            Bingo=1;
             //如果发现我们要找的目标,那么程序执行到这里就可以结束了。
            tvitem.hItem=(HTREEITEM)0x0;
             break ;
          }
           continue ;
        }
        
         if (Bingo!=1)
        {
           //当不能再展开的时候,选择下一个可见项目
          tvitem.hItem=(HTREEITEM)::SendMessage(hwnd,
                TVM_GETNEXTITEM,TVGN_NEXTVISIBLE,
                ( long )tvitem.hItem);
           //选中状态
          ::SendMessage(hwnd,
                TVM_SELECTITEM,
                TVGN_CARET,
                ( long )tvitem.hItem);
           //将设置好的结构插入目标进程
          WriteProcessMemory(hProcess,
                    ptvitem,
                    &tvitem,
                     sizeof (TVITEM),
                    NULL);
           //发送TVM_GETITEM消息
          ::SendMessage(hwnd,
                TVM_GETITEM,
                0,
                ( LPARAM )ptvitem);
                
          ReadProcessMemory(hProcess,
                  pItem,
                  ItemBuf,
                  512,
                  NULL); //获取pszText
                  
           //MessageBox(ItemBuf,"ITEM TEXT");
           if ( strnicmp( ItemBuf,
                  str_item_text,
                   strlen (str_item_text) ) == 0)
          {
            MessageBox( "已经找到!" , "恭喜" );
            Bingo=1;
             //如果发现我们要找的目标,那么程序执行到这里就可以结束了。
            tvitem.hItem=(HTREEITEM)0x0;
             break ;
          }
        }
        
      }
    }
  }
}
 
//释放内存
CloseHandle(hwnd);
CloseHandle(hProcess);
VirtualFreeEx(hProcess, ptvitem, 0, MEM_RELEASE);
//顺序查找完毕

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
HashMap的几种遍历方式如下: 1. Entry遍历:使用entrySet()方法可以同时遍历Map里面的Key和Value。可以通过迭代器或者foreach循环来实现。例如: ```java HashMap<String, Integer> map = new HashMap<>(); // 添加键值对 map.put("A", 1); map.put("B", 2); map.put("C", 3); // 使用entrySet()方法遍历 for (Map.Entry<String, Integer> entry : map.entrySet()) { String key = entry.getKey(); Integer value = entry.getValue(); // 处理key和value } ``` 2. keySet遍历:使用keySet()方法可以遍历Map里面的Key。可以通过迭代器或者foreach循环来实现。例如: ```java HashMap<String, Integer> map = new HashMap<>(); // 添加键值对 map.put("A", 1); map.put("B", 2); map.put("C", 3); // 使用keySet()方法遍历 for (String key : map.keySet()) { Integer value = map.get(key); // 处理key和value } ``` 3. foreach遍历:在JDK8及以上版本,可以直接使用foreach循环来遍历HashMap的键值对。例如: ```java HashMap<String, Integer> map = new HashMap<>(); // 添加键值对 map.put("A", 1); map.put("B", 2); map.put("C", 3); // 使用foreach遍历 map.forEach((key, value) -> { // 处理key和value }); ``` 4. keySet foreach遍历:在JDK8及以上版本,可以使用keySet()方法获取键的集合,然后使用foreach循环遍历。例如: ```java HashMap<String, Integer> map = new HashMap<>(); // 添加键值对 map.put("A", 1); map.put("B", 2); map.put("C", 3); // 使用keySet foreach遍历 for (String key : map.keySet()) { Integer value = map.get(key); // 处理key和value } ``` 以上是HashMap的几种常见遍历方式。根据具体的需求,可以选择适合的遍历方式来操作HashMap的键值对。 #### 引用[.reference_title] - *1* *3* [Java - 关于HashMap通过keySet遍历kv的二次调用问题](https://blog.csdn.net/Zong_0915/article/details/120905738)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [HashMap的七种遍历方式](https://blog.csdn.net/maojian_ohhey/article/details/115431835)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值