程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 遍歷和查找外部程序Tree-View中的項目

遍歷和查找外部程序Tree-View中的項目

編輯:關於VC++

《金山詞霸2002》中的附錄收集了很多古詩,有時為了尋找一篇古詩,得找很久很久(俺文科很差)。觀察其附錄的結構,發現是個Tree-View控件,如果能查找裡面的項目該有多好。

要查找首先得遍歷,連范圍都確定不好何談查找?所以本篇分兩部分進行講解:第一部分解決遍歷的問題;第二部分解決查找指定項目的問題。

第一部分:遍歷外部程序Tree-View中的項目

一:程序說明:

如圖一所示Tree-View控件的典型結構圖,我們將按照圖示的順序來遍歷其中的項目。

圖一

翻閱SDK手冊中關於Tree-View控件的相關章節,發現了幾個有用的消息:

TVM_GETNEXTITEM:得到項目的句柄(參數:TVGN_ROOT得到根句柄,TVGN_NEXTVISIBLE得到下一個可見項目的句柄);

TVM_EXPAND:展開或折疊指定項目(參數:TVE_EXPAND展開指定項目);

TVM_SELECTITEM:選中指定項目。

利用這些消息和SendMessage()函數,我們可以很容易寫出遍歷代碼。

二:具體實踐

在本文所提供的DEMO中,有一段將十六進制字符串轉換成十進制無符號長整型的代碼,作用是將用戶輸入的十六進制TV句柄值轉換成十進制並存放在變量dec_sum中。此代碼不列入本文討論的范疇,大家不閒弱智的話就將就著用吧。下面是實現遍歷功能的關鍵代碼:

  /*  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);
   //順序顯示(選中)完畢
三: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結構插入到目標進程的地址空間中去,代碼如下:

ptvitem=(TVITEM*)VirtualAllocEx(hProcess,NULL,sizeof(TVITEM),MEM_COMMIT,PAGE_READWRITE);//分配內存
WriteProcessMemory(hProcess,ptvitem,&tvitem,sizeof(TVITEM),NULL);//寫入內存
在寫入內存之前,要將TV_ITEM結構配置好:  tvitem.mask=TVIF_TEXT;
   tvitem.cchTextMax=512;
   tvitem.pszText=pItem;
mask要設置成TVIF_TEXT,因為我們需要的是pszText的值;cchTextMax可以設置得稍微大一些,cchTextMax=512即可;hItem的值用來指定究竟哪個項目來接收TVM_GETITEM消息,該值在遍歷的過程中動態獲得;重要的是用來存放項目名稱的緩沖區地址,即pszText參數的設置:和TV_ITEM結構一樣,也要把她插入到目標進程的地址空間中去:pItem=(char*)VirtualAllocEx(hProcess,NULL,16,MEM_COMMIT,PAGE_READWRITE);二:具體實踐:

作為演示,下面的這段程序將在我們指定的Tree-View控件中查找我們需要的項目,在發現第一個部分匹配的項目後,程序將停止運行,不再進行查找操作。作為演示程序,程序並沒有做速度上的優化,大家在具體應用的過程中可自行修改。程序找到目標後的效果圖(圖 三):

/*  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);
   //順序查找完畢
結束語

代碼寫得不夠幽雅,大家見笑了。在此之前,類似的拙文我已經寫了四篇,希望大家看完後能舉一反三。謝謝。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved