遍历和查找外部程序 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 * http://timw.yeah.net * http://timw.126.com * 本程序能顺序遍历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); //顺序显示(选中)完毕 |
图二
用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); //写入内存 |
| 1 2 3 | tvitem.mask=TVIF_TEXT; tvitem.cchTextMax=512; tvitem.pszText=pItem; |
| 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 * http://timw.yeah.net * http://timw.126.com * 本程序能按用户指定的项目名称顺序查找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); //顺序查找完毕 |
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
